diff --git a/docs/event-types-panel-redesign.org b/docs/event-types-panel-redesign.org index 531c257..c3bbccb 100644 --- a/docs/event-types-panel-redesign.org +++ b/docs/event-types-panel-redesign.org @@ -16,19 +16,19 @@ Clean implementation plan for the event network visualization, focusing on perfo * Implementation Phases ** Phase 1: Tag Anchor Controls Migration -- Move tag type selection from Settings to Legend -- Move expansion depth control from Settings to Legend -- Move requirePublications checkbox from Settings to Legend -- Use native HTML button instead of flowbite Toggle component -- Clean up Settings panel +- +Move tag type selection from Settings to Legend+ +- +Move expansion depth control from Settings to Legend+ +- +Move requirePublications checkbox from Settings to Legend+ +- +Use native HTML button instead of flowbite Toggle component+ +- +Clean up Settings panel+ ** Phase 2: Person Visualizer -- Add collapsible "Person Visualizer" section in Legend -- Display all event authors (pubkeys) as list items -- Fetch display names from kind 0 events -- Render person nodes as diamond shapes in graph -- Default all person nodes to disabled state -- Click to toggle individual person visibility +- +Add collapsible "Person Visualizer" section in Legend+ +- +Display all event authors (pubkeys) as list items+ +- +Fetch display names from kind 0 events+ +- +Render person nodes as diamond shapes in graph+ +- +Default all person nodes to disabled state+ +- +Click to toggle individual person visibility+ ** Phase 3: State Management Fixes - Replace reactive Set with object/map for disabled states @@ -89,4 +89,4 @@ const contentEvents = await $ndkInstance.fetchEvents({ 2. **Stability**: Avoids infinite loops and reactive state issues 3. **UX**: Smooth, instant toggle without freezing 4. **Maintainability**: Clear separation of concerns -5. **Scalability**: Handles large numbers of nodes efficiently \ No newline at end of file +5. **Scalability**: Handles large numbers of nodes efficiently diff --git a/src/lib/components/EventTypeConfig.svelte b/src/lib/components/EventTypeConfig.svelte index 09fa532..8d8e17c 100644 --- a/src/lib/components/EventTypeConfig.svelte +++ b/src/lib/components/EventTypeConfig.svelte @@ -6,10 +6,12 @@ let { onReload = () => {}, - eventCounts = {} + eventCounts = {}, + profileStats = { totalFetched: 0, displayLimit: 50 } } = $props<{ onReload?: () => void; eventCounts?: { [kind: number]: number }; + profileStats?: { totalFetched: number; displayLimit: number }; }>(); let newKind = $state(''); @@ -122,16 +124,32 @@ - - handleLimitChange(config.kind, e.currentTarget.value)} - title="Max to display" - /> + + {#if config.kind === 0} + handleLimitChange(config.kind, e.currentTarget.value)} + title="Max profiles to display" + /> + + of {profileStats.totalFetched} fetched + + {:else} + + handleLimitChange(config.kind, e.currentTarget.value)} + title="Max to display" + /> + {/if} {#if config.kind === 30040} @@ -162,11 +180,11 @@ {/if} - {#if isLoaded} + {#if config.kind !== 0 && isLoaded} ({eventCounts[config.kind]}) - {:else} + {:else if config.kind !== 0} (not loaded) diff --git a/src/lib/navigator/EventNetwork/index.svelte b/src/lib/navigator/EventNetwork/index.svelte index 8455ca8..18e4056 100644 --- a/src/lib/navigator/EventNetwork/index.svelte +++ b/src/lib/navigator/EventNetwork/index.svelte @@ -165,6 +165,7 @@ let personMap = $state>(new Map()); let totalPersonCount = $state(0); let displayedPersonCount = $state(0); + let hasInitializedPersons = $state(false); // Debug function - call from browser console: window.debugTagAnchors() if (typeof window !== "undefined") { @@ -357,13 +358,14 @@ // Extract person info for legend personAnchorInfo = extractPersonAnchorInfo(personAnchors, personMap); - // Auto-disable all person nodes by default (only on first show) - if (disabledPersons.size === 0) { + // Auto-disable all person nodes by default (only on first time showing) + if (!hasInitializedPersons && personAnchors.length > 0) { personAnchors.forEach(anchor => { if (anchor.pubkey) { disabledPersons.add(anchor.pubkey); } }); + hasInitializedPersons = true; } debug("Person anchors created", { @@ -374,6 +376,11 @@ }); } else { personAnchorInfo = []; + // Reset initialization flag when person nodes are hidden + if (hasInitializedPersons && personAnchorInfo.length === 0) { + hasInitializedPersons = false; + disabledPersons.clear(); + } } // Save current node positions before updating diff --git a/src/routes/visualize/+page.svelte b/src/routes/visualize/+page.svelte index ae4703d..a9964e1 100644 --- a/src/routes/visualize/+page.svelte +++ b/src/routes/visualize/+page.svelte @@ -237,11 +237,15 @@ let allFetchedEvents: NDKEvent[] = []; - // First, fetch non-publication events (like kind 0, 1, 3, etc.) - if (otherConfigs.length > 0) { - debug("Fetching non-publication events:", otherConfigs); + // First, fetch non-publication events (like kind 1, 3, etc. but NOT kind 0) + // We'll fetch kind 0 profiles after we know which pubkeys we need + const kind0Config = otherConfigs.find(c => c.kind === 0); + const nonProfileConfigs = otherConfigs.filter(c => c.kind !== 0); + + if (nonProfileConfigs.length > 0) { + debug("Fetching non-publication events (excluding profiles):", nonProfileConfigs); - for (const config of otherConfigs) { + for (const config of nonProfileConfigs) { try { // Special handling for kind 3 (follow lists) if (config.kind === 3) { @@ -483,26 +487,16 @@ baseEvents = [...allEvents]; // Store base events for tag expansion - // Step 6: Fetch profiles (kind 0) - debug("Fetching profiles for events"); - - // Get kind 0 config to respect its limit - const profileConfig = enabledConfigs.find(ec => ec.kind === 0); - const profileLimit = profileConfig?.limit || 50; - - // Collect all pubkeys that need profiles - const allPubkeys = new Set(); + // Step 6: Extract all pubkeys and fetch profiles + debug("Extracting pubkeys from all events"); - // Add event authors (these are the main content creators) - allEvents.forEach(event => { - if (event.pubkey) { - allPubkeys.add(event.pubkey); - } - }); + // Use the utility function to extract ALL pubkeys (authors + p tags + content) + const allPubkeys = extractPubkeysFromEvents(allEvents); - // Add pubkeys from follow lists (for tag anchors) + // Add pubkeys from follow lists if present if (followListEvents.length > 0) { followListEvents.forEach(event => { + if (event.pubkey) allPubkeys.add(event.pubkey); event.tags.forEach(tag => { if (tag[0] === 'p' && tag[1]) { allPubkeys.add(tag[1]); @@ -511,25 +505,38 @@ }); } - // Limit the number of profiles to fetch based on kind 0 limit - const pubkeysArray = Array.from(allPubkeys); - const pubkeysToFetch = profileLimit === -1 - ? pubkeysArray - : pubkeysArray.slice(0, profileLimit); - - debug("Profile fetch strategy:", { + debug("Profile extraction complete:", { totalPubkeys: allPubkeys.size, - profileLimit, - pubkeysToFetch: pubkeysToFetch.length, - followListsLoaded: followListEvents.length + fromEvents: allEvents.length, + fromFollowLists: followListEvents.length }); - profileLoadingProgress = { current: 0, total: pubkeysToFetch.length }; - await batchFetchProfiles(pubkeysToFetch, (fetched, total) => { - profileLoadingProgress = { current: fetched, total }; - }); - profileLoadingProgress = null; // Clear progress when done - debug("Profile fetch complete for", pubkeysToFetch.length, "pubkeys"); + // Fetch ALL profiles if kind 0 is enabled + if (kind0Config) { + debug("Fetching profiles for all discovered pubkeys"); + + // Update progress during fetch + profileLoadingProgress = { current: 0, total: allPubkeys.size }; + + await batchFetchProfiles( + Array.from(allPubkeys), + (fetched, total) => { + profileLoadingProgress = { current: fetched, total }; + } + ); + + profileLoadingProgress = null; + debug("Profile fetch complete"); + + // Store the total count for display + // The limit in kind0Config now controls display, not fetch + if (typeof window !== 'undefined' && window.profileStats) { + window.profileStats = { + totalFetched: allPubkeys.size, + displayLimit: kind0Config.limit + }; + } + } // Step 7: Apply display limits events = filterByDisplayLimits(allEvents, $displayLimits, $visualizationConfig);