Refactor role view models and member grouping

This commit is contained in:
2026-04-21 03:19:21 +05:30
parent 5a926ab6cf
commit 7259e4d2cf
6 changed files with 144 additions and 201 deletions
+99 -14
View File
@@ -1,4 +1,4 @@
import {derived, readable} from "svelte/store"
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"
@@ -53,6 +53,18 @@ export type RoomMember = {
roles: string[]
}
export type MemberRoleInfo = {
pubkey: string
roles: RoleDefinition[]
primaryRole?: RoleDefinition
}
export type MemberRoleGroup = {
key: string
role?: RoleDefinition
members: MemberRoleInfo[]
}
type ParsedRoleState = {
roles: Map<string, RoleDefinition>
hasPermissionTags: boolean
@@ -65,11 +77,7 @@ type RoomSnapshot = {
admins: RoomMember[]
}
export type SpaceMemberRoleInfo = {
roles: RoleDefinition[]
primaryRole?: RoleDefinition
sortKey: number
}
export type SpaceMemberRoleInfo = MemberRoleInfo
type SpaceRoleState = {
hasPermissionTags: boolean
@@ -275,8 +283,62 @@ const getResolvedRoles = (rolesByName: Map<string, RoleDefinition>, roleNames: s
export const sortRolesDesc = <T extends {order?: number}>(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)
return {
pubkey,
roles: sortedRoles,
primaryRole: first(sortedRoles),
}
}
const sortMemberRoleInfos = (members: MemberRoleInfo[]) =>
sortBy(member => -(member.primaryRole?.order ?? -Infinity), members)
export const groupMemberRoleInfos = (members: MemberRoleInfo[]) => {
const byRole = new Map<string, MemberRoleGroup>()
const ungrouped: MemberRoleGroup = {
key: "members",
members: [],
}
for (const member of sortMemberRoleInfos(members)) {
if (!member.primaryRole) {
ungrouped.members.push(member)
continue
}
const key = member.primaryRole.name
if (!byRole.has(key)) {
byRole.set(key, {
key,
role: member.primaryRole,
members: [],
})
}
byRole.get(key)!.members.push(member)
}
const groups = sortBy(group => -(group.role?.order ?? -Infinity), Array.from(byRole.values()))
if (ungrouped.members.length > 0) {
groups.push(ungrouped)
}
return groups
}
const deriveRoomRoleAssignments = simpleCache(([url, h]: [string, string]) =>
derived(
[deriveRoomRoleState(url, h), deriveRoomMembers(url, h), deriveRoomAdmins(url, h)],
@@ -523,6 +585,23 @@ export const deriveUserRoleColor = (url: string, h: string, targetPubkey: string
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) =>
derived([deriveRoomMembers(url, h), deriveRoomRoles(url, h)], ([$members, $roomRoles]) =>
sortMemberRoleInfos(
$members.map(member =>
toMemberRoleInfo(member.pubkey, getResolvedRoles($roomRoles.roles, member.roles)),
),
),
)
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)],
@@ -535,17 +614,23 @@ export const deriveSpaceMemberRoleInfo = (url: string) =>
const roleInfoByPubkey = new Map<string, SpaceMemberRoleInfo>()
for (const [pubkey, roles] of $spaceRoleState.memberRoles.entries()) {
const sortedRoles = sortRolesDesc(roles)
const primaryRole = first(sortedRoles)
roleInfoByPubkey.set(pubkey, {
roles: sortedRoles,
primaryRole,
sortKey: primaryRole?.order ?? -Infinity,
})
roleInfoByPubkey.set(pubkey, toMemberRoleInfo(pubkey, roles))
}
return roleInfoByPubkey
})
export const deriveSpaceMemberRoles = (url: string, targetPubkey: string) =>
derived(
deriveSpaceMemberRoleInfo(url),
$spaceMemberRoles => $spaceMemberRoles.get(targetPubkey)?.roles || [],
)
export const deriveGroupedSpaceMembers = (url: string, members: Readable<string[]>) =>
derived([members, deriveSpaceMemberRoleInfo(url)], ([$members, $spaceMemberRoles]) =>
groupMemberRoleInfos(
$members.map(pubkey => $spaceMemberRoles.get(pubkey) || toMemberRoleInfo(pubkey, [])),
),
)
export const roleColorToCSS = (hue: number) => `oklch(0.75 0.15 ${(hue * 360) / 255})`