From 98bcf4c3986ee287b4c6bba31736c090ed15014b Mon Sep 17 00:00:00 2001 From: 1amKhush Date: Tue, 21 Apr 2026 12:00:15 +0530 Subject: [PATCH] Polish RBAC role/member stores and remove state-role cycle --- src/app/components/RoleBadge.svelte | 18 +++----- src/app/components/RoomDetail.svelte | 6 +-- src/app/components/RoomMembers.svelte | 6 +-- src/app/components/SpaceMembers.svelte | 13 ++---- src/app/components/SpaceMembersBanned.svelte | 3 +- src/app/core/roles.ts | 45 ++++++++------------ src/app/core/state.ts | 9 ---- 7 files changed, 29 insertions(+), 71 deletions(-) diff --git a/src/app/components/RoleBadge.svelte b/src/app/components/RoleBadge.svelte index 75db3f7d..834fb9dc 100644 --- a/src/app/components/RoleBadge.svelte +++ b/src/app/components/RoleBadge.svelte @@ -4,29 +4,21 @@ import {roleColorToCSS} from "@app/core/roles" type Props = { - role: RoleDefinition | string - label?: string - color?: number + role: RoleDefinition class?: string } - const {role, label, color, ...props}: Props = $props() - - const roleName = $derived(typeof role === "string" ? role : role.name) - const roleLabel = $derived( - label || (typeof role === "string" ? undefined : role.label) || roleName, - ) - const roleColor = $derived(color ?? (typeof role === "string" ? undefined : role.color)) + const {role, ...props}: Props = $props() const style = $derived( - roleColor === undefined + role.color === undefined ? "" - : `color: ${roleColorToCSS(roleColor)}; border-color: ${roleColorToCSS(roleColor)};`, + : `color: ${roleColorToCSS(role.color)}; border-color: ${roleColorToCSS(role.color)};`, ) const className = $derived(cx("badge badge-outline badge-sm", props.class)) - {roleLabel} + {role.label || role.name} diff --git a/src/app/components/RoomDetail.svelte b/src/app/components/RoomDetail.svelte index ab9df8cf..53f34a9a 100644 --- a/src/app/components/RoomDetail.svelte +++ b/src/app/components/RoomDetail.svelte @@ -253,7 +253,7 @@ {/if} - {#if $members !== undefined && $members.length > 0} + {#if $members.length > 0}
Members: @@ -261,10 +261,6 @@
- {:else if $members === undefined} -
- Member list not available from this relay -
{/if} {#if $userIsAdmin && $roleDefinitions.length > 0}
diff --git a/src/app/components/RoomMembers.svelte b/src/app/components/RoomMembers.svelte index d96495f6..5ddbbdb2 100644 --- a/src/app/components/RoomMembers.svelte +++ b/src/app/components/RoomMembers.svelte @@ -83,11 +83,7 @@
- {#if $members === undefined} -
- Member list not available from this relay -
- {:else if $members.length === 0} + {#if $members.length === 0}
No members yet
diff --git a/src/app/components/SpaceMembers.svelte b/src/app/components/SpaceMembers.svelte index 56c314d7..5049e22d 100644 --- a/src/app/components/SpaceMembers.svelte +++ b/src/app/components/SpaceMembers.svelte @@ -22,13 +22,10 @@ import Profile from "@app/components/Profile.svelte" import SpaceMembersAdd from "@app/components/SpaceMembersAdd.svelte" import SpaceMembersBanned from "@app/components/SpaceMembersBanned.svelte" - import { - deriveSpaceMembers, - deriveSpaceBannedPubkeyItems, - deriveSupportedMethods, - } from "@app/core/state" + import {deriveSpaceMembers, deriveSpaceBannedPubkeyItems} from "@app/core/state" import { deriveGroupedSpaceMembers, + deriveSupportedMethods, deriveUserHasSpacePermission, ROOM_PERMISSION_ADD_MEMBER, ROOM_PERMISSION_REMOVE_MEMBER, @@ -126,11 +123,7 @@ {/if} {/if}
- {#if $members === undefined} -
- Member list not available from this space -
- {:else if $members.length === 0} + {#if $members.length === 0}
No members yet
diff --git a/src/app/components/SpaceMembersBanned.svelte b/src/app/components/SpaceMembersBanned.svelte index 135ce86e..6a21f011 100644 --- a/src/app/components/SpaceMembersBanned.svelte +++ b/src/app/components/SpaceMembersBanned.svelte @@ -16,7 +16,8 @@ import ModalSubtitle from "@lib/components/ModalSubtitle.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte" import Profile from "@app/components/Profile.svelte" - import {deriveSpaceBannedPubkeyItems, deriveSupportedMethods} from "@app/core/state" + import {deriveSupportedMethods} from "@app/core/roles" + import {deriveSpaceBannedPubkeyItems} from "@app/core/state" import {addSpaceMembers} from "@app/core/commands" import {pushToast} from "@app/util/toast" diff --git a/src/app/core/roles.ts b/src/app/core/roles.ts index 3fc05126..f2df0779 100644 --- a/src/app/core/roles.ts +++ b/src/app/core/roles.ts @@ -1,8 +1,9 @@ import {derived, readable, type Readable} from "svelte/store" import {first, memoize, removeUndefined, simpleCache, sortBy, uniq} from "@welshman/lib" import {deriveArray, deriveEventsByIdForUrl} from "@welshman/store" -import {pubkey, repository, tracker} from "@welshman/app" +import {pubkey, repository, tracker, manageRelay} from "@welshman/app" import { + ManagementMethod, ROOM_ADD_MEMBER, ROOM_REMOVE_MEMBER, ROOM_EDIT_META, @@ -13,7 +14,6 @@ import { isRelayUrl, } from "@welshman/util" import type {Filter, TrustedEvent} from "@welshman/util" -import {deriveSupportedMethods} from "@app/core/state" export const ROOM_ROLES = 39003 @@ -31,6 +31,15 @@ const ALL_ROOM_PERMISSIONS = [ ROOM_PERMISSION_BAN_USER, ] +export const deriveSupportedMethods = simpleCache(([url]: [string]) => + readable([], set => { + manageRelay(url, { + method: ManagementMethod.SupportedMethods, + params: [], + }).then(({result = []}) => set(result)) + }), +) + export type RoleAccess = "read" | "write" | "join" export type RoleDefinition = { @@ -53,13 +62,13 @@ export type RoomMember = { roles: string[] } -export type MemberRoleInfo = { +type MemberRoleInfo = { pubkey: string roles: RoleDefinition[] primaryRole?: RoleDefinition } -export type MemberRoleGroup = { +type MemberRoleGroup = { key: string role?: RoleDefinition members: MemberRoleInfo[] @@ -77,8 +86,6 @@ type RoomSnapshot = { admins: RoomMember[] } -export type SpaceMemberRoleInfo = MemberRoleInfo - type SpaceRoleState = { hasPermissionTags: boolean userPermissions: Set @@ -283,14 +290,10 @@ const getResolvedRoles = (rolesByName: Map, roleNames: s export const sortRolesDesc = (items: T[]) => sortBy(item => -(item.order ?? -Infinity), items) -export const getRoleLabel = (role: RoleDefinition) => role.label || role.name - export const getRolePermissionsLabel = (role: RoleDefinition) => role.permissions.join(", ") export const getRoleAccessLabel = (role: RoleDefinition) => Array.from(role.access).join(", ") -const getPrimaryRole = (roles: RoleDefinition[]) => first(sortRolesDesc(roles)) - const toMemberRoleInfo = (pubkey: string, roles: RoleDefinition[]): MemberRoleInfo => { const sortedRoles = sortRolesDesc(roles) @@ -304,7 +307,7 @@ const toMemberRoleInfo = (pubkey: string, roles: RoleDefinition[]): MemberRoleIn const sortMemberRoleInfos = (members: MemberRoleInfo[]) => sortBy(member => -(member.primaryRole?.order ?? -Infinity), members) -export const groupMemberRoleInfos = (members: MemberRoleInfo[]) => { +const groupMemberRoleInfos = (members: MemberRoleInfo[]) => { const byRole = new Map() const ungrouped: MemberRoleGroup = { key: "members", @@ -578,19 +581,12 @@ export const deriveHasPermission = (url: string, h: string, kind: number) => ([$permissions, $isSpaceAdmin]) => $isSpaceAdmin || $permissions.has(kind), ) -export const deriveUserRoleColor = (url: string, h: string, targetPubkey: string) => - derived( - [deriveUserRoles(url, h, targetPubkey), deriveRoomRoles(url, h)], - ([$roleNames, $roomRoles]) => - getPrimaryRole(getResolvedRoles($roomRoles.roles, $roleNames))?.color, - ) - export const deriveRoomRoleDefinitions = (url: string, h: string) => derived(deriveRoomRoles(url, h), $roomRoles => sortRolesDesc(Array.from($roomRoles.roles.values())), ) -export const deriveRoomMemberRoleInfo = (url: string, h: string) => +const deriveRoomMemberRoleInfo = (url: string, h: string) => derived([deriveRoomMembers(url, h), deriveRoomRoles(url, h)], ([$members, $roomRoles]) => sortMemberRoleInfos( $members.map(member => @@ -602,16 +598,9 @@ export const deriveRoomMemberRoleInfo = (url: string, h: string) => export const deriveGroupedRoomMembers = (url: string, h: string) => derived(deriveRoomMemberRoleInfo(url, h), $members => groupMemberRoleInfos($members)) -export const getRoleSortKey = (url: string, h: string, targetPubkey: string) => - derived( - [deriveUserRoles(url, h, targetPubkey), deriveRoomRoles(url, h)], - ([$roleNames, $roomRoles]) => - getPrimaryRole(getResolvedRoles($roomRoles.roles, $roleNames))?.order, - ) - -export const deriveSpaceMemberRoleInfo = (url: string) => +const deriveSpaceMemberRoleInfo = (url: string) => derived(deriveSpaceRoleState(url), $spaceRoleState => { - const roleInfoByPubkey = new Map() + const roleInfoByPubkey = new Map() for (const [pubkey, roles] of $spaceRoleState.memberRoles.entries()) { roleInfoByPubkey.set(pubkey, toMemberRoleInfo(pubkey, roles)) diff --git a/src/app/core/state.ts b/src/app/core/state.ts index b27f30e2..49d7cc97 100644 --- a/src/app/core/state.ts +++ b/src/app/core/state.ts @@ -1300,15 +1300,6 @@ export const deriveSocketStatus = (url: string) => }), ) -export const deriveSupportedMethods = simpleCache(([url]: [string]) => { - return readable([], set => { - manageRelay(url, { - method: ManagementMethod.SupportedMethods, - params: [], - }).then(({result = []}) => set(result)) - }) -}) - export const deriveHasLivekit = simpleCache(([url]: [string]) => readable(undefined, set => { checkRelayHasLivekit(url).then(has => set(has))