mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-09 23:16:50 +02:00
fix: improve relay state tracking and add relay type indicators
State Tracking Fixes: - Sync connection state for ALL relays in query, not just initialized ones - Defensively initialize missing relay states during sync - Handle events from unknown relays (defensive initialization) - Add debug console logs to track state transitions Relay Type Indicators: - Explicit relays: Blue link icon (relays specified directly) - Outbox relays: Purple sparkles (NIP-65 selected) - Fallback relays: Gray inbox icon (fallback when outbox incomplete) - Each type has tooltip explaining source This should fix: - "0/4 relays but events coming in" bug - "Stuck in LOADING" when events are arriving - Missing visibility for relay source types Tests: 634/634 passing
This commit is contained in:
@@ -16,6 +16,9 @@ import {
|
||||
Loader2,
|
||||
Mail,
|
||||
Send,
|
||||
Inbox,
|
||||
Sparkles,
|
||||
Link as LinkIcon,
|
||||
} from "lucide-react";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { useReqTimelineEnhanced } from "@/hooks/useReqTimelineEnhanced";
|
||||
@@ -1016,6 +1019,41 @@ export default function ReqViewer({
|
||||
// Find NIP-65 info for this relay (if using outbox)
|
||||
const nip65Info = reasoning?.find((r) => r.relay === url);
|
||||
|
||||
// Determine relay type
|
||||
const relayType = relays
|
||||
? "explicit" // Explicitly specified relays
|
||||
: nip65Info && !nip65Info.isFallback
|
||||
? "outbox" // NIP-65 outbox relay
|
||||
: "fallback"; // Fallback relay
|
||||
|
||||
// Type indicator icon
|
||||
const typeIcon = {
|
||||
explicit: (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<LinkIcon className="size-3 text-blue-500" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Explicit relay</TooltipContent>
|
||||
</Tooltip>
|
||||
),
|
||||
outbox: (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Sparkles className="size-3 text-purple-500" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>NIP-65 Outbox relay</TooltipContent>
|
||||
</Tooltip>
|
||||
),
|
||||
fallback: (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Inbox className="size-3 text-muted-foreground/60" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Fallback relay</TooltipContent>
|
||||
</Tooltip>
|
||||
),
|
||||
}[relayType];
|
||||
|
||||
return (
|
||||
<div
|
||||
key={url}
|
||||
@@ -1027,6 +1065,9 @@ export default function ReqViewer({
|
||||
className="flex-1 truncate font-mono text-foreground/80"
|
||||
/>
|
||||
<div className="flex items-center gap-1.5 flex-shrink-0 text-muted-foreground">
|
||||
{/* Relay type indicator */}
|
||||
{typeIcon}
|
||||
|
||||
{/* Event count */}
|
||||
{reqState && reqState.eventCount > 0 && (
|
||||
<Tooltip>
|
||||
@@ -1087,13 +1128,6 @@ export default function ReqViewer({
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{/* Fallback indicator */}
|
||||
{nip65Info && nip65Info.isFallback && (
|
||||
<span className="text-[10px] text-muted-foreground/60">
|
||||
fallback
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Auth icon */}
|
||||
{authIcon && (
|
||||
<Tooltip>
|
||||
|
||||
@@ -98,29 +98,58 @@ export function useReqTimelineEnhanced(
|
||||
// Sync connection states from RelayStateManager
|
||||
// This runs whenever globalRelayStates updates
|
||||
useEffect(() => {
|
||||
if (relays.length === 0) return;
|
||||
|
||||
setRelayStates((prev) => {
|
||||
const next = new Map(prev);
|
||||
let changed = false;
|
||||
|
||||
for (const [url, state] of prev) {
|
||||
// Sync state for all relays in our query
|
||||
for (const url of relays) {
|
||||
const globalState = globalRelayStates[url];
|
||||
if (
|
||||
globalState &&
|
||||
globalState.connectionState !== state.connectionState
|
||||
) {
|
||||
const currentState = prev.get(url);
|
||||
|
||||
// Initialize if relay not in map yet (shouldn't happen, but defensive)
|
||||
if (!currentState) {
|
||||
next.set(url, {
|
||||
...state,
|
||||
url,
|
||||
connectionState: globalState?.connectionState || "pending",
|
||||
subscriptionState: "waiting",
|
||||
eventCount: 0,
|
||||
connectedAt: globalState?.lastConnected,
|
||||
disconnectedAt: globalState?.lastDisconnected,
|
||||
});
|
||||
changed = true;
|
||||
console.log(
|
||||
"REQ Enhanced: Initialized missing relay state",
|
||||
url,
|
||||
globalState?.connectionState,
|
||||
);
|
||||
} else if (
|
||||
globalState &&
|
||||
globalState.connectionState !== currentState.connectionState
|
||||
) {
|
||||
// Update connection state if changed
|
||||
next.set(url, {
|
||||
...currentState,
|
||||
connectionState: globalState.connectionState as any,
|
||||
connectedAt: globalState.lastConnected,
|
||||
disconnectedAt: globalState.lastDisconnected,
|
||||
});
|
||||
changed = true;
|
||||
console.log(
|
||||
"REQ Enhanced: Connection state changed",
|
||||
url,
|
||||
currentState.connectionState,
|
||||
"→",
|
||||
globalState.connectionState,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return changed ? next : prev;
|
||||
});
|
||||
}, [globalRelayStates]);
|
||||
}, [globalRelayStates, relays]);
|
||||
|
||||
// Subscribe to events
|
||||
useEffect(() => {
|
||||
@@ -208,17 +237,34 @@ export function useReqTimelineEnhanced(
|
||||
if (relayUrl) {
|
||||
setRelayStates((prev) => {
|
||||
const state = prev.get(relayUrl);
|
||||
if (!state) return prev;
|
||||
|
||||
const now = Date.now();
|
||||
const next = new Map(prev);
|
||||
next.set(relayUrl, {
|
||||
...state,
|
||||
subscriptionState: "receiving",
|
||||
eventCount: state.eventCount + 1,
|
||||
firstEventAt: state.firstEventAt ?? now,
|
||||
lastEventAt: now,
|
||||
});
|
||||
|
||||
if (!state) {
|
||||
// Relay not in map - initialize it (defensive)
|
||||
console.warn(
|
||||
"REQ Enhanced: Event from unknown relay, initializing",
|
||||
relayUrl,
|
||||
);
|
||||
next.set(relayUrl, {
|
||||
url: relayUrl,
|
||||
connectionState: "connected",
|
||||
subscriptionState: "receiving",
|
||||
eventCount: 1,
|
||||
firstEventAt: now,
|
||||
lastEventAt: now,
|
||||
});
|
||||
} else {
|
||||
// Update existing relay state
|
||||
next.set(relayUrl, {
|
||||
...state,
|
||||
subscriptionState: "receiving",
|
||||
eventCount: state.eventCount + 1,
|
||||
firstEventAt: state.firstEventAt ?? now,
|
||||
lastEventAt: now,
|
||||
});
|
||||
}
|
||||
|
||||
return next;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user