join-approval #103

Merged
hodlbod merged 2 commits from join-approval into dev 2026-03-19 15:40:35 +00:00
4 changed files with 42 additions and 38 deletions
Showing only changes of commit 7c9b191bdd - Show all commits
+1 -1
View File
@@ -208,7 +208,7 @@
</div>
<div class="flex items-center gap-2">
<input type="checkbox" class="checkbox" bind:checked={values.isClosed} />
<span class="text-sm opacity-75">Ignore requests to join</span>
<span class="text-sm opacity-75">Require admins to approve join requests</span>
Outdated
Review

It seems slightly ambiguous what's going to happen if this box is unchecked. Can any member approve join requests? Are they approved automatically? I'm having trouble coming up with a better phrase though. Maybe something like "Membership requires approval" since all the other boxes here reference membership. Another option would be to change it to a select box labeled something like:

Room Membership: 
- anyone can join
- require admin approval
It seems slightly ambiguous what's going to happen if this box is unchecked. Can any member approve join requests? Are they approved automatically? I'm having trouble coming up with a better phrase though. Maybe something like "Membership requires approval" since all the other boxes here reference membership. Another option would be to change it to a select box labeled something like: ``` Room Membership: - anyone can join - require admin approval ```
Outdated
Review

Good suggestion, I think this form could be nuanced down the road too (e.g. if membership doesn't restrict read/write then it should auto-approve; if read/write aren't gated it doesn't make sense to make the room unlisted, etc).

Good suggestion, I think this form could be nuanced down the road too (e.g. if membership doesn't restrict read/write then it should auto-approve; if read/write aren't gated it doesn't make sense to make the room unlisted, etc).
</div>
</ModalBody>
{@render footer({loading})}
+10 -3
View File
@@ -47,10 +47,10 @@ export const makeFeed = ({
onForwardExhausted?: () => void
at?: number
}) => {
const interval = int(WEEK)
const controller = new AbortController()
const events = writable<TrustedEvent[]>([])
let interval = int(WEEK)
let buffer: TrustedEvent[] = []
let backwardWindow = [at - interval, at]
let forwardWindow = [at, at + interval]
@@ -111,13 +111,20 @@ export const makeFeed = ({
}),
]
const loadTimeframe = (since: number, until: number) => {
request({
const loadTimeframe = async (since: number, until: number) => {
const events = await request({
relays: [url],
autoClose: true,
signal: controller.signal,
filters: filters.map(filter => ({...filter, since, until})),
})
// If we found nothing, accelerate
if (events.length === 0) {
interval = Math.round(interval * 1.1)
} else {
interval = int(WEEK)
}
}
const backwardScroller = createScroller({
+3 -2
View File
@@ -111,6 +111,7 @@ import {
readRoomMeta,
makeRoomMeta,
ManagementMethod,
sortEventsAsc,
sortEventsDesc,
getAddress,
Address,
@@ -287,7 +288,7 @@ export const deriveRelaySignedEvents = (url: string, filters: Filter[] = [{}]) =
derived(
[deriveRelay(url), deriveEventsForUrl(url, filters)],
([relay, events]) => events,
// khatru doesn't support relay.self, uncomment when it's ready
// TODO: khatru doesn't support relay.self, uncomment when it's ready
// filter(spec({pubkey: relay.self}), events)
)
@@ -868,7 +869,7 @@ export const deriveRoomMembers = (url: string, h: string) => {
const members = new Set<string>()
for (const event of sortBy(e => -e.created_at, $events)) {
for (const event of sortEventsAsc($events)) {
const pubkeys = getPubkeyTagValues(event.tags)
if (event.kind === ROOM_ADD_MEMBER) {
+28 -32
View File
@@ -381,22 +381,20 @@
<div class="py-20">
<div class="card2 col-8 m-auto max-w-md items-center text-center">
<p class="opacity-75">You aren't currently a member of this room.</p>
{#if !$room.isClosed}
{#if $membershipStatus === MembershipStatus.Pending}
<Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}>
<Icon icon={ClockCircle} />
Access Pending
</Button>
{:else}
<Button class="btn btn-neutral btn-sm" disabled={joining} onclick={join}>
{#if joining}
<span class="loading loading-spinner loading-sm"></span>
{:else}
<Icon icon={Login2} />
{/if}
Join Room
</Button>
{/if}
{#if $membershipStatus === MembershipStatus.Pending}
<Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}>
<Icon icon={ClockCircle} />
Access Pending
</Button>
{:else}
<Button class="btn btn-neutral btn-sm" disabled={joining} onclick={join}>
{#if joining}
<span class="loading loading-spinner loading-sm"></span>
{:else}
<Icon icon={Login2} />
{/if}
Join Room
</Button>
{/if}
</div>
</div>
@@ -456,22 +454,20 @@
{:else if $room.isRestricted && $membershipStatus !== MembershipStatus.Granted}
<div class="bg-alt card m-4 flex flex-row items-center justify-between px-4 py-3">
<p class="opacity-75">Only members are allowed to post to this room.</p>
{#if !$room.isClosed}
{#if $membershipStatus === MembershipStatus.Pending}
<Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}>
<Icon icon={ClockCircle} />
Access Pending
</Button>
{:else}
<Button class="btn btn-neutral btn-sm" disabled={joining} onclick={join}>
{#if joining}
<span class="loading loading-spinner loading-sm"></span>
{:else}
<Icon icon={Login2} />
{/if}
Ask to Join
</Button>
{/if}
{#if $membershipStatus === MembershipStatus.Pending}
<Button class="btn btn-neutral btn-sm" disabled={leaving} onclick={leave}>
<Icon icon={ClockCircle} />
Access Pending
</Button>
{:else}
<Button class="btn btn-neutral btn-sm" disabled={joining} onclick={join}>
{#if joining}
<span class="loading loading-spinner loading-sm"></span>
{:else}
<Icon icon={Login2} />
{/if}
Ask to Join
</Button>
{/if}
</div>
{:else}