Optimize deriveUserItem, avoid double load of quotes
This commit is contained in:
parent
2a5849afcb
commit
934f1cdf10
12 changed files with 75 additions and 78 deletions
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import {preventDefault} from "@lib/html"
|
||||
import {RelayLists} from "@welshman/app"
|
||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||
import AltArrowRight from "@assets/icons/alt-arrow-right.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
|
|
@ -20,7 +21,7 @@
|
|||
|
||||
const {next}: Props = $props()
|
||||
|
||||
const userRelayList = deriveUserItem($app => $relayLists)
|
||||
const userRelayList = deriveUserItem(RelayLists)
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,21 @@
|
|||
import * as nip19 from "nostr-tools/nip19"
|
||||
import {derived, writable} from "svelte/store"
|
||||
import {removeUndefined} from "@welshman/lib"
|
||||
import type {Maybe} from "@welshman/lib"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {Address, MESSAGE, eventOutbox, relays as relaySelections, seen} from "@welshman/util"
|
||||
import {
|
||||
Address,
|
||||
MESSAGE,
|
||||
eventOutbox,
|
||||
getIdFilters,
|
||||
relays as relaySelections,
|
||||
seen,
|
||||
} from "@welshman/util"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import NoteCard from "@app/components/NoteCard.svelte"
|
||||
import NoteContent from "@app/components/NoteContent.svelte"
|
||||
import NoteContentMinimal from "@app/components/NoteContentMinimal.svelte"
|
||||
import {router} from "@app/core"
|
||||
import {network, router} from "@app/core"
|
||||
import {deriveEvent} from "@app/repository"
|
||||
import {entityLink} from "@app/env"
|
||||
import {goToEvent} from "@app/routes"
|
||||
|
|
@ -26,12 +32,16 @@
|
|||
const {id, identifier, kind, pubkey, relays = []} = value
|
||||
const idOrAddress = id || new Address(kind, pubkey, identifier).toString()
|
||||
const ref = {id, pubkey, kind, identifier, relays}
|
||||
const hints = removeUndefined([...relays, url])
|
||||
|
||||
const mergedRelays = writable(hints)
|
||||
|
||||
const quote = deriveEvent(idOrAddress, hints)
|
||||
|
||||
// Start with the hints we were handed, then widen to everything the router can work out:
|
||||
// where the quoted event has been seen, its author's outbox, and — since whoever quoted it
|
||||
// must have seen it — the relays the quoting event came from.
|
||||
const mergedRelays = writable(removeUndefined([...relays, url]))
|
||||
|
||||
// must have seen it — the relays the quoting event came from. Resolving that may take a
|
||||
// round trip for the author's relay list, so only load again if the hints came up empty.
|
||||
$router.resolver
|
||||
.relays([
|
||||
...relaySelections(removeUndefined([url])),
|
||||
|
|
@ -39,11 +49,13 @@
|
|||
eventOutbox(ref),
|
||||
seen(event, 0.5),
|
||||
])
|
||||
.then(urls => mergedRelays.set(urls))
|
||||
.then(urls => {
|
||||
mergedRelays.set(urls)
|
||||
|
||||
const quote = derived(mergedRelays, ($mergedRelays, set: (event: Maybe<TrustedEvent>) => void) =>
|
||||
deriveEvent(idOrAddress, $mergedRelays).subscribe(set),
|
||||
)
|
||||
if (!$quote) {
|
||||
$network.load({filters: getIdFilters([idOrAddress]), relays: urls})
|
||||
}
|
||||
})
|
||||
|
||||
const entity = derived(mergedRelays, $mergedRelays =>
|
||||
id
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import type {Snippet} from "svelte"
|
||||
import cx from "classnames"
|
||||
import {Profiles} from "@welshman/app"
|
||||
import Letter from "@assets/icons/letter.svg?dataurl"
|
||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||
import Widget from "@assets/icons/widget-4.svg?dataurl"
|
||||
|
|
@ -17,7 +18,7 @@
|
|||
import {pushModal} from "@app/modal"
|
||||
import {notifications} from "@app/notifications"
|
||||
import {goToChat, makeSpacePath} from "@app/routes"
|
||||
import {deriveUserItem, profiles} from "@app/core"
|
||||
import {deriveUserItem} from "@app/core"
|
||||
|
||||
type Props = {
|
||||
children?: Snippet
|
||||
|
|
@ -25,7 +26,7 @@
|
|||
|
||||
const {children}: Props = $props()
|
||||
|
||||
const userProfile = deriveUserItem($app => $profiles)
|
||||
const userProfile = deriveUserItem(Profiles)
|
||||
|
||||
const chatHandler = () => goToChat()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import {readable} from "svelte/store"
|
||||
import {clamp} from "@welshman/lib"
|
||||
import {WotScope} from "@welshman/app"
|
||||
import Shield from "@assets/icons/shield-minimalistic.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import ProfileCircles from "@app/components/ProfileCircles.svelte"
|
||||
|
|
@ -14,38 +14,18 @@
|
|||
const {pubkey: target, isSelf = false}: Props = $props()
|
||||
|
||||
const profileDisplay = $profiles.display(target).$
|
||||
const followers = $wot.followers(target).$
|
||||
|
||||
const score = $derived($wot.wotScore($user.pubkey, target).$)
|
||||
|
||||
const followsWhoFollow = $derived(
|
||||
!isSelf && $user.pubkey
|
||||
? $wot.followsWhoFollow($user.pubkey, target).$
|
||||
: readable<string[]>([]),
|
||||
)
|
||||
|
||||
const followerCount = $derived($followers.length)
|
||||
|
||||
const networkFollowCount = $derived(isSelf ? followerCount : $followsWhoFollow.length)
|
||||
|
||||
const displayScore = $derived(isSelf ? followerCount : Math.round(clamp([0, 100], $score)))
|
||||
const progress = $derived(isSelf ? undefined : displayScore)
|
||||
const followers = $wot.followers(target, WotScope.Follows).$
|
||||
const score = $wot.score(target, WotScope.Follows).$
|
||||
const display = $derived(isSelf ? $followers.length : clamp([0, 100], $score))
|
||||
|
||||
const trustMessage = $derived.by(() => {
|
||||
if (isSelf) {
|
||||
if (followerCount === 0) return "No followers in your network yet."
|
||||
|
||||
return `Followed by ${followerCount}+ people in your network.`
|
||||
if ($followers.length > 0) {
|
||||
return `Followed by ${$followers.length}+ people in your network.`
|
||||
}
|
||||
|
||||
if (networkFollowCount > 0) {
|
||||
return `Followed by ${networkFollowCount}+ people in your network.`
|
||||
}
|
||||
|
||||
if (displayScore >= 50) return "This user is highly trusted in your network."
|
||||
if (displayScore >= 10) return "This user has some trust in your network."
|
||||
|
||||
return "This user is not well known in your network."
|
||||
return isSelf
|
||||
? "No followers in your network yet."
|
||||
: "This user is not well known in your network."
|
||||
})
|
||||
|
||||
$effect(() => {
|
||||
|
|
@ -66,24 +46,24 @@
|
|||
<span class="text-sm opacity-75">{isSelf ? "Followers" : "Trust score"}</span>
|
||||
<span class="text-lg font-semibold">
|
||||
{#if isSelf}
|
||||
{displayScore}
|
||||
{display}
|
||||
{:else}
|
||||
{displayScore} / 100
|
||||
{display} / 100
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
{#if !isSelf}
|
||||
<progress class="progress w-full" value={progress} max="100"></progress>
|
||||
<progress class="progress w-full" value={display} max="100"></progress>
|
||||
{/if}
|
||||
<p class="text-sm opacity-75">{trustMessage}</p>
|
||||
</div>
|
||||
{#if $followsWhoFollow.length > 0}
|
||||
{#if !isSelf && $followers.length > 0}
|
||||
<div class="flex flex-col gap-2 border-t border-line pt-4">
|
||||
<p class="text-sm font-medium">People who follow {$profileDisplay}</p>
|
||||
<ProfileCircles pubkeys={$followsWhoFollow} limit={5} />
|
||||
<ProfileCircles pubkeys={$followers} limit={5} />
|
||||
<p class="text-sm opacity-75">
|
||||
{$followsWhoFollow.length}
|
||||
{$followsWhoFollow.length === 1 ? "person" : "people"} you follow also follow
|
||||
{$followers.length}
|
||||
{$followers.length === 1 ? "person" : "people"} you follow also follow
|
||||
{$profileDisplay}.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts">
|
||||
import {getWalletAddress} from "@welshman/util"
|
||||
import {Profiles} from "@welshman/app"
|
||||
import {errorMessage} from "@lib/util"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
|
|
@ -13,7 +14,7 @@
|
|||
import {clearModals} from "@app/modal"
|
||||
import {pushToast} from "@app/toast"
|
||||
|
||||
const userProfile = deriveUserItem($app => $profiles)
|
||||
const userProfile = deriveUserItem(Profiles)
|
||||
|
||||
const lud16 = getWalletAddress(wallet.get()!)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import {sleep} from "@welshman/lib"
|
||||
import {WalletType} from "@welshman/util"
|
||||
import type {NWCInfo} from "@welshman/util"
|
||||
import {Profiles} from "@welshman/app"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import Cpu from "@assets/icons/cpu-bolt.svg?dataurl"
|
||||
import Lock from "@assets/icons/lock-keyhole.svg?dataurl"
|
||||
|
|
@ -23,12 +24,12 @@
|
|||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import Divider from "@lib/components/Divider.svelte"
|
||||
import WalletAsReceivingAddress from "@app/components/WalletAsReceivingAddress.svelte"
|
||||
import {deriveUserItem, profiles} from "@app/core"
|
||||
import {deriveUserItem} from "@app/core"
|
||||
import {getWebLn, wallet} from "@app/lightning"
|
||||
import {pushToast} from "@app/toast"
|
||||
import {pushModal} from "@app/modal"
|
||||
|
||||
const userProfile = deriveUserItem($app => $profiles)
|
||||
const userProfile = deriveUserItem(Profiles)
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import {clamp} from "@welshman/lib"
|
||||
import {WotScope} from "@welshman/app"
|
||||
import {followLists, user, wot} from "@app/core"
|
||||
|
||||
interface Props {
|
||||
|
|
@ -27,7 +28,7 @@
|
|||
const radius = 6
|
||||
const center = radius + 1
|
||||
|
||||
const score = $derived($wot.wotScore($user.pubkey, target).$)
|
||||
const score = $derived($wot.score(target, WotScope.Follows).$)
|
||||
const follows = $derived($followLists.one($user.pubkey))
|
||||
const active = $derived(($follows?.pubkeys() ?? []).includes(target))
|
||||
const normalizedScore = $derived(clamp([0, max], $score) / max)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type {Readable} from "svelte/store"
|
|||
import {always} from "@welshman/lib"
|
||||
import type {Maybe} from "@welshman/lib"
|
||||
import {withGetter} from "@welshman/store"
|
||||
import type {ItemsByKey, ReadableWithGetter} from "@welshman/store"
|
||||
import type {ReadableWithGetter} from "@welshman/store"
|
||||
import {
|
||||
App,
|
||||
BlockedRelayLists,
|
||||
|
|
@ -37,7 +37,7 @@ import {
|
|||
appPolicyRelayStats,
|
||||
appPolicyWraps,
|
||||
} from "@welshman/app"
|
||||
import type {AppPolicy, IApp, Projection, Session} from "@welshman/app"
|
||||
import type {AppPolicy, DerivedPlugin, Plugin, Session} from "@welshman/app"
|
||||
import type {BaseEventReader, EventWriter, KindFactory} from "@welshman/domain"
|
||||
import {maybeMakeRelayMockAdapter} from "@lib/test/relayMocks"
|
||||
import {DEFAULT_RELAYS, DEFAULT_SEARCH_RELAYS, DUFFLEPUD_URL, INDEXER_RELAYS} from "@app/env"
|
||||
|
|
@ -106,17 +106,20 @@ export const user = withGetter(derived(app, $app => User.require($app)))
|
|||
export const fromApp = <T>(read: ($app: App) => Readable<T>): Readable<T> =>
|
||||
derived(app, ($app, set: (value: T) => void) => read($app).subscribe(set))
|
||||
|
||||
// The signed-in user's entry in a keyed collection, e.g.
|
||||
// deriveUserItem($app => $app.use(Profiles)).
|
||||
export const deriveUserItem = <T>(getPlugin: ($app: App) => {index: Projection<ItemsByKey<T>>}) =>
|
||||
derived(
|
||||
[app, fromApp($app => getPlugin($app).index.$)],
|
||||
([$app, $index]: [App, ItemsByKey<T>]) => {
|
||||
const $pubkey = $app.user?.pubkey
|
||||
// The signed-in user's entry in a keyed collection, e.g. deriveUserItem(Profiles).
|
||||
export const deriveUserItem = <T>(Ctor: Plugin<DerivedPlugin<T>>) =>
|
||||
derived(app, ($app, set: (item: Maybe<T>) => void) => {
|
||||
let previous: Maybe<T>
|
||||
|
||||
return $pubkey ? $index.get($pubkey) : undefined
|
||||
},
|
||||
)
|
||||
return $app.use(Ctor).index.$.subscribe($index => {
|
||||
const item = $app.user ? $index.get($app.user.pubkey) : undefined
|
||||
|
||||
if (item !== previous) {
|
||||
previous = item
|
||||
set(item)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
export const login = async ($session: Session) => {
|
||||
const $user = await User.fromSession($session)
|
||||
|
|
@ -135,8 +138,7 @@ export const login = async ($session: Session) => {
|
|||
// Plugins bound to the current app, so `$profiles` in a component and `profiles.get()` in a
|
||||
// module both stay pointed at the right one after login swaps it. Flotilla's own plugins expose
|
||||
// themselves the same way.
|
||||
export const usePlugin = <T>(Ctor: new (app: IApp) => T) =>
|
||||
withGetter(derived(app, $app => $app.use(Ctor)))
|
||||
export const usePlugin = <T>(Ctor: Plugin<T>) => withGetter(derived(app, $app => $app.use(Ctor)))
|
||||
|
||||
export const blockedRelayLists = usePlugin(BlockedRelayLists)
|
||||
export const blossomServerLists = usePlugin(BlossomServerLists)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import {get, writable} from "svelte/store"
|
||||
import {on, call, dissoc, assoc, noop, uniq} from "@welshman/lib"
|
||||
import {on, call, dissoc, assoc, uniq} from "@welshman/lib"
|
||||
import {isDVMKind, isEphemeralKind, verifyEvent} from "@welshman/util"
|
||||
import type {Socket, RelayMessage, ClientMessage} from "@welshman/net"
|
||||
import {
|
||||
AuthStatus,
|
||||
SocketEvent,
|
||||
isRelayEvent,
|
||||
isRelayOk,
|
||||
|
|
@ -15,7 +14,6 @@ import {
|
|||
isClientNegOpen,
|
||||
isClientNegClose,
|
||||
} from "@welshman/net"
|
||||
import {merged} from "@welshman/store"
|
||||
import {
|
||||
BlockedRelayLists,
|
||||
MessagingRelayLists,
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ export const publishRoomQuote = async ({
|
|||
|
||||
// User
|
||||
|
||||
export const userRoomList = deriveUserItem($app => $app.use(RoomLists))
|
||||
export const userRoomList = deriveUserItem(RoomLists)
|
||||
|
||||
export const userSpaceUrls = derived(userRoomList, $userRoomList => $userRoomList?.urls() ?? [])
|
||||
|
||||
|
|
|
|||
|
|
@ -96,13 +96,13 @@ const pullAndListen = ({url, signal, filters}: SyncOpts) => {
|
|||
})
|
||||
}
|
||||
|
||||
const userRoomList = deriveUserItem($app => $app.use(RoomLists))
|
||||
const userRoomList = deriveUserItem(RoomLists)
|
||||
|
||||
const userRelayList = deriveUserItem($app => $app.use(RelayLists))
|
||||
const userRelayList = deriveUserItem(RelayLists)
|
||||
|
||||
const userFollowList = deriveUserItem($app => $app.use(FollowLists))
|
||||
const userFollowList = deriveUserItem(FollowLists)
|
||||
|
||||
const userMessagingRelayList = deriveUserItem($app => $app.use(MessagingRelayLists))
|
||||
const userMessagingRelayList = deriveUserItem(MessagingRelayLists)
|
||||
|
||||
const getSpaceUrls = ($roomList: Maybe<RoomListReader>) =>
|
||||
PLATFORM_RELAYS.length > 0 ? PLATFORM_RELAYS : ($roomList?.urls() ?? [])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import {publish} from "@welshman/app"
|
||||
import {BlossomServerLists, MuteLists, publish} from "@welshman/app"
|
||||
import NotesMinimalistic from "@assets/icons/notes-minimalistic.svg?dataurl"
|
||||
import AddCircle from "@assets/icons/add-circle.svg?dataurl"
|
||||
import {preventDefault} from "@lib/html"
|
||||
|
|
@ -17,8 +17,8 @@
|
|||
import {PLATFORM_NAME} from "@app/env"
|
||||
import {userSettingsValues, publishSettings} from "@app/settings"
|
||||
|
||||
const userMuteList = deriveUserItem($app => $muteLists)
|
||||
const userBlossomServerList = deriveUserItem($app => $blossomServerLists)
|
||||
const userMuteList = deriveUserItem(MuteLists)
|
||||
const userBlossomServerList = deriveUserItem(BlossomServerLists)
|
||||
|
||||
const reset = () => {
|
||||
settings = {...$userSettingsValues}
|
||||
|
|
|
|||
Loading…
Reference in a new issue