forked from coracle/flotilla
feat(members): throttle merged profile derivation in SpaceMembers to reduce reactive invalidation
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import {removeUndefined} from "@welshman/lib"
|
||||
import {displayPubkey} from "@welshman/util"
|
||||
import {deriveHandleForPubkey, displayHandle, deriveProfileDisplay} from "@welshman/app"
|
||||
import {readable, type Readable} from "svelte/store"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||
@@ -18,13 +19,27 @@
|
||||
showPubkey?: boolean
|
||||
avatarSize?: number
|
||||
inert?: boolean
|
||||
profileDisplayValue?: string
|
||||
handleValue?: unknown
|
||||
}
|
||||
|
||||
const {pubkey, url, showPubkey, inert, avatarSize = 10}: Props = $props()
|
||||
const {
|
||||
pubkey,
|
||||
url,
|
||||
showPubkey,
|
||||
inert,
|
||||
avatarSize = 10,
|
||||
profileDisplayValue,
|
||||
handleValue,
|
||||
}: Props = $props()
|
||||
|
||||
const relays = removeUndefined([url])
|
||||
const profileDisplay = deriveProfileDisplay(pubkey, relays)
|
||||
const handle = deriveHandleForPubkey(pubkey)
|
||||
const profileDisplay: Readable<string> =
|
||||
profileDisplayValue !== undefined
|
||||
? readable(profileDisplayValue)
|
||||
: deriveProfileDisplay(pubkey, relays)
|
||||
const handle: Readable<any> =
|
||||
handleValue !== undefined ? readable(handleValue) : deriveHandleForPubkey(pubkey)
|
||||
|
||||
const openProfile = () => {
|
||||
pushModal(ProfileDetail, {pubkey, url})
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
<script lang="ts">
|
||||
import {ManagementMethod} from "@welshman/util"
|
||||
import {manageRelay, displayProfileByPubkey} from "@welshman/app"
|
||||
import {
|
||||
manageRelay,
|
||||
displayProfileByPubkey,
|
||||
deriveProfileDisplay,
|
||||
deriveHandleForPubkey,
|
||||
} from "@welshman/app"
|
||||
import {merged, throttled} from "@welshman/store"
|
||||
import {removeUndefined} from "@welshman/lib"
|
||||
import MenuDots from "@assets/icons/menu-dots.svg?dataurl"
|
||||
import UserMinus from "@assets/icons/user-minus.svg?dataurl"
|
||||
import MinusCircle from "@assets/icons/minus-circle.svg?dataurl"
|
||||
@@ -96,6 +103,49 @@
|
||||
})
|
||||
|
||||
let menuPubkey = $state<string | undefined>()
|
||||
let profileDisplayMap = $state<Map<string, string>>(new Map())
|
||||
let handleMap = $state<Map<string, unknown>>(new Map())
|
||||
|
||||
let unsubscribeDisplay = $state<() => void | undefined>()
|
||||
let unsubscribeHandle = $state<() => void | undefined>()
|
||||
|
||||
$effect(() => {
|
||||
unsubscribeDisplay?.()
|
||||
unsubscribeHandle?.()
|
||||
unsubscribeDisplay = undefined
|
||||
unsubscribeHandle = undefined
|
||||
|
||||
if ($members && $members.length > 0) {
|
||||
const relays = removeUndefined([url])
|
||||
const displayStores = $members.map(pubkey => deriveProfileDisplay(pubkey, relays))
|
||||
const handleStores = $members.map(pubkey => deriveHandleForPubkey(pubkey))
|
||||
|
||||
const mergedDisplay = throttled(300, merged(displayStores))
|
||||
const mergedHandle = throttled(300, merged(handleStores))
|
||||
|
||||
unsubscribeDisplay = mergedDisplay.subscribe(values => {
|
||||
const m = new Map<string, string>()
|
||||
for (let i = 0; i < $members.length; i++) m.set($members[i], values[i])
|
||||
profileDisplayMap = m
|
||||
})
|
||||
|
||||
unsubscribeHandle = mergedHandle.subscribe(values => {
|
||||
const m = new Map<string, unknown>()
|
||||
for (let i = 0; i < $members.length; i++) m.set($members[i], values[i])
|
||||
handleMap = m
|
||||
})
|
||||
} else {
|
||||
profileDisplayMap = new Map()
|
||||
handleMap = new Map()
|
||||
}
|
||||
|
||||
return () => {
|
||||
unsubscribeDisplay?.()
|
||||
unsubscribeHandle?.()
|
||||
unsubscribeDisplay = undefined
|
||||
unsubscribeHandle = undefined
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<Modal>
|
||||
@@ -126,7 +176,11 @@
|
||||
<div class="card2 card2-sm bg-alt relative">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<div class="min-w-0 flex-1">
|
||||
<Profile {pubkey} {url} />
|
||||
<Profile
|
||||
{pubkey}
|
||||
{url}
|
||||
profileDisplayValue={profileDisplayMap.get(pubkey)}
|
||||
handleValue={handleMap.get(pubkey)} />
|
||||
</div>
|
||||
{#if canBan || canUnallow}
|
||||
<div class="relative">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {derived} from "svelte/store"
|
||||
import {displayRelayUrl, EVENT_TIME, ZAP_GOAL, THREAD, CLASSIFIED, POLL} from "@welshman/util"
|
||||
import {EVENT_TIME, ZAP_GOAL, THREAD, CLASSIFIED, POLL} from "@welshman/util"
|
||||
import {deriveRelay, deriveRelayDisplay, createSearch, pubkey} from "@welshman/app"
|
||||
import {fly} from "@lib/transition"
|
||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||
@@ -154,7 +154,10 @@
|
||||
</div>
|
||||
{#if $notificationSettings.push && !$shouldNotify}
|
||||
<Icon icon={BellOff} size={3} class="opacity-50" />
|
||||
View Members ({$members.length})
|
||||
{/if}
|
||||
</strong>
|
||||
<Icon icon={AltArrowDown} />
|
||||
</div>
|
||||
</Button>
|
||||
{#if showMenu}
|
||||
<Popover hideOnClick onClose={toggleMenu}>
|
||||
@@ -178,7 +181,6 @@
|
||||
<Icon icon={UserRounded} />
|
||||
{#if $members === undefined}
|
||||
View Members
|
||||
View Members
|
||||
{:else}
|
||||
View Members ({$members.length})
|
||||
{/if}
|
||||
|
||||
@@ -972,6 +972,9 @@ export enum MembershipStatus {
|
||||
Granted,
|
||||
}
|
||||
|
||||
const eventTargetsUser = (event: TrustedEvent, pubkey: string) =>
|
||||
event.pubkey === pubkey || getPubkeyTagValues(event.tags).includes(pubkey)
|
||||
|
||||
export const deriveUserIsSpaceAdmin = memoize((url?: string) => {
|
||||
const store = writable(false)
|
||||
|
||||
@@ -1014,7 +1017,7 @@ export const deriveUserSpaceMembershipStatus = (url: string) => {
|
||||
} else {
|
||||
// No member list available - replay the user's add/remove history.
|
||||
for (const event of sortBy(e => e.created_at, $userAddRemoveEvents)) {
|
||||
if (event.pubkey !== $pubkey) {
|
||||
if (!eventTargetsUser(event, $pubkey!)) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1079,7 +1082,7 @@ export const deriveUserRoomMembershipStatus = (url: string, h: string) => {
|
||||
} else {
|
||||
// No member list available - replay the user's add/remove history.
|
||||
for (const event of sortEventsAsc($userAddRemoveEvents)) {
|
||||
if (event.pubkey !== $pubkey) {
|
||||
if (!eventTargetsUser(event, $pubkey!)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Server from "@assets/icons/server.svg?dataurl"
|
||||
import CloudCheck from "@assets/icons/cloud-check.svg?dataurl"
|
||||
|
||||
import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
|
||||
import ArrowRight from "@assets/icons/arrow-right.svg?dataurl"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
|
||||
Reference in New Issue
Block a user