mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-14 09:26:52 +02:00
Display user's blossom servers in menu (#90)
* feat: Display blossom servers in user menu with caching Implements caching and display of user's blossom server lists (kind 10063) in the user menu dropdown. **Key Changes:** 1. **Database Schema (db.ts)**: - Added `CachedBlossomServerList` interface - Added `blossomServers` table to Dexie v15 - Indexed by pubkey and updatedAt for efficient querying 2. **Caching Service (blossom-server-cache.ts)**: - Dual-layer caching: LRU memory cache (100 entries) + Dexie persistent cache - 24-hour TTL to reduce network requests - Auto-caches kind:10063 events from EventStore - Mirrors relay-list-cache pattern for consistency 3. **Sync Hooks**: - `useBlossomServerCacheSync`: Subscribes to EventStore for auto-caching kind:10063 events - `useAccountSync`: Extended to fetch and watch active account's blossom servers 4. **State Management**: - Added `blossomServers` field to `activeAccount` in GrimoireState - Created `setActiveAccountBlossomServers` pure function and callback - Reactive updates when user's server list changes 5. **User Menu UI (user-menu.tsx)**: - Added blossom servers section with HardDrive icon - Shows server count badge (e.g., "3 servers") - Clickable links open servers in new tabs - Displays only when user has configured servers **Architecture:** - Follows existing relay list caching pattern for consistency - Reactive: UI auto-updates when kind:10063 events arrive - Incremental sync: Fetches on login, caches for 24h - Performance: Memory cache for <1ms lookups, Dexie for persistence **Testing:** - Build: ✓ No TypeScript errors - Tests: ✓ All 838 tests passing * feat: Open blossom server file lists directly from menus **User Menu & Profile Viewer Improvements:** 1. **Enhanced Click Behavior**: - Clicking a blossom server now opens the file list for that server - Shows blobs uploaded by the user (user menu) or profile owner (profile viewer) - Pre-selects the clicked server in the dropdown 2. **UX Improvements**: - Removed server count from user menu label (cleaner UI) - Added `cursor-crosshair` to blossom server items (consistent with other clickable items) - Removed external link icon (not opening external URL anymore) 3. **Technical Changes**: - Updated `ListBlobsView` to accept optional `serverUrl` prop for pre-selection - User menu: Opens `blossom list` with `serverUrl` for active user - Profile viewer: Opens `blossom list` with both `pubkey` and `serverUrl` **Flow:** - User menu → Click server → Opens files for active user on that server - Profile viewer → Click server → Opens files for viewed user on that server * fix: Properly fetch blossom servers for any profile view **Problem:** Blossom servers were only visible for the logged-in user's profile, not for other users' profiles being viewed. **Solution:** Enhanced ProfileViewer blossom server fetching with multi-layer approach: 1. **Cache-first loading**: Check blossomServerCache for instant display 2. **EventStore check**: Use existing cached event if available 3. **Reactive subscription**: Subscribe to EventStore for real-time updates 4. **Network fetch**: Use addressLoader to fetch latest from relays 5. **Auto-caching**: Update cache when new events arrive **Benefits:** - Blossom servers now display for ANY user's profile - Instant display from cache (< 1ms) - Reactive updates when data changes - Proper cache hydration for future visits - Consistent with relay list fetching pattern **Technical:** - Imported and integrated blossomServerCache service - Added cache check before network fetch - Separated EventStore subscription from network fetch - Added cache updates on event arrival --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,12 +5,17 @@ import { useGrimoire } from "@/core/state";
|
||||
import { addressLoader } from "@/services/loaders";
|
||||
import type { RelayInfo } from "@/types/app";
|
||||
import { normalizeRelayURL } from "@/lib/relay-url";
|
||||
import { getServersFromEvent } from "@/services/blossom";
|
||||
|
||||
/**
|
||||
* Hook that syncs active account with Grimoire state and fetches relay lists
|
||||
* Hook that syncs active account with Grimoire state and fetches relay lists and blossom servers
|
||||
*/
|
||||
export function useAccountSync() {
|
||||
const { setActiveAccount, setActiveAccountRelays } = useGrimoire();
|
||||
const {
|
||||
setActiveAccount,
|
||||
setActiveAccountRelays,
|
||||
setActiveAccountBlossomServers,
|
||||
} = useGrimoire();
|
||||
const eventStore = useEventStore();
|
||||
|
||||
// Watch active account from accounts service
|
||||
@@ -83,4 +88,41 @@ export function useAccountSync() {
|
||||
storeSubscription.unsubscribe();
|
||||
};
|
||||
}, [activeAccount?.pubkey, eventStore, setActiveAccountRelays]);
|
||||
|
||||
// Fetch and watch blossom server list (kind 10063) when account changes
|
||||
useEffect(() => {
|
||||
if (!activeAccount?.pubkey) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pubkey = activeAccount.pubkey;
|
||||
let lastBlossomEventId: string | undefined;
|
||||
|
||||
// Subscribe to kind 10063 (blossom server list)
|
||||
const subscription = addressLoader({
|
||||
kind: 10063,
|
||||
pubkey,
|
||||
identifier: "",
|
||||
}).subscribe();
|
||||
|
||||
// Watch for blossom server list event in store
|
||||
const storeSubscription = eventStore
|
||||
.replaceable(10063, pubkey, "")
|
||||
.subscribe((blossomListEvent) => {
|
||||
if (!blossomListEvent) return;
|
||||
|
||||
// Only process if this is a new event
|
||||
if (blossomListEvent.id === lastBlossomEventId) return;
|
||||
lastBlossomEventId = blossomListEvent.id;
|
||||
|
||||
// Parse servers from event
|
||||
const servers = getServersFromEvent(blossomListEvent);
|
||||
setActiveAccountBlossomServers(servers);
|
||||
});
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
storeSubscription.unsubscribe();
|
||||
};
|
||||
}, [activeAccount?.pubkey, eventStore, setActiveAccountBlossomServers]);
|
||||
}
|
||||
|
||||
24
src/hooks/useBlossomServerCacheSync.ts
Normal file
24
src/hooks/useBlossomServerCacheSync.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Hook to keep blossom server cache in sync with EventStore
|
||||
*
|
||||
* Subscribes to kind:10063 events and automatically caches them in Dexie.
|
||||
* Should be used once at app root level.
|
||||
*/
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useEventStore } from "applesauce-react/hooks";
|
||||
import blossomServerCache from "@/services/blossom-server-cache";
|
||||
|
||||
export function useBlossomServerCacheSync() {
|
||||
const eventStore = useEventStore();
|
||||
|
||||
useEffect(() => {
|
||||
// Subscribe to EventStore for auto-caching
|
||||
blossomServerCache.subscribeToEventStore(eventStore);
|
||||
|
||||
// Cleanup on unmount
|
||||
return () => {
|
||||
blossomServerCache.unsubscribe();
|
||||
};
|
||||
}, [eventStore]);
|
||||
}
|
||||
Reference in New Issue
Block a user