import { invoke } from '@tauri-apps/api/core'; import type { GrpcConnection, GrpcEvent } from '@yaakapp-internal/models'; import { grpcConnectionsAtom, grpcEventsAtom, mergeModelsInStore, replaceModelsInStore, } from '@yaakapp-internal/models'; import { atom, useAtomValue } from 'jotai'; import { useEffect, useMemo } from 'react'; import { atomWithKVStorage } from '../lib/atoms/atomWithKVStorage'; import { activeRequestIdAtom } from './useActiveRequestId'; const pinnedGrpcConnectionIdsAtom = atomWithKVStorage>( 'pinned-grpc-connection-ids', {}, ); export const pinnedGrpcConnectionIdAtom = atom( (get) => { const activeRequestId = get(activeRequestIdAtom); const activeConnections = get(activeGrpcConnections); const latestConnection = activeConnections[0] ?? null; if (!activeRequestId) return null; const key = recordKey(activeRequestId, latestConnection); return get(pinnedGrpcConnectionIdsAtom)[key] ?? null; }, (get, set, id: string | null) => { const activeRequestId = get(activeRequestIdAtom); const activeConnections = get(activeGrpcConnections); const latestConnection = activeConnections[0] ?? null; if (!activeRequestId) return; const key = recordKey(activeRequestId, latestConnection); set(pinnedGrpcConnectionIdsAtom, (prev) => ({ ...prev, [key]: id, })); }, ); function recordKey(activeRequestId: string | null, latestConnection: GrpcConnection | null) { return `${activeRequestId}-${latestConnection?.id ?? 'none'}`; } export const activeGrpcConnections = atom((get) => { const activeRequestId = get(activeRequestIdAtom) ?? 'n/a'; return get(grpcConnectionsAtom).filter((c) => c.requestId === activeRequestId) ?? []; }); export const activeGrpcConnectionAtom = atom((get) => { const activeRequestId = get(activeRequestIdAtom) ?? 'n/a'; const activeConnections = get(activeGrpcConnections); const latestConnection = activeConnections[0] ?? null; const pinnedConnectionId = get(pinnedGrpcConnectionIdsAtom)[ recordKey(activeRequestId, latestConnection) ]; return activeConnections.find((c) => c.id === pinnedConnectionId) ?? activeConnections[0] ?? null; }); export function useGrpcEvents(connectionId: string | null) { const allEvents = useAtomValue(grpcEventsAtom); useEffect(() => { if (connectionId == null) { replaceModelsInStore('grpc_event', []); return; } // Fetch events from database, filtering out events from other connections and merging atomically invoke('models_grpc_events', { connectionId }).then((events) => mergeModelsInStore('grpc_event', events, (e) => e.connectionId === connectionId), ); }, [connectionId]); return useMemo( () => allEvents.filter((e) => e.connectionId === connectionId), [allEvents, connectionId], ); }