| 1 | import { useCallback, useEffect, useRef } from "react"; |
| 2 | import { recordFrontendDiagnostic, registerFrontendDiagnosticStartHook } from "./frontendDiagnosticBridge"; |
| 3 | import type { ProjectTreeVariant } from "./projectTreeTopic"; |
| 4 | import type { ProjectTreeSessionDiagnosticSummary } from "./projectTreeDiagnostics"; |
| 5 | |
| 6 | export type ProjectTreeDiagnosticSnapshot = ProjectTreeSessionDiagnosticSummary & { |
| 7 | directoryState: string; |
| 8 | scope: string; |
| 9 | variant: ProjectTreeVariant; |
| 10 | queryActive: boolean; |
| 11 | catalogPartial: boolean; |
| 12 | catalogRebuilding: boolean; |
| 13 | catalogRevision: number; |
| 14 | catalogIndexed: number; |
| 15 | catalogTotal: number; |
| 16 | unloadedSessions: number; |
| 17 | repairPending: number; |
| 18 | treeRevision: number; |
| 19 | organizationRevision: number; |
| 20 | }; |
| 21 | |
| 22 | function changeReason(previous: ProjectTreeDiagnosticSnapshot | null, current: ProjectTreeDiagnosticSnapshot): string { |
| 23 | if (!previous) return "initial"; |
| 24 | if (previous.recoveryCopies !== current.recoveryCopies || previous.recoveryCopySessions !== current.recoveryCopySessions) return "recovery-copy"; |
| 25 | if (previous.runtimeOnlySessions !== current.runtimeOnlySessions || previous.runtimeSessions !== current.runtimeSessions) return "runtime-session"; |
| 26 | if (previous.activeSessions !== current.activeSessions || previous.activeVisibleSessions !== current.activeVisibleSessions) return "active-session"; |
| 27 | if (previous.queryActive !== current.queryActive || previous.hiddenByFilter !== current.hiddenByFilter) return "filter"; |
| 28 | if (previous.visibleSessions !== current.visibleSessions || previous.hiddenSessions !== current.hiddenSessions || previous.hiddenByCollapsed !== current.hiddenByCollapsed || previous.hiddenByTruncation !== current.hiddenByTruncation || previous.expandedFolders !== current.expandedFolders || previous.showAllFolders !== current.showAllFolders) return "visibility"; |
| 29 | if (previous.workspaceSessions !== current.workspaceSessions || previous.folderCount !== current.folderCount || previous.catalogRevision !== current.catalogRevision || previous.catalogIndexed !== current.catalogIndexed || previous.catalogTotal !== current.catalogTotal || previous.unloadedSessions !== current.unloadedSessions || previous.repairPending !== current.repairPending || previous.treeRevision !== current.treeRevision || previous.organizationRevision !== current.organizationRevision || previous.directoryState !== current.directoryState) return "catalog"; |
| 30 | return "directory-update"; |
| 31 | } |
| 32 | |
| 33 | export function useProjectTreeFrontendDiagnostics(snapshot: ProjectTreeDiagnosticSnapshot): void { |
| 34 | const currentRef = useRef(snapshot); |
| 35 | const previousRef = useRef<ProjectTreeDiagnosticSnapshot | null>(null); |
| 36 | const lastSignatureRef = useRef(""); |
| 37 | currentRef.current = snapshot; |
| 38 | const signature = JSON.stringify(snapshot); |
| 39 | const emit = useCallback((force = false, reasonOverride?: string) => { |
| 40 | const current = currentRef.current; |
| 41 | if (!force && signature === lastSignatureRef.current) return; |
| 42 | const previous = previousRef.current; |
| 43 | recordFrontendDiagnostic("workspace", "workspace.session-directory", { |
| 44 | ...current, |
| 45 | changeReason: reasonOverride ?? changeReason(previous, current), |
| 46 | deltaWorkspaceSessions: previous ? current.workspaceSessions - previous.workspaceSessions : 0, |
| 47 | deltaVisibleSessions: previous ? current.visibleSessions - previous.visibleSessions : 0, |
| 48 | deltaHiddenSessions: previous ? current.hiddenSessions - previous.hiddenSessions : 0, |
| 49 | deltaRecoveryCopies: previous ? current.recoveryCopies - previous.recoveryCopies : 0, |
| 50 | deltaRuntimeOnlySessions: previous ? current.runtimeOnlySessions - previous.runtimeOnlySessions : 0, |
| 51 | }); |
| 52 | previousRef.current = current; |
| 53 | lastSignatureRef.current = signature; |
| 54 | }, [signature]); |
| 55 | useEffect(() => emit(), [emit]); |
| 56 | useEffect(() => registerFrontendDiagnosticStartHook(() => emit(true, "recorder-start")), [emit]); |
| 57 | } |
| 58 |