@petrarca/sonnet-graph 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +128 -19
- package/dist/index.js.map +1 -1
- package/package.json +34 -5
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/models/visual-graph.ts","../src/models/graph-types.ts","../src/graph/extractDisplayLabel.ts","../src/graph/enrichment.ts","../src/graph/normalize.ts","../src/stores/Selection.ts","../src/stores/GraphData.ts","../src/stores/GraphFilter.ts","../src/stores/GraphExploration.ts","../src/stores/GraphFocus.ts","../src/stores/ActionPanelStore.ts","../src/hooks/useWorkspaceStores.ts","../src/hooks/useLiveGraphData.ts","../src/hooks/useReagraphData.ts","../src/hooks/useCytoscapeData.ts","../src/hooks/useGraphRendererContext.ts","../src/hooks/graphRendererProvider.tsx","../src/components/rea/ReaGraph.tsx","../src/components/rea/theme.ts","../src/components/rea/LayoutAndCameraControls.tsx","../src/components/shared/RendererDropdown.tsx","../src/components/rea/NodeHoverInfo.tsx","../src/components/rea/ReaContextMenu.tsx","../src/components/cyto/CytoscapeGraph.tsx","../src/components/cyto/CytoscapeControls.tsx","../src/components/cyto/layoutPresets.ts","../src/components/cyto/contextMenuConfig.ts","../src/components/GraphVisualizer.tsx","../src/components/ActionPanel/ActionPanel.tsx","../src/components/ActionPanel/NodeInfoCard.tsx","../src/components/ActionPanel/EdgeInfoCard.tsx","../src/components/ActionPanel/Overview.tsx"],"sourcesContent":["/**\n * Visual Graph Model - Domain types combining API data with UI enrichment.\n *\n * These types are the canonical graph representation used throughout the application.\n * They combine backend API data (GraphNode/GraphEdge DTOs) with visual enrichment\n * (colors, display names, etc.) computed once at the data boundary.\n *\n * This is an internal refactoring - NO functional changes to the application.\n * All behavior, visuals, and capabilities remain identical.\n */\n\n/**\n * Visual enrichment data for a node.\n * Computed once during data ingress, then reused everywhere.\n */\nexport interface NodeVisual {\n /** User-friendly name extracted from properties (name, title, label, etc.) */\n displayName: string;\n\n /** Color from unified palette based on node label */\n color: string;\n\n /** Optional: Node size (can be computed from degree, importance, etc.) */\n size?: number;\n\n /** Optional: Icon URL for the node */\n icon?: string;\n}\n\n/**\n * Visual enrichment data for an edge.\n */\nexport interface EdgeVisual {\n /** Edge color (typically based on type or neutral color) */\n color: string;\n\n /** Optional: Edge thickness/width */\n size?: number;\n\n /** Optional: Whether to render as dashed line */\n dashed?: boolean;\n}\n\n/**\n * VisualGraphNode - The canonical node type for the application.\n *\n * Combines API data (aligned with backend GraphNode DTO) with visual enrichment.\n * This replaces the previous pattern of using reagraph GraphNode types throughout\n * the application, which caused coupling to the visualization library.\n *\n * Structure matches backend API exactly:\n * - id_: Unique node identifier\n * - label_: Node type/class (e.g., \"Person\", \"Movie\")\n * - properties_: Key-value pairs from the database\n *\n * Plus visual enrichment for UI consistency:\n * - visual.displayName: Computed once from properties\n * - visual.color: Assigned once from unified palette\n */\nexport interface VisualGraphNode {\n // Core data (matches API GraphNode structure)\n id_: number;\n label_: string;\n properties_: Record<string, string | number | Array<string | number>>;\n\n // Visual enrichment\n visual: NodeVisual;\n}\n\n/**\n * VisualGraphEdge - The canonical edge type for the application.\n *\n * Combines API data (aligned with backend GraphEdge DTO) with visual enrichment.\n *\n * Structure matches backend API exactly:\n * - id_: Unique edge identifier\n * - label_: Relationship type (e.g., \"ACTED_IN\", \"DIRECTED\")\n * - start_id_: Source node ID\n * - end_id_: Target node ID\n * - properties_: Optional key-value pairs\n *\n * Plus visual enrichment for UI consistency.\n */\nexport interface VisualGraphEdge {\n // Core data (matches API GraphEdge structure)\n id_: number;\n label_: string;\n start_id_: number;\n end_id_: number;\n properties_?: Record<string, string | number | Array<string | number>>;\n\n // Visual enrichment\n visual: EdgeVisual;\n}\n\n/**\n * Normalized graph structure using visual models.\n *\n * Provides O(1) lookup by ID for efficient access in components.\n * This is the internal representation used by the application after\n * data is fetched and enriched.\n */\nexport interface VisualGraphNormalized {\n /** Nodes indexed by string ID for O(1) lookup */\n nodesById: Record<string, VisualGraphNode>;\n\n /** Edges indexed by string ID for O(1) lookup */\n edgesById: Record<string, VisualGraphEdge>;\n\n /** Array of all node IDs (for iteration) */\n nodeIds: string[];\n\n /** Array of all edge IDs (for iteration) */\n edgeIds: string[];\n}\n\n/**\n * Type guard to check if an object is a VisualGraphNode.\n *\n * @param obj - Object to check\n * @returns true if obj is a valid VisualGraphNode\n */\nexport function isVisualNode(obj: unknown): obj is VisualGraphNode {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"id_\" in obj &&\n \"label_\" in obj &&\n \"properties_\" in obj &&\n \"visual\" in obj &&\n typeof (obj as any).visual === \"object\" &&\n \"displayName\" in (obj as any).visual &&\n \"color\" in (obj as any).visual\n );\n}\n\n/**\n * Type guard to check if an object is a VisualGraphEdge.\n *\n * @param obj - Object to check\n * @returns true if obj is a valid VisualGraphEdge\n */\nexport function isVisualEdge(obj: unknown): obj is VisualGraphEdge {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"id_\" in obj &&\n \"label_\" in obj &&\n \"start_id_\" in obj &&\n \"end_id_\" in obj &&\n \"visual\" in obj &&\n typeof (obj as any).visual === \"object\" &&\n \"color\" in (obj as any).visual\n );\n}\n","/**\n * Package-local raw graph types.\n *\n * These are the minimal structural types needed by the graph visualization layer.\n * They are structurally compatible with the API DTO types in `api/types.ts`\n * (GraphNode, GraphEdge) but live in the domain layer so graph-generic code\n * does not depend on API/transport types.\n */\n\nexport type GraphProperty = string | number | Array<string | number>;\n\nexport type GraphProperties = Record<string, GraphProperty>;\n\nexport type RawGraphNode = {\n id_?: number;\n label_: string;\n properties_?: GraphProperties;\n};\n\nexport type RawGraphEdge = {\n id_?: number;\n label_: string;\n start_id_: number;\n end_id_: number;\n properties_?: GraphProperties;\n};\n\n/**\n * Type guard to check if an object is a RawGraphNode (vs RawGraphEdge).\n * Edges have start_id_ and end_id_ properties, nodes don't.\n */\nexport function isRawGraphNode(\n obj: RawGraphNode | RawGraphEdge,\n): obj is RawGraphNode {\n return \"label_\" in obj && !(\"start_id_\" in obj) && !(\"end_id_\" in obj);\n}\n\n/**\n * Display configuration from schema metadata.\n * Mirrors api/types.ts DisplayConfig but lives in the domain layer so\n * graph-generic code (enrichment, extraction) does not depend on API types.\n */\nexport type GraphDisplayConfig = {\n labelTemplate?: string; // Template for display labels, e.g. \"{firstName} {lastName}\". Takes priority over labelProperty.\n labelProperty?: string; // Property for display labels (default: \"name\")\n fallbackProperty?: string; // Fallback if labelProperty missing\n sortProperty?: string; // Property for sorting (default: labelProperty)\n sortOrder?: \"ASC\" | \"DESC\"; // Sort direction (default: \"ASC\")\n filterProperty?: string; // Optional grouping/filtering column\n};\n\n/**\n * Resolved display config map: node label → GraphDisplayConfig.\n * Built once from schema data and passed into enrichNodes().\n * Only labels with explicit display config appear in this map.\n */\nexport type LabelDisplayMap = Record<string, GraphDisplayConfig>;\n","import type {\n GraphDisplayConfig,\n RawGraphNode,\n RawGraphEdge,\n} from \"../models/graph-types\";\nimport { isRawGraphNode } from \"../models/graph-types\";\n\n/**\n * Interpolate a label template against a properties object.\n * Placeholders: {propertyName} — missing properties are silently dropped.\n * Result is trimmed; empty string means the template produced nothing useful.\n *\n * @example\n * interpolateTemplate(\"{firstName} {lastName}\", { firstName: \"John\" }) // \"John\"\n * interpolateTemplate(\"{type}: {name}\", { type: \"npm\", name: \"react\" }) // \"npm: react\"\n */\nfunction interpolateTemplate(\n template: string,\n properties: Record<string, unknown>,\n): string {\n return template\n .replace(/\\{(\\w+)\\}/g, (_, key) => {\n const val = properties[key];\n return val !== undefined && val !== null ? String(val) : \"\";\n })\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\ntype LabelStrategy = () => string | undefined;\n\n/**\n * Walk a prioritized list of label resolution strategies.\n * Returns the first non-empty result, or `fallback` if none match.\n */\nfunction resolveLabel(strategies: LabelStrategy[], fallback: string): string {\n for (const strategy of strategies) {\n const result = strategy();\n if (result) return result;\n }\n return fallback;\n}\n\n/** Try interpolating displayConfig.labelTemplate against properties. */\nfunction fromTemplate(\n displayConfig: GraphDisplayConfig | undefined,\n props: Record<string, unknown> | undefined,\n): string | undefined {\n if (!displayConfig?.labelTemplate || !props) return undefined;\n return interpolateTemplate(displayConfig.labelTemplate, props) || undefined;\n}\n\n/** Try reading displayConfig.labelProperty from properties. */\nfunction fromLabelProperty(\n displayConfig: GraphDisplayConfig | undefined,\n props: Record<string, unknown> | undefined,\n): string | undefined {\n if (!displayConfig?.labelProperty || !props?.[displayConfig.labelProperty])\n return undefined;\n return String(props[displayConfig.labelProperty]);\n}\n\n/** Try reading displayConfig.fallbackProperty from properties. */\nfunction fromFallbackProperty(\n displayConfig: GraphDisplayConfig | undefined,\n props: Record<string, unknown> | undefined,\n): string | undefined {\n if (\n !displayConfig?.fallbackProperty ||\n !props?.[displayConfig.fallbackProperty]\n )\n return undefined;\n return String(props[displayConfig.fallbackProperty]);\n}\n\n/**\n * Extract display label from a node using resolved display config.\n *\n * Precedence:\n * 1. labelTemplate → interpolated against properties (skips missing, trims)\n * 2. labelProperty → properties[labelProperty]\n * 3. fallbackProperty → properties[fallbackProperty]\n * 4. properties.name (convention across all known graph schemas)\n * 5. first property value\n * 6. Node #${id_}\n * 7. \"Unknown\"\n */\nfunction extractNodeDisplayLabel(\n node: RawGraphNode,\n displayConfig?: GraphDisplayConfig,\n): string {\n const props = node?.properties_;\n return resolveLabel(\n [\n () => fromTemplate(displayConfig, props),\n () => fromLabelProperty(displayConfig, props),\n () => fromFallbackProperty(displayConfig, props),\n () => (props?.name ? String(props.name) : undefined),\n () => {\n const keys = props ? Object.keys(props) : [];\n return keys.length > 0 ? String(props![keys[0]]) : undefined;\n },\n () =>\n node?.id_ !== undefined && node.id_ !== null\n ? `Node #${node.id_}`\n : undefined,\n ],\n \"Unknown\",\n );\n}\n\n/**\n * Extract display label from an edge using resolved display config.\n *\n * Precedence:\n * 1. labelTemplate → interpolated against properties\n * 2. labelProperty → properties[labelProperty]\n * 3. fallbackProperty → properties[fallbackProperty]\n * 4. label_ (relationship type, e.g. \"ACTED_IN\")\n * 5. Edge #${id_}\n * 6. \"Unknown\"\n */\nfunction extractEdgeDisplayLabel(\n edge: RawGraphEdge,\n displayConfig?: GraphDisplayConfig,\n): string {\n const props = edge?.properties_;\n return resolveLabel(\n [\n () => fromTemplate(displayConfig, props),\n () => fromLabelProperty(displayConfig, props),\n () => fromFallbackProperty(displayConfig, props),\n () => (edge?.label_ ? edge.label_ : undefined),\n () =>\n edge?.id_ !== undefined && edge.id_ !== null\n ? `Edge #${edge.id_}`\n : undefined,\n ],\n \"Unknown\",\n );\n}\n\n/**\n * Extract display label from a node or edge using resolved display config.\n *\n * @param item - RawGraphNode or RawGraphEdge\n * @param displayConfig - Optional resolved GraphDisplayConfig for this label\n */\nexport function extractDisplayLabel(\n item: RawGraphNode | RawGraphEdge,\n displayConfig?: GraphDisplayConfig,\n): string {\n if (isRawGraphNode(item)) {\n return extractNodeDisplayLabel(item, displayConfig);\n } else {\n return extractEdgeDisplayLabel(item, displayConfig);\n }\n}\n","/**\n * Graph data enrichment - Converts API DTOs to Visual Graph Models.\n *\n * This is where API data gets transformed into the domain model with UI enrichment.\n * Enrichment happens ONCE at the data boundary (in useLiveGraphData), then the\n * enriched models are used throughout the application.\n */\n\nimport type {\n RawGraphNode,\n RawGraphEdge,\n GraphDisplayConfig,\n LabelDisplayMap,\n} from \"../models/graph-types\";\nimport { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\nimport { extractDisplayLabel } from \"./extractDisplayLabel\";\n\n/**\n * Color palette mapping node labels to colors.\n * Built once from label counts, then used for all nodes.\n */\nexport type ColorPalette = Record<string, string>;\n\n/**\n * Base color palette for node visualization.\n * MUST NOT CHANGE - this ensures consistent color assignments across the app.\n */\nconst BASE_COLORS = [\n \"#f94144\",\n \"#118ab2\",\n \"#f8961e\",\n \"#43aa8b\",\n \"#f3722c\",\n \"#90be6d\",\n \"#f9c74f\",\n \"#c4bbaf\",\n];\n\n/**\n * Builds a unified color palette from label counts.\n *\n * Colors are assigned to labels based on their order, cycling through BASE_COLORS.\n * Includes 'neutral' and 'faded' colors for edges and unlabeled nodes.\n *\n * @param labelCounts - Object mapping label names to counts\n * @returns Color palette mapping labels to hex colors\n *\n * @example\n * const counts = { Person: 10, Movie: 5 };\n * const palette = buildColorPalette(counts);\n * // { Person: '#f94144', Movie: '#118ab2', neutral: '#6c757d', faded: '#adb5bd' }\n */\nexport function buildColorPalette(\n labelCounts: Record<string, number>,\n): ColorPalette {\n const palette: ColorPalette = {};\n let i = 0;\n\n // Assign colors to each label in order (preserves existing behavior)\n for (const label of Object.keys(labelCounts)) {\n palette[label] = BASE_COLORS[i % BASE_COLORS.length];\n i++;\n }\n\n // Add special colors (preserves existing behavior)\n palette[\"neutral\"] = \"#6c757d\";\n palette[\"faded\"] = \"#adb5bd\";\n\n return palette;\n}\n\n/**\n * Convenience: build a color palette directly from an array of nodes.\n * Counts labels, then delegates to buildColorPalette.\n *\n * @param nodes - Array of nodes (any object with a `label_` string property)\n * @returns Color palette mapping labels to hex colors\n */\nexport function buildColorPaletteFromNodes(\n nodes: { label_: string }[],\n): ColorPalette {\n const labelCounts: Record<string, number> = {};\n for (const n of nodes) {\n const l = n?.label_;\n if (l) labelCounts[l] = (labelCounts[l] || 0) + 1;\n }\n return buildColorPalette(labelCounts);\n}\n\n/**\n * Enriches an API node with visual data to create a VisualGraphNode.\n *\n * This is the primary transformation from API DTO to domain model.\n * Extracts displayName from node properties, assigns color from the palette,\n * and provides fallback to neutral color for unlabeled nodes.\n *\n * @param apiNode - Node from backend API\n * @param colorPalette - Unified color palette\n * @param displayConfig - Optional resolved GraphDisplayConfig for this node's label\n * @returns Enriched VisualGraphNode\n */\nexport function enrichNode(\n apiNode: RawGraphNode,\n colorPalette: ColorPalette,\n displayConfig?: GraphDisplayConfig,\n): VisualGraphNode {\n // Extract display label from node properties using resolved display config\n const displayName = extractDisplayLabel(apiNode, displayConfig);\n\n // Get color from palette (may be undefined if label not in palette)\n // This preserves the legacy behavior where fill is only set if color exists\n const color = colorPalette[apiNode.label_];\n\n return {\n // Copy core data from API\n id_: apiNode.id_ ?? 0, // Handle optional id for creation scenarios\n label_: apiNode.label_,\n properties_: apiNode.properties_ ?? {},\n\n // Add visual enrichment\n visual: {\n displayName,\n // Use color from palette, or fall back to neutral if not found\n // This ensures every node has a color (no undefined)\n color: color || colorPalette[\"neutral\"] || \"#6c757d\",\n // Size can be added later if needed\n size: undefined,\n icon: undefined,\n },\n };\n}\n\n/**\n * Enriches an API edge with visual data to create a VisualGraphEdge.\n *\n * Adds neutral color and default size to edges for consistent visualization.\n *\n * @param apiEdge - Edge from backend API\n * @param colorPalette - Optional unified color palette (for neutral color)\n * @returns Enriched VisualGraphEdge\n */\nexport function enrichEdge(\n apiEdge: RawGraphEdge,\n colorPalette?: ColorPalette,\n): VisualGraphEdge {\n return {\n // Copy core data from API\n id_: apiEdge.id_ ?? 0,\n label_: apiEdge.label_,\n start_id_: apiEdge.start_id_,\n end_id_: apiEdge.end_id_,\n properties_: apiEdge.properties_ as\n | Record<string, string | number | Array<string | number>>\n | undefined,\n\n // Add visual enrichment\n visual: {\n // Use neutral color from palette if available, otherwise default\n color: colorPalette?.[\"neutral\"] ?? \"#999999\",\n // Default size of 3\n size: 3,\n dashed: undefined,\n },\n };\n}\n\n/**\n * Batch enrichment for multiple nodes.\n * More efficient than calling enrichNode repeatedly.\n *\n * @param apiNodes - Array of nodes from backend API\n * @param colorPalette - Unified color palette\n * @param labelDisplayMap - Optional resolved display config map (label → GraphDisplayConfig)\n * @returns Array of enriched VisualGraphNodes\n */\nexport function enrichNodes(\n apiNodes: RawGraphNode[],\n colorPalette: ColorPalette,\n labelDisplayMap?: LabelDisplayMap,\n): VisualGraphNode[] {\n return apiNodes.map((node) =>\n enrichNode(node, colorPalette, labelDisplayMap?.[node.label_]),\n );\n}\n\n/**\n * Batch enrichment for multiple edges.\n * More efficient than calling enrichEdge repeatedly.\n *\n * @param apiEdges - Array of edges from backend API\n * @param colorPalette - Optional unified color palette\n * @returns Array of enriched VisualGraphEdges\n */\nexport function enrichEdges(\n apiEdges: RawGraphEdge[],\n colorPalette?: ColorPalette,\n): VisualGraphEdge[] {\n return apiEdges.map((edge) => enrichEdge(edge, colorPalette));\n}\n","import {\n VisualGraphNode,\n VisualGraphEdge,\n VisualGraphNormalized,\n} from \"../models/visual-graph\";\n\n/**\n * Type alias for backward compatibility during refactoring.\n * This allows existing code to continue working while we migrate.\n */\nexport type NormalizedGraph = VisualGraphNormalized;\n\n/**\n * Normalizes visual graph data into an indexed structure for efficient lookups.\n *\n * This function converts arrays of nodes and edges into a Record structure\n * for O(1) lookup by ID, which is essential for performance in graph operations.\n *\n * INTERNAL REFACTORING: Function signature changed to use VisualGraph types,\n * but behavior is identical - same normalization logic, same performance.\n *\n * @param nodes - Array of VisualGraphNodes\n * @param edges - Array of VisualGraphEdges\n * @returns Normalized graph with indexed nodes and edges\n */\nexport function normalizeGraph(\n nodes: VisualGraphNode[],\n edges: VisualGraphEdge[],\n): VisualGraphNormalized {\n const nodesById: Record<string, VisualGraphNode> = {};\n const edgesById: Record<string, VisualGraphEdge> = {};\n\n // Index nodes by string ID for O(1) lookup\n for (const n of nodes) {\n const key = String(n.id_);\n nodesById[key] = n;\n }\n\n // Index edges by string ID for O(1) lookup\n for (const e of edges) {\n const key = String(e.id_);\n edgesById[key] = e;\n }\n\n return {\n nodesById,\n edgesById,\n nodeIds: Object.keys(nodesById),\n edgeIds: Object.keys(edgesById),\n };\n}\n\n/**\n * Empty normalized graph constant for initial state.\n */\nexport const EMPTY_NORMALIZED: VisualGraphNormalized = {\n nodesById: {},\n edgesById: {},\n nodeIds: [],\n edgeIds: [],\n};\n","import { VisualGraphEdge } from \"../models/visual-graph\";\nimport { create } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\nexport interface SelectionStore {\n selectedNodeIds: string[];\n setSelectedNodeIds: (ids: string[]) => void;\n selectedEdge: VisualGraphEdge | null;\n setSelectedEdge: (edge: VisualGraphEdge | null) => void;\n clear: () => void;\n}\n\n/**\n * Factory function to create a new Selection store instance.\n * Used by workspace system to create isolated store instances per workspace.\n *\n * For backward compatibility, the default export is a singleton instance.\n * Existing code continues to work without changes.\n */\nexport function createSelectionStore() {\n return create<SelectionStore>()((set, get) => ({\n selectedNodeIds: [],\n setSelectedNodeIds: (ids) => {\n const prev = get().selectedNodeIds;\n if (prev.length === ids.length && prev.every((v, i) => v === ids[i])) {\n // No change; skip state update & noisy logs\n return;\n }\n devLog(\"[SelectionStore] setSelectedNodeIds\", { prev, next: ids });\n set({ selectedNodeIds: ids });\n },\n selectedEdge: null,\n setSelectedEdge: (edge) => {\n devLog(\"[SelectionStore] setSelectedEdge\", {\n prev: get().selectedEdge?.id_,\n next: edge?.id_,\n });\n set({ selectedEdge: edge });\n },\n clear: () => {\n devLog(\"[SelectionStore] clear called\");\n set({ selectedNodeIds: [], selectedEdge: null });\n },\n }));\n}\n\n// Singleton instance for backward compatibility with existing code.\n// Existing imports continue to work without changes.\nconst useSelection = createSelectionStore();\n\nexport default useSelection;\n","/**\n * GraphData Store\n *\n * Central store for all graph data (query results + expanded nodes/edges).\n * This is the PRIMARY source of truth for graph visualization.\n *\n * Data sources:\n * 1. Query execution (setQueryData) - ACTIVELY USED\n * 2. Node expansion operations (mergeExpandedData) - ACTIVELY USED\n *\n * Data flow:\n * - Consumer calls setQueryData() with enriched nodes/edges after each query\n * - GraphExploration calls mergeExpandedData() when expanding nodes\n * - useLiveGraphData reads from this store and applies filters before rendering\n *\n * Merge strategy:\n * - setQueryData(): Replaces all data with new query results\n * - mergeExpandedData(): Adds expanded nodes/edges without duplicates\n */\n\nimport { create } from \"zustand\";\nimport { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\nimport { type GraphStatistics } from \"../interfaces\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\nexport interface GraphDataStore {\n /** All nodes (from query + expansions) */\n nodes: VisualGraphNode[];\n\n /** All edges (from query + expansions) */\n edges: VisualGraphEdge[];\n\n /** Query statistics from the last query execution */\n stats: GraphStatistics | undefined;\n\n /** Tabular values from value-set queries */\n values: string[][];\n\n /** Whether the last query was a value-set (tabular) query */\n isValueSet: boolean;\n\n /** IDs of nodes from the original query */\n queryNodeIds: Set<string>;\n\n /** IDs of nodes from expansion operations */\n expandedNodeIds: Set<string>;\n\n /** IDs of edges from the original query */\n queryEdgeIds: Set<string>;\n\n /** IDs of edges from expansion operations */\n expandedEdgeIds: Set<string>;\n\n // --- Actions ---\n\n /**\n * Set graph data from a query execution.\n * Replaces all existing data.\n *\n * @param nodes - Enriched nodes from query\n * @param edges - Enriched edges from query\n * @param stats - Query statistics\n * @param values - Tabular values for value-set queries\n * @param isValueSet - Whether this is a value-set query\n */\n setQueryData: (\n nodes: VisualGraphNode[],\n edges: VisualGraphEdge[],\n stats?: GraphStatistics,\n values?: string[][],\n isValueSet?: boolean,\n ) => void;\n\n /**\n * Merge expanded nodes/edges into existing graph.\n * Deduplicates by ID - existing elements are preserved.\n *\n * @param nodes - New nodes from expansion\n * @param edges - New edges from expansion\n */\n mergeExpandedData: (\n nodes: VisualGraphNode[],\n edges: VisualGraphEdge[],\n ) => void;\n\n /**\n * Clear all graph data\n */\n clear: () => void;\n\n /**\n * Get statistics about data sources\n */\n getStats: () => {\n totalNodes: number;\n totalEdges: number;\n queryNodes: number;\n expandedNodes: number;\n queryEdges: number;\n expandedEdges: number;\n };\n}\n\n/**\n * Factory function to create a new GraphData store instance.\n * Used by workspace system to create isolated store instances per workspace.\n *\n * For backward compatibility, the default export is a singleton instance.\n * Existing code continues to work without changes.\n */\nexport function createGraphDataStore() {\n return create<GraphDataStore>()((set, get) => ({\n nodes: [],\n edges: [],\n stats: undefined,\n values: [],\n isValueSet: false,\n queryNodeIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n queryEdgeIds: new Set<string>(),\n expandedEdgeIds: new Set<string>(),\n\n setQueryData: (nodes, edges, stats, values, isValueSet = false) => {\n const nodeIds = new Set(nodes.map((n) => String(n.id_)));\n const edgeIds = new Set(edges.map((e) => String(e.id_)));\n\n devLog(\"[GraphData] setQueryData\", {\n nodes: nodes.length,\n edges: edges.length,\n });\n\n set({\n nodes,\n edges,\n stats,\n values: values || [],\n isValueSet,\n queryNodeIds: nodeIds,\n queryEdgeIds: edgeIds,\n expandedNodeIds: new Set<string>(),\n expandedEdgeIds: new Set<string>(),\n });\n },\n\n mergeExpandedData: (newNodes, newEdges) => {\n const state = get();\n\n // Create maps for O(1) lookup of existing elements\n const existingNodesMap = new Map(\n state.nodes.map((n) => [String(n.id_), n]),\n );\n const existingEdgesMap = new Map(\n state.edges.map((e) => [String(e.id_), e]),\n );\n\n // Track expanded element IDs\n const newExpandedNodeIds = new Set(state.expandedNodeIds);\n const newExpandedEdgeIds = new Set(state.expandedEdgeIds);\n\n // Merge nodes - only add if not already present\n const nodesToAdd: VisualGraphNode[] = [];\n for (const node of newNodes) {\n const id = String(node.id_);\n if (!existingNodesMap.has(id)) {\n nodesToAdd.push(node);\n newExpandedNodeIds.add(id);\n }\n }\n\n // Merge edges - only add if not already present\n const edgesToAdd: VisualGraphEdge[] = [];\n for (const edge of newEdges) {\n const id = String(edge.id_);\n if (!existingEdgesMap.has(id)) {\n edgesToAdd.push(edge);\n newExpandedEdgeIds.add(id);\n }\n }\n\n devLog(\"[GraphData] mergeExpandedData\", {\n newNodes: newNodes.length,\n newEdges: newEdges.length,\n addedNodes: nodesToAdd.length,\n addedEdges: edgesToAdd.length,\n duplicatesSkipped: {\n nodes: newNodes.length - nodesToAdd.length,\n edges: newEdges.length - edgesToAdd.length,\n },\n });\n\n // Only update if we have new data\n if (nodesToAdd.length > 0 || edgesToAdd.length > 0) {\n set({\n nodes: [...state.nodes, ...nodesToAdd],\n edges: [...state.edges, ...edgesToAdd],\n expandedNodeIds: newExpandedNodeIds,\n expandedEdgeIds: newExpandedEdgeIds,\n });\n } else {\n devLog(\n \"[GraphData] mergeExpandedData: No new elements to add (all duplicates)\",\n );\n }\n },\n\n clear: () => {\n devLog(\"[GraphData] clear\");\n\n set({\n nodes: [],\n edges: [],\n stats: undefined,\n values: [],\n isValueSet: false,\n queryNodeIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n queryEdgeIds: new Set<string>(),\n expandedEdgeIds: new Set<string>(),\n });\n },\n\n getStats: () => {\n const state = get();\n return {\n totalNodes: state.nodes.length,\n totalEdges: state.edges.length,\n queryNodes: state.queryNodeIds.size,\n expandedNodes: state.expandedNodeIds.size,\n queryEdges: state.queryEdgeIds.size,\n expandedEdges: state.expandedEdgeIds.size,\n };\n },\n }));\n}\n\n// Singleton instance for backward compatibility with existing code.\n// Existing imports continue to work without changes.\nconst useGraphData = createGraphDataStore();\n\nexport default useGraphData;\n","import { create } from \"zustand\";\n\n/**\n * GraphFilterStore - Node/edge label filtering and data-change tracking.\n *\n * Graph-generic filtering store. Separated from Cypher-specific\n * query editing (QueryEditorStore stays in the consumer).\n */\nexport interface GraphFilterStore {\n // Node label filtering\n nodeLabelFilters: string[];\n allLabelsDisabled: boolean;\n toggleNodeLabelFilter: (label: string, allAvailableLabels?: string[]) => void;\n clearNodeLabelFilters: () => void;\n setNodeLabelFilters: (labels: string[]) => void;\n toggleAllLabelsDisabled: () => void;\n\n // Edge label filtering\n edgeLabelFilters: string[];\n allEdgeLabelsDisabled: boolean;\n toggleEdgeLabelFilter: (\n label: string,\n allAvailableLabels?: string[],\n edgeToNodeLabels?: Record<string, string[]>,\n ) => void;\n clearEdgeLabelFilters: () => void;\n setEdgeLabelFilters: (labels: string[]) => void;\n toggleAllEdgeLabelsDisabled: () => void;\n\n // Data change tracking — notified on query execution so renderers can react\n lastDataChangeTime: number;\n notifyDataChange: () => void;\n\n // Reset all active filters (called on new query execution)\n resetFilters: () => void;\n}\n\n/**\n * Calculates which node labels need to be enabled when an edge type is enabled.\n */\nfunction calculateNodeLabelUpdate(\n affectedLabels: string[],\n currentNodeFilters: string[],\n allNodesDisabled: boolean,\n): { allLabelsDisabled?: boolean; nodeLabelFilters: string[] } | null {\n if (affectedLabels.length === 0) return null;\n\n if (allNodesDisabled) {\n return { allLabelsDisabled: false, nodeLabelFilters: affectedLabels };\n }\n\n if (currentNodeFilters.length > 0) {\n const labelsToAdd = affectedLabels.filter(\n (l) => !currentNodeFilters.includes(l),\n );\n if (labelsToAdd.length > 0) {\n return { nodeLabelFilters: [...currentNodeFilters, ...labelsToAdd] };\n }\n }\n\n return null;\n}\n\ntype SetFn = (partial: Partial<GraphFilterStore>) => void;\n\ntype NodeLabelUpdate = {\n allLabelsDisabled?: boolean;\n nodeLabelFilters: string[];\n} | null;\n\n/** Re-enable a single edge label from the \"all disabled\" state. */\nfunction handleEnableFromAllDisabled(\n label: string,\n getNodeLabelUpdate: (l: string) => NodeLabelUpdate,\n set: SetFn,\n): void {\n const nodeUpdate = getNodeLabelUpdate(label);\n set({\n allEdgeLabelsDisabled: false,\n edgeLabelFilters: [label],\n ...nodeUpdate,\n });\n}\n\n/** First filter toggle when no filters are active (show-all → single-off). */\nfunction handleFirstFilter(\n label: string,\n allAvailableLabels: string[],\n set: SetFn,\n): void {\n const next = allAvailableLabels.filter((l) => l !== label);\n set({ edgeLabelFilters: next });\n}\n\n/** Normal toggle: add/remove label and handle the \"last one removed\" edge case. */\nfunction handleToggleFilter(\n label: string,\n current: string[],\n exists: boolean,\n getNodeLabelUpdate: (l: string) => NodeLabelUpdate,\n set: SetFn,\n): void {\n const next = exists\n ? current.filter((l) => l !== label)\n : [...current, label];\n\n if (next.length === 0 && exists) {\n set({ allEdgeLabelsDisabled: true, edgeLabelFilters: [] });\n return;\n }\n\n const nodeUpdate = exists ? null : getNodeLabelUpdate(label);\n set({ edgeLabelFilters: next, ...nodeUpdate });\n}\n\nexport function createGraphFilterStore() {\n return create<GraphFilterStore>()((set, get) => ({\n nodeLabelFilters: [],\n allLabelsDisabled: false,\n edgeLabelFilters: [],\n allEdgeLabelsDisabled: false,\n lastDataChangeTime: 0,\n\n notifyDataChange: () => set({ lastDataChangeTime: Date.now() }),\n\n resetFilters: () =>\n set({\n nodeLabelFilters: [],\n allLabelsDisabled: false,\n edgeLabelFilters: [],\n allEdgeLabelsDisabled: false,\n }),\n\n toggleNodeLabelFilter: (label, allAvailableLabels) => {\n const wasAllDisabled = get().allLabelsDisabled;\n if (wasAllDisabled) set({ allLabelsDisabled: false });\n const current = get().nodeLabelFilters;\n const exists = current.includes(label);\n\n if (wasAllDisabled) {\n set({ nodeLabelFilters: [label] });\n } else if (\n current.length === 0 &&\n !exists &&\n allAvailableLabels &&\n allAvailableLabels.length > 0\n ) {\n const next = allAvailableLabels.filter((l) => l !== label);\n set({ nodeLabelFilters: next });\n } else {\n const next = exists\n ? current.filter((l) => l !== label)\n : [...current, label];\n if (next.length === 0 && exists) {\n set({ allLabelsDisabled: true, nodeLabelFilters: [] });\n } else {\n set({ nodeLabelFilters: next });\n }\n }\n },\n clearNodeLabelFilters: () => set({ nodeLabelFilters: [] }),\n setNodeLabelFilters: (labels) => set({ nodeLabelFilters: labels }),\n toggleAllLabelsDisabled: () => {\n const now = !get().allLabelsDisabled;\n set({ allLabelsDisabled: now, nodeLabelFilters: [] });\n },\n\n toggleEdgeLabelFilter: (label, allAvailableLabels, edgeToNodeLabels) => {\n const getNodeLabelUpdate = (edgeLabel: string) => {\n if (!edgeToNodeLabels) return null;\n const affectedLabels = edgeToNodeLabels[edgeLabel] || [];\n return calculateNodeLabelUpdate(\n affectedLabels,\n get().nodeLabelFilters,\n get().allLabelsDisabled,\n );\n };\n\n if (get().allEdgeLabelsDisabled) {\n handleEnableFromAllDisabled(label, getNodeLabelUpdate, set);\n } else if (\n get().edgeLabelFilters.length === 0 &&\n allAvailableLabels &&\n allAvailableLabels.length > 0\n ) {\n handleFirstFilter(label, allAvailableLabels, set);\n } else {\n const current = get().edgeLabelFilters;\n handleToggleFilter(\n label,\n current,\n current.includes(label),\n getNodeLabelUpdate,\n set,\n );\n }\n },\n clearEdgeLabelFilters: () => set({ edgeLabelFilters: [] }),\n setEdgeLabelFilters: (labels) => set({ edgeLabelFilters: labels }),\n toggleAllEdgeLabelsDisabled: () => {\n const now = !get().allEdgeLabelsDisabled;\n set({ allEdgeLabelsDisabled: now, edgeLabelFilters: [] });\n },\n }));\n}\n\n// Global singleton — used by the global QueryEditor singleton and GraphExploration singleton.\nconst useGraphFilter = createGraphFilterStore();\nexport default useGraphFilter;\n","/**\n * GraphExploration Store\n *\n * Manages visual exploration state for the graph visualizer:\n * - Focus mode: Show only selected nodes\n * - Hidden elements: Temporarily hide nodes/edges from view\n * - Expansion tracking: Track which nodes have been expanded\n *\n * This state is separate from:\n * - Selection (which elements are selected)\n * - GraphFocus (zoom/pan actions)\n * - GraphFilter (label filters)\n */\n\nimport { create, StoreApi, UseBoundStore } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\nimport type { GraphDataStore } from \"./GraphData\";\nimport type { SelectionStore } from \"./Selection\";\nimport type { GraphFocusStore } from \"./GraphFocus\";\nimport type { GraphFilterStore } from \"./GraphFilter\";\nimport {\n enrichNodes,\n enrichEdges,\n buildColorPaletteFromNodes,\n} from \"../graph/enrichment\";\nimport type {\n RawGraphNode,\n RawGraphEdge,\n LabelDisplayMap,\n} from \"../models/graph-types\";\n\n/**\n * Store dependencies for GraphExploration.\n * Allows workspace-specific or global store injection.\n */\nexport interface GraphExplorationDeps {\n graphData: UseBoundStore<StoreApi<GraphDataStore>>;\n selection: UseBoundStore<StoreApi<SelectionStore>>;\n graphFocus: UseBoundStore<StoreApi<GraphFocusStore>>;\n graphFilter: UseBoundStore<StoreApi<GraphFilterStore>>;\n\n // Pluggable backend access — decouples store from specific API implementation\n expandNode: (\n id: number,\n ) => Promise<{ nodes: RawGraphNode[]; edges: RawGraphEdge[] }>;\n getNodes: (ids: number[]) => Promise<RawGraphNode[]>;\n\n // Optional: resolved display config map for node label enrichment\n getLabelDisplayMap?: () => LabelDisplayMap;\n}\n\nexport interface GraphExplorationStore {\n /** Node IDs to show in focus mode (empty = not in focus mode) */\n focusedNodeIds: Set<string>;\n\n /** Whether focus mode is active */\n isFocusMode: boolean;\n\n /** Element IDs (nodes + edges) to hide from view */\n hiddenElementIds: Set<string>;\n\n /** Node IDs that have been expanded (for UI feedback) */\n expandedNodeIds: Set<string>;\n\n // --- Actions ---\n\n /**\n * Enter focus mode showing only specified nodes\n * @param nodeIds - IDs of nodes to focus on\n */\n setFocusMode: (nodeIds: string[]) => void;\n\n /**\n * Enter focus mode on a node and its immediate neighborhood\n * (includes the node itself + all directly connected nodes)\n * @param nodeId - ID of the node to focus on\n */\n setFocusModeWithNeighborhood: (nodeId: string) => void;\n\n /**\n * Exit focus mode (show all label-filtered nodes)\n */\n clearFocusMode: () => void;\n\n /**\n * Hide elements from the graph\n * @param elementIds - IDs of nodes and/or edges to hide\n */\n hideElements: (elementIds: string[]) => void;\n\n /**\n * Show previously hidden elements\n * @param elementIds - IDs of nodes and/or edges to show\n */\n showElements: (elementIds: string[]) => void;\n\n /**\n * Hide all nodes that have paths leading TO the specified node (predecessors/ancestors).\n * The clicked node itself remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param nodeId - ID of the node (kept visible)\n */\n hideNodeIncoming: (nodeId: string) => void;\n\n /**\n * Hide all nodes that have paths FROM the specified node (successors/descendants).\n * The clicked node itself remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param nodeId - ID of the node (kept visible)\n */\n hideNodeOutgoing: (nodeId: string) => void;\n\n /**\n * Hide the edge AND the forward path (target node + all its outgoing connections).\n * The source node of the edge remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param edgeId - ID of the edge to hide\n */\n hideEdgeForwardPath: (edgeId: string) => void;\n\n /**\n * Hide the edge AND the reverse path (source node + all its incoming connections).\n * The target node of the edge remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param edgeId - ID of the edge to hide\n */\n hideEdgeReversePath: (edgeId: string) => void;\n\n /**\n * Focus on edges of a specific type, automatically determining direction from selection state.\n *\n * Behavior:\n * - If 1 node + edge selected: Uses the selected node as reference (outgoing if source, incoming if target)\n * - If 2 nodes + edge selected: Defaults to outgoing from start node\n * - Shows all nodes connected via edges of the same type in the determined direction\n *\n * @param edgeId - ID of the edge (to get type and endpoints)\n */\n focusEdge: (edgeId: string) => void;\n\n /**\n * Focus on a specific edge type: show only edges of this type and their connected nodes.\n * All other nodes and edges are hidden.\n *\n * @param edgeId - ID of the edge (to determine the edge type/label)\n */\n focusOnEdgeType: (edgeId: string) => void;\n\n /**\n * Reset all exploration state (clear focus + hidden)\n * Note: Keeps expandedNodeIds since those nodes are still in the data\n */\n resetView: () => void;\n\n /**\n * Reset ALL exploration state including expanded nodes.\n * Should be called when new query data is loaded to ensure clean state.\n */\n resetForNewQuery: () => void;\n\n /**\n * Mark a node as expanded (for UI feedback)\n * @param nodeId - ID of expanded node\n */\n markNodeExpanded: (nodeId: string) => void;\n\n /**\n * Check if a node has been expanded\n * @param nodeId - ID to check\n */\n isNodeExpanded: (nodeId: string) => boolean;\n\n /**\n * Expand a node by fetching connected nodes/edges from backend\n * and merging them into the graph data.\n * @param nodeId - ID of the node to expand\n * @returns Promise that resolves when expansion is complete\n */\n expandNode: (nodeId: string) => Promise<void>;\n\n /**\n * Add a node to the graph by ID.\n * If the node already exists in the graph, just focuses it (if autoFocus=true).\n * If not, fetches it from the API, enriches it with visual data,\n * adds it to the graph, and optionally focuses it.\n *\n * @param nodeId - ID of the node to add\n * @param autoFocus - Whether to automatically focus the node after adding (default: false)\n * @returns Promise that resolves when the node is added/focused\n */\n addNodeById: (nodeId: number, autoFocus?: boolean) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Shared traversal helper\n// ---------------------------------------------------------------------------\n\ninterface TraversalResult {\n nodes: Set<string>;\n edges: Set<string>;\n}\n\n/**\n * Recursively collect all node/edge IDs reachable from `startId` by following\n * edges in the given direction. The start node itself is excluded when\n * `includeStart` is false (used for \"boundary marker\" behaviour).\n */\nfunction collectReachable(\n startId: string,\n direction: \"in\" | \"out\",\n allEdges: { id_?: number; start_id_: number; end_id_: number }[],\n includeStart: boolean,\n): TraversalResult {\n const nodes = new Set<string>();\n const edges = new Set<string>();\n const visited = new Set<string>();\n\n const traverse = (currentId: string, isStart: boolean) => {\n if (visited.has(currentId)) return;\n visited.add(currentId);\n\n if (!isStart || includeStart) nodes.add(currentId);\n\n for (const edge of allEdges) {\n const srcId = String(edge.start_id_);\n const tgtId = String(edge.end_id_);\n const edgeId = String(edge.id_);\n\n if (direction === \"in\" && tgtId === currentId) {\n edges.add(edgeId);\n traverse(srcId, false);\n } else if (direction === \"out\" && srcId === currentId) {\n edges.add(edgeId);\n traverse(tgtId, false);\n }\n }\n };\n\n traverse(startId, true);\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// focusEdge helpers\n// ---------------------------------------------------------------------------\n\ninterface EdgeEndpoints {\n edgeLabel: string;\n startNodeId: string;\n endNodeId: string;\n}\n\n/**\n * Determine the traversal direction and reference node for focusEdge,\n * based on the current selection state.\n */\nfunction determineEdgeDirection(\n endpoints: EdgeEndpoints,\n selectedNodeIds: string[],\n): { direction: \"outgoing\" | \"incoming\"; referenceNodeId: string } {\n const { startNodeId, endNodeId } = endpoints;\n\n if (selectedNodeIds.length !== 1) {\n // Two nodes selected or edge selected directly – default to outgoing from start\n return { direction: \"outgoing\", referenceNodeId: startNodeId };\n }\n\n // Single node selected – use it as reference\n const selected = selectedNodeIds[0];\n\n if (selected === startNodeId) {\n return { direction: \"outgoing\", referenceNodeId: selected };\n }\n if (selected === endNodeId) {\n return { direction: \"incoming\", referenceNodeId: selected };\n }\n\n // Selected node is not an endpoint (shouldn't happen, but safe fallback)\n devLog(\n \"[GraphExploration] focusEdge - selected node not an endpoint, defaulting to outgoing\",\n { selectedNode: selected, startNodeId, endNodeId },\n );\n return { direction: \"outgoing\", referenceNodeId: startNodeId };\n}\n\n/**\n * Build the set of node IDs to focus on: the reference node plus all nodes\n * connected via edges of the same label in the given direction.\n */\nfunction buildFocusSet(\n referenceNodeId: string,\n direction: \"outgoing\" | \"incoming\",\n edgeLabel: string,\n allEdges: {\n id_?: number;\n start_id_: number;\n end_id_: number;\n label_: string;\n }[],\n): Set<string> {\n const focusNodeIds = new Set<string>([referenceNodeId]);\n\n for (const e of allEdges) {\n if (e.label_ !== edgeLabel) continue;\n\n const sourceId = String(e.start_id_);\n const targetId = String(e.end_id_);\n\n if (direction === \"outgoing\" && sourceId === referenceNodeId) {\n focusNodeIds.add(targetId);\n } else if (direction === \"incoming\" && targetId === referenceNodeId) {\n focusNodeIds.add(sourceId);\n }\n }\n\n return focusNodeIds;\n}\n\n// ---------------------------------------------------------------------------\n// addNodeById helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Handle the case where the node already exists in the graph.\n * Returns true if the node was found (caller should return early).\n */\nfunction handleExistingNode(\n nodeId: number,\n nodeIdStr: string,\n existingNodes: RawGraphNode[],\n autoFocus: boolean,\n graphFocusStore: GraphExplorationDeps[\"graphFocus\"],\n): boolean {\n const existingNode = existingNodes.find((n) => n.id_ === nodeId);\n if (!existingNode) return false;\n\n if (autoFocus) {\n devLog(\"[GraphExploration] Node already in graph, focusing\", { nodeId });\n graphFocusStore.getState().requestFocus(nodeIdStr, \"node\", false);\n } else {\n devLog(\"[GraphExploration] Node already in graph, skipping focus\", {\n nodeId,\n });\n }\n return true;\n}\n\n/**\n * Fetch the node from the backend, enrich it, and merge it into the graph\n * data store. Returns the array of enriched nodes.\n */\nasync function fetchAndEnrichNode(\n nodeId: number,\n existingNodes: RawGraphNode[],\n stores: GraphExplorationDeps,\n): Promise<ReturnType<typeof enrichNodes>> {\n devLog(\"[GraphExploration] Fetching node from backend\", { nodeId });\n const result = await stores.getNodes([nodeId]);\n\n if (result.length === 0) {\n throw new Error(`Node ${nodeId} not found`);\n }\n\n const colorPalette = buildColorPaletteFromNodes([\n ...existingNodes,\n ...result,\n ]);\n const enrichedNodes = enrichNodes(\n result,\n colorPalette,\n stores.getLabelDisplayMap?.(),\n );\n\n devLog(\"[GraphExploration] Enriched nodes\", {\n nodeId,\n enrichedCount: enrichedNodes.length,\n });\n\n stores.graphData.getState().mergeExpandedData(enrichedNodes, []);\n return enrichedNodes;\n}\n\n/**\n * Ensure the first enriched node's label is included in the active\n * node-label filters (prevents new nodes from being immediately hidden).\n */\nfunction ensureNodeLabelInFilters(\n enrichedNodes: ReturnType<typeof enrichNodes>,\n nodeId: number,\n graphFilterStore: GraphExplorationDeps[\"graphFilter\"],\n): void {\n const addedNode = enrichedNodes[0];\n if (!addedNode) return;\n\n const { nodeLabelFilters: currentFilters } = graphFilterStore.getState();\n const nodeLabel = addedNode.label_;\n\n if (currentFilters.length > 0 && !currentFilters.includes(nodeLabel)) {\n devLog(\"[GraphExploration] Adding node label to active filters\", {\n nodeId,\n nodeLabel,\n currentFilters,\n });\n graphFilterStore\n .getState()\n .setNodeLabelFilters([...currentFilters, nodeLabel]);\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Factory function to create a new GraphExploration store instance.\n * Used by workspace system to create isolated store instances per workspace.\n *\n * @param deps - Store and service dependencies (graphData, selection, graphFocus, graphFilter, expandNode, getNodes)\n */\nexport function createGraphExplorationStore(deps: GraphExplorationDeps) {\n const stores = deps;\n\n return create<GraphExplorationStore>()((set, get) => ({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n hiddenElementIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n\n setFocusMode: (nodeIds) => {\n devLog(\"[GraphExploration] setFocusMode\", {\n nodeIds,\n count: nodeIds.length,\n });\n\n set({\n focusedNodeIds: new Set(nodeIds),\n isFocusMode: true,\n });\n },\n\n setFocusModeWithNeighborhood: (nodeId) => {\n // Get all edges from GraphData store\n const edges = stores.graphData.getState().edges;\n\n // Find all nodes connected to this node via edges\n const connectedNodeIds = new Set<string>();\n const nodeIdStr = String(nodeId);\n\n for (const edge of edges) {\n const sourceId = String(edge.start_id_);\n const targetId = String(edge.end_id_);\n\n // If this edge connects to our node, add the other end\n if (sourceId === nodeIdStr) {\n connectedNodeIds.add(targetId);\n } else if (targetId === nodeIdStr) {\n connectedNodeIds.add(sourceId);\n }\n }\n\n // Include the clicked node itself plus all connected nodes\n const focusNodeIds = [nodeIdStr, ...Array.from(connectedNodeIds)];\n\n devLog(\"[GraphExploration] setFocusModeWithNeighborhood\", {\n nodeId: nodeIdStr,\n connectedNodes: connectedNodeIds.size,\n totalFocused: focusNodeIds.length,\n });\n\n set({\n focusedNodeIds: new Set(focusNodeIds),\n isFocusMode: true,\n });\n },\n\n clearFocusMode: () => {\n devLog(\"[GraphExploration] clearFocusMode\");\n\n set({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n });\n },\n\n hideElements: (elementIds) => {\n const current = get().hiddenElementIds;\n const updated = new Set(current);\n\n elementIds.forEach((id) => updated.add(id));\n\n devLog(\"[GraphExploration] hideElements\", {\n newIds: elementIds,\n totalHidden: updated.size,\n });\n\n set({ hiddenElementIds: updated });\n },\n\n showElements: (elementIds) => {\n const current = get().hiddenElementIds;\n const updated = new Set(current);\n\n elementIds.forEach((id) => updated.delete(id));\n\n devLog(\"[GraphExploration] showElements\", {\n restoredIds: elementIds,\n remainingHidden: updated.size,\n });\n\n set({ hiddenElementIds: updated });\n },\n\n hideNodeIncoming: (nodeId) => {\n devLog(\"[GraphExploration] hideNodeIncoming - hiding predecessors\", {\n nodeId,\n });\n\n const { edges } = stores.graphData.getState();\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n nodeId,\n \"in\",\n edges,\n false,\n );\n\n devLog(\"[GraphExploration] hideNodeIncoming - traversal complete\", {\n nodeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) {\n get().hideElements(allElementsToHide);\n } else {\n devLog(\"[GraphExploration] hideNodeIncoming - no predecessors found\");\n }\n },\n\n hideNodeOutgoing: (nodeId) => {\n devLog(\"[GraphExploration] hideNodeOutgoing - hiding successors\", {\n nodeId,\n });\n\n const { edges } = stores.graphData.getState();\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n nodeId,\n \"out\",\n edges,\n false,\n );\n\n devLog(\"[GraphExploration] hideNodeOutgoing - traversal complete\", {\n nodeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) {\n get().hideElements(allElementsToHide);\n } else {\n devLog(\"[GraphExploration] hideNodeOutgoing - no successors found\");\n }\n },\n\n hideEdgeForwardPath: (edgeId: string) => {\n devLog(\n \"[GraphExploration] hideEdgeForwardPath - hiding edge + target + downstream\",\n { edgeId },\n );\n\n const { edges } = stores.graphData.getState();\n const edge = edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] hideEdgeForwardPath - edge not found\", {\n edgeId,\n });\n return;\n }\n\n const targetNodeId = String(edge.end_id_);\n\n // Hide the clicked edge first, then target and all downstream nodes/edges\n get().hideElements([edgeId]);\n\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n targetNodeId,\n \"out\",\n edges,\n true,\n );\n\n devLog(\"[GraphExploration] hideEdgeForwardPath - traversal complete\", {\n edgeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) get().hideElements(allElementsToHide);\n },\n\n hideEdgeReversePath: (edgeId: string) => {\n devLog(\n \"[GraphExploration] hideEdgeReversePath - hiding edge + source + upstream\",\n { edgeId },\n );\n\n const { edges } = stores.graphData.getState();\n const edge = edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] hideEdgeReversePath - edge not found\", {\n edgeId,\n });\n return;\n }\n\n const sourceNodeId = String(edge.start_id_);\n\n // Hide the clicked edge first, then source and all upstream nodes/edges\n get().hideElements([edgeId]);\n\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n sourceNodeId,\n \"in\",\n edges,\n true,\n );\n\n devLog(\"[GraphExploration] hideEdgeReversePath - traversal complete\", {\n edgeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) get().hideElements(allElementsToHide);\n },\n\n focusOnEdgeType: (edgeId: string) => {\n devLog(\n \"[GraphExploration] focusOnEdgeType - show only edges of this type and connected nodes\",\n { edgeId },\n );\n\n const graphData = stores.graphData.getState();\n\n // Find the edge to get its type (label)\n const edge = graphData.edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] focusOnEdgeType - edge not found\", {\n edgeId,\n });\n return;\n }\n\n const edgeLabel = edge.label_;\n devLog(\"[GraphExploration] focusOnEdgeType - filtering by label\", {\n edgeId,\n edgeLabel,\n });\n\n // Find all edges of this type\n const edgesOfType = graphData.edges.filter((e) => e.label_ === edgeLabel);\n\n // Collect node IDs connected by edges of this type\n const connectedNodeIds = new Set<string>();\n const visibleEdgeIds = new Set<string>();\n\n for (const e of edgesOfType) {\n connectedNodeIds.add(String(e.start_id_));\n connectedNodeIds.add(String(e.end_id_));\n visibleEdgeIds.add(String(e.id_));\n }\n\n // Determine what to hide: nodes not connected, edges not of this type\n const nodesToHide: string[] = [];\n const edgesToHide: string[] = [];\n\n for (const node of graphData.nodes) {\n const nodeId = String(node.id_);\n if (!connectedNodeIds.has(nodeId)) {\n nodesToHide.push(nodeId);\n }\n }\n\n for (const e of graphData.edges) {\n const eId = String(e.id_);\n if (!visibleEdgeIds.has(eId)) {\n edgesToHide.push(eId);\n }\n }\n\n devLog(\"[GraphExploration] focusOnEdgeType - hiding elements\", {\n edgeLabel,\n visibleEdges: visibleEdgeIds.size,\n visibleNodes: connectedNodeIds.size,\n hidingNodes: nodesToHide.length,\n hidingEdges: edgesToHide.length,\n });\n\n // Hide all non-matching elements\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) {\n get().hideElements(allElementsToHide);\n }\n },\n\n focusEdge: (edgeId: string) => {\n devLog(\n \"[GraphExploration] focusEdge - unified focus with auto-direction detection\",\n { edgeId },\n );\n\n const graphData = stores.graphData.getState();\n const selection = stores.selection.getState();\n\n // Find the edge to get its type and endpoints\n const edge = graphData.edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] focusEdge - edge not found\", { edgeId });\n return;\n }\n\n const endpoints: EdgeEndpoints = {\n edgeLabel: edge.label_,\n startNodeId: String(edge.start_id_),\n endNodeId: String(edge.end_id_),\n };\n\n const { direction, referenceNodeId } = determineEdgeDirection(\n endpoints,\n selection.selectedNodeIds,\n );\n\n devLog(\"[GraphExploration] focusEdge - determined direction\", {\n edgeId,\n edgeLabel: endpoints.edgeLabel,\n direction,\n referenceNodeId,\n selectionMode:\n selection.selectedNodeIds.length === 1\n ? \"single-node\"\n : \"traditional\",\n });\n\n const focusNodeIds = buildFocusSet(\n referenceNodeId,\n direction,\n endpoints.edgeLabel,\n graphData.edges,\n );\n\n devLog(\"[GraphExploration] focusEdge - found nodes\", {\n edgeLabel: endpoints.edgeLabel,\n direction,\n referenceNodeId,\n totalNodes: focusNodeIds.size,\n });\n\n // Set focus mode with all found nodes\n set({\n focusedNodeIds: focusNodeIds,\n isFocusMode: true,\n });\n },\n\n resetView: () => {\n devLog(\"[GraphExploration] resetView - clearing all exploration state\");\n\n set({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n hiddenElementIds: new Set<string>(),\n // Note: We keep expandedNodeIds - those nodes are still in the data\n });\n },\n\n resetForNewQuery: () => {\n devLog(\n \"[GraphExploration] resetForNewQuery - clearing ALL exploration state for new query\",\n );\n\n set({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n hiddenElementIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n });\n },\n\n markNodeExpanded: (nodeId) => {\n const current = get().expandedNodeIds;\n const updated = new Set(current);\n updated.add(nodeId);\n\n devLog(\"[GraphExploration] markNodeExpanded\", { nodeId });\n\n set({ expandedNodeIds: updated });\n },\n\n isNodeExpanded: (nodeId) => {\n return get().expandedNodeIds.has(nodeId);\n },\n\n expandNode: async (nodeId) => {\n devLog(\"[GraphExploration] expandNode\", { nodeId });\n\n try {\n // Fetch connected nodes and edges via injected backend provider\n const result = await stores.expandNode(Number(nodeId));\n\n devLog(\"[GraphExploration] Expansion API result\", {\n nodeId,\n newNodes: result.nodes.length,\n newEdges: result.edges.length,\n });\n\n // If no new nodes/edges found, log and return\n if (result.nodes.length === 0 && result.edges.length === 0) {\n devLog(\"[GraphExploration] No connected nodes found\", { nodeId });\n return;\n }\n\n // Get existing nodes to build consistent color palette\n const existingNodes = stores.graphData.getState().nodes;\n const colorPalette = buildColorPaletteFromNodes([\n ...existingNodes,\n ...result.nodes,\n ]);\n\n // Enrich the new nodes and edges with visual properties\n const enrichedNodes = enrichNodes(\n result.nodes,\n colorPalette,\n stores.getLabelDisplayMap?.(),\n );\n const enrichedEdges = enrichEdges(result.edges);\n\n // Merge into GraphData store (handles deduplication)\n stores.graphData\n .getState()\n .mergeExpandedData(enrichedNodes, enrichedEdges);\n\n // Ensure all new node labels are included in active filters\n // This prevents expanded nodes from being immediately filtered out\n const graphFilterState = stores.graphFilter.getState();\n const currentFilters = graphFilterState.nodeLabelFilters;\n\n // Only modify filters if they're actively filtering (not showing all)\n if (currentFilters.length > 0 && enrichedNodes.length > 0) {\n const newLabels = new Set(enrichedNodes.map((n) => n.label_));\n const labelsToAdd = Array.from(newLabels).filter(\n (label) => !currentFilters.includes(label),\n );\n\n if (labelsToAdd.length > 0) {\n devLog(\n \"[GraphExploration] Adding expanded node labels to active filters\",\n {\n nodeId,\n labelsToAdd,\n currentFilters,\n },\n );\n stores.graphFilter\n .getState()\n .setNodeLabelFilters([...currentFilters, ...labelsToAdd]);\n }\n }\n\n // Mark node as expanded for UI feedback\n get().markNodeExpanded(nodeId);\n\n // If in focus mode, add the new nodes to the focused set so they become visible\n const currentState = get();\n if (currentState.isFocusMode) {\n const newFocusedIds = new Set(currentState.focusedNodeIds);\n for (const node of enrichedNodes) {\n newFocusedIds.add(String(node.id_));\n }\n\n devLog(\"[GraphExploration] Adding expanded nodes to focus set\", {\n nodeId,\n previousFocusCount: currentState.focusedNodeIds.size,\n addedToFocus: enrichedNodes.length,\n newFocusCount: newFocusedIds.size,\n });\n\n set({ focusedNodeIds: newFocusedIds });\n }\n\n devLog(\"[GraphExploration] Expansion complete\", {\n nodeId,\n addedNodes: enrichedNodes.length,\n addedEdges: enrichedEdges.length,\n });\n } catch (error) {\n devLog(\"[GraphExploration] Expansion failed\", { nodeId, error });\n throw error; // Re-throw so UI can handle it\n }\n },\n\n addNodeById: async (nodeId, autoFocus = false) => {\n const nodeIdStr = String(nodeId);\n devLog(\"[GraphExploration] addNodeById\", { nodeId, autoFocus });\n\n try {\n // Check if node already exists in the graph\n const existingNodes = stores.graphData.getState().nodes;\n\n if (\n handleExistingNode(\n nodeId,\n nodeIdStr,\n existingNodes,\n autoFocus,\n stores.graphFocus,\n )\n ) {\n return;\n }\n\n // Node doesn't exist -> fetch, enrich, and merge into store\n const enrichedNodes = await fetchAndEnrichNode(\n nodeId,\n existingNodes,\n stores,\n );\n\n // Ensure the node's label is included in active filters\n ensureNodeLabelInFilters(enrichedNodes, nodeId, stores.graphFilter);\n\n // Optionally focus the newly added node\n // NOTE: For clipboard additions, autoFocus should be false to avoid override system\n // conflicts. The node will appear in the graph naturally and can be selected manually.\n if (autoFocus) {\n devLog(\"[GraphExploration] Requesting focus for newly added node\", {\n nodeId,\n });\n stores.graphFocus.getState().requestFocus(nodeIdStr, \"node\", false);\n } else {\n devLog(\"[GraphExploration] Skipping focus for newly added node\", {\n nodeId,\n });\n }\n\n // If in focus mode, add the new node to the focused set so it becomes visible\n const currentState = get();\n if (currentState.isFocusMode) {\n const newFocusedIds = new Set(currentState.focusedNodeIds);\n newFocusedIds.add(nodeIdStr);\n\n devLog(\"[GraphExploration] Adding node to focus set\", {\n nodeId,\n previousFocusCount: currentState.focusedNodeIds.size,\n newFocusCount: newFocusedIds.size,\n });\n\n set({ focusedNodeIds: newFocusedIds });\n }\n\n devLog(\"[GraphExploration] addNodeById complete\", {\n nodeId,\n addedNodes: enrichedNodes.length,\n autoFocus,\n });\n } catch (error) {\n devLog(\"[GraphExploration] addNodeById failed\", { nodeId, error });\n throw error; // Re-throw so UI can handle it\n }\n },\n }));\n}\n\n// No global singleton in the package — consumers wire their own deps via createGraphExplorationStore().\n","/**\n * GraphFocus Store\n *\n * Manages graph element focus/zoom actions across different renderers (Cytoscape, Reagraph).\n * Provides a decoupled way for tools to request focus on specific elements without\n * needing direct access to the renderer instance.\n *\n * Pattern: tools dispatch focus actions → store holds state → renderers subscribe and react\n */\n\nimport { create } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\n/** Descriptor for a pending focus action */\nexport interface GraphFocusAction {\n /** ID of the node or edge to focus on */\n elementId: string;\n\n /** Type of element */\n elementType: \"node\" | \"edge\";\n\n /** Action to perform: focus only or focus and select */\n action: \"focus\" | \"focus-and-select\";\n\n /** Timestamp ensures uniqueness — triggers subscription even for same element */\n timestamp: number;\n}\n\nexport interface GraphFocusStore {\n /** Current focus action (null when no action is pending) */\n focusAction: GraphFocusAction | null;\n\n /** Element IDs to show despite active filters (temporary override) */\n overrideElementIds: Set<string>;\n\n /**\n * Request focus on a graph element.\n * @param elementId - ID of the node or edge\n * @param elementType - 'node' or 'edge'\n * @param shouldSelect - Also select the element after focusing\n */\n requestFocus: (\n elementId: string,\n elementType: \"node\" | \"edge\",\n shouldSelect: boolean,\n ) => void;\n\n /** Clear the current focus action and all overrides */\n clear: () => void;\n\n /** Clear filter overrides only (keeps the current focus action) */\n clearOverrides: () => void;\n}\n\nfunction buildStore() {\n return (\n set: (partial: Partial<GraphFocusStore>) => void,\n get: () => GraphFocusStore,\n ) => ({\n focusAction: null,\n overrideElementIds: new Set<string>(),\n\n requestFocus: (\n elementId: string,\n elementType: \"node\" | \"edge\",\n shouldSelect: boolean,\n ) => {\n const action: GraphFocusAction = {\n elementId,\n elementType,\n action: shouldSelect ? \"focus-and-select\" : \"focus\",\n timestamp: Date.now(),\n };\n devLog(\"[GraphFocusStore] requestFocus\", {\n elementId,\n elementType,\n action: action.action,\n });\n // overrideElementIds are set by the renderer after it determines whether\n // the element is already visible. Setting them here would cause unnecessary redraws.\n set({ focusAction: action });\n },\n\n clear: () => {\n const prev = get().focusAction;\n if (prev) {\n devLog(\"[GraphFocusStore] clear\", { prevElementId: prev.elementId });\n }\n set({ focusAction: null, overrideElementIds: new Set<string>() });\n },\n\n clearOverrides: () => {\n devLog(\"[GraphFocusStore] clearOverrides\");\n set({ overrideElementIds: new Set<string>() });\n },\n });\n}\n\n/** Create an isolated GraphFocus store instance (use for multi-workspace scenarios). */\nexport function createGraphFocusStore() {\n return create<GraphFocusStore>()(buildStore());\n}\n\n/** Global singleton — sufficient for single-workspace applications. */\nconst useGraphFocus = createGraphFocusStore();\nexport default useGraphFocus;\n","import { create } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\nexport type ActionPanelState = \"hidden\" | \"visible\";\n\nexport interface ActionPanelStore {\n state: ActionPanelState;\n setState: (state: ActionPanelState) => void;\n hide: () => void;\n show: () => void;\n isHidden: () => boolean;\n}\n\nfunction buildStore() {\n return (\n set: (partial: Partial<ActionPanelStore>) => void,\n get: () => ActionPanelStore,\n ) => ({\n state: \"visible\" as ActionPanelState,\n\n setState: (state: ActionPanelState) => {\n devLog(\"[ActionPanelStore] setState\", { state });\n set({ state });\n },\n\n hide: () => {\n devLog(\"[ActionPanelStore] hide\");\n set({ state: \"hidden\" });\n },\n\n show: () => {\n devLog(\"[ActionPanelStore] show\");\n set({ state: \"visible\" });\n },\n\n isHidden: () => get().state === \"hidden\",\n });\n}\n\n/** Create an isolated ActionPanel store instance. */\nexport function createActionPanelStore() {\n return create<ActionPanelStore>()(buildStore());\n}\n\n/** Global singleton — sufficient for single-workspace applications. */\nexport const useActionPanelStore = createActionPanelStore();\n","/**\n * Graph Workspace Store Hooks\n *\n * Provides access to workspace-specific graph store instances via React context.\n * Consumers wrap their graph UI with <GraphStoresProvider> and supply the store bundle.\n *\n * This replaces the explorer's WorkspaceManager-based hooks with a simple\n * context-based approach that works in any host application.\n */\n\nimport { createContext, useContext } from \"react\";\nimport type { StoreApi, UseBoundStore } from \"zustand\";\nimport type { WorkspaceStores } from \"../stores/types\";\nimport type { GraphFilterStore } from \"../stores/GraphFilter\";\nimport type { GraphDataStore } from \"../stores/GraphData\";\nimport type { GraphExplorationStore } from \"../stores/GraphExploration\";\nimport type { SelectionStore } from \"../stores/Selection\";\n\n/**\n * Re-export WorkspaceStores as the canonical bundle type.\n * Components and consumers use this to provide stores via context.\n */\nexport type { WorkspaceStores as GraphStoreBundle };\n\n/**\n * Context for providing graph stores to visualization components.\n * Must be set by the host application (e.g., explorer, Atlas).\n */\nexport const GraphStoresContext = createContext<WorkspaceStores | null>(null);\n\nfunction useGraphStores(): WorkspaceStores {\n const ctx = useContext(GraphStoresContext);\n if (!ctx) {\n throw new Error(\n \"useGraphStores must be used within a GraphStoresProvider. \" +\n \"Wrap your graph UI with <GraphStoresContext.Provider value={...}>.\",\n );\n }\n return ctx;\n}\n\n/** Get GraphFilter store from context. */\nexport function useWorkspaceGraphFilter(): UseBoundStore<\n StoreApi<GraphFilterStore>\n> {\n return useGraphStores().graphFilter;\n}\n\n/** Get GraphData store from context. */\nexport function useWorkspaceGraphData(): UseBoundStore<\n StoreApi<GraphDataStore>\n> {\n return useGraphStores().graphData;\n}\n\n/** Get GraphExploration store from context. */\nexport function useWorkspaceGraphExploration(): UseBoundStore<\n StoreApi<GraphExplorationStore>\n> {\n return useGraphStores().graphExploration;\n}\n\n/** Get Selection store from context. */\nexport function useWorkspaceSelection(): UseBoundStore<\n StoreApi<SelectionStore>\n> {\n return useGraphStores().selection;\n}\n","import { useMemo, useEffect } from \"react\";\nimport {\n useWorkspaceGraphFilter,\n useWorkspaceGraphData,\n useWorkspaceGraphExploration,\n} from \"./useWorkspaceStores\";\nimport useGraphFocus from \"../stores/GraphFocus\";\nimport { buildColorPalette, ColorPalette } from \"../graph/enrichment\";\nimport { type GraphStatistics } from \"../interfaces\";\nimport {\n normalizeGraph,\n EMPTY_NORMALIZED,\n NormalizedGraph,\n} from \"../graph/normalize\";\nimport { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\n/**\n * Result type for useLiveGraphData hook.\n *\n * Returns enriched VisualGraph data with color palette and statistics.\n */\nexport interface LiveGraphDataResult {\n nodes: VisualGraphNode[];\n edges: VisualGraphEdge[];\n stats: GraphStatistics | undefined;\n /** Node label counts after hidden/focus filters, before label-checkbox filters */\n labelCounts: Record<string, number>;\n /** Edge label counts after node visibility filters, before edge-label-checkbox filters */\n edgeLabelCounts: Record<string, number>;\n /** Value rows for non-graph (tabular) query results */\n values: string[][];\n colorPalette: ColorPalette;\n /** Filtered graph for visualization (respects all active filters) */\n normalized: NormalizedGraph;\n /** Unfiltered graph containing all nodes/edges from the last query */\n baseNormalized: NormalizedGraph;\n}\n\nexport function useLiveGraphData() {\n // Get workspace-scoped stores (uses \"default\" workspace from context)\n const useGraphFilter = useWorkspaceGraphFilter();\n const useGraphData = useWorkspaceGraphData();\n const useGraphExploration = useWorkspaceGraphExploration();\n\n const lastDataChangeTime = useGraphFilter((s) => s.lastDataChangeTime);\n const filterLabels = useGraphFilter((s) => s.nodeLabelFilters);\n const allLabelsDisabled = useGraphFilter((s) => s.allLabelsDisabled);\n const edgeFilterLabels = useGraphFilter((s) => s.edgeLabelFilters);\n const allEdgeLabelsDisabled = useGraphFilter((s) => s.allEdgeLabelsDisabled);\n\n // Subscribe to focus overrides for reactive filtering\n const overrideElementIds = useGraphFocus((s) => s.overrideElementIds);\n\n // Subscribe to exploration state for focus/hidden filtering\n const isFocusMode = useGraphExploration((s) => s.isFocusMode);\n const focusedNodeIds = useGraphExploration((s) => s.focusedNodeIds);\n const hiddenElementIds = useGraphExploration((s) => s.hiddenElementIds);\n\n // Subscribe to GraphData store for enriched data\n const baseNodes = useGraphData((s) => s.nodes);\n const baseEdges = useGraphData((s) => s.edges);\n const stats = useGraphData((s) => s.stats);\n const values = useGraphData((s) => s.values);\n const isValueSet = useGraphData((s) => s.isValueSet);\n\n devLog(\"[useLiveGraphData] Store data\", {\n baseNodes: baseNodes.length,\n baseEdges: baseEdges.length,\n isFocusMode,\n focusedCount: focusedNodeIds.size,\n hiddenCount: hiddenElementIds.size,\n });\n\n // Clear overrides when query is executed (new data = old overrides are stale)\n useEffect(() => {\n useGraphFocus.getState().clearOverrides();\n }, [lastDataChangeTime]);\n\n // Compute ALL label counts from baseNodes for color palette\n // This includes all nodes (query + expanded), used only for color palette generation\n const allLabelCounts = useMemo(() => {\n if (isValueSet) return {} as Record<string, number>;\n const counts: Record<string, number> = {};\n for (const n of baseNodes) {\n const l = n?.label_;\n if (l) counts[l] = (counts[l] || 0) + 1;\n }\n return counts;\n }, [baseNodes, isValueSet]);\n\n // Stable color palette derived from all labels (not filtered)\n const colorPalette = useMemo(() => {\n if (isValueSet) return {} as ColorPalette;\n return buildColorPalette(allLabelCounts);\n }, [allLabelCounts, isValueSet]);\n\n // Compute \"available\" nodes for label counting (BEFORE label filters, AFTER hidden/focus)\n // This represents nodes that could be shown if their label is enabled\n const availableNodes = useMemo(() => {\n let available = baseNodes;\n\n // Apply focus mode filter\n if (isFocusMode && focusedNodeIds.size > 0) {\n available = available.filter((n: VisualGraphNode) =>\n focusedNodeIds.has(String(n.id_)),\n );\n }\n\n // Apply hidden elements filter\n if (hiddenElementIds.size > 0) {\n available = available.filter(\n (n: VisualGraphNode) => !hiddenElementIds.has(String(n.id_)),\n );\n }\n\n return available;\n }, [baseNodes, isFocusMode, focusedNodeIds, hiddenElementIds]);\n\n // Compute \"available\" edges for label counting (BEFORE edge label filters, AFTER node filters/hidden)\n const availableEdges = useMemo(() => {\n // First, determine which nodes are available\n const availableNodeIds = new Set(\n availableNodes.map((n: VisualGraphNode) => String(n.id_)),\n );\n\n // Edges are available if both their endpoints are available nodes\n let available = baseEdges.filter(\n (e: VisualGraphEdge) =>\n availableNodeIds.has(String(e.start_id_)) &&\n availableNodeIds.has(String(e.end_id_)),\n );\n\n // Apply hidden elements filter for edges\n if (hiddenElementIds.size > 0) {\n available = available.filter(\n (e: VisualGraphEdge) => !hiddenElementIds.has(String(e.id_)),\n );\n }\n\n return available;\n }, [baseEdges, availableNodes, hiddenElementIds]);\n\n // Label counts for badges - shows \"available\" nodes (respects hidden/focus, ignores label filters)\n const labelCounts = useMemo(() => {\n if (isValueSet) return {} as Record<string, number>;\n const counts: Record<string, number> = {};\n for (const n of availableNodes) {\n const l = n?.label_;\n if (l) counts[l] = (counts[l] || 0) + 1;\n }\n return counts;\n }, [availableNodes, isValueSet]);\n\n // Edge label counts for badges - shows \"available\" edges (respects node visibility/hidden, ignores edge label filters)\n const edgeLabelCounts = useMemo(() => {\n if (isValueSet) return {} as Record<string, number>;\n const counts: Record<string, number> = {};\n for (const e of availableEdges) {\n const l = e?.label_;\n if (l) counts[l] = (counts[l] || 0) + 1;\n }\n return counts;\n }, [availableEdges, isValueSet]);\n\n const filteredNodes = useMemo(() => {\n let filtered: VisualGraphNode[];\n\n // Step 1: Apply label filters (from GraphFilter store)\n if (allLabelsDisabled) {\n filtered = [];\n } else if (filterLabels && filterLabels.length > 0) {\n const setLabels = new Set(filterLabels);\n filtered = baseNodes.filter((n: VisualGraphNode) =>\n setLabels.has(n.label_),\n );\n } else {\n filtered = baseNodes;\n }\n\n // Step 2: Apply focus mode filter (from GraphExploration store)\n if (isFocusMode && focusedNodeIds.size > 0) {\n devLog(\"[useLiveGraphData] Applying focus mode filter\", {\n focusedCount: focusedNodeIds.size,\n beforeFilter: filtered.length,\n });\n filtered = filtered.filter((n) => focusedNodeIds.has(String(n.id_)));\n devLog(\"[useLiveGraphData] After focus mode filter\", {\n afterFilter: filtered.length,\n });\n }\n\n // Step 3: Apply hidden elements filter (from GraphExploration store)\n if (hiddenElementIds.size > 0) {\n devLog(\"[useLiveGraphData] Applying hidden elements filter\", {\n hiddenCount: hiddenElementIds.size,\n beforeFilter: filtered.length,\n });\n filtered = filtered.filter((n) => !hiddenElementIds.has(String(n.id_)));\n devLog(\"[useLiveGraphData] After hidden elements filter\", {\n afterFilter: filtered.length,\n });\n }\n\n // Step 4: Apply focus overrides (from GraphFocus store)\n // Must happen AFTER all other filters so overrides bypass them\n if (overrideElementIds.size > 0) {\n const filteredIds = new Set(\n filtered.map((n: VisualGraphNode) => String(n.id_)),\n );\n const overrideNodes = baseNodes.filter(\n (n: VisualGraphNode) =>\n overrideElementIds.has(String(n.id_)) &&\n !filteredIds.has(String(n.id_)),\n );\n if (overrideNodes.length > 0) {\n devLog(\"[useLiveGraphData] Adding override nodes\", {\n overrideCount: overrideNodes.length,\n overrideIds: overrideNodes.map((n: VisualGraphNode) => n.id_),\n totalAfterOverride: filtered.length + overrideNodes.length,\n });\n filtered = [...filtered, ...overrideNodes];\n }\n }\n\n return filtered;\n }, [\n baseNodes,\n filterLabels,\n allLabelsDisabled,\n isFocusMode,\n focusedNodeIds,\n hiddenElementIds,\n overrideElementIds,\n ]);\n\n const filteredEdges = useMemo(() => {\n let edgesStage: VisualGraphEdge[];\n\n // Step 1: Apply label filters (disable all labels or filter by edge labels)\n if (allLabelsDisabled || allEdgeLabelsDisabled) {\n edgesStage = [];\n } else {\n // Filter by node labels first (already applied via filteredNodes). If no node label filters, we consider all nodes.\n const nodeIds = new Set(\n filteredNodes.map((n: VisualGraphNode) => String(n.id_)),\n );\n edgesStage = baseEdges.filter(\n (e: VisualGraphEdge) =>\n nodeIds.has(String(e.start_id_)) && nodeIds.has(String(e.end_id_)),\n );\n\n if (edgeFilterLabels && edgeFilterLabels.length > 0) {\n const setEdge = new Set(edgeFilterLabels);\n edgesStage = edgesStage.filter((e) => setEdge.has(e.label_));\n }\n }\n\n // Step 2: Apply hidden elements filter (from GraphExploration store)\n if (hiddenElementIds.size > 0) {\n devLog(\"[useLiveGraphData] Applying hidden elements filter to edges\", {\n hiddenCount: hiddenElementIds.size,\n beforeFilter: edgesStage.length,\n });\n edgesStage = edgesStage.filter(\n (e) => !hiddenElementIds.has(String(e.id_)),\n );\n devLog(\"[useLiveGraphData] After hidden elements filter (edges)\", {\n afterFilter: edgesStage.length,\n });\n }\n\n // Step 3: Apply focus overrides (from GraphFocus store)\n // Must happen AFTER the disabled checks so overrides bypass them\n if (overrideElementIds.size > 0) {\n const filteredIds = new Set(\n edgesStage.map((e: VisualGraphEdge) => String(e.id_)),\n );\n const overrideEdges = baseEdges.filter(\n (e: VisualGraphEdge) =>\n overrideElementIds.has(String(e.id_)) &&\n !filteredIds.has(String(e.id_)),\n );\n if (overrideEdges.length > 0) {\n devLog(\"[useLiveGraphData] Adding override edges\", {\n overrideCount: overrideEdges.length,\n overrideIds: overrideEdges.map((e: VisualGraphEdge) => e.id_),\n totalAfterOverride: edgesStage.length + overrideEdges.length,\n });\n edgesStage = [...edgesStage, ...overrideEdges];\n }\n }\n\n return edgesStage;\n }, [\n baseEdges,\n filteredNodes,\n allLabelsDisabled,\n allEdgeLabelsDisabled,\n edgeFilterLabels,\n hiddenElementIds,\n overrideElementIds,\n ]);\n\n // Base normalized graph - contains ALL nodes and edges from query (unfiltered)\n // Useful for tools that need to search/query the complete dataset\n const baseNormalized = useMemo(() => {\n if (isValueSet) return EMPTY_NORMALIZED;\n return normalizeGraph(baseNodes, baseEdges);\n }, [isValueSet, baseNodes, baseEdges]);\n\n // Filtered normalized graph - contains only visible nodes and edges (respects label filters)\n // Used for graph visualization\n const normalized = useMemo(() => {\n if (isValueSet) return EMPTY_NORMALIZED;\n return normalizeGraph(filteredNodes, filteredEdges);\n }, [isValueSet, filteredNodes, filteredEdges]);\n\n // Derive arrays FROM normalized (Phase C step 1)\n const nodes = useMemo(\n () => normalized.nodeIds.map((id) => normalized.nodesById[id]),\n [normalized],\n );\n const edges = useMemo(\n () => normalized.edgeIds.map((id) => normalized.edgesById[id]),\n [normalized],\n );\n\n // Update stats to show \"available\" counts (respects hidden/focus, not label filters)\n // This makes the star badge show realistic totals\n const adjustedStats = useMemo(() => {\n if (!stats) return undefined;\n return {\n ...stats,\n nodes: availableNodes.length,\n edges: availableEdges.length,\n };\n }, [stats, availableNodes.length, availableEdges.length]);\n\n // Clear focus overrides when filters change (user explicitly changed filters, so overrides should reset)\n useEffect(() => {\n const { clearOverrides } = useGraphFocus.getState();\n clearOverrides();\n }, [\n filterLabels,\n allLabelsDisabled,\n edgeFilterLabels,\n allEdgeLabelsDisabled,\n ]);\n\n return {\n nodes,\n edges,\n stats: adjustedStats,\n labelCounts,\n edgeLabelCounts,\n values,\n colorPalette,\n normalized,\n baseNormalized,\n };\n}\n","/**\n * ReGraph Visualization Adapter\n *\n * Converts VisualGraph domain model to reagraph-specific format.\n * Isolates the reagraph dependency to the ReGraph renderer only.\n *\n * Data flow:\n * GraphData store → VisualGraph (enriched) → ReagraphNode/Edge (visualization format)\n */\n\nimport { useMemo } from \"react\";\nimport { GraphNode as ReagraphNode, GraphEdge as ReagraphEdge } from \"reagraph\";\nimport { useLiveGraphData } from \"./useLiveGraphData\";\nimport type { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\n\n/**\n * Converts a VisualGraphNode to reagraph's node format.\n * Exported for use in tests and custom renderers.\n */\nexport function toReagraphNode(visualNode: VisualGraphNode): ReagraphNode {\n return {\n id: String(visualNode.id_),\n label: visualNode.visual.displayName,\n fill: visualNode.visual.color,\n size: visualNode.visual.size,\n icon: visualNode.visual.icon,\n // Embed full visual node so event handlers can access all domain data\n data: visualNode,\n } as ReagraphNode;\n}\n\n/**\n * Converts a VisualGraphEdge to reagraph's edge format.\n * Exported for use in tests and custom renderers.\n */\nexport function toReagraphEdge(visualEdge: VisualGraphEdge): ReagraphEdge {\n return {\n id: String(visualEdge.id_),\n source: String(visualEdge.start_id_),\n target: String(visualEdge.end_id_),\n label: visualEdge.label_,\n fill: visualEdge.visual.color,\n size: visualEdge.visual.size ?? 3,\n dashed: visualEdge.visual.dashed,\n // Embed full visual edge so event handlers can access all domain data\n data: visualEdge,\n } as ReagraphEdge;\n}\n\n/**\n * Returns live graph data converted to reagraph's node/edge format.\n * Consumes the workspace GraphData + filter stores via useLiveGraphData.\n */\nexport function useReagraphData() {\n const live = useLiveGraphData();\n\n const nodes = useMemo<ReagraphNode[]>(\n () => live.nodes.map(toReagraphNode),\n [live.nodes],\n );\n\n const edges = useMemo<ReagraphEdge[]>(\n () => live.edges.map(toReagraphEdge),\n [live.edges],\n );\n\n return {\n nodes,\n edges,\n stats: live.stats,\n colorPalette: live.colorPalette,\n };\n}\n","/**\n * Cytoscape Visualization Adapter\n *\n * Converts VisualGraph domain model to Cytoscape.js element format.\n * Isolates the cytoscape dependency to the Cytoscape renderer only.\n *\n * Data flow:\n * GraphData store → VisualGraph (enriched) → Cytoscape Elements (visualization format)\n */\n\nimport { useMemo } from \"react\";\nimport type cytoscape from \"cytoscape\";\ntype ElementsDefinition = cytoscape.ElementsDefinition;\nimport { useLiveGraphData } from \"./useLiveGraphData\";\nimport type { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\n\n/**\n * Converts a VisualGraphNode to Cytoscape's element format.\n * Exported for use in tests and custom renderers.\n */\nexport function toCytoscapeNode(visualNode: VisualGraphNode) {\n const color = visualNode.visual.color ?? \"#4285F4\";\n const size = visualNode.visual.size ?? 40;\n\n return {\n data: {\n id: String(visualNode.id_),\n label: visualNode.visual.displayName,\n id_: visualNode.id_,\n label_: visualNode.label_,\n properties_: visualNode.properties_,\n displayName: visualNode.visual.displayName,\n color,\n size,\n icon: visualNode.visual.icon,\n // Full node reference for context menu and event handlers\n visualGraph: visualNode,\n },\n // No inline styles — stylesheet handles all styling via data mappers\n };\n}\n\n/**\n * Converts a VisualGraphEdge to Cytoscape's element format.\n * Exported for use in tests and custom renderers.\n */\nexport function toCytoscapeEdge(visualEdge: VisualGraphEdge) {\n return {\n data: {\n id: String(visualEdge.id_),\n source: String(visualEdge.start_id_),\n target: String(visualEdge.end_id_),\n label: visualEdge.label_,\n id_: visualEdge.id_,\n label_: visualEdge.label_,\n start_id_: visualEdge.start_id_,\n end_id_: visualEdge.end_id_,\n properties_: visualEdge.properties_,\n color: visualEdge.visual.color ?? \"#9E9E9E\",\n size: visualEdge.visual.size ?? 3,\n // Only set dashed when true — falsy values omitted to avoid stylesheet noise\n dashed: visualEdge.visual.dashed || undefined,\n },\n // No inline styles — stylesheet handles all styling via data mappers\n };\n}\n\n/**\n * Returns live graph data converted to Cytoscape's element format.\n * Consumes the workspace GraphData + filter stores via useLiveGraphData.\n */\nexport function useCytoscapeData() {\n const live = useLiveGraphData();\n\n const elements = useMemo<ElementsDefinition>(\n () => ({\n nodes: live.nodes.map(toCytoscapeNode),\n edges: live.edges.map(toCytoscapeEdge),\n }),\n [live.nodes, live.edges],\n );\n\n return {\n elements,\n stats: live.stats,\n colorPalette: live.colorPalette,\n };\n}\n","import { createContext, useContext } from \"react\";\n\nexport type GraphRenderer = \"reagraph\" | \"cytoscape\";\n\nexport type GraphRendererContextType = {\n renderer: GraphRenderer;\n setRenderer: (renderer: GraphRenderer) => void;\n};\n\nexport const GraphRendererContext =\n createContext<GraphRendererContextType | null>(null);\n\nexport function useGraphRenderer(): GraphRendererContextType {\n const ctx = useContext(GraphRendererContext);\n if (!ctx) {\n throw new Error(\n \"useGraphRenderer must be used within a GraphRendererProvider\",\n );\n }\n return ctx;\n}\n","import React, { useState, useCallback } from \"react\";\nimport { GraphRendererContext } from \"./useGraphRendererContext\";\nimport type { GraphRenderer } from \"./useGraphRendererContext\";\n\ntype ProviderProps = {\n children: React.ReactNode;\n /**\n * Initial renderer to use. Defaults to 'cytoscape'.\n * The host application controls which renderer is active — typically\n * driven by route state, user preference, or local storage.\n */\n defaultRenderer?: GraphRenderer;\n /**\n * Optional callback invoked when the user switches renderer via the toolbar.\n * Use this to persist the choice (e.g. URL, localStorage, zustand store).\n */\n onRendererChange?: (renderer: GraphRenderer) => void;\n};\n\nexport function GraphRendererProvider({\n children,\n defaultRenderer = \"cytoscape\",\n onRendererChange,\n}: ProviderProps): React.ReactElement {\n const [renderer, setRendererState] = useState<GraphRenderer>(defaultRenderer);\n\n const setRenderer = useCallback(\n (newRenderer: GraphRenderer) => {\n setRendererState(newRenderer);\n onRendererChange?.(newRenderer);\n },\n [onRendererChange],\n );\n\n return (\n <GraphRendererContext.Provider value={{ renderer, setRenderer }}>\n {children}\n </GraphRendererContext.Provider>\n );\n}\n","import {\n type ReactNode,\n useEffect,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport { devLog } from \"@petrarca/sonnet-core\";\nimport {\n GraphCanvas,\n GraphCanvasRef,\n GraphNode,\n GraphEdge,\n LayoutTypes,\n PathSelectionTypes,\n useSelection,\n} from \"reagraph\";\nimport { theme } from \"./theme\";\nimport { cn } from \"@petrarca/sonnet-core\";\nimport LayoutAndCameraControls from \"./LayoutAndCameraControls\";\nimport { Card } from \"@petrarca/sonnet-ui\";\nimport {\n useWorkspaceSelection,\n useWorkspaceGraphExploration,\n useWorkspaceGraphFilter,\n} from \"../../hooks/useWorkspaceStores\";\nimport NodeHoverInfo from \"./NodeHoverInfo\";\nimport { useReagraphData } from \"../../hooks/useReagraphData\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport useGraphFocus from \"../../stores/GraphFocus\";\nimport ReaContextMenu from \"./ReaContextMenu\";\nimport type {\n VisualGraphNode,\n VisualGraphEdge,\n} from \"../../models/visual-graph\";\nimport { toast } from \"sonner\";\nimport type { SelectionStore } from \"../../stores/Selection\";\n\ntype ElementType = \"node\" | \"edge\";\n\ninterface FoundElement {\n element: GraphNode | GraphEdge;\n actualElementType: ElementType;\n}\n\n/** Look up an element by ID, falling back to the other collection on type mismatch. */\nfunction findElementInGraphData(\n elementId: string,\n elementType: ElementType,\n nodes: GraphNode[],\n edges: GraphEdge[],\n): FoundElement | null {\n if (elementType === \"node\") {\n const node = nodes.find((n) => n.id === elementId);\n if (node) return { element: node, actualElementType: \"node\" };\n const edge = edges.find((e) => e.id === elementId);\n if (edge) {\n devLog(\"[ReGraph] ID mismatch: requested as node but found as edge\", {\n elementId,\n });\n return { element: edge, actualElementType: \"edge\" };\n }\n } else {\n const edge = edges.find((e) => e.id === elementId);\n if (edge) return { element: edge, actualElementType: \"edge\" };\n const node = nodes.find((n) => n.id === elementId);\n if (node) {\n devLog(\"[ReGraph] ID mismatch: requested as edge but found as node\", {\n elementId,\n });\n return { element: node, actualElementType: \"node\" };\n }\n }\n return null;\n}\n\n/** Execute a single focus action: find the element, pan to it, optionally select it. */\nfunction processFocusAction(\n focusAction: { elementId: string; elementType: ElementType; action: string },\n canvasRef: GraphCanvasRef,\n nodes: GraphNode[],\n edges: GraphEdge[],\n setSelectedNodeIds: (ids: string[]) => void,\n setSelectedEdge: (edge: VisualGraphEdge | null) => void,\n): boolean {\n const { elementId, elementType, action } = focusAction;\n const found = findElementInGraphData(elementId, elementType, nodes, edges);\n\n if (!found) {\n devLog(\"[ReGraph] Element not found in current Reagraph data\", {\n elementId,\n elementType,\n availableNodes: nodes.length,\n availableEdges: edges.length,\n nodeIds: nodes.slice(0, 5).map((n) => n.id),\n edgeIds: edges.slice(0, 5).map((e) => e.id),\n });\n return false;\n }\n\n const { element, actualElementType } = found;\n devLog(\"[ReGraph] Element found, focusing\", {\n elementId,\n elementType: actualElementType,\n });\n\n if (actualElementType === \"node\") {\n canvasRef.fitNodesInView([elementId]);\n } else {\n const edge = element as GraphEdge;\n canvasRef.fitNodesInView([edge.source, edge.target]);\n }\n\n if (action === \"focus-and-select\") {\n if (actualElementType === \"node\") {\n setSelectedNodeIds([elementId]);\n } else {\n const edgeForFocus = edges.find((e) => e.id === elementId);\n setSelectedEdge(\n edgeForFocus ? (edgeForFocus.data as VisualGraphEdge) : null,\n );\n }\n }\n\n return true;\n}\n\ninterface ReaGraphProps {\n /** Callback when a node is copied from context menu. */\n onCopyNode?: (node: VisualGraphNode) => void;\n /** Extra toolbar content (e.g. clipboard UI) injected into the toolbar. */\n extraToolbarContent?: ReactNode;\n}\n\nfunction ReaGraph({ onCopyNode, extraToolbarContent }: ReaGraphProps) {\n const isMountedRef = useRef(false);\n const { nodes, edges } = useReagraphData();\n const { normalized } = useLiveGraphData();\n\n useEffect(() => {\n devLog(\"[ReGraph] counts\", { nodes: nodes.length, edges: edges.length });\n if (nodes.length > 0) devLog(\"[ReGraph] sample node\", nodes[0]);\n if (edges.length > 0) devLog(\"[ReGraph] sample edge\", edges[0]);\n }, [nodes, edges]);\n\n const canvas = useRef<GraphCanvasRef>(null);\n const [hoveredNode, setHoveredNode] = useState<GraphNode | undefined>(\n undefined,\n );\n const [layout, setLayout] = useState<LayoutTypes>(\"forceDirected2d\");\n const [fullscreen, setFullscreen] = useState(false);\n const [pathSelectionType, setPathSelectionType] =\n useState<PathSelectionTypes>(\"direct\");\n\n // Get workspace-scoped stores\n const useGraphSelection = useWorkspaceSelection();\n const useGraphFilter = useWorkspaceGraphFilter();\n const useGraphExploration = useWorkspaceGraphExploration();\n\n // Subscribe to exploration state for toolbar visibility\n const hiddenElementIds = useGraphExploration((s) => s.hiddenElementIds);\n const isFocusMode = useGraphExploration((s) => s.isFocusMode);\n const hasHiddenElements = hiddenElementIds.size > 0;\n\n const { setSelectedNodeIds, setSelectedEdge } = useGraphSelection(\n (s: SelectionStore) => s,\n );\n\n // Get data-change timestamp to detect query re-runs\n const lastDataChangeTime = useGraphFilter((s) => s.lastDataChangeTime);\n\n // --- Selection Handling (no re-render on selection change) ---\n // Access setter functions once (stable in Zustand) to avoid subscribing component render\n const { clear: clearSelectionStore } = useGraphSelection.getState();\n\n const {\n selections,\n actives,\n onNodeClick,\n onCanvasClick,\n clearSelections,\n setSelections,\n } = useSelection({\n ref: canvas,\n nodes,\n edges,\n pathSelectionType,\n type: \"multi\",\n });\n\n // Subscribe to GraphFocus store for focus requests from tools\n useEffect(() => {\n const unsubscribe = useGraphFocus.subscribe((state) => {\n const focusAction = state.focusAction;\n if (!focusAction || !canvas.current) return;\n\n devLog(\"[ReGraph] Processing focus action\", {\n elementId: focusAction.elementId,\n elementType: focusAction.elementType,\n action: focusAction.action,\n timestamp: focusAction.timestamp,\n });\n\n const handled = processFocusAction(\n focusAction,\n canvas.current,\n nodes,\n edges,\n setSelectedNodeIds,\n setSelectedEdge,\n );\n\n if (handled) {\n useGraphFocus.setState({ focusAction: null });\n }\n // Don't clear the focus action if not handled - let it persist in case the element appears later\n });\n\n return unsubscribe;\n }, [nodes, edges, setSelectedNodeIds, setSelectedEdge]);\n\n // Mirror ReGraph behavior: clear selections when query is executed (prevents stale selections)\n // Don't clear on every node change (e.g., override additions), only on query execution\n useEffect(() => {\n if (!canvas.current) return;\n clearSelections();\n clearSelectionStore();\n }, [lastDataChangeTime, clearSelections, clearSelectionStore]);\n\n const fitToScreen = useCallback(\n (reason?: string) => {\n if (!isMountedRef.current) return;\n if (nodes.length === 0) return;\n // Two nested rAFs ensure reagraph has completed its own layout paint\n // before we call fitNodesInView. One rAF is not enough because reagraph\n // schedules its own geometry update in the first frame after data changes.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (!isMountedRef.current) return;\n const ref = canvas.current;\n if (!ref) return;\n try {\n ref.fitNodesInView();\n devLog(\"[ReGraph] fitToScreen\", {\n reason,\n nodeCount: nodes.length,\n });\n } catch (e) {\n devLog(\"[ReGraph] fitToScreen failed\", {\n reason,\n error: (e as Error).message,\n });\n }\n });\n });\n },\n [nodes.length],\n );\n\n // Mounted state\n useEffect(() => {\n isMountedRef.current = true;\n fitToScreen(\"mount\");\n\n // Subscribe to external selection changes (e.g., from Cytoscape renderer) and update Reagraph visuals\n // One-time initial visual sync from existing store selection when mounting\n const state = useGraphSelection.getState();\n if (state.selectedNodeIds.length || state.selectedEdge) {\n devLog(\"[ReGraph] Initial sync of selection store\", {\n selectedNodeIds: state.selectedNodeIds,\n selectedEdge: state.selectedEdge,\n });\n\n // Apply existing selection to Reagraph\n if (state.selectedNodeIds.length > 0) {\n setSelections(state.selectedNodeIds);\n }\n if (state.selectedEdge) {\n setSelectedEdge(state.selectedEdge);\n }\n }\n\n return () => {\n isMountedRef.current = false;\n };\n }, [fitToScreen, setSelections, setSelectedEdge, useGraphSelection]);\n\n // Re-fit when counts change\n useEffect(() => {\n if (isMountedRef.current) fitToScreen(\"counts-changed\");\n }, [nodes.length, edges.length, fitToScreen]);\n\n function updateLayout(next: LayoutTypes) {\n setLayout(next);\n fitToScreen(\"layout-change\");\n }\n\n function handleNodeClick(node: GraphNode) {\n setSelectedEdge(null);\n if (selections.length < 2 && onNodeClick) onNodeClick(node);\n }\n\n function handleEdgeClick(edge: GraphEdge) {\n const startNode = normalized.nodesById[edge.data.start_id_ + \"\"];\n const endNode = normalized.nodesById[edge.data.end_id_ + \"\"];\n\n if (!startNode || !endNode) return;\n\n const startNodeId = String(startNode.id_);\n const endNodeId = String(endNode.id_);\n\n // Get currently selected nodes from global store\n const currentSelectedIds = useGraphSelection.getState().selectedNodeIds;\n\n // CASE 1: One node already selected AND it's an endpoint of this edge\n // Keep only that node selected + select edge (enables directional operations)\n if (currentSelectedIds.length === 1) {\n const selectedNodeId = currentSelectedIds[0];\n\n if (selectedNodeId === startNodeId || selectedNodeId === endNodeId) {\n devLog(\"[ReGraph] handleEdgeClick - node+edge selection\", {\n edgeId: edge.id,\n selectedNode: selectedNodeId,\n direction: selectedNodeId === startNodeId ? \"outgoing\" : \"incoming\",\n });\n\n // Keep only the selected node (selection is already in place from node click)\n setSelectedEdge(edge.data as VisualGraphEdge);\n return; // Early exit\n }\n }\n\n // CASE 2: Default behavior (no node selected, or node not an endpoint)\n // Select BOTH endpoints + edge (traditional behavior)\n devLog(\"[ReGraph] handleEdgeClick - default (both endpoints)\", {\n edgeId: edge.id,\n });\n\n // Use setSelections to directly set both node IDs at once\n setSelections([startNodeId, endNodeId]);\n setSelectedEdge(edge.data as VisualGraphEdge);\n }\n\n function handleCanvasClick(e: MouseEvent) {\n clearSelections();\n setSelectedNodeIds([]);\n setSelectedEdge(null);\n if (onCanvasClick) onCanvasClick(e);\n }\n\n // Sync outward selections\n useEffect(() => {\n if (!isMountedRef.current) return;\n if (selections.length > 0 && selections.length <= 2) {\n const selectedNodes = selections\n .map((id) => nodes.find((n: GraphNode) => n.id === id))\n .filter(Boolean) as GraphNode[];\n setSelectedNodeIds(selectedNodes.map((n) => n.id));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selections, nodes]);\n\n // Remove selections if nodes disappear\n useEffect(() => {\n if (!isMountedRef.current) return;\n const currentSelectedIds: string[] =\n useGraphSelection.getState().selectedNodeIds;\n if (!currentSelectedIds.length) return;\n const stillPresentIds = currentSelectedIds.filter((id: string) =>\n nodes.find((n: GraphNode) => n.id === id),\n );\n if (stillPresentIds.length !== currentSelectedIds.length) {\n clearSelections();\n setSelectedNodeIds(stillPresentIds);\n if (stillPresentIds.length < 2) setSelectedEdge(null);\n }\n }, [\n nodes,\n clearSelections,\n setSelectedNodeIds,\n setSelectedEdge,\n useGraphSelection,\n ]);\n\n // Reconcile global selection store (preserve visible)\n useEffect(() => {\n if (!isMountedRef.current) return;\n const currentSelectedIds: string[] =\n useGraphSelection.getState().selectedNodeIds;\n if (!currentSelectedIds.length) return;\n const stillPresentIds = currentSelectedIds.filter((id: string) =>\n nodes.find((n: GraphNode) => n.id === id),\n );\n if (stillPresentIds.length !== currentSelectedIds.length) {\n setSelectedNodeIds(stillPresentIds);\n if (stillPresentIds.length < 2) setSelectedEdge(null);\n }\n }, [nodes, setSelectedNodeIds, setSelectedEdge, useGraphSelection]);\n\n // Fullscreen side-effects\n useEffect(() => {\n if (!fullscreen) return;\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n fitToScreen(\"enter-fullscreen\");\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setFullscreen(false);\n };\n window.addEventListener(\"keydown\", handleKey);\n return () => {\n document.body.style.overflow = prevOverflow;\n window.removeEventListener(\"keydown\", handleKey);\n };\n }, [fullscreen, fitToScreen]);\n\n // When entering fullscreen ensure Reagraph recalculates size\n useEffect(() => {\n if (!fullscreen) return;\n // Delay to allow DOM classes/layout to apply\n const id = setTimeout(() => {\n if (canvas.current) {\n fitToScreen(\"fullscreen-resize-delay\");\n }\n }, 50);\n return () => clearTimeout(id);\n }, [fullscreen, fitToScreen]);\n\n // Handle window resize events only when component is mounted\n useEffect(() => {\n if (!isMountedRef.current) return;\n\n const handleResize = () => {\n if (isMountedRef.current && canvas.current) {\n fitToScreen(\"window-resize\");\n }\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [fitToScreen]);\n\n // First data arrival fit\n const firstDataRef = useRef(true);\n useEffect(() => {\n if (!isMountedRef.current) return;\n if (nodes.length > 0) {\n if (firstDataRef.current) {\n fitToScreen(\"first-data\");\n firstDataRef.current = false;\n }\n } else {\n firstDataRef.current = true;\n }\n }, [nodes.length, fitToScreen]);\n\n if (nodes.length === 0) {\n devLog(\"[ReGraph] empty state render\");\n return (\n <Card className=\"relative w-full h-full items-center justify-center text-slate-500 gap-2 shadow-xs p-4\">\n <div>No data to display.</div>\n <div>\n Please{\" \"}\n <span className=\"font-semibold\">\n run a query, check filters, or add a node\n </span>{\" \"}\n to the workbench to populate the graph.\n </div>\n </Card>\n );\n }\n\n return (\n <div\n className={cn(\n \"bg-white\",\n fullscreen\n ? \"fixed inset-0 z-50 w-screen h-screen p-0 m-0\"\n : \"relative w-full h-full\",\n )}\n >\n <Card className=\"h-full shadow-xs p-4\">\n <GraphCanvas\n ref={canvas}\n theme={theme}\n nodes={nodes}\n edges={edges}\n draggable\n layoutType={layout}\n selections={selections}\n actives={actives}\n onCanvasClick={handleCanvasClick}\n onNodeClick={(e) => handleNodeClick(e)}\n edgeArrowPosition=\"end\"\n edgeLabelPosition=\"natural\"\n labelType=\"all\"\n onNodePointerOver={setHoveredNode}\n onNodePointerOut={() => setHoveredNode(undefined)}\n onEdgeClick={handleEdgeClick}\n contextMenu={({ data, onClose }) => {\n const elementType = \"source\" in data ? \"edge\" : \"node\";\n devLog(\"[ReGraph] Context menu opened\", {\n elementId: data.id,\n elementType,\n });\n return (\n <ReaContextMenu\n data={data}\n onClose={onClose}\n elementType={elementType}\n useGraphExploration={useGraphExploration}\n onCopyNode={onCopyNode}\n />\n );\n }}\n />\n </Card>\n\n {hoveredNode && <NodeHoverInfo node={hoveredNode} />}\n\n <LayoutAndCameraControls\n fitToScreen={fitToScreen}\n fullscreen={fullscreen}\n toggleFullscreen={() => setFullscreen((prev) => !prev)}\n updateLayout={updateLayout}\n setPathSelectionType={setPathSelectionType}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n onResetView={() => {\n useGraphExploration.getState().resetView();\n toast.success(\n isFocusMode ? \"Focus mode cleared\" : \"Hidden elements restored\",\n );\n }}\n extraToolbarContent={extraToolbarContent}\n />\n </div>\n );\n}\n\nexport default ReaGraph;\n","import { lightTheme } from \"reagraph\";\n\nconst highlightColor = \"#ffb512\";\nconst highlightColorText = \"#c98a02\";\nconst theme = {\n ...lightTheme,\n node: {\n ...lightTheme.node,\n activeFill: highlightColor,\n label: {\n ...lightTheme.node.label,\n activeColor: highlightColorText,\n },\n },\n ring: {\n ...lightTheme.ring,\n activeFill: highlightColor,\n },\n edge: {\n ...lightTheme.edge,\n activeFill: highlightColor,\n label: {\n ...lightTheme.edge.label,\n activeColor: highlightColorText,\n },\n },\n arrow: {\n ...lightTheme.arrow,\n activeFill: highlightColor,\n },\n};\n\nexport { theme };\n","import {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n SimpleTooltip,\n} from \"@petrarca/sonnet-ui\";\nimport { LayoutPanelTop, Maximize, Shrink, ArrowUp, Eye } from \"lucide-react\";\nimport { LayoutTypes, PathSelectionTypes } from \"reagraph\";\nimport { type ReactNode, useState } from \"react\";\nimport { RendererDropdown } from \"../shared/RendererDropdown\";\n\ntype Props = {\n updateLayout: (layout: LayoutTypes) => void;\n fitToScreen: () => void;\n toggleFullscreen: () => void;\n fullscreen: boolean;\n setPathSelectionType: (type: PathSelectionTypes) => void;\n hasHiddenElements?: boolean;\n isFocusMode?: boolean;\n onResetView?: () => void;\n extraToolbarContent?: ReactNode;\n};\n\n/* ------------------------------------------------------------------ */\n/* PathSelectionDropdown */\n/* ------------------------------------------------------------------ */\n\ntype PathSelectionDropdownProps = {\n setPathSelectionType: (type: PathSelectionTypes) => void;\n};\n\nfunction PathSelectionDropdown({\n setPathSelectionType,\n}: PathSelectionDropdownProps) {\n return (\n <DropdownMenu>\n <SimpleTooltip label=\"Path Selection Type\" side=\"left\">\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <ArrowUp />\n </Button>\n </DropdownMenuTrigger>\n </SimpleTooltip>\n\n <DropdownMenuContent side=\"left\" align=\"start\">\n <DropdownMenuItem onClick={() => setPathSelectionType(\"direct\")}>\n None\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setPathSelectionType(\"all\")}>\n All Paths\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setPathSelectionType(\"in\")}>\n Inbound\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setPathSelectionType(\"out\")}>\n Outbound\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* LayoutDropdown */\n/* ------------------------------------------------------------------ */\n\ntype LayoutDropdownProps = {\n updateLayout: (layout: LayoutTypes) => void;\n};\n\nfunction LayoutDropdown({ updateLayout }: LayoutDropdownProps) {\n const [showTooltip, setShowTooltip] = useState(true);\n\n const handleSelect = (layout: LayoutTypes) => {\n updateLayout(layout);\n setShowTooltip(false);\n // Re-enable tooltip after a short delay\n setTimeout(() => setShowTooltip(true), 500);\n };\n\n const trigger = (\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <LayoutPanelTop />\n </Button>\n </DropdownMenuTrigger>\n );\n\n return (\n <DropdownMenu>\n {showTooltip ? (\n <SimpleTooltip label=\"Layout\" side=\"left\">\n {trigger}\n </SimpleTooltip>\n ) : (\n trigger\n )}\n\n <DropdownMenuContent side=\"left\" align=\"start\">\n <DropdownMenuLabel>Force-directed Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"forceDirected2d\")}>\n Force Directed\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"forceatlas2\")}>\n Force Atlas 2\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Tree Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"treeTd2d\")}>\n Tree Top-Down\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"treeLr2d\")}>\n Tree Left-Right\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Circular & Radial Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"circular2d\")}>\n Circular\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"radialOut2d\")}>\n Radial Out\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"concentric2d\")}>\n Concentric\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Utility Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"nooverlap\")}>\n No Overlap\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* ViewControls */\n/* ------------------------------------------------------------------ */\n\ntype ViewControlsProps = {\n fullscreen: boolean;\n toggleFullscreen: () => void;\n fitToScreen: () => void;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n onResetView?: () => void;\n};\n\nfunction ViewControls({\n fullscreen,\n toggleFullscreen,\n fitToScreen,\n hasHiddenElements,\n isFocusMode,\n onResetView,\n}: ViewControlsProps) {\n return (\n <>\n <SimpleTooltip label=\"Fullscreen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleFullscreen}>\n {!fullscreen ? <Maximize /> : <Shrink />}\n </Button>\n </SimpleTooltip>\n\n <SimpleTooltip label=\"Fit to screen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={fitToScreen}>\n <Shrink />\n </Button>\n </SimpleTooltip>\n\n {(hasHiddenElements || isFocusMode) && onResetView && (\n <SimpleTooltip\n label={isFocusMode ? \"Reset Focus\" : \"Show All Hidden\"}\n side=\"left\"\n >\n <Button variant=\"ghost\" size=\"icon\" onClick={onResetView}>\n <Eye />\n </Button>\n </SimpleTooltip>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* LayoutAndCameraControls (composed) */\n/* ------------------------------------------------------------------ */\n\nfunction LayoutAndCameraControls({\n fitToScreen,\n fullscreen,\n toggleFullscreen,\n updateLayout,\n setPathSelectionType,\n hasHiddenElements = false,\n isFocusMode = false,\n onResetView,\n extraToolbarContent,\n}: Props) {\n return (\n <div className=\"absolute right-2 top-2 flex flex-col border\">\n <RendererDropdown />\n\n <ViewControls\n fullscreen={fullscreen}\n toggleFullscreen={toggleFullscreen}\n fitToScreen={fitToScreen}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n onResetView={onResetView}\n />\n\n <PathSelectionDropdown setPathSelectionType={setPathSelectionType} />\n\n {extraToolbarContent}\n\n <LayoutDropdown updateLayout={updateLayout} />\n </div>\n );\n}\n\nexport default LayoutAndCameraControls;\n","import {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n SimpleTooltip,\n} from \"@petrarca/sonnet-ui\";\nimport { useGraphRenderer } from \"../../hooks/useGraphRenderer\";\n\n/**\n * Shared renderer selection dropdown used by both rea and cyto toolbars.\n * Reads and sets the active renderer (reagraph vs cytoscape) from context.\n */\nexport function RendererDropdown() {\n const { renderer, setRenderer } = useGraphRenderer();\n\n return (\n <DropdownMenu>\n <SimpleTooltip label=\"Renderer\" side=\"left\">\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n {renderer === \"reagraph\" ? \"RG\" : \"CY\"}\n </Button>\n </DropdownMenuTrigger>\n </SimpleTooltip>\n <DropdownMenuContent side=\"left\" align=\"start\">\n <DropdownMenuItem\n onClick={() => setRenderer(\"reagraph\")}\n className={renderer === \"reagraph\" ? \"text-blue-600\" : \"\"}\n >\n Reagraph\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => setRenderer(\"cytoscape\")}\n className={renderer === \"cytoscape\" ? \"text-blue-600\" : \"\"}\n >\n Cytoscape\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","import { Card, Separator } from \"@petrarca/sonnet-ui\";\nimport { GraphNode } from \"reagraph\";\n\ntype Props = {\n node: GraphNode;\n};\n\nfunction NodeHoverInfo({ node }: Props) {\n return (\n <Card className=\"absolute top-2 left-1/2 -translate-x-1/2 bg-white shadow-md p-2\">\n <div className=\"flex flex-row items-center gap-2\">\n <Separator\n orientation=\"vertical\"\n decorative\n className=\"h-10 w-1\"\n style={{ backgroundColor: node.fill as string }}\n />\n <div>\n <p>\n <strong>{node.data.label_}: </strong>\n {node.label}\n </p>\n <p className=\"text-sm text-muted-foreground\">{node.data.id_}</p>\n </div>\n </div>\n </Card>\n );\n}\n\nexport default NodeHoverInfo;\n","import React from \"react\";\nimport { devLog } from \"@petrarca/sonnet-core\";\nimport type { GraphNode, GraphEdge } from \"reagraph\";\nimport type { StoreApi, UseBoundStore } from \"zustand\";\nimport type { VisualGraphNode } from \"../../models/visual-graph\";\nimport type { GraphExplorationStore } from \"../../stores/GraphExploration\";\n\ntype Props = Readonly<{\n data: GraphNode | GraphEdge;\n onClose: () => void;\n elementType: \"node\" | \"edge\";\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n onCopyNode?: (node: VisualGraphNode) => void;\n}>;\n\nfunction ReaContextMenu({\n data,\n onClose,\n elementType,\n useGraphExploration,\n onCopyNode,\n}: Props) {\n const handleFocus = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Focus on node and neighborhood:\", nodeId);\n useGraphExploration.getState().setFocusModeWithNeighborhood(nodeId);\n } else {\n // For edges, focus on the start node\n const startNodeId = data.data.start_id_;\n devLog(\"[ReaContextMenu] Focus on edge start node:\", startNodeId);\n useGraphExploration.getState().setFocusModeWithNeighborhood(startNodeId);\n }\n onClose();\n };\n\n const handleCopy = () => {\n devLog(\"[ReaContextMenu] Copy to clipboard\");\n\n if (elementType === \"node\") {\n const visualGraph = data.data?.visualGraph;\n if (visualGraph && onCopyNode) {\n onCopyNode(visualGraph);\n } else if (!visualGraph) {\n // Fallback: use browser clipboard for basic text\n const nodeText = `Node: ${data.label || data.id}`;\n navigator.clipboard.writeText(nodeText);\n }\n } else {\n // For edges, copy the edge info as text\n const edgeText = `Edge: ${data.data.start_id_} -> ${data.data.end_id_}`;\n navigator.clipboard.writeText(edgeText);\n }\n onClose();\n };\n\n const handleHideNode = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Hide node:\", nodeId);\n useGraphExploration.getState().hideElements([nodeId]);\n }\n onClose();\n };\n\n const handleHideIncoming = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Hide incoming edges:\", nodeId);\n useGraphExploration.getState().hideNodeIncoming(nodeId);\n }\n onClose();\n };\n\n const handleHideOutgoing = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Hide outgoing edges:\", nodeId);\n useGraphExploration.getState().hideNodeOutgoing(nodeId);\n }\n onClose();\n };\n\n const handleExpand = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Expand node:\", nodeId);\n useGraphExploration.getState().expandNode(nodeId);\n }\n onClose();\n };\n\n const handleHideForwardPath = () => {\n if (elementType === \"edge\") {\n const edgeId = data.id;\n devLog(\"[ReaContextMenu] Hide forward path from edge:\", edgeId);\n useGraphExploration.getState().hideEdgeForwardPath(edgeId);\n }\n onClose();\n };\n\n const handleHideReversePath = () => {\n if (elementType === \"edge\") {\n const edgeId = data.id;\n devLog(\"[ReaContextMenu] Hide reverse path from edge:\", edgeId);\n useGraphExploration.getState().hideEdgeReversePath(edgeId);\n }\n onClose();\n };\n\n const handleFocusOnEdgeType = () => {\n if (elementType === \"edge\") {\n const edgeId = data.id;\n const edgeLabel = data.data?.label_ || \"edge\";\n devLog(\"[ReaContextMenu] Focus on edge type:\", edgeId, edgeLabel);\n useGraphExploration.getState().focusOnEdgeType(edgeId);\n }\n onClose();\n };\n\n // Menu items for nodes - identical to Cytoscape\n const nodeMenuItems = [\n { label: \"Focus\", action: handleFocus },\n { label: \"Copy\", action: handleCopy },\n { label: \"Hide Node\", action: handleHideNode },\n { label: \"Hide Incoming\", action: handleHideIncoming },\n { label: \"Hide Outgoing\", action: handleHideOutgoing },\n { label: \"Expand\", action: handleExpand },\n ];\n\n // Menu items for edges - consistent with Cytoscape\n const edgeMenuItems = [\n { label: \"Focus\", action: handleFocus },\n { label: \"Focus Edge Type\", action: handleFocusOnEdgeType },\n { label: \"Copy\", action: handleCopy },\n { label: \"Hide Forward Path\", action: handleHideForwardPath },\n { label: \"Hide Reverse Path\", action: handleHideReversePath },\n ];\n\n const menuItems = elementType === \"node\" ? nodeMenuItems : edgeMenuItems;\n\n // Simple div-based menu (Reagraph handles positioning)\n return (\n <div className=\"bg-white border border-gray-200 rounded-md shadow-lg py-1 min-w-48\">\n {menuItems.map((item, index) => (\n <React.Fragment key={item.label}>\n <button\n className=\"w-full text-left px-3 py-2 text-sm hover:bg-gray-100 cursor-pointer\"\n onClick={item.action}\n >\n {item.label}\n </button>\n {index === 1 && <div className=\"border-t border-gray-200 my-1\" />}\n </React.Fragment>\n ))}\n </div>\n );\n}\n\nexport default ReaContextMenu;\n","import {\n type ReactNode,\n useEffect,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport { devLog, errorLog } from \"@petrarca/sonnet-core\";\nimport cytoscape from \"cytoscape\";\ntype Core = cytoscape.Core;\ntype LayoutOptions = cytoscape.LayoutOptions;\nimport fcose from \"cytoscape-fcose\";\nimport cola from \"cytoscape-cola\";\nimport dagre from \"cytoscape-dagre\";\nimport klay from \"cytoscape-klay\";\nimport elk from \"cytoscape-elk\";\nimport cise from \"cytoscape-cise\";\nimport cxtmenu from \"cytoscape-cxtmenu\";\nimport { useCytoscapeData } from \"../../hooks/useCytoscapeData\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport {\n useWorkspaceSelection,\n useWorkspaceGraphFilter,\n useWorkspaceGraphExploration,\n} from \"../../hooks/useWorkspaceStores\";\nimport useGraphFocus, { type GraphFocusAction } from \"../../stores/GraphFocus\";\nimport CytoscapeControls from \"./CytoscapeControls\";\nimport { StandardLayout, getLayoutPreset } from \"./layoutPresets\";\nimport type {\n VisualGraphNode,\n VisualGraphEdge,\n} from \"../../models/visual-graph\";\nimport {\n createNodeContextMenu,\n createEdgeContextMenu,\n} from \"./contextMenuConfig\";\nimport { toast } from \"sonner\";\n\n// Register extensions once (cytoscape guards duplicates)\ntry {\n cytoscape.use(fcose);\n cytoscape.use(cola);\n cytoscape.use(dagre);\n cytoscape.use(klay);\n cytoscape.use(elk);\n cytoscape.use(cise);\n cxtmenu(cytoscape); // Register cxtmenu extension\n} catch {\n /* ignore */\n}\n\ninterface CytoscapeGraphProps {\n layout?: StandardLayout; // chosen standard layout or 'auto'\n fitPadding?: number; // padding when fitting after layout\n /** Callback when a node is copied from context menu. */\n onCopyNode?: (node: VisualGraphNode) => void;\n /** Extra toolbar content (e.g. clipboard UI) injected into the toolbar. */\n extraToolbarContent?: ReactNode;\n}\n\n// --- Extracted helpers for data-update useEffect (reduces cyclomatic complexity) ---\n\n/** Valid layouts for the update effect */\nconst ALLOWED_LAYOUTS: StandardLayout[] = [\n \"auto\",\n \"fcose\",\n \"cola\",\n \"dagre\",\n \"klay\",\n \"elk\",\n \"cise\",\n \"grid\",\n \"cose\",\n \"concentric\",\n \"breadthfirst\",\n \"tree\",\n \"circle\",\n \"random\",\n];\n\ninterface SkipUpdateParams {\n cy: Core;\n currentIds: string;\n elementIdsRef: React.MutableRefObject<string>;\n lastLayoutRef: React.MutableRefObject<string>;\n lastFitPaddingRef: React.MutableRefObject<number>;\n currentLayout: string;\n fitPadding: number;\n nodeCount: number;\n edgeCount: number;\n}\n\n/** Returns 'skip' if the update can be skipped entirely, 'refit' if only a refit is needed, or 'update' for a full redraw. */\nfunction classifyUpdate({\n cy,\n currentIds,\n elementIdsRef,\n lastLayoutRef,\n lastFitPaddingRef,\n currentLayout,\n fitPadding,\n nodeCount,\n edgeCount,\n}: SkipUpdateParams): \"skip\" | \"refit\" | \"update\" {\n const paddingChanged = fitPadding !== lastFitPaddingRef.current;\n const cyHasElements =\n cy.nodes().length === nodeCount && cy.edges().length === edgeCount;\n const layoutChanged = currentLayout !== lastLayoutRef.current;\n\n // If only padding changed, just refit without redrawing\n if (\n paddingChanged &&\n currentIds === elementIdsRef.current &&\n cyHasElements &&\n !layoutChanged\n ) {\n return \"refit\";\n }\n\n // Skip if actual data hasn't changed AND Cytoscape has the elements AND layout hasn't changed\n if (currentIds === elementIdsRef.current && cyHasElements && !layoutChanged) {\n return \"skip\";\n }\n\n return \"update\";\n}\n\ninterface ApplyLayoutParams {\n cy: Core;\n chosen: StandardLayout;\n nodeCount: number;\n nodesForLayout: Array<{ id: string; data: { label_: string } }>;\n fitPadding: number;\n}\n\n/** Apply layout to cytoscape instance with error fallbacks. */\nfunction applyLayout({\n cy,\n chosen,\n nodeCount,\n nodesForLayout,\n fitPadding,\n}: ApplyLayoutParams): void {\n const layoutOpts = getLayoutPreset({\n layoutName: chosen,\n count: nodeCount,\n nodeData: nodesForLayout,\n }) as LayoutOptions & { fit?: boolean; roots?: unknown };\n\n if (chosen === \"tree\") {\n const cyNodes = cy.nodes();\n const rootCandidates = cyNodes.filter((n) => n.indegree(false) === 0);\n if (rootCandidates.length > 0) {\n (layoutOpts as unknown as { [k: string]: unknown }).roots =\n rootCandidates;\n } else if (cyNodes.length) {\n (layoutOpts as unknown as { [k: string]: unknown }).roots = cyNodes[0];\n }\n }\n\n const getPreset = (name: StandardLayout) =>\n getLayoutPreset({\n layoutName: name,\n count: nodeCount,\n nodeData: nodesForLayout,\n });\n\n try {\n cy.layout(layoutOpts).run();\n } catch (e) {\n errorLog(\"Layout error, falling back to dagre:\", e);\n if (chosen === \"klay\") {\n try {\n cy.layout(getPreset(\"dagre\")).run();\n } catch (inner) {\n errorLog(\"Fallback layout also failed, using grid:\", inner);\n cy.layout(getPreset(\"grid\")).run();\n }\n } else {\n cy.layout(getPreset(\"grid\")).run();\n }\n }\n\n // Perform a single external fit only if layout didn't already handle fitting\n if (!layoutOpts.fit) {\n cy.fit(undefined, fitPadding);\n }\n}\n\ninterface ProcessPendingFocusParams {\n cy: Core;\n pendingFocus: NonNullable<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n pendingFocusActionRef: React.MutableRefObject<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n}\n\n/** Process a pending focus action after graph data is updated. */\nfunction processPendingFocus({\n cy,\n pendingFocus,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n pendingFocusActionRef,\n}: ProcessPendingFocusParams): void {\n devLog(\"[CytoscapeGraph] Processing pending focus action\", {\n elementId: pendingFocus.elementId,\n elementType: pendingFocus.elementType,\n });\n\n setTimeout(() => {\n const element = cy.$id(pendingFocus.elementId);\n\n if (element.length === 0) {\n devLog(\n \"[CytoscapeGraph] Focus requested but element not found after graph update\",\n {\n elementId: pendingFocus.elementId,\n elementType: pendingFocus.elementType,\n },\n );\n pendingFocusActionRef.current = null;\n useGraphFocus.setState({ focusAction: null });\n return;\n }\n\n // Animate focus with explicit zoom and center\n cy.animate(\n { zoom: 2.0, center: { eles: element } },\n { duration: 500, easing: \"ease-in-out-cubic\" },\n );\n\n // If focus-and-select, also trigger selection\n if (pendingFocus.action === \"focus-and-select\") {\n selectFocusedElement({\n cy,\n pendingFocus,\n element,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n });\n }\n\n pendingFocusActionRef.current = null;\n useGraphFocus.setState({ focusAction: null });\n }, 100);\n}\n\ninterface SelectFocusedElementParams {\n cy: Core;\n pendingFocus: NonNullable<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n element: ReturnType<Core[\"$id\"]>;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n}\n\n/** Handle selection for a focused element (node or edge). */\nfunction selectFocusedElement({\n cy,\n pendingFocus,\n element,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n}: SelectFocusedElementParams): void {\n if (pendingFocus.elementType === \"node\") {\n cy.batch(() => {\n cy.elements().unselect();\n element.select();\n });\n setSelectedNodeIdsStore([pendingFocus.elementId]);\n selectedNodeIdsRef.current = [pendingFocus.elementId];\n setSelectedEdgeStore(null);\n selectedEdgeRef.current = null;\n } else {\n const edgeObj = edgesRef.current.find(\n (e) => String(e.id_) === pendingFocus.elementId,\n );\n if (edgeObj) {\n const sourceId = String(edgeObj.start_id_);\n const targetId = String(edgeObj.end_id_);\n cy.batch(() => {\n cy.elements().unselect();\n cy.$id(sourceId).select();\n cy.$id(targetId).select();\n element.select();\n });\n setSelectedNodeIdsStore([sourceId, targetId]);\n selectedNodeIdsRef.current = [sourceId, targetId];\n setSelectedEdgeStore(edgeObj);\n selectedEdgeRef.current = edgeObj;\n }\n }\n}\n\n// --- Helper: handle a single GraphFocus store state change ---\n\ninterface HandleFocusStateChangeParams {\n focusAction: GraphFocusAction | null;\n cyRef: React.MutableRefObject<Core | null>;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n pendingFocusActionRef: React.MutableRefObject<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n baseNormalized: { edgesById: Record<string, VisualGraphEdge> };\n}\n\nfunction handleFocusStateChange({\n focusAction,\n cyRef,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n pendingFocusActionRef,\n baseNormalized,\n}: HandleFocusStateChangeParams): void {\n if (!focusAction || !cyRef.current) return;\n\n devLog(\"[CytoscapeGraph] Processing focus action\", {\n elementId: focusAction.elementId,\n timestamp: focusAction.timestamp,\n });\n\n const cy = cyRef.current;\n const elementId = focusAction.elementId;\n const element = cy.$id(elementId);\n\n // CASE 1: Element already exists in Cytoscape -> focus immediately\n if (element.length > 0) {\n handleImmediateFocus({\n cy,\n element,\n focusAction,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n });\n return;\n }\n\n // CASE 2: Element NOT in Cytoscape -> needs override\n devLog(\"[CytoscapeGraph] Element not visible, setting up override\", {\n elementId,\n elementType: focusAction.elementType,\n });\n\n pendingFocusActionRef.current = focusAction;\n\n useGraphFocus.setState((state) => {\n const overrides = new Set(state.overrideElementIds);\n overrides.add(elementId);\n\n if (focusAction.elementType === \"edge\") {\n let edgeObj = edgesRef.current.find((e) => String(e.id_) === elementId);\n if (!edgeObj) {\n edgeObj = baseNormalized.edgesById[elementId];\n }\n if (edgeObj) {\n overrides.add(String(edgeObj.start_id_));\n overrides.add(String(edgeObj.end_id_));\n devLog(\"[CytoscapeGraph] Added edge and endpoints to overrides\", {\n edgeId: elementId,\n startId: edgeObj.start_id_,\n endId: edgeObj.end_id_,\n });\n }\n } else {\n devLog(\"[CytoscapeGraph] Added node to overrides\", { nodeId: elementId });\n }\n\n return { overrideElementIds: overrides };\n });\n}\n\ninterface HandleImmediateFocusParams {\n cy: Core;\n element: ReturnType<Core[\"$id\"]>;\n focusAction: GraphFocusAction;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n}\n\nfunction handleImmediateFocus({\n cy,\n element,\n focusAction,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n}: HandleImmediateFocusParams): void {\n const elementId = focusAction.elementId;\n\n devLog(\"[CytoscapeGraph] Element already visible, focusing immediately\", {\n elementId,\n elementType: focusAction.elementType,\n });\n\n cy.animate(\n { zoom: 2.0, center: { eles: element } },\n { duration: 500, easing: \"ease-in-out-cubic\" },\n );\n\n if (focusAction.action === \"focus-and-select\") {\n selectFocusedElement({\n cy,\n pendingFocus: focusAction,\n element,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n });\n }\n\n useGraphFocus.setState({ focusAction: null });\n}\n\n// --- Helper: compute view state flags and CSS classes ---\n\ninterface GraphViewStateInput {\n hasNodes: boolean;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n fullscreen: boolean;\n}\n\nfunction computeGraphViewState({\n hasNodes,\n hasHiddenElements,\n isFocusMode,\n fullscreen,\n}: GraphViewStateInput) {\n const hasExplorationState = hasHiddenElements || isFocusMode;\n return {\n showEmptyMessage: !hasNodes && !hasExplorationState,\n showFilteredMessage: !hasNodes && hasExplorationState,\n showControls: hasNodes || hasExplorationState,\n outerClass: fullscreen\n ? \"fixed inset-0 z-50 w-screen h-screen bg-white flex flex-col\"\n : \"w-full h-full flex flex-col relative\",\n innerClass: fullscreen\n ? \"flex-1 relative overflow-hidden bg-white\"\n : \"flex-1 relative border border-gray-300 rounded-md overflow-hidden bg-white\",\n };\n}\n\n// --- Custom hook: fullscreen state + ESC handler + body scroll lock ---\n\nfunction useFullscreen(\n fitToScreen: () => void,\n cyRef: React.MutableRefObject<Core | null>,\n) {\n const [fullscreen, setFullscreen] = useState(false);\n\n // Handle body scroll lock & ESC to exit fullscreen\n useEffect(() => {\n if (fullscreen) {\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n fitToScreen();\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setFullscreen(false);\n };\n window.addEventListener(\"keydown\", handleKey);\n return () => {\n document.body.style.overflow = prevOverflow;\n window.removeEventListener(\"keydown\", handleKey);\n };\n }\n }, [fullscreen, fitToScreen]);\n\n // When entering fullscreen ensure Cytoscape recalculates size\n useEffect(() => {\n if (!fullscreen) return;\n const id = setTimeout(() => {\n if (cyRef.current) {\n cyRef.current.resize();\n fitToScreen();\n }\n }, 50);\n return () => clearTimeout(id);\n }, [fullscreen, fitToScreen, cyRef]);\n\n return {\n fullscreen,\n setFullscreen,\n toggleFullscreen: useCallback(() => setFullscreen((f) => !f), []),\n };\n}\n\n// --- Helper: set up all Cytoscape event handlers ---\n\ninterface SetupEventHandlersParams {\n cy: Core;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n clearSelectionStore: () => void;\n useGraphExploration: ReturnType<typeof useWorkspaceGraphExploration>;\n onCopyNode?: (node: VisualGraphNode) => void;\n}\n\nfunction setupCytoscapeEventHandlers({\n cy,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n clearSelectionStore,\n useGraphExploration,\n onCopyNode,\n}: SetupEventHandlersParams): void {\n const updateSelectedNodeIds = (nodeIds: string[]) => {\n setSelectedNodeIdsStore(nodeIds);\n selectedNodeIdsRef.current = nodeIds;\n };\n const updateSelectedEdge = (edgeToSet: VisualGraphEdge | null) => {\n setSelectedEdgeStore(edgeToSet);\n selectedEdgeRef.current = edgeToSet;\n };\n\n const clearAll = () => {\n cy.batch(() => {\n cy.elements().unselect();\n });\n clearSelectionStore();\n selectedNodeIdsRef.current = [];\n selectedEdgeRef.current = null;\n };\n\n cy.on(\"select\", \"node\", (evt) => {\n const nodeEle = evt.target;\n const evtCy = evt.cy;\n const id = nodeEle.id();\n\n devLog(\"[CytoscapeGraph] node selected\", { id });\n\n if (selectedEdgeRef.current) {\n devLog(\"[CytoscapeGraph] clearing edge due to node selection\", {\n edgeId: selectedEdgeRef.current.id_,\n });\n updateSelectedEdge(null);\n }\n\n let selectedIds = evtCy.$(\"node:selected\").map((e) => e.id());\n\n if (selectedIds.length > 2) {\n const currentOrder = [...selectedNodeIdsRef.current];\n const updatedOrder = [...currentOrder.filter((cid) => cid !== id), id];\n const keep = updatedOrder.slice(-2);\n evtCy.batch(() => {\n evtCy.$(\"node:selected\").unselect();\n keep.forEach((kid) => evtCy.$id(kid).select());\n });\n selectedIds = keep;\n\n devLog(\"[CytoscapeGraph] enforced max 2 after select\", { keep });\n }\n updateSelectedNodeIds(selectedIds);\n });\n\n cy.on(\"unselect\", \"node\", (evt) => {\n devLog(\"[CytoscapeGraph] node unselected\", { id: evt.target.id() });\n const selectedIds = evt.cy.$(\"node:selected\").map((e) => e.id());\n updateSelectedNodeIds(selectedIds);\n });\n\n cy.on(\"tap\", \"edge\", (evt) => {\n const edgeEle = evt.target;\n const edgeId = edgeEle.id();\n const edgeObj = edgesRef.current.find((e) => String(e.id_) === edgeId);\n if (!edgeObj) return;\n\n const sourceId = edgeEle.data(\"source\");\n const targetId = edgeEle.data(\"target\");\n const evtCy = evt.cy;\n const currentlySelectedNodes = evtCy.$(\"node:selected\").toArray();\n\n if (currentlySelectedNodes.length === 1) {\n const selectedNodeId = currentlySelectedNodes[0].id();\n if (selectedNodeId === sourceId || selectedNodeId === targetId) {\n devLog(\"[CytoscapeGraph] tap edge - node+edge selection\", {\n edgeId,\n selectedNode: selectedNodeId,\n direction: selectedNodeId === sourceId ? \"outgoing\" : \"incoming\",\n });\n evtCy.batch(() => {\n evtCy.elements().unselect();\n evtCy.$id(selectedNodeId).select();\n edgeEle.select();\n });\n updateSelectedNodeIds([selectedNodeId]);\n updateSelectedEdge(edgeObj);\n return;\n }\n }\n\n devLog(\"[CytoscapeGraph] tap edge - default (both endpoints)\", { edgeId });\n evtCy.batch(() => {\n evtCy.elements().unselect();\n evtCy.$id(sourceId).select();\n evtCy.$id(targetId).select();\n edgeEle.select();\n });\n updateSelectedNodeIds([sourceId, targetId]);\n updateSelectedEdge(edgeObj);\n });\n\n cy.on(\"tap\", (evt) => {\n if (evt.target === cy) clearAll();\n });\n\n createNodeContextMenu({ cy, useGraphExploration, onCopyNode });\n createEdgeContextMenu({ cy, useGraphExploration });\n}\n\nfunction CytoscapeGraph({\n layout: initialLayout = \"auto\",\n fitPadding = 30,\n onCopyNode,\n extraToolbarContent,\n}: CytoscapeGraphProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const cyRef = useRef<Core | null>(null);\n const isInitializedRef = useRef<boolean>(false);\n const [currentLayout, setCurrentLayout] =\n useState<StandardLayout>(initialLayout);\n // Refs to always have latest nodes/edges inside event handlers\n const nodesRef = useRef<VisualGraphNode[]>([]);\n const edgesRef = useRef<VisualGraphEdge[]>([]);\n // Ref to track pending focus action (processed after graph update)\n const pendingFocusActionRef =\n useRef<ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]>(null);\n\n const cytoData = useCytoscapeData();\n const live = useLiveGraphData();\n const nodes = live.nodes; // VisualGraphNode[]\n const edges = live.edges; // VisualGraphEdge[]\n const baseNormalized = live.baseNormalized; // All nodes/edges (unfiltered)\n\n // Get workspace-scoped stores\n const useGraphFilter = useWorkspaceGraphFilter();\n const useGraphExploration = useWorkspaceGraphExploration();\n const useSelection = useWorkspaceSelection();\n\n // Get data-change timestamp to detect query re-runs\n const lastDataChangeTime = useGraphFilter((s) => s.lastDataChangeTime);\n\n // Graph exploration store\n const resetView = useGraphExploration((s) => s.resetView);\n const hasHiddenElements = useGraphExploration(\n (s) => s.hiddenElementIds.size > 0,\n );\n const isFocusMode = useGraphExploration((s) => s.isFocusMode);\n\n // --- Selection Handling (no re-render on selection change) ---\n // Access setter functions once (stable in Zustand) to avoid subscribing component render\n const {\n setSelectedNodeIds: setSelectedNodeIdsStore,\n setSelectedEdge: setSelectedEdgeStore,\n clear: clearSelectionStore,\n } = useSelection.getState();\n\n // Internal refs mirror selection state without causing React renders\n const selectedNodeIdsRef = useRef<string[]>(\n useSelection.getState().selectedNodeIds,\n );\n const selectedEdgeRef = useRef<VisualGraphEdge | null>(\n useSelection.getState().selectedEdge,\n );\n\n // Subscribe to external selection changes (e.g., from Reagraph renderer) and update Cytoscape visuals\n // One-time initial visual sync from existing store selection when mounting\n useEffect(() => {\n const state = useSelection.getState();\n selectedNodeIdsRef.current = state.selectedNodeIds;\n selectedEdgeRef.current = state.selectedEdge;\n const cy = cyRef.current;\n if (cy && (state.selectedNodeIds.length || state.selectedEdge)) {\n cy.batch(() => {\n cy.elements().unselect();\n state.selectedNodeIds.forEach((id: string) => cy.$id(id).select());\n if (state.selectedEdge) {\n const edge = cy.$id(String(state.selectedEdge.id_));\n if (edge) {\n edge.select();\n cy.$id(edge.data(\"source\")).select();\n cy.$id(edge.data(\"target\")).select();\n }\n }\n });\n }\n }, [useSelection]);\n\n // Keep graph data refs current (used in event handlers)\n useEffect(() => {\n nodesRef.current = nodes;\n }, [nodes]);\n useEffect(() => {\n edgesRef.current = edges;\n }, [edges]);\n\n useEffect(() => {\n if (!containerRef.current || cyRef.current) return;\n isInitializedRef.current = true;\n cyRef.current = cytoscape({\n container: containerRef.current,\n elements: [],\n selectionType: \"additive\", // allow clicking multiple nodes without modifier\n style: [\n // Base node style with data mappers for dynamic properties\n {\n selector: \"node\",\n style: {\n \"background-color\": \"data(color)\", // Read color from element data\n \"background-opacity\": 0.9,\n width: \"data(size)\", // Read size from element data\n height: \"data(size)\",\n shape: \"ellipse\",\n label: \"data(label)\",\n // Dark gray text for readability on subtle gray background\n color: \"#374151\",\n \"font-size\": \"11px\", // Increased from 10px\n \"font-weight\": \"bold\",\n \"text-valign\": \"bottom\",\n \"text-halign\": \"center\",\n \"text-wrap\": \"wrap\",\n \"text-max-width\": \"120px\", // Increased from 100px for longer labels\n \"text-margin-y\": 5,\n // Subtle light gray label background\n \"text-background-color\": \"#e5e7eb\", // gray-200\n \"text-background-opacity\": 1,\n \"text-background-padding\": \"3px\",\n \"text-background-shape\": \"roundrectangle\",\n \"border-width\": 1,\n \"border-color\": \"#ffffff\",\n \"border-opacity\": 0.8,\n } as Record<string, unknown>,\n },\n // Override background color only when fill data is present\n {\n selector: \"node[fill]\",\n style: {\n \"background-color\": \"data(fill)\",\n },\n },\n {\n selector: \"edge\",\n style: {\n width: \"data(size)\", // Read width from element data\n \"line-color\": \"data(color)\", // Read color from element data\n \"target-arrow-color\": \"data(color)\",\n \"target-arrow-shape\": \"triangle\",\n \"curve-style\": \"bezier\",\n \"control-point-step-size\": 40,\n \"control-point-weight\": 0.5,\n opacity: 0.8,\n \"arrow-scale\": 0.8,\n \"mid-target-arrow-shape\": \"none\",\n \"source-endpoint\": \"outside-to-node-or-label\",\n \"target-endpoint\": \"outside-to-node-or-label\",\n },\n },\n // Dashed edges (when dashed property is true)\n {\n selector: \"edge[dashed]\",\n style: {\n \"line-style\": \"dashed\",\n },\n },\n // Show edge labels by default with good styling\n {\n selector: \"edge[label]\",\n style: {\n label: \"data(label)\",\n \"font-size\": \"10px\", // Increased from 8px for better readability\n \"font-weight\": \"500\", // Semi-bold for better visibility\n \"text-background-color\": \"#ffffff\",\n \"text-background-opacity\": 0.9, // Increased from 0.8 for better contrast\n \"text-background-padding\": \"3px\", // Increased from 2px\n \"text-background-shape\": \"roundrectangle\",\n \"text-rotation\": \"autorotate\",\n \"text-margin-y\": -8, // Adjusted for larger font\n color: \"#1a1a1a\", // Darker for better contrast\n },\n },\n {\n selector: \"edge:selected\",\n style: {\n \"line-color\": \"#ff1a1a\",\n \"target-arrow-color\": \"#ff1a1a\",\n width: 8, // even thicker\n \"z-index\": 999,\n \"font-size\": \"11px\",\n \"font-weight\": \"bold\",\n \"text-background-opacity\": 1,\n \"text-background-color\": \"#ffffff\",\n \"text-background-padding\": \"3px\",\n \"arrow-scale\": 1.35,\n opacity: 1,\n \"overlay-color\": \"#ff1a1a\",\n \"overlay-opacity\": 0.08,\n },\n },\n {\n selector: \"node:selected\",\n style: {\n \"border-width\": 10, // thicker circle outline\n \"border-color\": \"#ff1a1a\",\n \"border-opacity\": 1,\n \"background-opacity\": 1,\n \"text-background-opacity\": 1,\n \"text-background-color\": \"#ffffff\",\n \"text-background-padding\": \"4px\",\n \"overlay-color\": \"#ff1a1a\",\n \"overlay-opacity\": 0.18,\n width: 48, // slight size bump from 40\n height: 48,\n } as Record<string, unknown>,\n },\n ],\n layout: { name: \"grid\", fit: true, avoidOverlap: true, condense: true }, // initial quick layout\n wheelSensitivity: 0.2,\n });\n const cy = cyRef.current;\n if (cy) {\n setupCytoscapeEventHandlers({\n cy,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n clearSelectionStore,\n useGraphExploration,\n onCopyNode,\n });\n }\n return () => {\n cyRef.current?.destroy();\n cyRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Track element IDs to detect actual data changes (not just array reference changes)\n const elementIdsRef = useRef<string>(\"\");\n const lastLayoutRef = useRef<string>(\"\");\n const lastFitPaddingRef = useRef<number>(fitPadding);\n\n useEffect(() => {\n // Only process data changes when component is mounted and initialized\n const cy = cyRef.current;\n if (!cy || !isInitializedRef.current) return;\n\n // Create a stable key from element IDs to detect actual data changes\n const currentIds =\n nodes\n .map((n) => n.id_)\n .sort()\n .join(\",\") +\n \"|\" +\n edges\n .map((e) => e.id_)\n .sort()\n .join(\",\");\n\n // Classify whether we need a full update, just a refit, or can skip entirely\n const action = classifyUpdate({\n cy,\n currentIds,\n elementIdsRef,\n lastLayoutRef,\n lastFitPaddingRef,\n currentLayout,\n fitPadding,\n nodeCount: nodes.length,\n edgeCount: edges.length,\n });\n\n if (action === \"refit\") {\n lastFitPaddingRef.current = fitPadding;\n cy.fit(undefined, fitPadding);\n return;\n }\n if (action === \"skip\") {\n return;\n }\n\n // Full update path\n elementIdsRef.current = currentIds;\n lastLayoutRef.current = currentLayout;\n lastFitPaddingRef.current = fitPadding;\n\n // Use cytoscape-formatted elements from the adapter\n const { nodes: nodeElements, edges: edgeElements } = cytoData.elements;\n\n // Batch operations for better performance\n cy.batch(() => {\n cy.elements().remove();\n cy.add([...nodeElements, ...edgeElements]);\n });\n\n // Apply current selection state (initial mount / data refresh) without triggering re-render\n if (selectedNodeIdsRef.current.length > 0 || selectedEdgeRef.current) {\n cy.batch(() => {\n cy.elements().unselect();\n selectedNodeIdsRef.current.forEach((id: string) => cy.$id(id).select());\n if (selectedEdgeRef.current) {\n const edge = cy.$id(String(selectedEdgeRef.current.id_));\n if (edge) {\n edge.select();\n cy.$id(edge.data(\"source\")).select();\n cy.$id(edge.data(\"target\")).select();\n }\n }\n });\n }\n\n // Validate and resolve layout\n const chosen: StandardLayout = (ALLOWED_LAYOUTS as string[]).includes(\n currentLayout,\n )\n ? currentLayout\n : \"auto\";\n\n // Convert VisualGraphNode to format expected by getLayoutPreset (for CiSE clustering by label)\n const nodesForLayout = nodes.map((n) => ({\n id: String(n.id_),\n data: { label_: n.label_ },\n }));\n\n applyLayout({\n cy,\n chosen,\n nodeCount: nodes.length,\n nodesForLayout,\n fitPadding,\n });\n\n // Process pending focus action AFTER graph data is updated\n const pendingFocus = pendingFocusActionRef.current;\n if (pendingFocus) {\n processPendingFocus({\n cy,\n pendingFocus,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n pendingFocusActionRef,\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [nodes, edges, currentLayout, fitPadding]); // fitPadding tracked via ref to avoid full redraw\n\n // Mirror ReGraph behavior: clear selections when query is executed (prevents stale selections)\n // Don't clear on every node change (e.g., override additions), only on query execution\n useEffect(() => {\n if (!cyRef.current) return;\n cyRef.current.elements().unselect();\n clearSelectionStore();\n }, [lastDataChangeTime, clearSelectionStore]);\n\n // Subscribe to GraphFocus store\n useEffect(() => {\n const unsubscribe = useGraphFocus.subscribe((state) => {\n handleFocusStateChange({\n focusAction: state.focusAction,\n cyRef,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n pendingFocusActionRef,\n baseNormalized,\n });\n });\n\n return unsubscribe;\n }, [baseNormalized, setSelectedEdgeStore, setSelectedNodeIdsStore]);\n\n // Function to update the layout\n const updateLayout = (newLayout: StandardLayout) => {\n setCurrentLayout(newLayout);\n };\n\n // Function to fit the graph to the screen\n const fitToScreen = useCallback(() => {\n if (cyRef.current) {\n cyRef.current.fit(undefined, fitPadding);\n }\n }, [fitPadding]);\n\n // Re-fit when node set size changes (post cutover)\n useEffect(() => {\n fitToScreen();\n }, [nodes.length, fitToScreen]);\n\n // Handle window resize events only when component is mounted\n useEffect(() => {\n if (!isInitializedRef.current) return;\n\n const handleResize = () => cyRef.current?.resize();\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n // Fullscreen state + ESC handler + body scroll lock + resize\n const { fullscreen, toggleFullscreen } = useFullscreen(fitToScreen, cyRef);\n\n // Pre-compute visibility flags and CSS classes to reduce JSX complexity\n const {\n outerClass,\n innerClass,\n showEmptyMessage,\n showFilteredMessage,\n showControls,\n } = computeGraphViewState({\n hasNodes: nodes.length > 0,\n hasHiddenElements,\n isFocusMode,\n fullscreen,\n });\n\n return (\n <div className={outerClass}>\n <div className={innerClass}>\n <div ref={containerRef} className=\"absolute inset-0\" />\n {showEmptyMessage && (\n <div className=\"absolute inset-0 flex items-center justify-center text-xs text-gray-500 pointer-events-none select-none\">\n No graph data to visualize (run a query or check the filters)\n </div>\n )}\n {showFilteredMessage && (\n <div className=\"absolute inset-0 flex items-center justify-center text-xs text-gray-500 pointer-events-none select-none\">\n All elements are hidden or filtered (click \"Reset Focus\" to restore)\n </div>\n )}\n {showControls && (\n <CytoscapeControls\n updateLayout={updateLayout}\n fitToScreen={fitToScreen}\n onResetView={() => {\n resetView();\n toast.success(\n isFocusMode ? \"Focus mode cleared\" : \"Hidden elements restored\",\n );\n }}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n extraToolbarContent={extraToolbarContent}\n zoomIn={() => {\n if (cyRef.current) {\n const z = cyRef.current.zoom();\n cyRef.current.zoom({\n level: Math.min(z * 1.2, 5),\n renderedPosition: {\n x: cyRef.current.width() / 2,\n y: cyRef.current.height() / 2,\n },\n });\n }\n }}\n zoomOut={() => {\n if (cyRef.current) {\n const z = cyRef.current.zoom();\n cyRef.current.zoom({\n level: Math.max(z / 1.2, 0.1),\n renderedPosition: {\n x: cyRef.current.width() / 2,\n y: cyRef.current.height() / 2,\n },\n });\n }\n }}\n currentLayout={currentLayout}\n fullscreen={fullscreen}\n toggleFullscreen={toggleFullscreen}\n />\n )}\n </div>\n </div>\n );\n}\n\nexport default CytoscapeGraph;\n","import { type ReactNode } from \"react\";\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n SimpleTooltip,\n} from \"@petrarca/sonnet-ui\";\nimport { LayoutPanelTop, Monitor, Frame, Eye, Minus } from \"lucide-react\";\nimport { StandardLayout } from \"./layoutPresets\";\nimport { RendererDropdown } from \"../shared/RendererDropdown\";\n\ntype Props = {\n updateLayout: (layout: StandardLayout) => void;\n fitToScreen: () => void;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n zoomIn: () => void;\n zoomOut: () => void;\n currentLayout: StandardLayout;\n fullscreen: boolean;\n toggleFullscreen: () => void;\n /** Optional callback when the user resets the view (show hidden / exit focus). */\n onResetView?: () => void;\n /** Optional extra toolbar content (e.g. clipboard UI) injected by the host app. */\n extraToolbarContent?: ReactNode;\n};\n\n/* ------------------------------------------------------------------ */\n/* ViewControls */\n/* ------------------------------------------------------------------ */\n\ntype ViewControlsProps = {\n zoomIn: () => void;\n zoomOut: () => void;\n fullscreen: boolean;\n toggleFullscreen: () => void;\n fitToScreen: () => void;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n onResetView?: () => void;\n};\n\nfunction ViewControls({\n zoomIn,\n zoomOut,\n fullscreen,\n toggleFullscreen,\n fitToScreen,\n hasHiddenElements,\n isFocusMode,\n onResetView,\n}: ViewControlsProps) {\n return (\n <>\n <SimpleTooltip label=\"Zoom In\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={zoomIn}>\n <span style={{ fontWeight: 600 }}>+</span>\n </Button>\n </SimpleTooltip>\n <SimpleTooltip label=\"Zoom Out\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={zoomOut}>\n <Minus />\n </Button>\n </SimpleTooltip>\n <SimpleTooltip label=\"Fullscreen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleFullscreen}>\n {!fullscreen ? <Monitor /> : <Frame />}\n </Button>\n </SimpleTooltip>\n <SimpleTooltip label=\"Fit to screen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={fitToScreen}>\n <Frame />\n </Button>\n </SimpleTooltip>\n {(hasHiddenElements || isFocusMode) && onResetView && (\n <SimpleTooltip\n label={isFocusMode ? \"Reset Focus\" : \"Show All Hidden\"}\n side=\"left\"\n >\n <Button variant=\"ghost\" size=\"icon\" onClick={onResetView}>\n <Eye />\n </Button>\n </SimpleTooltip>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* LayoutDropdown */\n/* ------------------------------------------------------------------ */\n\ntype LayoutGroup = {\n label: string;\n items: { layout: StandardLayout; name: string }[];\n};\n\nconst LAYOUT_GROUPS: LayoutGroup[] = [\n {\n label: \"Force-directed Layouts\",\n items: [\n { layout: \"cola\", name: \"Cola (Best for Knowledge Graphs)\" },\n { layout: \"fcose\", name: \"F-CoSE (Large Graphs)\" },\n { layout: \"cise\", name: \"CiSE (Clustered Circles)\" },\n { layout: \"cose\", name: \"CoSE\" },\n ],\n },\n {\n label: \"Hierarchical Layouts\",\n items: [\n { layout: \"dagre\", name: \"Dagre (Left to Right)\" },\n { layout: \"klay\", name: \"KLay (Layered)\" },\n { layout: \"elk\", name: \"ELK (Layered)\" },\n { layout: \"breadthfirst\", name: \"Breadth-first\" },\n { layout: \"tree\", name: \"Tree (Top-Down)\" },\n ],\n },\n {\n label: \"Other Layouts\",\n items: [\n { layout: \"concentric\", name: \"Concentric\" },\n { layout: \"circle\", name: \"Circle\" },\n { layout: \"grid\", name: \"Grid\" },\n ],\n },\n];\n\ntype LayoutDropdownProps = {\n currentLayout: StandardLayout;\n updateLayout: (layout: StandardLayout) => void;\n};\n\nfunction LayoutDropdown({ currentLayout, updateLayout }: LayoutDropdownProps) {\n return (\n <DropdownMenu>\n <SimpleTooltip label=\"Layout\" side=\"left\">\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <LayoutPanelTop />\n </Button>\n </DropdownMenuTrigger>\n </SimpleTooltip>\n\n <DropdownMenuContent side=\"left\" align=\"start\">\n {LAYOUT_GROUPS.map((group, groupIdx) => (\n <div key={group.label}>\n {groupIdx > 0 && <DropdownMenuSeparator />}\n <DropdownMenuLabel>{group.label}</DropdownMenuLabel>\n {group.items.map((item) => (\n <DropdownMenuItem\n key={item.layout}\n onClick={() => updateLayout(item.layout)}\n className={currentLayout === item.layout ? \"text-blue-600\" : \"\"}\n >\n {item.name}\n </DropdownMenuItem>\n ))}\n </div>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* CytoscapeControls (composed) */\n/* ------------------------------------------------------------------ */\n\nfunction CytoscapeControls({\n fitToScreen,\n hasHiddenElements,\n isFocusMode,\n updateLayout,\n zoomIn,\n zoomOut,\n currentLayout,\n fullscreen,\n toggleFullscreen,\n onResetView,\n extraToolbarContent,\n}: Props) {\n return (\n <div className=\"absolute right-2 top-2 flex flex-col border bg-white rounded-md shadow-sm z-10\">\n <RendererDropdown />\n <ViewControls\n zoomIn={zoomIn}\n zoomOut={zoomOut}\n fullscreen={fullscreen}\n toggleFullscreen={toggleFullscreen}\n fitToScreen={fitToScreen}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n onResetView={onResetView}\n />\n {extraToolbarContent}\n <LayoutDropdown\n currentLayout={currentLayout}\n updateLayout={updateLayout}\n />\n </div>\n );\n}\n\nexport default CytoscapeControls;\n","/**\n * Cytoscape Layout Presets\n *\n * Provides optimized layout configurations for knowledge graphs.\n * Each layout is tuned based on graph size (node count) for best performance and visual quality.\n */\n\nimport type cytoscape from \"cytoscape\";\ntype LayoutOptions = cytoscape.LayoutOptions;\n\nexport type StandardLayout =\n | \"auto\"\n | \"fcose\"\n | \"cola\"\n | \"dagre\"\n | \"klay\"\n | \"elk\"\n | \"cise\"\n | \"cose\"\n | \"concentric\"\n | \"breadthfirst\"\n | \"tree\"\n | \"circle\"\n | \"grid\"\n | \"random\";\n\nexport interface LayoutPresetOptions {\n layoutName: StandardLayout;\n count: number;\n /** Node data for cluster-based layouts (e.g., CiSE) */\n nodeData?: Array<{ id: string; data?: { label_?: string } }>;\n}\n\ntype NodeDataItem = { id: string; data?: { label_?: string } };\ntype LayoutFactory = (count: number, nodeData: NodeDataItem[]) => LayoutOptions;\n\n// --- Individual layout factory functions ---\n\nfunction buildColaLayout(count: number): LayoutOptions {\n return {\n name: \"cola\",\n // Always animate regardless of node count for better user experience\n animate: true,\n // Increase refresh rate for smoother animation\n refresh: 2,\n // Limit simulation time to prevent hanging with large graphs\n maxSimulationTime: 2000,\n // Prevent grabbing during simulation for better performance\n ungrabifyWhileSimulating: true,\n fit: true,\n padding: 50,\n // Scale spacing based on node count for better distribution\n nodeSpacing: () => Math.max(10, 30 - Math.log(count) * 3),\n edgeLength: () => Math.max(80, 150 - Math.log(count) * 10),\n // Always avoid node overlap\n avoidOverlap: true,\n // Prevent infinite running\n infinite: false,\n // Add convergence threshold for faster completion with large graphs\n convergenceThreshold: 0.01,\n // Add randomize false to maintain consistent layouts\n randomize: false,\n } as unknown as LayoutOptions;\n}\n\nfunction buildDagreLayout(count: number): LayoutOptions {\n return {\n name: \"dagre\",\n rankDir: \"LR\", // Left to right\n // Much more compact separation for tree-like hierarchical layouts\n rankSep: Math.min(80, 50 + Math.sqrt(count) * 1.5), // Further reduced\n nodeSep: Math.min(40, 25 + Math.sqrt(count) * 0.8), // Further reduced\n edgeSep: Math.min(10, 5 + Math.log(count) * 0.5), // Further reduced\n // Always animate for better user experience\n animate: true,\n fit: true,\n padding: 30, // Reduced for more compact layout\n } as unknown as LayoutOptions;\n}\n\nfunction buildTreeLayout(count: number): LayoutOptions {\n // Tree (top-down) using breadthfirst; roots auto-detected later (indegree 0)\n return {\n name: \"breadthfirst\",\n fit: true,\n padding: 30, // Reduced for more compact layout\n animate: true,\n directed: true,\n spacingFactor: Math.min(0.9, 0.7 + 60 / (count + 50)), // Compact spacing: 0.7 to 0.9\n circle: false,\n } as LayoutOptions;\n}\n\nfunction buildKlayLayout(count: number): LayoutOptions {\n // NOTE: cytoscape-klay only supports a well-defined subset of options.\n // Passing unknown props inside the nested `klay` object (like nodeSpacing / edgeSpacing)\n // can cause runtime errors in some builds (observed as generic [object Object]).\n // We therefore keep to documented options: direction, spacing, layoutHierarchy,\n // nodeLayering, thoroughness, edgeRouting, mergeEdges, crossingMinimization.\n return {\n name: \"klay\",\n nodeDimensionsIncludeLabels: true,\n fit: true,\n padding: 30, // Reduced for more compact layout\n animate: true,\n animationDuration: 500,\n klay: {\n direction: \"RIGHT\",\n spacing: Math.min(30, 12 + Math.sqrt(count) * 1.5), // Further reduced for much denser layout\n nodeLayering: \"NETWORK_SIMPLEX\",\n layoutHierarchy: true,\n // Increase thoroughness a bit for nicer layering on medium graphs\n thoroughness: count < 400 ? 30 : 10,\n },\n } as unknown as LayoutOptions;\n}\n\nfunction buildFcoseLayout(count: number): LayoutOptions {\n return {\n name: \"fcose\",\n animate: true,\n animationDuration: 600,\n fit: true,\n padding: 50,\n // Scale edge length based on node count\n idealEdgeLength: Math.min(150, 80 + Math.sqrt(count) * 3),\n // Scale repulsion based on node count\n nodeRepulsion: Math.min(30000, 4000 + count * 50),\n // Scale separation based on node count\n nodeSeparation: Math.min(100, 50 + Math.sqrt(count) * 2),\n // Adjust gravity based on node count\n gravity: 0.3,\n // Never randomize for consistent layouts\n randomize: false,\n // Consistent energy for all graph sizes\n initialEnergyOnIncremental: 0.5,\n // Always use sampling for better performance\n samplingType: true,\n // Use default quality for best balance\n quality: \"default\",\n // Limit iterations for large graphs\n numIter: Math.min(2500, 1000 + count * 5),\n // Use consistent cooling factor\n coolingFactor: 0.95,\n // Prevent infinite running\n infinite: false,\n } as unknown as LayoutOptions;\n}\n\nfunction buildCiseLayout(\n count: number,\n nodeData: NodeDataItem[],\n): LayoutOptions {\n // Cluster nodes by label for CiSE layout\n const labelToIds: Record<string, string[]> = {};\n nodeData.forEach((n) => {\n const label = n.data?.label_ || \"Unknown\";\n if (!labelToIds[label]) labelToIds[label] = [];\n labelToIds[label].push(n.id);\n });\n const clusters = Object.values(labelToIds).filter((arr) => arr.length > 0);\n return {\n name: \"cise\",\n animate: true,\n animationDuration: 600,\n clusters,\n nodeSeparation: Math.min(40, 20 + Math.sqrt(count)),\n idealInterClusterEdgeLengthCoefficient: 1.2,\n allowNodesInsideCircle: false,\n maxRatioOfNodesInsideCircle: 0.1,\n springCoeff: 0.45,\n nodeRepulsion: 4500,\n gravity: 0.25,\n gravityRange: 3.8,\n fit: true,\n padding: 50,\n } as unknown as LayoutOptions;\n}\n\nfunction buildElkLayout(count: number): LayoutOptions {\n // ELK (Eclipse Layout Kernel) good for layered + constraint aware layouts.\n // Keep config minimal to avoid large bundle of options; adjust spacing dynamically.\n return {\n name: \"elk\",\n // elk algorithm options under `elk` key\n elk: {\n algorithm: \"layered\",\n \"elk.direction\": \"RIGHT\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": Math.min(\n 150,\n 60 + Math.sqrt(count) * 10,\n ),\n \"elk.spacing.nodeNode\": Math.min(120, 40 + Math.sqrt(count) * 8),\n \"elk.layered.crossingMinimization.semiInteractive\": \"true\",\n },\n fit: true,\n padding: 50,\n animate: true,\n animationDuration: 500,\n } as unknown as LayoutOptions;\n}\n\nfunction buildCoseLayout(count: number): LayoutOptions {\n return {\n name: \"cose\",\n // Always animate for better user experience\n animate: true,\n fit: true,\n padding: 50,\n // Scale overlap based on node count\n nodeOverlap: Math.min(30, 15 + Math.sqrt(count)),\n // Scale spacing based on node count\n componentSpacing: Math.min(150, 80 + Math.sqrt(count) * 2),\n // Increase refresh for smoother animation\n refresh: 10,\n // Scale parameters based on node count\n idealEdgeLength: () => Math.min(150, 80 + Math.sqrt(count) * 2),\n edgeElasticity: () => Math.min(150, 80 + Math.sqrt(count) * 2),\n nodeRepulsion: () => Math.min(600000, 200000 + count * 1000),\n nestingFactor: 1.2,\n // Adjust gravity based on node count\n gravity: Math.min(100, 60 + Math.sqrt(count)),\n // Limit iterations for large graphs\n numIter: Math.min(2500, 1000 + count * 5),\n // Use consistent cooling factor\n coolingFactor: 0.95,\n };\n}\n\nfunction buildConcentricLayout(count: number): LayoutOptions {\n return {\n name: \"concentric\",\n fit: true,\n padding: 50,\n // Always animate for better user experience\n animate: true,\n // Scale spacing based on node count\n minNodeSpacing: Math.min(60, 40 + Math.log(count) * 3),\n // Adjust level width based on node count\n levelWidth: () => Math.max(1, 3 - Math.log(count) * 0.3),\n // Use degree for concentric layout\n concentric: (node: cytoscape.NodeSingular) => node.degree(),\n // Start from outside for better distribution\n startAngle: Math.PI * 1.5,\n } as LayoutOptions;\n}\n\nfunction buildBreadthfirstLayout(count: number): LayoutOptions {\n return {\n name: \"breadthfirst\",\n fit: true,\n padding: 50,\n // Always animate for better user experience\n animate: true,\n directed: true,\n // Scale spacing based on node count\n spacingFactor: Math.min(1.8, 1.2 + 100 / (count + 50)),\n // Add circle option for better distribution with smaller graphs\n circle: count < 100,\n } as LayoutOptions;\n}\n\nfunction buildCircleLayout(count: number): LayoutOptions {\n return {\n name: \"circle\",\n fit: true,\n padding: 50,\n // Always animate for better user experience\n animate: true,\n // Scale radius based on node count\n radius: Math.min(500, count * 3 + 50),\n // Add startAngle for consistent layout\n startAngle: Math.PI / 2,\n };\n}\n\nfunction buildGridLayout(count: number): LayoutOptions {\n // Optimized grid: favor a wider layout (common landscape viewport) and add\n // extra overlap padding so long wrapped labels don't collide.\n const approxCols = Math.ceil(Math.sqrt(count * 1.5)); // widen vs square\n const cols = Math.max(approxCols, 1);\n const rows = Math.max(Math.ceil(count / cols), 1);\n return {\n name: \"grid\",\n fit: true,\n padding: 40,\n avoidOverlap: true,\n // Extra space around each node beyond actual dimensions\n avoidOverlapPadding: Math.min(80, 20 + Math.log(count + 1) * 10),\n // Do NOT condense; we want uniform padding for labels\n condense: false,\n animate: true,\n animationDuration: 400,\n rows,\n cols,\n } as unknown as LayoutOptions;\n}\n\n// --- Layout registry ---\n\nconst layoutFactories: Record<string, LayoutFactory> = {\n cola: buildColaLayout,\n dagre: buildDagreLayout,\n tree: buildTreeLayout,\n klay: buildKlayLayout,\n fcose: buildFcoseLayout,\n cise: buildCiseLayout,\n elk: buildElkLayout,\n cose: buildCoseLayout,\n concentric: buildConcentricLayout,\n breadthfirst: buildBreadthfirstLayout,\n circle: buildCircleLayout,\n grid: buildGridLayout,\n};\n\n/**\n * Get optimized layout configuration for cytoscape based on layout type and graph size.\n *\n * @param options - Layout configuration options\n * @returns Cytoscape LayoutOptions\n */\nexport function getLayoutPreset(options: LayoutPresetOptions): LayoutOptions {\n let { layoutName } = options;\n const { count, nodeData = [] } = options;\n\n // Always use cola for knowledge graphs regardless of size\n // It provides the best balance of performance and quality\n if (layoutName === \"auto\") {\n layoutName = \"cola\";\n }\n\n const factory = layoutFactories[layoutName] ?? layoutFactories.grid;\n return factory(count, nodeData);\n}\n","import type cytoscape from \"cytoscape\";\ntype Core = cytoscape.Core;\nimport { VisualGraphNode } from \"../../models/visual-graph\";\nimport { devLog, errorLog } from \"@petrarca/sonnet-core\";\nimport type { StoreApi, UseBoundStore } from \"zustand\";\nimport type { GraphExplorationStore } from \"../../stores/GraphExploration\";\nimport { toast } from \"sonner\";\n\n/** cytoscape-cxtmenu adds `.cxtmenu()` at runtime but has no official TS types. */\ntype CoreWithCxtmenu = Core & {\n cxtmenu(options: Record<string, unknown>): unknown;\n};\n\ninterface NodeContextMenuOptions {\n cy: Core;\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n onCopyNode?: (node: VisualGraphNode) => void;\n}\n\ninterface EdgeContextMenuOptions {\n cy: Core;\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n}\n\n// Node context menu configuration\nexport const createNodeContextMenu = ({\n cy,\n useGraphExploration,\n onCopyNode,\n}: NodeContextMenuOptions) => {\n devLog(\"[CxtMenu] Initializing node context menu\");\n return (cy as CoreWithCxtmenu).cxtmenu({\n selector: \"node\",\n commands: [\n {\n content: \"Focus\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Focus on node and neighborhood:\", nodeId);\n useGraphExploration.getState().setFocusModeWithNeighborhood(nodeId);\n },\n },\n {\n content: \"Copy\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n devLog(\"[CxtMenu] Copy node to clipboard\");\n\n // Get full VisualGraphNode from element data\n const visualGraph: VisualGraphNode | undefined =\n ele.data(\"visualGraph\");\n\n if (visualGraph) {\n onCopyNode?.(visualGraph);\n } else {\n errorLog(\"[CxtMenu] visualGraph not found in element data\");\n }\n },\n },\n {\n content: \"Hide Node\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Hide node:\", nodeId);\n useGraphExploration.getState().hideElements([nodeId]);\n },\n },\n {\n content: \"Hide Incoming\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Hide incoming (predecessors) of node:\", nodeId);\n useGraphExploration.getState().hideNodeIncoming(nodeId);\n },\n },\n {\n content: \"Hide Outgoing\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Hide outgoing (successors) of node:\", nodeId);\n useGraphExploration.getState().hideNodeOutgoing(nodeId);\n },\n },\n {\n content: \"Expand\",\n select: async (ele: any) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Expanding node:\", nodeId);\n\n try {\n await useGraphExploration.getState().expandNode(nodeId);\n devLog(\"[CxtMenu] Expansion complete\");\n } catch (error) {\n errorLog(\"[CxtMenu] Expansion failed:\", error);\n toast.error(\"Failed to expand node\");\n }\n },\n },\n ],\n menuRadius: 60, // Increased for more items (default is 100)\n fillColor: \"rgba(0, 0, 0, 0.75)\",\n activeFillColor: \"rgba(59, 130, 246, 0.75)\", // blue-500\n activePadding: 10,\n indicatorSize: 12,\n separatorWidth: 2,\n spotlightPadding: 2,\n adaptativeNodeSpotlightRadius: true,\n minSpotlightRadius: 12,\n maxSpotlightRadius: 20,\n openMenuEvents: \"cxttapstart taphold\",\n itemColor: \"white\",\n itemTextShadowColor: \"transparent\",\n zIndex: 9999,\n atMouse: false,\n });\n};\n\n// Edge context menu configuration\nexport const createEdgeContextMenu = ({\n cy,\n useGraphExploration,\n}: EdgeContextMenuOptions) => {\n return (cy as CoreWithCxtmenu).cxtmenu({\n selector: \"edge\",\n commands: [\n {\n content: \"Focus\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\n \"[CxtMenu] Focus on edge (auto-direction based on selection):\",\n edgeId,\n );\n useGraphExploration.getState().focusEdge(edgeId);\n },\n },\n {\n content: \"Focus Edge Type\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\"[CxtMenu] Focus on edge type:\", edgeId);\n useGraphExploration.getState().focusOnEdgeType(edgeId);\n },\n },\n {\n content: \"Hide Forward Path\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\n \"[CxtMenu] Hide forward path (edge + target + downstream):\",\n edgeId,\n );\n useGraphExploration.getState().hideEdgeForwardPath(edgeId);\n },\n },\n {\n content: \"Hide Reverse Path\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\n \"[CxtMenu] Hide reverse path (edge + source + upstream):\",\n edgeId,\n );\n useGraphExploration.getState().hideEdgeReversePath(edgeId);\n },\n },\n ],\n menuRadius: 90, // Increased for more items\n fillColor: \"rgba(0, 0, 0, 0.75)\",\n activeFillColor: \"rgba(239, 68, 68, 0.75)\", // red-500\n activePadding: 10,\n indicatorSize: 12,\n separatorWidth: 2,\n spotlightPadding: 2,\n openMenuEvents: \"cxttapstart taphold\",\n itemColor: \"white\",\n itemTextShadowColor: \"transparent\",\n zIndex: 9999,\n atMouse: false,\n });\n};\n","import { type ReactNode } from \"react\";\nimport { useGraphRenderer } from \"../hooks/useGraphRenderer\";\nimport ReaGraph from \"./rea/ReaGraph\";\nimport CytoscapeGraph from \"./cyto/CytoscapeGraph\";\nimport type { VisualGraphNode } from \"../models/visual-graph\";\n\nexport interface GraphVisualizerProps {\n /** Callback when a node is copied (e.g. to clipboard). Decouples renderers from clipboard store. */\n onCopyNode?: (node: VisualGraphNode) => void;\n /** Extra toolbar content (e.g. clipboard UI) injected into the renderer toolbar. */\n extraToolbarContent?: ReactNode;\n}\n\nfunction GraphVisualizer({\n onCopyNode,\n extraToolbarContent,\n}: GraphVisualizerProps) {\n const { renderer } = useGraphRenderer();\n\n return (\n <div className=\"relative w-full h-full flex flex-col overflow-hidden\">\n {/* Render only the active graph component */}\n <div className=\"flex-1 h-full\">\n {renderer === \"reagraph\" && (\n <ReaGraph\n key=\"reagraph\"\n onCopyNode={onCopyNode}\n extraToolbarContent={extraToolbarContent}\n />\n )}\n {renderer === \"cytoscape\" && (\n <CytoscapeGraph\n key=\"cytoscape\"\n onCopyNode={onCopyNode}\n extraToolbarContent={extraToolbarContent}\n />\n )}\n </div>\n </div>\n );\n}\n\nexport default GraphVisualizer;\n","import { Card } from \"@petrarca/sonnet-ui\";\nimport NodeInfoCard from \"./NodeInfoCard\";\nimport EdgeInfoCard from \"./EdgeInfoCard\";\nimport Overview from \"./Overview\";\nimport { useWorkspaceSelection } from \"../../hooks/useWorkspaceStores\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport { type ReactNode, useMemo } from \"react\";\nimport type { SelectionStore } from \"../../stores/Selection\";\n\ninterface ActionPanelProps {\n /** Optional actions rendered at the top of the panel (e.g. CRUD buttons) */\n actions?: ReactNode;\n}\n\nfunction ActionPanel({ actions }: ActionPanelProps) {\n // Get workspace-scoped store\n const useSelection = useWorkspaceSelection();\n\n // Select only the specific slices we need from the store to reduce unnecessary re-renders.\n const selectedNodeIds = useSelection(\n (s: SelectionStore) => s.selectedNodeIds,\n );\n const selectedEdge = useSelection((s: SelectionStore) => s.selectedEdge);\n const live = useLiveGraphData();\n\n // Memoize selected node objects so referential identity only changes when inputs change.\n const selectedNodes = useMemo(\n () =>\n selectedNodeIds\n .map((id) => live.normalized.nodesById[id])\n .filter(Boolean),\n [selectedNodeIds, live.normalized],\n );\n\n const firstNode = selectedNodes[0];\n const secondNode = selectedNodes?.[1];\n const hasEdge = !!selectedEdge;\n const showOverview = !firstNode && !hasEdge;\n\n return (\n <Card\n className=\"h-full min-w-64 flex flex-col bg-gray-50 shadow-xs p-4\"\n style={{ maxHeight: \"100%\", overflow: \"hidden\" }}\n >\n {actions && <div className=\"flex-shrink-0 mb-2\">{actions}</div>}\n <div className=\"flex-1 overflow-auto pr-1\">\n <div className=\"flex flex-col gap-4\">\n {firstNode && <NodeInfoCard node={firstNode} />}\n {hasEdge && selectedEdge && <EdgeInfoCard edge={selectedEdge} />}\n {secondNode && <NodeInfoCard node={secondNode} />}\n {showOverview && <Overview />}\n </div>\n </div>\n </Card>\n );\n}\n\nexport default ActionPanel;\n","import { useState } from \"react\";\nimport {\n Card,\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@petrarca/sonnet-ui\";\nimport { VisualGraphNode } from \"../../models/visual-graph\";\nimport { copyTextToClipboard } from \"@petrarca/sonnet-core\";\n\ntype Props = {\n node: VisualGraphNode;\n};\n\nfunction NodeInfoCard({ node }: Props) {\n const [showProperties, setShowProperties] = useState(false);\n\n return (\n <Card\n className=\"w-full rounded-lg overflow-hidden bg-gray-100 border p-4 shadow-xs\"\n style={{\n background: \"#f3f4f6\",\n borderLeft: `4px solid ${node.visual.color}`,\n }}\n >\n {/* Node type label */}\n <p className=\"leading-tight font-semibold mb-0\">{node.label_}</p>\n\n {/* Display name from visual enrichment */}\n <p className=\"leading-tight mb-1\">{node.visual.displayName}</p>\n\n {/* Internal node ID */}\n <p\n className=\"text-xs text-muted-foreground cursor-pointer select-all mb-2\"\n onClick={() => copyTextToClipboard(String(node.id_))}\n title=\"Click to copy id\"\n >\n {node.id_}\n </p>\n\n {/* Properties collapsible */}\n <Collapsible open={showProperties} onOpenChange={setShowProperties}>\n <CollapsibleTrigger asChild>\n <button className=\"text-xs cursor-pointer\">\n {showProperties ? \"Hide\" : \"Show more\"}\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <ul className=\"list-none mt-2\">\n <p className=\"text-sm font-semibold mb-1 tracking-wide\">\n Properties\n </p>\n {Object.entries(node.properties_ || {}).map(([key, value]) => (\n <li key={key} className=\"mb-2 leading-tight\">\n <p className=\"text-xs text-slate-600 uppercase tracking-wide\">\n {key}\n </p>\n <p\n className=\"text-sm truncate max-w-[190px] cursor-pointer\"\n onClick={() => copyTextToClipboard(String(value))}\n title=\"Click to copy value\"\n >\n {String(value)}\n </p>\n </li>\n ))}\n </ul>\n </CollapsibleContent>\n </Collapsible>\n </Card>\n );\n}\n\nexport default NodeInfoCard;\n","import { useState } from \"react\";\nimport { VisualGraphEdge } from \"../../models/visual-graph\";\nimport {\n Card,\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@petrarca/sonnet-ui\";\nimport { ArrowDown } from \"lucide-react\";\nimport { copyTextToClipboard } from \"@petrarca/sonnet-core\";\n\ntype Props = {\n edge: VisualGraphEdge;\n};\n\nfunction EdgeInfoCard({ edge }: Props) {\n const [showProperties, setShowProperties] = useState(false);\n\n return (\n <Card\n className=\"w-full rounded-lg overflow-hidden bg-gray-100 border p-4 shadow-xs\"\n style={{\n background: \"#f3f4f6\",\n borderLeft: `4px solid ${edge.visual.color}`,\n }}\n >\n {/* Edge type label */}\n <p className=\"leading-tight mb-1\">\n <ArrowDown className=\"inline-block mr-1 opacity-70 align-middle\" />\n <strong className=\"font-semibold align-middle\">{edge.label_}</strong>\n </p>\n\n {/* Internal edge ID */}\n {edge.id_ && (\n <p\n className=\"text-xs text-muted-foreground select-all cursor-pointer mt-1 mb-2\"\n title=\"Click to copy edge id\"\n onClick={() => copyTextToClipboard(String(edge.id_))}\n >\n {edge.id_}\n </p>\n )}\n\n {/* Properties display */}\n {edge.properties_ && Object.keys(edge.properties_).length > 0 && (\n <Collapsible open={showProperties} onOpenChange={setShowProperties}>\n <CollapsibleTrigger asChild>\n <button className=\"text-xs cursor-pointer\">\n {showProperties ? \"Hide\" : \"Show more\"}\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <ul className=\"list-none mt-2\">\n <p className=\"text-sm font-semibold mb-1 tracking-wide\">\n Properties\n </p>\n {Object.entries(edge.properties_ || {}).map(([key, value]) => (\n <li key={key} className=\"mb-2 leading-tight\">\n <p className=\"text-xs text-slate-600 uppercase tracking-wide\">\n {key}\n </p>\n <p\n className=\"text-sm truncate max-w-[190px] cursor-pointer\"\n onClick={() => copyTextToClipboard(String(value))}\n title=\"Click to copy value\"\n >\n {String(value)}\n </p>\n </li>\n ))}\n </ul>\n </CollapsibleContent>\n </Collapsible>\n )}\n </Card>\n );\n}\n\nexport default EdgeInfoCard;\n","import { useWorkspaceGraphFilter } from \"../../hooks/useWorkspaceStores\";\nimport { Badge } from \"@petrarca/sonnet-ui\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport { formatNumber, devLog } from \"@petrarca/sonnet-core\";\nimport { useMemo } from \"react\";\n\n/**\n * Compute a mapping from edge labels to the node labels they connect.\n * Uses actual graph data (not schema) to determine which node labels are affected.\n */\nfunction computeEdgeToNodeLabels(\n nodesById: Record<string, { label_: string }>,\n edgesById: Record<\n string,\n { label_: string; start_id_: number; end_id_: number }\n >,\n): Record<string, string[]> {\n const mapping: Record<string, Set<string>> = {};\n\n for (const edge of Object.values(edgesById)) {\n const edgeLabel = edge.label_;\n const startNode = nodesById[String(edge.start_id_)];\n const endNode = nodesById[String(edge.end_id_)];\n\n if (!mapping[edgeLabel]) {\n mapping[edgeLabel] = new Set();\n }\n\n if (startNode) mapping[edgeLabel].add(startNode.label_);\n if (endNode) mapping[edgeLabel].add(endNode.label_);\n }\n\n // Convert Sets to arrays\n const result: Record<string, string[]> = {};\n for (const [edgeLabel, nodeLabels] of Object.entries(mapping)) {\n result[edgeLabel] = Array.from(nodeLabels);\n }\n return result;\n}\n\nfunction resolveBadgeColor(\n isAllDisabled: boolean,\n filters: string[],\n label: string,\n colorPalette: Record<string, string>,\n activeColor: string,\n): string {\n if (isAllDisabled) return colorPalette[\"faded\"];\n if (filters.length === 0 || filters.includes(label))\n return colorPalette[activeColor];\n return colorPalette[\"faded\"];\n}\n\nfunction AllToggleBadge({\n allDisabled,\n colorPalette,\n count,\n onToggle,\n badgeKey,\n}: {\n allDisabled: boolean;\n colorPalette: Record<string, string>;\n count: number;\n onToggle: () => void;\n badgeKey: string;\n}) {\n const bgColor = allDisabled ? colorPalette[\"faded\"] : colorPalette[\"neutral\"];\n return (\n <Badge\n key={badgeKey}\n className=\"cursor-pointer text-sm px-3 py-1\"\n style={{\n textTransform: \"none\",\n backgroundColor: bgColor,\n borderRadius: \"10px\",\n }}\n onClick={onToggle}\n >\n * ({formatNumber(count)})\n </Badge>\n );\n}\n\nfunction NodeLabelBadges({\n labels,\n labelCounts,\n colorPalette,\n allLabelsDisabled,\n nodeLabelFilters,\n toggleNodeLabelFilter,\n}: {\n labels: string[];\n labelCounts: Record<string, number>;\n colorPalette: Record<string, string>;\n allLabelsDisabled: boolean;\n nodeLabelFilters: string[];\n toggleNodeLabelFilter: (label: string, allLabels: string[]) => void;\n}) {\n return labels.map((label) => {\n const bgColor = resolveBadgeColor(\n allLabelsDisabled,\n nodeLabelFilters,\n label,\n colorPalette,\n label,\n );\n return (\n <Badge\n key={label}\n className=\"cursor-pointer text-sm px-3 py-1\"\n style={{\n textTransform: \"none\",\n backgroundColor: bgColor,\n borderRadius: \"10px\",\n }}\n onClick={() => toggleNodeLabelFilter(label, labels)}\n >\n {label} ({formatNumber(labelCounts[label])})\n </Badge>\n );\n });\n}\n\nfunction EdgeLabelBadges({\n labels,\n edgeLabelCounts,\n colorPalette,\n allEdgeLabelsDisabled,\n edgeLabelFilters,\n toggleEdgeLabelFilter,\n edgeToNodeLabels,\n}: {\n labels: string[];\n edgeLabelCounts: Record<string, number>;\n colorPalette: Record<string, string>;\n allEdgeLabelsDisabled: boolean;\n edgeLabelFilters: string[];\n toggleEdgeLabelFilter: (\n label: string,\n allLabels: string[],\n mapping: Record<string, string[]>,\n ) => void;\n edgeToNodeLabels: Record<string, string[]>;\n}) {\n return labels.map((label) => {\n const bgColor = resolveBadgeColor(\n allEdgeLabelsDisabled,\n edgeLabelFilters,\n label,\n colorPalette,\n \"neutral\",\n );\n return (\n <Badge\n key={label}\n className=\"cursor-pointer text-sm px-3 py-1\"\n style={{\n textTransform: \"none\",\n backgroundColor: bgColor,\n borderRadius: \"10px\",\n }}\n onClick={() => toggleEdgeLabelFilter(label, labels, edgeToNodeLabels)}\n >\n {label} ({formatNumber(edgeLabelCounts[label])})\n </Badge>\n );\n });\n}\n\n/** Renders the graph overview with node/edge label filter badges. */\nfunction GraphOverview({\n stats,\n colorPalette,\n labelCounts,\n edgeLabelCounts,\n edgeToNodeLabels,\n}: {\n stats: { nodes: number; edges: number };\n colorPalette: Record<string, string>;\n labelCounts: Record<string, number>;\n edgeLabelCounts: Record<string, number>;\n edgeToNodeLabels: Record<string, string[]>;\n}) {\n const useGraphFilter = useWorkspaceGraphFilter();\n const nodeLabelFilters = useGraphFilter((state) => state.nodeLabelFilters);\n const allLabelsDisabled = useGraphFilter((state) => state.allLabelsDisabled);\n const edgeLabelFilters = useGraphFilter((state) => state.edgeLabelFilters);\n const allEdgeLabelsDisabled = useGraphFilter(\n (state) => state.allEdgeLabelsDisabled,\n );\n const toggleNodeLabelFilter = useGraphFilter(\n (state) => state.toggleNodeLabelFilter,\n );\n const clearNodeLabelFilters = useGraphFilter(\n (state) => state.clearNodeLabelFilters,\n );\n const toggleAllLabelsDisabled = useGraphFilter(\n (state: any) => state.toggleAllLabelsDisabled,\n );\n const toggleEdgeLabelFilter = useGraphFilter(\n (state: any) => state.toggleEdgeLabelFilter,\n );\n const clearEdgeLabelFilters = useGraphFilter(\n (state: any) => state.clearEdgeLabelFilters,\n );\n const toggleAllEdgeLabelsDisabled = useGraphFilter(\n (state: any) => state.toggleAllEdgeLabelsDisabled,\n );\n\n const allLabels = Object.keys(labelCounts).sort();\n devLog(\"[Overview] Rendering labels\", {\n labels: allLabels,\n colorKeys: Object.keys(colorPalette || {}),\n labelCounts: labelCounts,\n stats: stats,\n });\n\n const allEdgeLabels = Object.keys(edgeLabelCounts || {}).sort();\n\n const handleNodeToggle = () => {\n if (allLabelsDisabled) {\n toggleAllLabelsDisabled();\n clearNodeLabelFilters();\n } else {\n toggleAllLabelsDisabled();\n }\n };\n\n const handleEdgeToggle = () => {\n if (allEdgeLabelsDisabled) {\n toggleAllEdgeLabelsDisabled();\n clearEdgeLabelFilters();\n } else {\n toggleAllEdgeLabelsDisabled();\n }\n };\n\n return (\n <>\n <p className=\"mt-2 text-sm font-semibold\">Overview</p>\n\n {allLabels.length > 0 && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2\">\n Node Labels\n </p>\n <div className=\"flex flex-col items-start gap-2\">\n <AllToggleBadge\n allDisabled={allLabelsDisabled}\n colorPalette={colorPalette}\n count={stats.nodes}\n onToggle={handleNodeToggle}\n badgeKey=\"all\"\n />\n <NodeLabelBadges\n labels={allLabels}\n labelCounts={labelCounts}\n colorPalette={colorPalette}\n allLabelsDisabled={allLabelsDisabled}\n nodeLabelFilters={nodeLabelFilters}\n toggleNodeLabelFilter={toggleNodeLabelFilter}\n />\n </div>\n </div>\n )}\n {allEdgeLabels.length > 0 && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2\">\n Edge Types\n </p>\n <div className=\"flex flex-col items-start gap-2\">\n <AllToggleBadge\n allDisabled={allEdgeLabelsDisabled}\n colorPalette={colorPalette}\n count={stats.edges}\n onToggle={handleEdgeToggle}\n badgeKey=\"edge-all\"\n />\n <EdgeLabelBadges\n labels={allEdgeLabels}\n edgeLabelCounts={edgeLabelCounts}\n colorPalette={colorPalette}\n allEdgeLabelsDisabled={allEdgeLabelsDisabled}\n edgeLabelFilters={edgeLabelFilters}\n toggleEdgeLabelFilter={toggleEdgeLabelFilter}\n edgeToNodeLabels={edgeToNodeLabels}\n />\n </div>\n </div>\n )}\n </>\n );\n}\n\nfunction Overview() {\n const { stats, colorPalette, labelCounts, edgeLabelCounts, baseNormalized } =\n useLiveGraphData();\n\n // Compute edge-to-node-labels mapping from actual graph data\n const edgeToNodeLabels = useMemo(() => {\n if (!baseNormalized?.nodesById || !baseNormalized?.edgesById) return {};\n return computeEdgeToNodeLabels(\n baseNormalized.nodesById,\n baseNormalized.edgesById,\n );\n }, [baseNormalized]);\n\n if (stats && stats.values != null && stats.values > 0) {\n return (\n <>\n <p className=\"mt-2 text-sm font-semibold\">Overview</p>\n\n <p className=\"text-sm text-slate-700\">\n {formatNumber(stats.values)} Values\n </p>\n </>\n );\n }\n\n if (stats && stats.nodes > 0 && colorPalette) {\n return (\n <GraphOverview\n stats={stats}\n colorPalette={colorPalette}\n labelCounts={labelCounts}\n edgeLabelCounts={edgeLabelCounts}\n edgeToNodeLabels={edgeToNodeLabels}\n />\n );\n }\n\n return null;\n}\n\nexport default Overview;\n"],"mappings":"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","names":["create","devLog","create","create","devLog","devLog","create","create","devLog","create","devLog","buildStore","devLog","useGraphFilter","useGraphData","useMemo","useMemo","useMemo","useMemo","createContext","useContext","useEffect","useState","useCallback","devLog","useSelection","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","SimpleTooltip","useState","jsx","jsx","jsxs","DropdownMenu","SimpleTooltip","DropdownMenuTrigger","Button","DropdownMenuContent","DropdownMenuItem","useState","Card","jsx","jsxs","React","devLog","jsx","jsxs","jsx","jsxs","devLog","useEffect","useState","useGraphFilter","useSelection","useCallback","Card","useEffect","useRef","useState","useCallback","devLog","errorLog","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuTrigger","SimpleTooltip","LayoutPanelTop","Eye","Fragment","jsx","jsxs","ViewControls","SimpleTooltip","Button","Eye","LayoutDropdown","DropdownMenu","DropdownMenuTrigger","LayoutPanelTop","DropdownMenuContent","DropdownMenuSeparator","DropdownMenuLabel","DropdownMenuItem","devLog","toast","toast","jsx","jsxs","errorLog","devLog","useState","useEffect","useCallback","useRef","useGraphFilter","useSelection","jsx","jsxs","Card","useState","Card","jsx","jsxs","useState","Card","Collapsible","CollapsibleContent","CollapsibleTrigger","copyTextToClipboard","jsx","jsxs","devLog","useMemo","Fragment","jsx","jsxs","useGraphFilter","useMemo","jsx","jsxs","useSelection","Card"]}
|
|
1
|
+
{"version":3,"sources":["../src/models/visual-graph.ts","../src/models/graph-types.ts","../src/graph/extractDisplayLabel.ts","../src/graph/enrichment.ts","../src/graph/normalize.ts","../src/stores/Selection.ts","../src/stores/GraphData.ts","../src/stores/GraphFilter.ts","../src/stores/GraphExploration.ts","../src/stores/GraphFocus.ts","../src/stores/ActionPanelStore.ts","../src/hooks/useWorkspaceStores.ts","../src/hooks/useLiveGraphData.ts","../src/hooks/useReagraphData.ts","../src/hooks/useCytoscapeData.ts","../src/hooks/useGraphRendererContext.ts","../src/hooks/graphRendererProvider.tsx","../src/components/rea/ReaGraph.tsx","../src/components/rea/theme.ts","../src/components/rea/LayoutAndCameraControls.tsx","../src/components/shared/RendererDropdown.tsx","../src/components/rea/NodeHoverInfo.tsx","../src/components/rea/ReaContextMenu.tsx","../src/components/cyto/CytoscapeGraph.tsx","../src/components/cyto/CytoscapeControls.tsx","../src/components/cyto/layoutPresets.ts","../src/components/cyto/contextMenuConfig.ts","../src/components/GraphVisualizer.tsx","../src/components/ActionPanel/ActionPanel.tsx","../src/components/ActionPanel/NodeInfoCard.tsx","../src/components/ActionPanel/EdgeInfoCard.tsx","../src/components/ActionPanel/Overview.tsx","../src/components/GraphA11yList/GraphA11yList.tsx"],"sourcesContent":["/**\n * Visual Graph Model - Domain types combining API data with UI enrichment.\n *\n * These types are the canonical graph representation used throughout the application.\n * They combine backend API data (GraphNode/GraphEdge DTOs) with visual enrichment\n * (colors, display names, etc.) computed once at the data boundary.\n *\n * This is an internal refactoring - NO functional changes to the application.\n * All behavior, visuals, and capabilities remain identical.\n */\n\n/**\n * Visual enrichment data for a node.\n * Computed once during data ingress, then reused everywhere.\n */\nexport interface NodeVisual {\n /** User-friendly name extracted from properties (name, title, label, etc.) */\n displayName: string;\n\n /** Color from unified palette based on node label */\n color: string;\n\n /** Optional: Node size (can be computed from degree, importance, etc.) */\n size?: number;\n\n /** Optional: Icon URL for the node */\n icon?: string;\n}\n\n/**\n * Visual enrichment data for an edge.\n */\nexport interface EdgeVisual {\n /** Edge color (typically based on type or neutral color) */\n color: string;\n\n /** Optional: Edge thickness/width */\n size?: number;\n\n /** Optional: Whether to render as dashed line */\n dashed?: boolean;\n}\n\n/**\n * VisualGraphNode - The canonical node type for the application.\n *\n * Combines API data (aligned with backend GraphNode DTO) with visual enrichment.\n * This replaces the previous pattern of using reagraph GraphNode types throughout\n * the application, which caused coupling to the visualization library.\n *\n * Structure matches backend API exactly:\n * - id_: Unique node identifier\n * - label_: Node type/class (e.g., \"Person\", \"Movie\")\n * - properties_: Key-value pairs from the database\n *\n * Plus visual enrichment for UI consistency:\n * - visual.displayName: Computed once from properties\n * - visual.color: Assigned once from unified palette\n */\nexport interface VisualGraphNode {\n // Core data (matches API GraphNode structure)\n id_: number;\n label_: string;\n properties_: Record<string, string | number | Array<string | number>>;\n\n // Visual enrichment\n visual: NodeVisual;\n}\n\n/**\n * VisualGraphEdge - The canonical edge type for the application.\n *\n * Combines API data (aligned with backend GraphEdge DTO) with visual enrichment.\n *\n * Structure matches backend API exactly:\n * - id_: Unique edge identifier\n * - label_: Relationship type (e.g., \"ACTED_IN\", \"DIRECTED\")\n * - start_id_: Source node ID\n * - end_id_: Target node ID\n * - properties_: Optional key-value pairs\n *\n * Plus visual enrichment for UI consistency.\n */\nexport interface VisualGraphEdge {\n // Core data (matches API GraphEdge structure)\n id_: number;\n label_: string;\n start_id_: number;\n end_id_: number;\n properties_?: Record<string, string | number | Array<string | number>>;\n\n // Visual enrichment\n visual: EdgeVisual;\n}\n\n/**\n * Normalized graph structure using visual models.\n *\n * Provides O(1) lookup by ID for efficient access in components.\n * This is the internal representation used by the application after\n * data is fetched and enriched.\n */\nexport interface VisualGraphNormalized {\n /** Nodes indexed by string ID for O(1) lookup */\n nodesById: Record<string, VisualGraphNode>;\n\n /** Edges indexed by string ID for O(1) lookup */\n edgesById: Record<string, VisualGraphEdge>;\n\n /** Array of all node IDs (for iteration) */\n nodeIds: string[];\n\n /** Array of all edge IDs (for iteration) */\n edgeIds: string[];\n}\n\n/**\n * Type guard to check if an object is a VisualGraphNode.\n *\n * @param obj - Object to check\n * @returns true if obj is a valid VisualGraphNode\n */\nexport function isVisualNode(obj: unknown): obj is VisualGraphNode {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"id_\" in obj &&\n \"label_\" in obj &&\n \"properties_\" in obj &&\n \"visual\" in obj &&\n typeof (obj as any).visual === \"object\" &&\n \"displayName\" in (obj as any).visual &&\n \"color\" in (obj as any).visual\n );\n}\n\n/**\n * Type guard to check if an object is a VisualGraphEdge.\n *\n * @param obj - Object to check\n * @returns true if obj is a valid VisualGraphEdge\n */\nexport function isVisualEdge(obj: unknown): obj is VisualGraphEdge {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"id_\" in obj &&\n \"label_\" in obj &&\n \"start_id_\" in obj &&\n \"end_id_\" in obj &&\n \"visual\" in obj &&\n typeof (obj as any).visual === \"object\" &&\n \"color\" in (obj as any).visual\n );\n}\n","/**\n * Package-local raw graph types.\n *\n * These are the minimal structural types needed by the graph visualization layer.\n * They are structurally compatible with the API DTO types in `api/types.ts`\n * (GraphNode, GraphEdge) but live in the domain layer so graph-generic code\n * does not depend on API/transport types.\n */\n\nexport type GraphProperty = string | number | Array<string | number>;\n\nexport type GraphProperties = Record<string, GraphProperty>;\n\nexport type RawGraphNode = {\n id_?: number;\n label_: string;\n properties_?: GraphProperties;\n};\n\nexport type RawGraphEdge = {\n id_?: number;\n label_: string;\n start_id_: number;\n end_id_: number;\n properties_?: GraphProperties;\n};\n\n/**\n * Type guard to check if an object is a RawGraphNode (vs RawGraphEdge).\n * Edges have start_id_ and end_id_ properties, nodes don't.\n */\nexport function isRawGraphNode(\n obj: RawGraphNode | RawGraphEdge,\n): obj is RawGraphNode {\n return \"label_\" in obj && !(\"start_id_\" in obj) && !(\"end_id_\" in obj);\n}\n\n/**\n * Display configuration from schema metadata.\n * Mirrors api/types.ts DisplayConfig but lives in the domain layer so\n * graph-generic code (enrichment, extraction) does not depend on API types.\n */\nexport type GraphDisplayConfig = {\n labelTemplate?: string; // Template for display labels, e.g. \"{firstName} {lastName}\". Takes priority over labelProperty.\n labelProperty?: string; // Property for display labels (default: \"name\")\n fallbackProperty?: string; // Fallback if labelProperty missing\n sortProperty?: string; // Property for sorting (default: labelProperty)\n sortOrder?: \"ASC\" | \"DESC\"; // Sort direction (default: \"ASC\")\n filterProperty?: string; // Optional grouping/filtering column\n};\n\n/**\n * Resolved display config map: node label → GraphDisplayConfig.\n * Built once from schema data and passed into enrichNodes().\n * Only labels with explicit display config appear in this map.\n */\nexport type LabelDisplayMap = Record<string, GraphDisplayConfig>;\n","import type {\n GraphDisplayConfig,\n RawGraphNode,\n RawGraphEdge,\n} from \"../models/graph-types\";\nimport { isRawGraphNode } from \"../models/graph-types\";\n\n/**\n * Interpolate a label template against a properties object.\n * Placeholders: {propertyName} — missing properties are silently dropped.\n * Result is trimmed; empty string means the template produced nothing useful.\n *\n * @example\n * interpolateTemplate(\"{firstName} {lastName}\", { firstName: \"John\" }) // \"John\"\n * interpolateTemplate(\"{type}: {name}\", { type: \"npm\", name: \"react\" }) // \"npm: react\"\n */\nfunction interpolateTemplate(\n template: string,\n properties: Record<string, unknown>,\n): string {\n return template\n .replace(/\\{(\\w+)\\}/g, (_, key) => {\n const val = properties[key];\n return val !== undefined && val !== null ? String(val) : \"\";\n })\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\ntype LabelStrategy = () => string | undefined;\n\n/**\n * Walk a prioritized list of label resolution strategies.\n * Returns the first non-empty result, or `fallback` if none match.\n */\nfunction resolveLabel(strategies: LabelStrategy[], fallback: string): string {\n for (const strategy of strategies) {\n const result = strategy();\n if (result) return result;\n }\n return fallback;\n}\n\n/** Try interpolating displayConfig.labelTemplate against properties. */\nfunction fromTemplate(\n displayConfig: GraphDisplayConfig | undefined,\n props: Record<string, unknown> | undefined,\n): string | undefined {\n if (!displayConfig?.labelTemplate || !props) return undefined;\n return interpolateTemplate(displayConfig.labelTemplate, props) || undefined;\n}\n\n/** Try reading displayConfig.labelProperty from properties. */\nfunction fromLabelProperty(\n displayConfig: GraphDisplayConfig | undefined,\n props: Record<string, unknown> | undefined,\n): string | undefined {\n if (!displayConfig?.labelProperty || !props?.[displayConfig.labelProperty])\n return undefined;\n return String(props[displayConfig.labelProperty]);\n}\n\n/** Try reading displayConfig.fallbackProperty from properties. */\nfunction fromFallbackProperty(\n displayConfig: GraphDisplayConfig | undefined,\n props: Record<string, unknown> | undefined,\n): string | undefined {\n if (\n !displayConfig?.fallbackProperty ||\n !props?.[displayConfig.fallbackProperty]\n )\n return undefined;\n return String(props[displayConfig.fallbackProperty]);\n}\n\n/**\n * Extract display label from a node using resolved display config.\n *\n * Precedence:\n * 1. labelTemplate → interpolated against properties (skips missing, trims)\n * 2. labelProperty → properties[labelProperty]\n * 3. fallbackProperty → properties[fallbackProperty]\n * 4. properties.name (convention across all known graph schemas)\n * 5. first property value\n * 6. Node #${id_}\n * 7. \"Unknown\"\n */\nfunction extractNodeDisplayLabel(\n node: RawGraphNode,\n displayConfig?: GraphDisplayConfig,\n): string {\n const props = node?.properties_;\n return resolveLabel(\n [\n () => fromTemplate(displayConfig, props),\n () => fromLabelProperty(displayConfig, props),\n () => fromFallbackProperty(displayConfig, props),\n () => (props?.name ? String(props.name) : undefined),\n () => {\n const keys = props ? Object.keys(props) : [];\n return keys.length > 0 ? String(props![keys[0]]) : undefined;\n },\n () =>\n node?.id_ !== undefined && node.id_ !== null\n ? `Node #${node.id_}`\n : undefined,\n ],\n \"Unknown\",\n );\n}\n\n/**\n * Extract display label from an edge using resolved display config.\n *\n * Precedence:\n * 1. labelTemplate → interpolated against properties\n * 2. labelProperty → properties[labelProperty]\n * 3. fallbackProperty → properties[fallbackProperty]\n * 4. label_ (relationship type, e.g. \"ACTED_IN\")\n * 5. Edge #${id_}\n * 6. \"Unknown\"\n */\nfunction extractEdgeDisplayLabel(\n edge: RawGraphEdge,\n displayConfig?: GraphDisplayConfig,\n): string {\n const props = edge?.properties_;\n return resolveLabel(\n [\n () => fromTemplate(displayConfig, props),\n () => fromLabelProperty(displayConfig, props),\n () => fromFallbackProperty(displayConfig, props),\n () => (edge?.label_ ? edge.label_ : undefined),\n () =>\n edge?.id_ !== undefined && edge.id_ !== null\n ? `Edge #${edge.id_}`\n : undefined,\n ],\n \"Unknown\",\n );\n}\n\n/**\n * Extract display label from a node or edge using resolved display config.\n *\n * @param item - RawGraphNode or RawGraphEdge\n * @param displayConfig - Optional resolved GraphDisplayConfig for this label\n */\nexport function extractDisplayLabel(\n item: RawGraphNode | RawGraphEdge,\n displayConfig?: GraphDisplayConfig,\n): string {\n if (isRawGraphNode(item)) {\n return extractNodeDisplayLabel(item, displayConfig);\n } else {\n return extractEdgeDisplayLabel(item, displayConfig);\n }\n}\n","/**\n * Graph data enrichment - Converts API DTOs to Visual Graph Models.\n *\n * This is where API data gets transformed into the domain model with UI enrichment.\n * Enrichment happens ONCE at the data boundary (in useLiveGraphData), then the\n * enriched models are used throughout the application.\n */\n\nimport type {\n RawGraphNode,\n RawGraphEdge,\n GraphDisplayConfig,\n LabelDisplayMap,\n} from \"../models/graph-types\";\nimport { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\nimport { extractDisplayLabel } from \"./extractDisplayLabel\";\n\n/**\n * Color palette mapping node labels to colors.\n * Built once from label counts, then used for all nodes.\n */\nexport type ColorPalette = Record<string, string>;\n\n/**\n * Base color palette for node visualization.\n * MUST NOT CHANGE - this ensures consistent color assignments across the app.\n */\nconst BASE_COLORS = [\n \"#f94144\",\n \"#118ab2\",\n \"#f8961e\",\n \"#43aa8b\",\n \"#f3722c\",\n \"#90be6d\",\n \"#f9c74f\",\n \"#c4bbaf\",\n];\n\n/**\n * Builds a unified color palette from label counts.\n *\n * Colors are assigned to labels based on their order, cycling through BASE_COLORS.\n * Includes 'neutral' and 'faded' colors for edges and unlabeled nodes.\n *\n * @param labelCounts - Object mapping label names to counts\n * @returns Color palette mapping labels to hex colors\n *\n * @example\n * const counts = { Person: 10, Movie: 5 };\n * const palette = buildColorPalette(counts);\n * // { Person: '#f94144', Movie: '#118ab2', neutral: '#6c757d', faded: '#adb5bd' }\n */\nexport function buildColorPalette(\n labelCounts: Record<string, number>,\n): ColorPalette {\n const palette: ColorPalette = {};\n let i = 0;\n\n // Assign colors to each label in order (preserves existing behavior)\n for (const label of Object.keys(labelCounts)) {\n palette[label] = BASE_COLORS[i % BASE_COLORS.length];\n i++;\n }\n\n // Add special colors (preserves existing behavior)\n palette[\"neutral\"] = \"#6c757d\";\n palette[\"faded\"] = \"#adb5bd\";\n\n return palette;\n}\n\n/**\n * Convenience: build a color palette directly from an array of nodes.\n * Counts labels, then delegates to buildColorPalette.\n *\n * @param nodes - Array of nodes (any object with a `label_` string property)\n * @returns Color palette mapping labels to hex colors\n */\nexport function buildColorPaletteFromNodes(\n nodes: { label_: string }[],\n): ColorPalette {\n const labelCounts: Record<string, number> = {};\n for (const n of nodes) {\n const l = n?.label_;\n if (l) labelCounts[l] = (labelCounts[l] || 0) + 1;\n }\n return buildColorPalette(labelCounts);\n}\n\n/**\n * Enriches an API node with visual data to create a VisualGraphNode.\n *\n * This is the primary transformation from API DTO to domain model.\n * Extracts displayName from node properties, assigns color from the palette,\n * and provides fallback to neutral color for unlabeled nodes.\n *\n * @param apiNode - Node from backend API\n * @param colorPalette - Unified color palette\n * @param displayConfig - Optional resolved GraphDisplayConfig for this node's label\n * @returns Enriched VisualGraphNode\n */\nexport function enrichNode(\n apiNode: RawGraphNode,\n colorPalette: ColorPalette,\n displayConfig?: GraphDisplayConfig,\n): VisualGraphNode {\n // Extract display label from node properties using resolved display config\n const displayName = extractDisplayLabel(apiNode, displayConfig);\n\n // Get color from palette (may be undefined if label not in palette)\n // This preserves the legacy behavior where fill is only set if color exists\n const color = colorPalette[apiNode.label_];\n\n return {\n // Copy core data from API\n id_: apiNode.id_ ?? 0, // Handle optional id for creation scenarios\n label_: apiNode.label_,\n properties_: apiNode.properties_ ?? {},\n\n // Add visual enrichment\n visual: {\n displayName,\n // Use color from palette, or fall back to neutral if not found\n // This ensures every node has a color (no undefined)\n color: color || colorPalette[\"neutral\"] || \"#6c757d\",\n // Size can be added later if needed\n size: undefined,\n icon: undefined,\n },\n };\n}\n\n/**\n * Enriches an API edge with visual data to create a VisualGraphEdge.\n *\n * Adds neutral color and default size to edges for consistent visualization.\n *\n * @param apiEdge - Edge from backend API\n * @param colorPalette - Optional unified color palette (for neutral color)\n * @returns Enriched VisualGraphEdge\n */\nexport function enrichEdge(\n apiEdge: RawGraphEdge,\n colorPalette?: ColorPalette,\n): VisualGraphEdge {\n return {\n // Copy core data from API\n id_: apiEdge.id_ ?? 0,\n label_: apiEdge.label_,\n start_id_: apiEdge.start_id_,\n end_id_: apiEdge.end_id_,\n properties_: apiEdge.properties_ as\n | Record<string, string | number | Array<string | number>>\n | undefined,\n\n // Add visual enrichment\n visual: {\n // Use neutral color from palette if available, otherwise default\n color: colorPalette?.[\"neutral\"] ?? \"#999999\",\n // Default size of 3\n size: 3,\n dashed: undefined,\n },\n };\n}\n\n/**\n * Batch enrichment for multiple nodes.\n * More efficient than calling enrichNode repeatedly.\n *\n * @param apiNodes - Array of nodes from backend API\n * @param colorPalette - Unified color palette\n * @param labelDisplayMap - Optional resolved display config map (label → GraphDisplayConfig)\n * @returns Array of enriched VisualGraphNodes\n */\nexport function enrichNodes(\n apiNodes: RawGraphNode[],\n colorPalette: ColorPalette,\n labelDisplayMap?: LabelDisplayMap,\n): VisualGraphNode[] {\n return apiNodes.map((node) =>\n enrichNode(node, colorPalette, labelDisplayMap?.[node.label_]),\n );\n}\n\n/**\n * Batch enrichment for multiple edges.\n * More efficient than calling enrichEdge repeatedly.\n *\n * @param apiEdges - Array of edges from backend API\n * @param colorPalette - Optional unified color palette\n * @returns Array of enriched VisualGraphEdges\n */\nexport function enrichEdges(\n apiEdges: RawGraphEdge[],\n colorPalette?: ColorPalette,\n): VisualGraphEdge[] {\n return apiEdges.map((edge) => enrichEdge(edge, colorPalette));\n}\n","import {\n VisualGraphNode,\n VisualGraphEdge,\n VisualGraphNormalized,\n} from \"../models/visual-graph\";\n\n/**\n * Type alias for backward compatibility during refactoring.\n * This allows existing code to continue working while we migrate.\n */\nexport type NormalizedGraph = VisualGraphNormalized;\n\n/**\n * Normalizes visual graph data into an indexed structure for efficient lookups.\n *\n * This function converts arrays of nodes and edges into a Record structure\n * for O(1) lookup by ID, which is essential for performance in graph operations.\n *\n * INTERNAL REFACTORING: Function signature changed to use VisualGraph types,\n * but behavior is identical - same normalization logic, same performance.\n *\n * @param nodes - Array of VisualGraphNodes\n * @param edges - Array of VisualGraphEdges\n * @returns Normalized graph with indexed nodes and edges\n */\nexport function normalizeGraph(\n nodes: VisualGraphNode[],\n edges: VisualGraphEdge[],\n): VisualGraphNormalized {\n const nodesById: Record<string, VisualGraphNode> = {};\n const edgesById: Record<string, VisualGraphEdge> = {};\n\n // Index nodes by string ID for O(1) lookup\n for (const n of nodes) {\n const key = String(n.id_);\n nodesById[key] = n;\n }\n\n // Index edges by string ID for O(1) lookup\n for (const e of edges) {\n const key = String(e.id_);\n edgesById[key] = e;\n }\n\n return {\n nodesById,\n edgesById,\n nodeIds: Object.keys(nodesById),\n edgeIds: Object.keys(edgesById),\n };\n}\n\n/**\n * Empty normalized graph constant for initial state.\n */\nexport const EMPTY_NORMALIZED: VisualGraphNormalized = {\n nodesById: {},\n edgesById: {},\n nodeIds: [],\n edgeIds: [],\n};\n","import { VisualGraphEdge } from \"../models/visual-graph\";\nimport { create } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\nexport interface SelectionStore {\n selectedNodeIds: string[];\n setSelectedNodeIds: (ids: string[]) => void;\n selectedEdge: VisualGraphEdge | null;\n setSelectedEdge: (edge: VisualGraphEdge | null) => void;\n clear: () => void;\n}\n\n/**\n * Factory function to create a new Selection store instance.\n * Used by workspace system to create isolated store instances per workspace.\n *\n * For backward compatibility, the default export is a singleton instance.\n * Existing code continues to work without changes.\n */\nexport function createSelectionStore() {\n return create<SelectionStore>()((set, get) => ({\n selectedNodeIds: [],\n setSelectedNodeIds: (ids) => {\n const prev = get().selectedNodeIds;\n if (prev.length === ids.length && prev.every((v, i) => v === ids[i])) {\n // No change; skip state update & noisy logs\n return;\n }\n devLog(\"[SelectionStore] setSelectedNodeIds\", { prev, next: ids });\n set({ selectedNodeIds: ids });\n },\n selectedEdge: null,\n setSelectedEdge: (edge) => {\n devLog(\"[SelectionStore] setSelectedEdge\", {\n prev: get().selectedEdge?.id_,\n next: edge?.id_,\n });\n set({ selectedEdge: edge });\n },\n clear: () => {\n devLog(\"[SelectionStore] clear called\");\n set({ selectedNodeIds: [], selectedEdge: null });\n },\n }));\n}\n\n// Singleton instance for backward compatibility with existing code.\n// Existing imports continue to work without changes.\nconst useSelection = createSelectionStore();\n\nexport default useSelection;\n","/**\n * GraphData Store\n *\n * Central store for all graph data (query results + expanded nodes/edges).\n * This is the PRIMARY source of truth for graph visualization.\n *\n * Data sources:\n * 1. Query execution (setQueryData) - ACTIVELY USED\n * 2. Node expansion operations (mergeExpandedData) - ACTIVELY USED\n *\n * Data flow:\n * - Consumer calls setQueryData() with enriched nodes/edges after each query\n * - GraphExploration calls mergeExpandedData() when expanding nodes\n * - useLiveGraphData reads from this store and applies filters before rendering\n *\n * Merge strategy:\n * - setQueryData(): Replaces all data with new query results\n * - mergeExpandedData(): Adds expanded nodes/edges without duplicates\n */\n\nimport { create } from \"zustand\";\nimport { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\nimport { type GraphStatistics } from \"../interfaces\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\nexport interface GraphDataStore {\n /** All nodes (from query + expansions) */\n nodes: VisualGraphNode[];\n\n /** All edges (from query + expansions) */\n edges: VisualGraphEdge[];\n\n /** Query statistics from the last query execution */\n stats: GraphStatistics | undefined;\n\n /** Tabular values from value-set queries */\n values: string[][];\n\n /** Whether the last query was a value-set (tabular) query */\n isValueSet: boolean;\n\n /** IDs of nodes from the original query */\n queryNodeIds: Set<string>;\n\n /** IDs of nodes from expansion operations */\n expandedNodeIds: Set<string>;\n\n /** IDs of edges from the original query */\n queryEdgeIds: Set<string>;\n\n /** IDs of edges from expansion operations */\n expandedEdgeIds: Set<string>;\n\n // --- Actions ---\n\n /**\n * Set graph data from a query execution.\n * Replaces all existing data.\n *\n * @param nodes - Enriched nodes from query\n * @param edges - Enriched edges from query\n * @param stats - Query statistics\n * @param values - Tabular values for value-set queries\n * @param isValueSet - Whether this is a value-set query\n */\n setQueryData: (\n nodes: VisualGraphNode[],\n edges: VisualGraphEdge[],\n stats?: GraphStatistics,\n values?: string[][],\n isValueSet?: boolean,\n ) => void;\n\n /**\n * Merge expanded nodes/edges into existing graph.\n * Deduplicates by ID - existing elements are preserved.\n *\n * @param nodes - New nodes from expansion\n * @param edges - New edges from expansion\n */\n mergeExpandedData: (\n nodes: VisualGraphNode[],\n edges: VisualGraphEdge[],\n ) => void;\n\n /**\n * Clear all graph data\n */\n clear: () => void;\n\n /**\n * Get statistics about data sources\n */\n getStats: () => {\n totalNodes: number;\n totalEdges: number;\n queryNodes: number;\n expandedNodes: number;\n queryEdges: number;\n expandedEdges: number;\n };\n}\n\n/**\n * Factory function to create a new GraphData store instance.\n * Used by workspace system to create isolated store instances per workspace.\n *\n * For backward compatibility, the default export is a singleton instance.\n * Existing code continues to work without changes.\n */\nexport function createGraphDataStore() {\n return create<GraphDataStore>()((set, get) => ({\n nodes: [],\n edges: [],\n stats: undefined,\n values: [],\n isValueSet: false,\n queryNodeIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n queryEdgeIds: new Set<string>(),\n expandedEdgeIds: new Set<string>(),\n\n setQueryData: (nodes, edges, stats, values, isValueSet = false) => {\n const nodeIds = new Set(nodes.map((n) => String(n.id_)));\n const edgeIds = new Set(edges.map((e) => String(e.id_)));\n\n devLog(\"[GraphData] setQueryData\", {\n nodes: nodes.length,\n edges: edges.length,\n });\n\n set({\n nodes,\n edges,\n stats,\n values: values || [],\n isValueSet,\n queryNodeIds: nodeIds,\n queryEdgeIds: edgeIds,\n expandedNodeIds: new Set<string>(),\n expandedEdgeIds: new Set<string>(),\n });\n },\n\n mergeExpandedData: (newNodes, newEdges) => {\n const state = get();\n\n // Create maps for O(1) lookup of existing elements\n const existingNodesMap = new Map(\n state.nodes.map((n) => [String(n.id_), n]),\n );\n const existingEdgesMap = new Map(\n state.edges.map((e) => [String(e.id_), e]),\n );\n\n // Track expanded element IDs\n const newExpandedNodeIds = new Set(state.expandedNodeIds);\n const newExpandedEdgeIds = new Set(state.expandedEdgeIds);\n\n // Merge nodes - only add if not already present\n const nodesToAdd: VisualGraphNode[] = [];\n for (const node of newNodes) {\n const id = String(node.id_);\n if (!existingNodesMap.has(id)) {\n nodesToAdd.push(node);\n newExpandedNodeIds.add(id);\n }\n }\n\n // Merge edges - only add if not already present\n const edgesToAdd: VisualGraphEdge[] = [];\n for (const edge of newEdges) {\n const id = String(edge.id_);\n if (!existingEdgesMap.has(id)) {\n edgesToAdd.push(edge);\n newExpandedEdgeIds.add(id);\n }\n }\n\n devLog(\"[GraphData] mergeExpandedData\", {\n newNodes: newNodes.length,\n newEdges: newEdges.length,\n addedNodes: nodesToAdd.length,\n addedEdges: edgesToAdd.length,\n duplicatesSkipped: {\n nodes: newNodes.length - nodesToAdd.length,\n edges: newEdges.length - edgesToAdd.length,\n },\n });\n\n // Only update if we have new data\n if (nodesToAdd.length > 0 || edgesToAdd.length > 0) {\n set({\n nodes: [...state.nodes, ...nodesToAdd],\n edges: [...state.edges, ...edgesToAdd],\n expandedNodeIds: newExpandedNodeIds,\n expandedEdgeIds: newExpandedEdgeIds,\n });\n } else {\n devLog(\n \"[GraphData] mergeExpandedData: No new elements to add (all duplicates)\",\n );\n }\n },\n\n clear: () => {\n devLog(\"[GraphData] clear\");\n\n set({\n nodes: [],\n edges: [],\n stats: undefined,\n values: [],\n isValueSet: false,\n queryNodeIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n queryEdgeIds: new Set<string>(),\n expandedEdgeIds: new Set<string>(),\n });\n },\n\n getStats: () => {\n const state = get();\n return {\n totalNodes: state.nodes.length,\n totalEdges: state.edges.length,\n queryNodes: state.queryNodeIds.size,\n expandedNodes: state.expandedNodeIds.size,\n queryEdges: state.queryEdgeIds.size,\n expandedEdges: state.expandedEdgeIds.size,\n };\n },\n }));\n}\n\n// Singleton instance for backward compatibility with existing code.\n// Existing imports continue to work without changes.\nconst useGraphData = createGraphDataStore();\n\nexport default useGraphData;\n","import { create } from \"zustand\";\n\n/**\n * GraphFilterStore - Node/edge label filtering and data-change tracking.\n *\n * Graph-generic filtering store. Separated from Cypher-specific\n * query editing (QueryEditorStore stays in the consumer).\n */\nexport interface GraphFilterStore {\n // Node label filtering\n nodeLabelFilters: string[];\n allLabelsDisabled: boolean;\n toggleNodeLabelFilter: (label: string, allAvailableLabels?: string[]) => void;\n clearNodeLabelFilters: () => void;\n setNodeLabelFilters: (labels: string[]) => void;\n toggleAllLabelsDisabled: () => void;\n\n // Edge label filtering\n edgeLabelFilters: string[];\n allEdgeLabelsDisabled: boolean;\n toggleEdgeLabelFilter: (\n label: string,\n allAvailableLabels?: string[],\n edgeToNodeLabels?: Record<string, string[]>,\n ) => void;\n clearEdgeLabelFilters: () => void;\n setEdgeLabelFilters: (labels: string[]) => void;\n toggleAllEdgeLabelsDisabled: () => void;\n\n // Data change tracking — notified on query execution so renderers can react\n lastDataChangeTime: number;\n notifyDataChange: () => void;\n\n // Reset all active filters (called on new query execution)\n resetFilters: () => void;\n}\n\n/**\n * Calculates which node labels need to be enabled when an edge type is enabled.\n */\nfunction calculateNodeLabelUpdate(\n affectedLabels: string[],\n currentNodeFilters: string[],\n allNodesDisabled: boolean,\n): { allLabelsDisabled?: boolean; nodeLabelFilters: string[] } | null {\n if (affectedLabels.length === 0) return null;\n\n if (allNodesDisabled) {\n return { allLabelsDisabled: false, nodeLabelFilters: affectedLabels };\n }\n\n if (currentNodeFilters.length > 0) {\n const labelsToAdd = affectedLabels.filter(\n (l) => !currentNodeFilters.includes(l),\n );\n if (labelsToAdd.length > 0) {\n return { nodeLabelFilters: [...currentNodeFilters, ...labelsToAdd] };\n }\n }\n\n return null;\n}\n\ntype SetFn = (partial: Partial<GraphFilterStore>) => void;\n\ntype NodeLabelUpdate = {\n allLabelsDisabled?: boolean;\n nodeLabelFilters: string[];\n} | null;\n\n/** Re-enable a single edge label from the \"all disabled\" state. */\nfunction handleEnableFromAllDisabled(\n label: string,\n getNodeLabelUpdate: (l: string) => NodeLabelUpdate,\n set: SetFn,\n): void {\n const nodeUpdate = getNodeLabelUpdate(label);\n set({\n allEdgeLabelsDisabled: false,\n edgeLabelFilters: [label],\n ...nodeUpdate,\n });\n}\n\n/** First filter toggle when no filters are active (show-all → single-off). */\nfunction handleFirstFilter(\n label: string,\n allAvailableLabels: string[],\n set: SetFn,\n): void {\n const next = allAvailableLabels.filter((l) => l !== label);\n set({ edgeLabelFilters: next });\n}\n\n/** Normal toggle: add/remove label and handle the \"last one removed\" edge case. */\nfunction handleToggleFilter(\n label: string,\n current: string[],\n exists: boolean,\n getNodeLabelUpdate: (l: string) => NodeLabelUpdate,\n set: SetFn,\n): void {\n const next = exists\n ? current.filter((l) => l !== label)\n : [...current, label];\n\n if (next.length === 0 && exists) {\n set({ allEdgeLabelsDisabled: true, edgeLabelFilters: [] });\n return;\n }\n\n const nodeUpdate = exists ? null : getNodeLabelUpdate(label);\n set({ edgeLabelFilters: next, ...nodeUpdate });\n}\n\nexport function createGraphFilterStore() {\n return create<GraphFilterStore>()((set, get) => ({\n nodeLabelFilters: [],\n allLabelsDisabled: false,\n edgeLabelFilters: [],\n allEdgeLabelsDisabled: false,\n lastDataChangeTime: 0,\n\n notifyDataChange: () => set({ lastDataChangeTime: Date.now() }),\n\n resetFilters: () =>\n set({\n nodeLabelFilters: [],\n allLabelsDisabled: false,\n edgeLabelFilters: [],\n allEdgeLabelsDisabled: false,\n }),\n\n toggleNodeLabelFilter: (label, allAvailableLabels) => {\n const wasAllDisabled = get().allLabelsDisabled;\n if (wasAllDisabled) set({ allLabelsDisabled: false });\n const current = get().nodeLabelFilters;\n const exists = current.includes(label);\n\n if (wasAllDisabled) {\n set({ nodeLabelFilters: [label] });\n } else if (\n current.length === 0 &&\n !exists &&\n allAvailableLabels &&\n allAvailableLabels.length > 0\n ) {\n const next = allAvailableLabels.filter((l) => l !== label);\n set({ nodeLabelFilters: next });\n } else {\n const next = exists\n ? current.filter((l) => l !== label)\n : [...current, label];\n if (next.length === 0 && exists) {\n set({ allLabelsDisabled: true, nodeLabelFilters: [] });\n } else {\n set({ nodeLabelFilters: next });\n }\n }\n },\n clearNodeLabelFilters: () => set({ nodeLabelFilters: [] }),\n setNodeLabelFilters: (labels) => set({ nodeLabelFilters: labels }),\n toggleAllLabelsDisabled: () => {\n const now = !get().allLabelsDisabled;\n set({ allLabelsDisabled: now, nodeLabelFilters: [] });\n },\n\n toggleEdgeLabelFilter: (label, allAvailableLabels, edgeToNodeLabels) => {\n const getNodeLabelUpdate = (edgeLabel: string) => {\n if (!edgeToNodeLabels) return null;\n const affectedLabels = edgeToNodeLabels[edgeLabel] || [];\n return calculateNodeLabelUpdate(\n affectedLabels,\n get().nodeLabelFilters,\n get().allLabelsDisabled,\n );\n };\n\n if (get().allEdgeLabelsDisabled) {\n handleEnableFromAllDisabled(label, getNodeLabelUpdate, set);\n } else if (\n get().edgeLabelFilters.length === 0 &&\n allAvailableLabels &&\n allAvailableLabels.length > 0\n ) {\n handleFirstFilter(label, allAvailableLabels, set);\n } else {\n const current = get().edgeLabelFilters;\n handleToggleFilter(\n label,\n current,\n current.includes(label),\n getNodeLabelUpdate,\n set,\n );\n }\n },\n clearEdgeLabelFilters: () => set({ edgeLabelFilters: [] }),\n setEdgeLabelFilters: (labels) => set({ edgeLabelFilters: labels }),\n toggleAllEdgeLabelsDisabled: () => {\n const now = !get().allEdgeLabelsDisabled;\n set({ allEdgeLabelsDisabled: now, edgeLabelFilters: [] });\n },\n }));\n}\n\n// Global singleton — used by the global QueryEditor singleton and GraphExploration singleton.\nconst useGraphFilter = createGraphFilterStore();\nexport default useGraphFilter;\n","/**\n * GraphExploration Store\n *\n * Manages visual exploration state for the graph visualizer:\n * - Focus mode: Show only selected nodes\n * - Hidden elements: Temporarily hide nodes/edges from view\n * - Expansion tracking: Track which nodes have been expanded\n *\n * This state is separate from:\n * - Selection (which elements are selected)\n * - GraphFocus (zoom/pan actions)\n * - GraphFilter (label filters)\n */\n\nimport { create, StoreApi, UseBoundStore } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\nimport type { GraphDataStore } from \"./GraphData\";\nimport type { SelectionStore } from \"./Selection\";\nimport type { GraphFocusStore } from \"./GraphFocus\";\nimport type { GraphFilterStore } from \"./GraphFilter\";\nimport {\n enrichNodes,\n enrichEdges,\n buildColorPaletteFromNodes,\n} from \"../graph/enrichment\";\nimport type {\n RawGraphNode,\n RawGraphEdge,\n LabelDisplayMap,\n} from \"../models/graph-types\";\n\n/**\n * Store dependencies for GraphExploration.\n * Allows workspace-specific or global store injection.\n */\nexport interface GraphExplorationDeps {\n graphData: UseBoundStore<StoreApi<GraphDataStore>>;\n selection: UseBoundStore<StoreApi<SelectionStore>>;\n graphFocus: UseBoundStore<StoreApi<GraphFocusStore>>;\n graphFilter: UseBoundStore<StoreApi<GraphFilterStore>>;\n\n // Pluggable backend access — decouples store from specific API implementation\n expandNode: (\n id: number,\n ) => Promise<{ nodes: RawGraphNode[]; edges: RawGraphEdge[] }>;\n getNodes: (ids: number[]) => Promise<RawGraphNode[]>;\n\n // Optional: resolved display config map for node label enrichment\n getLabelDisplayMap?: () => LabelDisplayMap;\n}\n\nexport interface GraphExplorationStore {\n /** Node IDs to show in focus mode (empty = not in focus mode) */\n focusedNodeIds: Set<string>;\n\n /** Whether focus mode is active */\n isFocusMode: boolean;\n\n /** Element IDs (nodes + edges) to hide from view */\n hiddenElementIds: Set<string>;\n\n /** Node IDs that have been expanded (for UI feedback) */\n expandedNodeIds: Set<string>;\n\n // --- Actions ---\n\n /**\n * Enter focus mode showing only specified nodes\n * @param nodeIds - IDs of nodes to focus on\n */\n setFocusMode: (nodeIds: string[]) => void;\n\n /**\n * Enter focus mode on a node and its immediate neighborhood\n * (includes the node itself + all directly connected nodes)\n * @param nodeId - ID of the node to focus on\n */\n setFocusModeWithNeighborhood: (nodeId: string) => void;\n\n /**\n * Exit focus mode (show all label-filtered nodes)\n */\n clearFocusMode: () => void;\n\n /**\n * Hide elements from the graph\n * @param elementIds - IDs of nodes and/or edges to hide\n */\n hideElements: (elementIds: string[]) => void;\n\n /**\n * Show previously hidden elements\n * @param elementIds - IDs of nodes and/or edges to show\n */\n showElements: (elementIds: string[]) => void;\n\n /**\n * Hide all nodes that have paths leading TO the specified node (predecessors/ancestors).\n * The clicked node itself remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param nodeId - ID of the node (kept visible)\n */\n hideNodeIncoming: (nodeId: string) => void;\n\n /**\n * Hide all nodes that have paths FROM the specified node (successors/descendants).\n * The clicked node itself remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param nodeId - ID of the node (kept visible)\n */\n hideNodeOutgoing: (nodeId: string) => void;\n\n /**\n * Hide the edge AND the forward path (target node + all its outgoing connections).\n * The source node of the edge remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param edgeId - ID of the edge to hide\n */\n hideEdgeForwardPath: (edgeId: string) => void;\n\n /**\n * Hide the edge AND the reverse path (source node + all its incoming connections).\n * The target node of the edge remains VISIBLE as a boundary marker.\n * Uses recursive traversal with cycle protection.\n * @param edgeId - ID of the edge to hide\n */\n hideEdgeReversePath: (edgeId: string) => void;\n\n /**\n * Focus on edges of a specific type, automatically determining direction from selection state.\n *\n * Behavior:\n * - If 1 node + edge selected: Uses the selected node as reference (outgoing if source, incoming if target)\n * - If 2 nodes + edge selected: Defaults to outgoing from start node\n * - Shows all nodes connected via edges of the same type in the determined direction\n *\n * @param edgeId - ID of the edge (to get type and endpoints)\n */\n focusEdge: (edgeId: string) => void;\n\n /**\n * Focus on a specific edge type: show only edges of this type and their connected nodes.\n * All other nodes and edges are hidden.\n *\n * @param edgeId - ID of the edge (to determine the edge type/label)\n */\n focusOnEdgeType: (edgeId: string) => void;\n\n /**\n * Reset all exploration state (clear focus + hidden)\n * Note: Keeps expandedNodeIds since those nodes are still in the data\n */\n resetView: () => void;\n\n /**\n * Reset ALL exploration state including expanded nodes.\n * Should be called when new query data is loaded to ensure clean state.\n */\n resetForNewQuery: () => void;\n\n /**\n * Mark a node as expanded (for UI feedback)\n * @param nodeId - ID of expanded node\n */\n markNodeExpanded: (nodeId: string) => void;\n\n /**\n * Check if a node has been expanded\n * @param nodeId - ID to check\n */\n isNodeExpanded: (nodeId: string) => boolean;\n\n /**\n * Expand a node by fetching connected nodes/edges from backend\n * and merging them into the graph data.\n * @param nodeId - ID of the node to expand\n * @returns Promise that resolves when expansion is complete\n */\n expandNode: (nodeId: string) => Promise<void>;\n\n /**\n * Add a node to the graph by ID.\n * If the node already exists in the graph, just focuses it (if autoFocus=true).\n * If not, fetches it from the API, enriches it with visual data,\n * adds it to the graph, and optionally focuses it.\n *\n * @param nodeId - ID of the node to add\n * @param autoFocus - Whether to automatically focus the node after adding (default: false)\n * @returns Promise that resolves when the node is added/focused\n */\n addNodeById: (nodeId: number, autoFocus?: boolean) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Shared traversal helper\n// ---------------------------------------------------------------------------\n\ninterface TraversalResult {\n nodes: Set<string>;\n edges: Set<string>;\n}\n\n/**\n * Recursively collect all node/edge IDs reachable from `startId` by following\n * edges in the given direction. The start node itself is excluded when\n * `includeStart` is false (used for \"boundary marker\" behaviour).\n */\nfunction collectReachable(\n startId: string,\n direction: \"in\" | \"out\",\n allEdges: { id_?: number; start_id_: number; end_id_: number }[],\n includeStart: boolean,\n): TraversalResult {\n const nodes = new Set<string>();\n const edges = new Set<string>();\n const visited = new Set<string>();\n\n const traverse = (currentId: string, isStart: boolean) => {\n if (visited.has(currentId)) return;\n visited.add(currentId);\n\n if (!isStart || includeStart) nodes.add(currentId);\n\n for (const edge of allEdges) {\n const srcId = String(edge.start_id_);\n const tgtId = String(edge.end_id_);\n const edgeId = String(edge.id_);\n\n if (direction === \"in\" && tgtId === currentId) {\n edges.add(edgeId);\n traverse(srcId, false);\n } else if (direction === \"out\" && srcId === currentId) {\n edges.add(edgeId);\n traverse(tgtId, false);\n }\n }\n };\n\n traverse(startId, true);\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// focusEdge helpers\n// ---------------------------------------------------------------------------\n\ninterface EdgeEndpoints {\n edgeLabel: string;\n startNodeId: string;\n endNodeId: string;\n}\n\n/**\n * Determine the traversal direction and reference node for focusEdge,\n * based on the current selection state.\n */\nfunction determineEdgeDirection(\n endpoints: EdgeEndpoints,\n selectedNodeIds: string[],\n): { direction: \"outgoing\" | \"incoming\"; referenceNodeId: string } {\n const { startNodeId, endNodeId } = endpoints;\n\n if (selectedNodeIds.length !== 1) {\n // Two nodes selected or edge selected directly – default to outgoing from start\n return { direction: \"outgoing\", referenceNodeId: startNodeId };\n }\n\n // Single node selected – use it as reference\n const selected = selectedNodeIds[0];\n\n if (selected === startNodeId) {\n return { direction: \"outgoing\", referenceNodeId: selected };\n }\n if (selected === endNodeId) {\n return { direction: \"incoming\", referenceNodeId: selected };\n }\n\n // Selected node is not an endpoint (shouldn't happen, but safe fallback)\n devLog(\n \"[GraphExploration] focusEdge - selected node not an endpoint, defaulting to outgoing\",\n { selectedNode: selected, startNodeId, endNodeId },\n );\n return { direction: \"outgoing\", referenceNodeId: startNodeId };\n}\n\n/**\n * Build the set of node IDs to focus on: the reference node plus all nodes\n * connected via edges of the same label in the given direction.\n */\nfunction buildFocusSet(\n referenceNodeId: string,\n direction: \"outgoing\" | \"incoming\",\n edgeLabel: string,\n allEdges: {\n id_?: number;\n start_id_: number;\n end_id_: number;\n label_: string;\n }[],\n): Set<string> {\n const focusNodeIds = new Set<string>([referenceNodeId]);\n\n for (const e of allEdges) {\n if (e.label_ !== edgeLabel) continue;\n\n const sourceId = String(e.start_id_);\n const targetId = String(e.end_id_);\n\n if (direction === \"outgoing\" && sourceId === referenceNodeId) {\n focusNodeIds.add(targetId);\n } else if (direction === \"incoming\" && targetId === referenceNodeId) {\n focusNodeIds.add(sourceId);\n }\n }\n\n return focusNodeIds;\n}\n\n// ---------------------------------------------------------------------------\n// addNodeById helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Handle the case where the node already exists in the graph.\n * Returns true if the node was found (caller should return early).\n */\nfunction handleExistingNode(\n nodeId: number,\n nodeIdStr: string,\n existingNodes: RawGraphNode[],\n autoFocus: boolean,\n graphFocusStore: GraphExplorationDeps[\"graphFocus\"],\n): boolean {\n const existingNode = existingNodes.find((n) => n.id_ === nodeId);\n if (!existingNode) return false;\n\n if (autoFocus) {\n devLog(\"[GraphExploration] Node already in graph, focusing\", { nodeId });\n graphFocusStore.getState().requestFocus(nodeIdStr, \"node\", false);\n } else {\n devLog(\"[GraphExploration] Node already in graph, skipping focus\", {\n nodeId,\n });\n }\n return true;\n}\n\n/**\n * Fetch the node from the backend, enrich it, and merge it into the graph\n * data store. Returns the array of enriched nodes.\n */\nasync function fetchAndEnrichNode(\n nodeId: number,\n existingNodes: RawGraphNode[],\n stores: GraphExplorationDeps,\n): Promise<ReturnType<typeof enrichNodes>> {\n devLog(\"[GraphExploration] Fetching node from backend\", { nodeId });\n const result = await stores.getNodes([nodeId]);\n\n if (result.length === 0) {\n throw new Error(`Node ${nodeId} not found`);\n }\n\n const colorPalette = buildColorPaletteFromNodes([\n ...existingNodes,\n ...result,\n ]);\n const enrichedNodes = enrichNodes(\n result,\n colorPalette,\n stores.getLabelDisplayMap?.(),\n );\n\n devLog(\"[GraphExploration] Enriched nodes\", {\n nodeId,\n enrichedCount: enrichedNodes.length,\n });\n\n stores.graphData.getState().mergeExpandedData(enrichedNodes, []);\n return enrichedNodes;\n}\n\n/**\n * Ensure the first enriched node's label is included in the active\n * node-label filters (prevents new nodes from being immediately hidden).\n */\nfunction ensureNodeLabelInFilters(\n enrichedNodes: ReturnType<typeof enrichNodes>,\n nodeId: number,\n graphFilterStore: GraphExplorationDeps[\"graphFilter\"],\n): void {\n const addedNode = enrichedNodes[0];\n if (!addedNode) return;\n\n const { nodeLabelFilters: currentFilters } = graphFilterStore.getState();\n const nodeLabel = addedNode.label_;\n\n if (currentFilters.length > 0 && !currentFilters.includes(nodeLabel)) {\n devLog(\"[GraphExploration] Adding node label to active filters\", {\n nodeId,\n nodeLabel,\n currentFilters,\n });\n graphFilterStore\n .getState()\n .setNodeLabelFilters([...currentFilters, nodeLabel]);\n }\n}\n\n// ---------------------------------------------------------------------------\n\n/**\n * Factory function to create a new GraphExploration store instance.\n * Used by workspace system to create isolated store instances per workspace.\n *\n * @param deps - Store and service dependencies (graphData, selection, graphFocus, graphFilter, expandNode, getNodes)\n */\nexport function createGraphExplorationStore(deps: GraphExplorationDeps) {\n const stores = deps;\n\n return create<GraphExplorationStore>()((set, get) => ({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n hiddenElementIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n\n setFocusMode: (nodeIds) => {\n devLog(\"[GraphExploration] setFocusMode\", {\n nodeIds,\n count: nodeIds.length,\n });\n\n set({\n focusedNodeIds: new Set(nodeIds),\n isFocusMode: true,\n });\n },\n\n setFocusModeWithNeighborhood: (nodeId) => {\n // Get all edges from GraphData store\n const edges = stores.graphData.getState().edges;\n\n // Find all nodes connected to this node via edges\n const connectedNodeIds = new Set<string>();\n const nodeIdStr = String(nodeId);\n\n for (const edge of edges) {\n const sourceId = String(edge.start_id_);\n const targetId = String(edge.end_id_);\n\n // If this edge connects to our node, add the other end\n if (sourceId === nodeIdStr) {\n connectedNodeIds.add(targetId);\n } else if (targetId === nodeIdStr) {\n connectedNodeIds.add(sourceId);\n }\n }\n\n // Include the clicked node itself plus all connected nodes\n const focusNodeIds = [nodeIdStr, ...Array.from(connectedNodeIds)];\n\n devLog(\"[GraphExploration] setFocusModeWithNeighborhood\", {\n nodeId: nodeIdStr,\n connectedNodes: connectedNodeIds.size,\n totalFocused: focusNodeIds.length,\n });\n\n set({\n focusedNodeIds: new Set(focusNodeIds),\n isFocusMode: true,\n });\n },\n\n clearFocusMode: () => {\n devLog(\"[GraphExploration] clearFocusMode\");\n\n set({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n });\n },\n\n hideElements: (elementIds) => {\n const current = get().hiddenElementIds;\n const updated = new Set(current);\n\n elementIds.forEach((id) => updated.add(id));\n\n devLog(\"[GraphExploration] hideElements\", {\n newIds: elementIds,\n totalHidden: updated.size,\n });\n\n set({ hiddenElementIds: updated });\n },\n\n showElements: (elementIds) => {\n const current = get().hiddenElementIds;\n const updated = new Set(current);\n\n elementIds.forEach((id) => updated.delete(id));\n\n devLog(\"[GraphExploration] showElements\", {\n restoredIds: elementIds,\n remainingHidden: updated.size,\n });\n\n set({ hiddenElementIds: updated });\n },\n\n hideNodeIncoming: (nodeId) => {\n devLog(\"[GraphExploration] hideNodeIncoming - hiding predecessors\", {\n nodeId,\n });\n\n const { edges } = stores.graphData.getState();\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n nodeId,\n \"in\",\n edges,\n false,\n );\n\n devLog(\"[GraphExploration] hideNodeIncoming - traversal complete\", {\n nodeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) {\n get().hideElements(allElementsToHide);\n } else {\n devLog(\"[GraphExploration] hideNodeIncoming - no predecessors found\");\n }\n },\n\n hideNodeOutgoing: (nodeId) => {\n devLog(\"[GraphExploration] hideNodeOutgoing - hiding successors\", {\n nodeId,\n });\n\n const { edges } = stores.graphData.getState();\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n nodeId,\n \"out\",\n edges,\n false,\n );\n\n devLog(\"[GraphExploration] hideNodeOutgoing - traversal complete\", {\n nodeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) {\n get().hideElements(allElementsToHide);\n } else {\n devLog(\"[GraphExploration] hideNodeOutgoing - no successors found\");\n }\n },\n\n hideEdgeForwardPath: (edgeId: string) => {\n devLog(\n \"[GraphExploration] hideEdgeForwardPath - hiding edge + target + downstream\",\n { edgeId },\n );\n\n const { edges } = stores.graphData.getState();\n const edge = edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] hideEdgeForwardPath - edge not found\", {\n edgeId,\n });\n return;\n }\n\n const targetNodeId = String(edge.end_id_);\n\n // Hide the clicked edge first, then target and all downstream nodes/edges\n get().hideElements([edgeId]);\n\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n targetNodeId,\n \"out\",\n edges,\n true,\n );\n\n devLog(\"[GraphExploration] hideEdgeForwardPath - traversal complete\", {\n edgeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) get().hideElements(allElementsToHide);\n },\n\n hideEdgeReversePath: (edgeId: string) => {\n devLog(\n \"[GraphExploration] hideEdgeReversePath - hiding edge + source + upstream\",\n { edgeId },\n );\n\n const { edges } = stores.graphData.getState();\n const edge = edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] hideEdgeReversePath - edge not found\", {\n edgeId,\n });\n return;\n }\n\n const sourceNodeId = String(edge.start_id_);\n\n // Hide the clicked edge first, then source and all upstream nodes/edges\n get().hideElements([edgeId]);\n\n const { nodes: nodesToHide, edges: edgesToHide } = collectReachable(\n sourceNodeId,\n \"in\",\n edges,\n true,\n );\n\n devLog(\"[GraphExploration] hideEdgeReversePath - traversal complete\", {\n edgeId,\n nodesToHide: nodesToHide.size,\n edgesToHide: edgesToHide.size,\n });\n\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) get().hideElements(allElementsToHide);\n },\n\n focusOnEdgeType: (edgeId: string) => {\n devLog(\n \"[GraphExploration] focusOnEdgeType - show only edges of this type and connected nodes\",\n { edgeId },\n );\n\n const graphData = stores.graphData.getState();\n\n // Find the edge to get its type (label)\n const edge = graphData.edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] focusOnEdgeType - edge not found\", {\n edgeId,\n });\n return;\n }\n\n const edgeLabel = edge.label_;\n devLog(\"[GraphExploration] focusOnEdgeType - filtering by label\", {\n edgeId,\n edgeLabel,\n });\n\n // Find all edges of this type\n const edgesOfType = graphData.edges.filter((e) => e.label_ === edgeLabel);\n\n // Collect node IDs connected by edges of this type\n const connectedNodeIds = new Set<string>();\n const visibleEdgeIds = new Set<string>();\n\n for (const e of edgesOfType) {\n connectedNodeIds.add(String(e.start_id_));\n connectedNodeIds.add(String(e.end_id_));\n visibleEdgeIds.add(String(e.id_));\n }\n\n // Determine what to hide: nodes not connected, edges not of this type\n const nodesToHide: string[] = [];\n const edgesToHide: string[] = [];\n\n for (const node of graphData.nodes) {\n const nodeId = String(node.id_);\n if (!connectedNodeIds.has(nodeId)) {\n nodesToHide.push(nodeId);\n }\n }\n\n for (const e of graphData.edges) {\n const eId = String(e.id_);\n if (!visibleEdgeIds.has(eId)) {\n edgesToHide.push(eId);\n }\n }\n\n devLog(\"[GraphExploration] focusOnEdgeType - hiding elements\", {\n edgeLabel,\n visibleEdges: visibleEdgeIds.size,\n visibleNodes: connectedNodeIds.size,\n hidingNodes: nodesToHide.length,\n hidingEdges: edgesToHide.length,\n });\n\n // Hide all non-matching elements\n const allElementsToHide = [...nodesToHide, ...edgesToHide];\n if (allElementsToHide.length > 0) {\n get().hideElements(allElementsToHide);\n }\n },\n\n focusEdge: (edgeId: string) => {\n devLog(\n \"[GraphExploration] focusEdge - unified focus with auto-direction detection\",\n { edgeId },\n );\n\n const graphData = stores.graphData.getState();\n const selection = stores.selection.getState();\n\n // Find the edge to get its type and endpoints\n const edge = graphData.edges.find((e) => String(e.id_) === edgeId);\n\n if (!edge) {\n devLog(\"[GraphExploration] focusEdge - edge not found\", { edgeId });\n return;\n }\n\n const endpoints: EdgeEndpoints = {\n edgeLabel: edge.label_,\n startNodeId: String(edge.start_id_),\n endNodeId: String(edge.end_id_),\n };\n\n const { direction, referenceNodeId } = determineEdgeDirection(\n endpoints,\n selection.selectedNodeIds,\n );\n\n devLog(\"[GraphExploration] focusEdge - determined direction\", {\n edgeId,\n edgeLabel: endpoints.edgeLabel,\n direction,\n referenceNodeId,\n selectionMode:\n selection.selectedNodeIds.length === 1\n ? \"single-node\"\n : \"traditional\",\n });\n\n const focusNodeIds = buildFocusSet(\n referenceNodeId,\n direction,\n endpoints.edgeLabel,\n graphData.edges,\n );\n\n devLog(\"[GraphExploration] focusEdge - found nodes\", {\n edgeLabel: endpoints.edgeLabel,\n direction,\n referenceNodeId,\n totalNodes: focusNodeIds.size,\n });\n\n // Set focus mode with all found nodes\n set({\n focusedNodeIds: focusNodeIds,\n isFocusMode: true,\n });\n },\n\n resetView: () => {\n devLog(\"[GraphExploration] resetView - clearing all exploration state\");\n\n set({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n hiddenElementIds: new Set<string>(),\n // Note: We keep expandedNodeIds - those nodes are still in the data\n });\n },\n\n resetForNewQuery: () => {\n devLog(\n \"[GraphExploration] resetForNewQuery - clearing ALL exploration state for new query\",\n );\n\n set({\n focusedNodeIds: new Set<string>(),\n isFocusMode: false,\n hiddenElementIds: new Set<string>(),\n expandedNodeIds: new Set<string>(),\n });\n },\n\n markNodeExpanded: (nodeId) => {\n const current = get().expandedNodeIds;\n const updated = new Set(current);\n updated.add(nodeId);\n\n devLog(\"[GraphExploration] markNodeExpanded\", { nodeId });\n\n set({ expandedNodeIds: updated });\n },\n\n isNodeExpanded: (nodeId) => {\n return get().expandedNodeIds.has(nodeId);\n },\n\n expandNode: async (nodeId) => {\n devLog(\"[GraphExploration] expandNode\", { nodeId });\n\n try {\n // Fetch connected nodes and edges via injected backend provider\n const result = await stores.expandNode(Number(nodeId));\n\n devLog(\"[GraphExploration] Expansion API result\", {\n nodeId,\n newNodes: result.nodes.length,\n newEdges: result.edges.length,\n });\n\n // If no new nodes/edges found, log and return\n if (result.nodes.length === 0 && result.edges.length === 0) {\n devLog(\"[GraphExploration] No connected nodes found\", { nodeId });\n return;\n }\n\n // Get existing nodes to build consistent color palette\n const existingNodes = stores.graphData.getState().nodes;\n const colorPalette = buildColorPaletteFromNodes([\n ...existingNodes,\n ...result.nodes,\n ]);\n\n // Enrich the new nodes and edges with visual properties\n const enrichedNodes = enrichNodes(\n result.nodes,\n colorPalette,\n stores.getLabelDisplayMap?.(),\n );\n const enrichedEdges = enrichEdges(result.edges);\n\n // Merge into GraphData store (handles deduplication)\n stores.graphData\n .getState()\n .mergeExpandedData(enrichedNodes, enrichedEdges);\n\n // Ensure all new node labels are included in active filters\n // This prevents expanded nodes from being immediately filtered out\n const graphFilterState = stores.graphFilter.getState();\n const currentFilters = graphFilterState.nodeLabelFilters;\n\n // Only modify filters if they're actively filtering (not showing all)\n if (currentFilters.length > 0 && enrichedNodes.length > 0) {\n const newLabels = new Set(enrichedNodes.map((n) => n.label_));\n const labelsToAdd = Array.from(newLabels).filter(\n (label) => !currentFilters.includes(label),\n );\n\n if (labelsToAdd.length > 0) {\n devLog(\n \"[GraphExploration] Adding expanded node labels to active filters\",\n {\n nodeId,\n labelsToAdd,\n currentFilters,\n },\n );\n stores.graphFilter\n .getState()\n .setNodeLabelFilters([...currentFilters, ...labelsToAdd]);\n }\n }\n\n // Mark node as expanded for UI feedback\n get().markNodeExpanded(nodeId);\n\n // If in focus mode, add the new nodes to the focused set so they become visible\n const currentState = get();\n if (currentState.isFocusMode) {\n const newFocusedIds = new Set(currentState.focusedNodeIds);\n for (const node of enrichedNodes) {\n newFocusedIds.add(String(node.id_));\n }\n\n devLog(\"[GraphExploration] Adding expanded nodes to focus set\", {\n nodeId,\n previousFocusCount: currentState.focusedNodeIds.size,\n addedToFocus: enrichedNodes.length,\n newFocusCount: newFocusedIds.size,\n });\n\n set({ focusedNodeIds: newFocusedIds });\n }\n\n devLog(\"[GraphExploration] Expansion complete\", {\n nodeId,\n addedNodes: enrichedNodes.length,\n addedEdges: enrichedEdges.length,\n });\n } catch (error) {\n devLog(\"[GraphExploration] Expansion failed\", { nodeId, error });\n throw error; // Re-throw so UI can handle it\n }\n },\n\n addNodeById: async (nodeId, autoFocus = false) => {\n const nodeIdStr = String(nodeId);\n devLog(\"[GraphExploration] addNodeById\", { nodeId, autoFocus });\n\n try {\n // Check if node already exists in the graph\n const existingNodes = stores.graphData.getState().nodes;\n\n if (\n handleExistingNode(\n nodeId,\n nodeIdStr,\n existingNodes,\n autoFocus,\n stores.graphFocus,\n )\n ) {\n return;\n }\n\n // Node doesn't exist -> fetch, enrich, and merge into store\n const enrichedNodes = await fetchAndEnrichNode(\n nodeId,\n existingNodes,\n stores,\n );\n\n // Ensure the node's label is included in active filters\n ensureNodeLabelInFilters(enrichedNodes, nodeId, stores.graphFilter);\n\n // Optionally focus the newly added node\n // NOTE: For clipboard additions, autoFocus should be false to avoid override system\n // conflicts. The node will appear in the graph naturally and can be selected manually.\n if (autoFocus) {\n devLog(\"[GraphExploration] Requesting focus for newly added node\", {\n nodeId,\n });\n stores.graphFocus.getState().requestFocus(nodeIdStr, \"node\", false);\n } else {\n devLog(\"[GraphExploration] Skipping focus for newly added node\", {\n nodeId,\n });\n }\n\n // If in focus mode, add the new node to the focused set so it becomes visible\n const currentState = get();\n if (currentState.isFocusMode) {\n const newFocusedIds = new Set(currentState.focusedNodeIds);\n newFocusedIds.add(nodeIdStr);\n\n devLog(\"[GraphExploration] Adding node to focus set\", {\n nodeId,\n previousFocusCount: currentState.focusedNodeIds.size,\n newFocusCount: newFocusedIds.size,\n });\n\n set({ focusedNodeIds: newFocusedIds });\n }\n\n devLog(\"[GraphExploration] addNodeById complete\", {\n nodeId,\n addedNodes: enrichedNodes.length,\n autoFocus,\n });\n } catch (error) {\n devLog(\"[GraphExploration] addNodeById failed\", { nodeId, error });\n throw error; // Re-throw so UI can handle it\n }\n },\n }));\n}\n\n// No global singleton in the package — consumers wire their own deps via createGraphExplorationStore().\n","/**\n * GraphFocus Store\n *\n * Manages graph element focus/zoom actions across different renderers (Cytoscape, Reagraph).\n * Provides a decoupled way for tools to request focus on specific elements without\n * needing direct access to the renderer instance.\n *\n * Pattern: tools dispatch focus actions → store holds state → renderers subscribe and react\n */\n\nimport { create } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\n/** Descriptor for a pending focus action */\nexport interface GraphFocusAction {\n /** ID of the node or edge to focus on */\n elementId: string;\n\n /** Type of element */\n elementType: \"node\" | \"edge\";\n\n /** Action to perform: focus only or focus and select */\n action: \"focus\" | \"focus-and-select\";\n\n /** Timestamp ensures uniqueness — triggers subscription even for same element */\n timestamp: number;\n}\n\nexport interface GraphFocusStore {\n /** Current focus action (null when no action is pending) */\n focusAction: GraphFocusAction | null;\n\n /** Element IDs to show despite active filters (temporary override) */\n overrideElementIds: Set<string>;\n\n /**\n * Request focus on a graph element.\n * @param elementId - ID of the node or edge\n * @param elementType - 'node' or 'edge'\n * @param shouldSelect - Also select the element after focusing\n */\n requestFocus: (\n elementId: string,\n elementType: \"node\" | \"edge\",\n shouldSelect: boolean,\n ) => void;\n\n /** Clear the current focus action and all overrides */\n clear: () => void;\n\n /** Clear filter overrides only (keeps the current focus action) */\n clearOverrides: () => void;\n}\n\nfunction buildStore() {\n return (\n set: (partial: Partial<GraphFocusStore>) => void,\n get: () => GraphFocusStore,\n ) => ({\n focusAction: null,\n overrideElementIds: new Set<string>(),\n\n requestFocus: (\n elementId: string,\n elementType: \"node\" | \"edge\",\n shouldSelect: boolean,\n ) => {\n const action: GraphFocusAction = {\n elementId,\n elementType,\n action: shouldSelect ? \"focus-and-select\" : \"focus\",\n timestamp: Date.now(),\n };\n devLog(\"[GraphFocusStore] requestFocus\", {\n elementId,\n elementType,\n action: action.action,\n });\n // overrideElementIds are set by the renderer after it determines whether\n // the element is already visible. Setting them here would cause unnecessary redraws.\n set({ focusAction: action });\n },\n\n clear: () => {\n const prev = get().focusAction;\n if (prev) {\n devLog(\"[GraphFocusStore] clear\", { prevElementId: prev.elementId });\n }\n set({ focusAction: null, overrideElementIds: new Set<string>() });\n },\n\n clearOverrides: () => {\n devLog(\"[GraphFocusStore] clearOverrides\");\n set({ overrideElementIds: new Set<string>() });\n },\n });\n}\n\n/** Create an isolated GraphFocus store instance (use for multi-workspace scenarios). */\nexport function createGraphFocusStore() {\n return create<GraphFocusStore>()(buildStore());\n}\n\n/** Global singleton — sufficient for single-workspace applications. */\nconst useGraphFocus = createGraphFocusStore();\nexport default useGraphFocus;\n","import { create } from \"zustand\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\nexport type ActionPanelState = \"hidden\" | \"visible\";\n\nexport interface ActionPanelStore {\n state: ActionPanelState;\n setState: (state: ActionPanelState) => void;\n hide: () => void;\n show: () => void;\n isHidden: () => boolean;\n}\n\nfunction buildStore() {\n return (\n set: (partial: Partial<ActionPanelStore>) => void,\n get: () => ActionPanelStore,\n ) => ({\n state: \"visible\" as ActionPanelState,\n\n setState: (state: ActionPanelState) => {\n devLog(\"[ActionPanelStore] setState\", { state });\n set({ state });\n },\n\n hide: () => {\n devLog(\"[ActionPanelStore] hide\");\n set({ state: \"hidden\" });\n },\n\n show: () => {\n devLog(\"[ActionPanelStore] show\");\n set({ state: \"visible\" });\n },\n\n isHidden: () => get().state === \"hidden\",\n });\n}\n\n/** Create an isolated ActionPanel store instance. */\nexport function createActionPanelStore() {\n return create<ActionPanelStore>()(buildStore());\n}\n\n/** Global singleton — sufficient for single-workspace applications. */\nexport const useActionPanelStore = createActionPanelStore();\n","/**\n * Graph Workspace Store Hooks\n *\n * Provides access to workspace-specific graph store instances via React context.\n * Consumers wrap their graph UI with <GraphStoresProvider> and supply the store bundle.\n *\n * This replaces the explorer's WorkspaceManager-based hooks with a simple\n * context-based approach that works in any host application.\n */\n\nimport { createContext, useContext } from \"react\";\nimport type { StoreApi, UseBoundStore } from \"zustand\";\nimport type { WorkspaceStores } from \"../stores/types\";\nimport type { GraphFilterStore } from \"../stores/GraphFilter\";\nimport type { GraphDataStore } from \"../stores/GraphData\";\nimport type { GraphExplorationStore } from \"../stores/GraphExploration\";\nimport type { SelectionStore } from \"../stores/Selection\";\n\n/**\n * Re-export WorkspaceStores as the canonical bundle type.\n * Components and consumers use this to provide stores via context.\n */\nexport type { WorkspaceStores as GraphStoreBundle };\n\n/**\n * Context for providing graph stores to visualization components.\n * Must be set by the host application (e.g., explorer, Atlas).\n */\nexport const GraphStoresContext = createContext<WorkspaceStores | null>(null);\n\nfunction useGraphStores(): WorkspaceStores {\n const ctx = useContext(GraphStoresContext);\n if (!ctx) {\n throw new Error(\n \"useGraphStores must be used within a GraphStoresProvider. \" +\n \"Wrap your graph UI with <GraphStoresContext.Provider value={...}>.\",\n );\n }\n return ctx;\n}\n\n/** Get GraphFilter store from context. */\nexport function useWorkspaceGraphFilter(): UseBoundStore<\n StoreApi<GraphFilterStore>\n> {\n return useGraphStores().graphFilter;\n}\n\n/** Get GraphData store from context. */\nexport function useWorkspaceGraphData(): UseBoundStore<\n StoreApi<GraphDataStore>\n> {\n return useGraphStores().graphData;\n}\n\n/** Get GraphExploration store from context. */\nexport function useWorkspaceGraphExploration(): UseBoundStore<\n StoreApi<GraphExplorationStore>\n> {\n return useGraphStores().graphExploration;\n}\n\n/** Get Selection store from context. */\nexport function useWorkspaceSelection(): UseBoundStore<\n StoreApi<SelectionStore>\n> {\n return useGraphStores().selection;\n}\n","import { useMemo, useEffect } from \"react\";\nimport {\n useWorkspaceGraphFilter,\n useWorkspaceGraphData,\n useWorkspaceGraphExploration,\n} from \"./useWorkspaceStores\";\nimport useGraphFocus from \"../stores/GraphFocus\";\nimport { buildColorPalette, ColorPalette } from \"../graph/enrichment\";\nimport { type GraphStatistics } from \"../interfaces\";\nimport {\n normalizeGraph,\n EMPTY_NORMALIZED,\n NormalizedGraph,\n} from \"../graph/normalize\";\nimport { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\nimport { devLog } from \"@petrarca/sonnet-core\";\n\n/**\n * Result type for useLiveGraphData hook.\n *\n * Returns enriched VisualGraph data with color palette and statistics.\n */\nexport interface LiveGraphDataResult {\n nodes: VisualGraphNode[];\n edges: VisualGraphEdge[];\n stats: GraphStatistics | undefined;\n /** Node label counts after hidden/focus filters, before label-checkbox filters */\n labelCounts: Record<string, number>;\n /** Edge label counts after node visibility filters, before edge-label-checkbox filters */\n edgeLabelCounts: Record<string, number>;\n /** Value rows for non-graph (tabular) query results */\n values: string[][];\n colorPalette: ColorPalette;\n /** Filtered graph for visualization (respects all active filters) */\n normalized: NormalizedGraph;\n /** Unfiltered graph containing all nodes/edges from the last query */\n baseNormalized: NormalizedGraph;\n}\n\nexport function useLiveGraphData() {\n // Get workspace-scoped stores (uses \"default\" workspace from context)\n const useGraphFilter = useWorkspaceGraphFilter();\n const useGraphData = useWorkspaceGraphData();\n const useGraphExploration = useWorkspaceGraphExploration();\n\n const lastDataChangeTime = useGraphFilter((s) => s.lastDataChangeTime);\n const filterLabels = useGraphFilter((s) => s.nodeLabelFilters);\n const allLabelsDisabled = useGraphFilter((s) => s.allLabelsDisabled);\n const edgeFilterLabels = useGraphFilter((s) => s.edgeLabelFilters);\n const allEdgeLabelsDisabled = useGraphFilter((s) => s.allEdgeLabelsDisabled);\n\n // Subscribe to focus overrides for reactive filtering\n const overrideElementIds = useGraphFocus((s) => s.overrideElementIds);\n\n // Subscribe to exploration state for focus/hidden filtering\n const isFocusMode = useGraphExploration((s) => s.isFocusMode);\n const focusedNodeIds = useGraphExploration((s) => s.focusedNodeIds);\n const hiddenElementIds = useGraphExploration((s) => s.hiddenElementIds);\n\n // Subscribe to GraphData store for enriched data\n const baseNodes = useGraphData((s) => s.nodes);\n const baseEdges = useGraphData((s) => s.edges);\n const stats = useGraphData((s) => s.stats);\n const values = useGraphData((s) => s.values);\n const isValueSet = useGraphData((s) => s.isValueSet);\n\n devLog(\"[useLiveGraphData] Store data\", {\n baseNodes: baseNodes.length,\n baseEdges: baseEdges.length,\n isFocusMode,\n focusedCount: focusedNodeIds.size,\n hiddenCount: hiddenElementIds.size,\n });\n\n // Clear overrides when query is executed (new data = old overrides are stale)\n useEffect(() => {\n useGraphFocus.getState().clearOverrides();\n }, [lastDataChangeTime]);\n\n // Compute ALL label counts from baseNodes for color palette\n // This includes all nodes (query + expanded), used only for color palette generation\n const allLabelCounts = useMemo(() => {\n if (isValueSet) return {} as Record<string, number>;\n const counts: Record<string, number> = {};\n for (const n of baseNodes) {\n const l = n?.label_;\n if (l) counts[l] = (counts[l] || 0) + 1;\n }\n return counts;\n }, [baseNodes, isValueSet]);\n\n // Stable color palette derived from all labels (not filtered)\n const colorPalette = useMemo(() => {\n if (isValueSet) return {} as ColorPalette;\n return buildColorPalette(allLabelCounts);\n }, [allLabelCounts, isValueSet]);\n\n // Compute \"available\" nodes for label counting (BEFORE label filters, AFTER hidden/focus)\n // This represents nodes that could be shown if their label is enabled\n const availableNodes = useMemo(() => {\n let available = baseNodes;\n\n // Apply focus mode filter\n if (isFocusMode && focusedNodeIds.size > 0) {\n available = available.filter((n: VisualGraphNode) =>\n focusedNodeIds.has(String(n.id_)),\n );\n }\n\n // Apply hidden elements filter\n if (hiddenElementIds.size > 0) {\n available = available.filter(\n (n: VisualGraphNode) => !hiddenElementIds.has(String(n.id_)),\n );\n }\n\n return available;\n }, [baseNodes, isFocusMode, focusedNodeIds, hiddenElementIds]);\n\n // Compute \"available\" edges for label counting (BEFORE edge label filters, AFTER node filters/hidden)\n const availableEdges = useMemo(() => {\n // First, determine which nodes are available\n const availableNodeIds = new Set(\n availableNodes.map((n: VisualGraphNode) => String(n.id_)),\n );\n\n // Edges are available if both their endpoints are available nodes\n let available = baseEdges.filter(\n (e: VisualGraphEdge) =>\n availableNodeIds.has(String(e.start_id_)) &&\n availableNodeIds.has(String(e.end_id_)),\n );\n\n // Apply hidden elements filter for edges\n if (hiddenElementIds.size > 0) {\n available = available.filter(\n (e: VisualGraphEdge) => !hiddenElementIds.has(String(e.id_)),\n );\n }\n\n return available;\n }, [baseEdges, availableNodes, hiddenElementIds]);\n\n // Label counts for badges - shows \"available\" nodes (respects hidden/focus, ignores label filters)\n const labelCounts = useMemo(() => {\n if (isValueSet) return {} as Record<string, number>;\n const counts: Record<string, number> = {};\n for (const n of availableNodes) {\n const l = n?.label_;\n if (l) counts[l] = (counts[l] || 0) + 1;\n }\n return counts;\n }, [availableNodes, isValueSet]);\n\n // Edge label counts for badges - shows \"available\" edges (respects node visibility/hidden, ignores edge label filters)\n const edgeLabelCounts = useMemo(() => {\n if (isValueSet) return {} as Record<string, number>;\n const counts: Record<string, number> = {};\n for (const e of availableEdges) {\n const l = e?.label_;\n if (l) counts[l] = (counts[l] || 0) + 1;\n }\n return counts;\n }, [availableEdges, isValueSet]);\n\n const filteredNodes = useMemo(() => {\n let filtered: VisualGraphNode[];\n\n // Step 1: Apply label filters (from GraphFilter store)\n if (allLabelsDisabled) {\n filtered = [];\n } else if (filterLabels && filterLabels.length > 0) {\n const setLabels = new Set(filterLabels);\n filtered = baseNodes.filter((n: VisualGraphNode) =>\n setLabels.has(n.label_),\n );\n } else {\n filtered = baseNodes;\n }\n\n // Step 2: Apply focus mode filter (from GraphExploration store)\n if (isFocusMode && focusedNodeIds.size > 0) {\n devLog(\"[useLiveGraphData] Applying focus mode filter\", {\n focusedCount: focusedNodeIds.size,\n beforeFilter: filtered.length,\n });\n filtered = filtered.filter((n) => focusedNodeIds.has(String(n.id_)));\n devLog(\"[useLiveGraphData] After focus mode filter\", {\n afterFilter: filtered.length,\n });\n }\n\n // Step 3: Apply hidden elements filter (from GraphExploration store)\n if (hiddenElementIds.size > 0) {\n devLog(\"[useLiveGraphData] Applying hidden elements filter\", {\n hiddenCount: hiddenElementIds.size,\n beforeFilter: filtered.length,\n });\n filtered = filtered.filter((n) => !hiddenElementIds.has(String(n.id_)));\n devLog(\"[useLiveGraphData] After hidden elements filter\", {\n afterFilter: filtered.length,\n });\n }\n\n // Step 4: Apply focus overrides (from GraphFocus store)\n // Must happen AFTER all other filters so overrides bypass them\n if (overrideElementIds.size > 0) {\n const filteredIds = new Set(\n filtered.map((n: VisualGraphNode) => String(n.id_)),\n );\n const overrideNodes = baseNodes.filter(\n (n: VisualGraphNode) =>\n overrideElementIds.has(String(n.id_)) &&\n !filteredIds.has(String(n.id_)),\n );\n if (overrideNodes.length > 0) {\n devLog(\"[useLiveGraphData] Adding override nodes\", {\n overrideCount: overrideNodes.length,\n overrideIds: overrideNodes.map((n: VisualGraphNode) => n.id_),\n totalAfterOverride: filtered.length + overrideNodes.length,\n });\n filtered = [...filtered, ...overrideNodes];\n }\n }\n\n return filtered;\n }, [\n baseNodes,\n filterLabels,\n allLabelsDisabled,\n isFocusMode,\n focusedNodeIds,\n hiddenElementIds,\n overrideElementIds,\n ]);\n\n const filteredEdges = useMemo(() => {\n let edgesStage: VisualGraphEdge[];\n\n // Step 1: Apply label filters (disable all labels or filter by edge labels)\n if (allLabelsDisabled || allEdgeLabelsDisabled) {\n edgesStage = [];\n } else {\n // Filter by node labels first (already applied via filteredNodes). If no node label filters, we consider all nodes.\n const nodeIds = new Set(\n filteredNodes.map((n: VisualGraphNode) => String(n.id_)),\n );\n edgesStage = baseEdges.filter(\n (e: VisualGraphEdge) =>\n nodeIds.has(String(e.start_id_)) && nodeIds.has(String(e.end_id_)),\n );\n\n if (edgeFilterLabels && edgeFilterLabels.length > 0) {\n const setEdge = new Set(edgeFilterLabels);\n edgesStage = edgesStage.filter((e) => setEdge.has(e.label_));\n }\n }\n\n // Step 2: Apply hidden elements filter (from GraphExploration store)\n if (hiddenElementIds.size > 0) {\n devLog(\"[useLiveGraphData] Applying hidden elements filter to edges\", {\n hiddenCount: hiddenElementIds.size,\n beforeFilter: edgesStage.length,\n });\n edgesStage = edgesStage.filter(\n (e) => !hiddenElementIds.has(String(e.id_)),\n );\n devLog(\"[useLiveGraphData] After hidden elements filter (edges)\", {\n afterFilter: edgesStage.length,\n });\n }\n\n // Step 3: Apply focus overrides (from GraphFocus store)\n // Must happen AFTER the disabled checks so overrides bypass them\n if (overrideElementIds.size > 0) {\n const filteredIds = new Set(\n edgesStage.map((e: VisualGraphEdge) => String(e.id_)),\n );\n const overrideEdges = baseEdges.filter(\n (e: VisualGraphEdge) =>\n overrideElementIds.has(String(e.id_)) &&\n !filteredIds.has(String(e.id_)),\n );\n if (overrideEdges.length > 0) {\n devLog(\"[useLiveGraphData] Adding override edges\", {\n overrideCount: overrideEdges.length,\n overrideIds: overrideEdges.map((e: VisualGraphEdge) => e.id_),\n totalAfterOverride: edgesStage.length + overrideEdges.length,\n });\n edgesStage = [...edgesStage, ...overrideEdges];\n }\n }\n\n return edgesStage;\n }, [\n baseEdges,\n filteredNodes,\n allLabelsDisabled,\n allEdgeLabelsDisabled,\n edgeFilterLabels,\n hiddenElementIds,\n overrideElementIds,\n ]);\n\n // Base normalized graph - contains ALL nodes and edges from query (unfiltered)\n // Useful for tools that need to search/query the complete dataset\n const baseNormalized = useMemo(() => {\n if (isValueSet) return EMPTY_NORMALIZED;\n return normalizeGraph(baseNodes, baseEdges);\n }, [isValueSet, baseNodes, baseEdges]);\n\n // Filtered normalized graph - contains only visible nodes and edges (respects label filters)\n // Used for graph visualization\n const normalized = useMemo(() => {\n if (isValueSet) return EMPTY_NORMALIZED;\n return normalizeGraph(filteredNodes, filteredEdges);\n }, [isValueSet, filteredNodes, filteredEdges]);\n\n // Derive arrays FROM normalized (Phase C step 1)\n const nodes = useMemo(\n () => normalized.nodeIds.map((id) => normalized.nodesById[id]),\n [normalized],\n );\n const edges = useMemo(\n () => normalized.edgeIds.map((id) => normalized.edgesById[id]),\n [normalized],\n );\n\n // Update stats to show \"available\" counts (respects hidden/focus, not label filters)\n // This makes the star badge show realistic totals\n const adjustedStats = useMemo(() => {\n if (!stats) return undefined;\n return {\n ...stats,\n nodes: availableNodes.length,\n edges: availableEdges.length,\n };\n }, [stats, availableNodes.length, availableEdges.length]);\n\n // Clear focus overrides when filters change (user explicitly changed filters, so overrides should reset)\n useEffect(() => {\n const { clearOverrides } = useGraphFocus.getState();\n clearOverrides();\n }, [\n filterLabels,\n allLabelsDisabled,\n edgeFilterLabels,\n allEdgeLabelsDisabled,\n ]);\n\n return {\n nodes,\n edges,\n stats: adjustedStats,\n labelCounts,\n edgeLabelCounts,\n values,\n colorPalette,\n normalized,\n baseNormalized,\n };\n}\n","/**\n * ReGraph Visualization Adapter\n *\n * Converts VisualGraph domain model to reagraph-specific format.\n * Isolates the reagraph dependency to the ReGraph renderer only.\n *\n * Data flow:\n * GraphData store → VisualGraph (enriched) → ReagraphNode/Edge (visualization format)\n */\n\nimport { useMemo } from \"react\";\nimport { GraphNode as ReagraphNode, GraphEdge as ReagraphEdge } from \"reagraph\";\nimport { useLiveGraphData } from \"./useLiveGraphData\";\nimport type { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\n\n/**\n * Converts a VisualGraphNode to reagraph's node format.\n * Exported for use in tests and custom renderers.\n */\nexport function toReagraphNode(visualNode: VisualGraphNode): ReagraphNode {\n return {\n id: String(visualNode.id_),\n label: visualNode.visual.displayName,\n fill: visualNode.visual.color,\n size: visualNode.visual.size,\n icon: visualNode.visual.icon,\n // Embed full visual node so event handlers can access all domain data\n data: visualNode,\n } as ReagraphNode;\n}\n\n/**\n * Converts a VisualGraphEdge to reagraph's edge format.\n * Exported for use in tests and custom renderers.\n */\nexport function toReagraphEdge(visualEdge: VisualGraphEdge): ReagraphEdge {\n return {\n id: String(visualEdge.id_),\n source: String(visualEdge.start_id_),\n target: String(visualEdge.end_id_),\n label: visualEdge.label_,\n fill: visualEdge.visual.color,\n size: visualEdge.visual.size ?? 3,\n dashed: visualEdge.visual.dashed,\n // Embed full visual edge so event handlers can access all domain data\n data: visualEdge,\n } as ReagraphEdge;\n}\n\n/**\n * Returns live graph data converted to reagraph's node/edge format.\n * Consumes the workspace GraphData + filter stores via useLiveGraphData.\n */\nexport function useReagraphData() {\n const live = useLiveGraphData();\n\n const nodes = useMemo<ReagraphNode[]>(\n () => live.nodes.map(toReagraphNode),\n [live.nodes],\n );\n\n const edges = useMemo<ReagraphEdge[]>(\n () => live.edges.map(toReagraphEdge),\n [live.edges],\n );\n\n return {\n nodes,\n edges,\n stats: live.stats,\n colorPalette: live.colorPalette,\n };\n}\n","/**\n * Cytoscape Visualization Adapter\n *\n * Converts VisualGraph domain model to Cytoscape.js element format.\n * Isolates the cytoscape dependency to the Cytoscape renderer only.\n *\n * Data flow:\n * GraphData store → VisualGraph (enriched) → Cytoscape Elements (visualization format)\n */\n\nimport { useMemo } from \"react\";\nimport type cytoscape from \"cytoscape\";\ntype ElementsDefinition = cytoscape.ElementsDefinition;\nimport { useLiveGraphData } from \"./useLiveGraphData\";\nimport type { VisualGraphNode, VisualGraphEdge } from \"../models/visual-graph\";\n\n/**\n * Converts a VisualGraphNode to Cytoscape's element format.\n * Exported for use in tests and custom renderers.\n */\nexport function toCytoscapeNode(visualNode: VisualGraphNode) {\n const color = visualNode.visual.color ?? \"#4285F4\";\n const size = visualNode.visual.size ?? 40;\n\n return {\n data: {\n id: String(visualNode.id_),\n label: visualNode.visual.displayName,\n id_: visualNode.id_,\n label_: visualNode.label_,\n properties_: visualNode.properties_,\n displayName: visualNode.visual.displayName,\n color,\n size,\n icon: visualNode.visual.icon,\n // Full node reference for context menu and event handlers\n visualGraph: visualNode,\n },\n // No inline styles — stylesheet handles all styling via data mappers\n };\n}\n\n/**\n * Converts a VisualGraphEdge to Cytoscape's element format.\n * Exported for use in tests and custom renderers.\n */\nexport function toCytoscapeEdge(visualEdge: VisualGraphEdge) {\n return {\n data: {\n id: String(visualEdge.id_),\n source: String(visualEdge.start_id_),\n target: String(visualEdge.end_id_),\n label: visualEdge.label_,\n id_: visualEdge.id_,\n label_: visualEdge.label_,\n start_id_: visualEdge.start_id_,\n end_id_: visualEdge.end_id_,\n properties_: visualEdge.properties_,\n color: visualEdge.visual.color ?? \"#9E9E9E\",\n size: visualEdge.visual.size ?? 3,\n // Only set dashed when true — falsy values omitted to avoid stylesheet noise\n dashed: visualEdge.visual.dashed || undefined,\n },\n // No inline styles — stylesheet handles all styling via data mappers\n };\n}\n\n/**\n * Returns live graph data converted to Cytoscape's element format.\n * Consumes the workspace GraphData + filter stores via useLiveGraphData.\n */\nexport function useCytoscapeData() {\n const live = useLiveGraphData();\n\n const elements = useMemo<ElementsDefinition>(\n () => ({\n nodes: live.nodes.map(toCytoscapeNode),\n edges: live.edges.map(toCytoscapeEdge),\n }),\n [live.nodes, live.edges],\n );\n\n return {\n elements,\n stats: live.stats,\n colorPalette: live.colorPalette,\n };\n}\n","import { createContext, useContext } from \"react\";\n\nexport type GraphRenderer = \"reagraph\" | \"cytoscape\";\n\nexport type GraphRendererContextType = {\n renderer: GraphRenderer;\n setRenderer: (renderer: GraphRenderer) => void;\n};\n\nexport const GraphRendererContext =\n createContext<GraphRendererContextType | null>(null);\n\nexport function useGraphRenderer(): GraphRendererContextType {\n const ctx = useContext(GraphRendererContext);\n if (!ctx) {\n throw new Error(\n \"useGraphRenderer must be used within a GraphRendererProvider\",\n );\n }\n return ctx;\n}\n","import React, { useState, useCallback } from \"react\";\nimport { GraphRendererContext } from \"./useGraphRendererContext\";\nimport type { GraphRenderer } from \"./useGraphRendererContext\";\n\ntype ProviderProps = {\n children: React.ReactNode;\n /**\n * Initial renderer to use. Defaults to 'cytoscape'.\n * The host application controls which renderer is active — typically\n * driven by route state, user preference, or local storage.\n */\n defaultRenderer?: GraphRenderer;\n /**\n * Optional callback invoked when the user switches renderer via the toolbar.\n * Use this to persist the choice (e.g. URL, localStorage, zustand store).\n */\n onRendererChange?: (renderer: GraphRenderer) => void;\n};\n\nexport function GraphRendererProvider({\n children,\n defaultRenderer = \"cytoscape\",\n onRendererChange,\n}: ProviderProps): React.ReactElement {\n const [renderer, setRendererState] = useState<GraphRenderer>(defaultRenderer);\n\n const setRenderer = useCallback(\n (newRenderer: GraphRenderer) => {\n setRendererState(newRenderer);\n onRendererChange?.(newRenderer);\n },\n [onRendererChange],\n );\n\n return (\n <GraphRendererContext.Provider value={{ renderer, setRenderer }}>\n {children}\n </GraphRendererContext.Provider>\n );\n}\n","import {\n type ReactNode,\n useEffect,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport { devLog } from \"@petrarca/sonnet-core\";\nimport {\n GraphCanvas,\n GraphCanvasRef,\n GraphNode,\n GraphEdge,\n LayoutTypes,\n PathSelectionTypes,\n useSelection,\n} from \"reagraph\";\nimport { theme } from \"./theme\";\nimport { cn } from \"@petrarca/sonnet-core\";\nimport LayoutAndCameraControls from \"./LayoutAndCameraControls\";\nimport { Card } from \"@petrarca/sonnet-ui\";\nimport {\n useWorkspaceSelection,\n useWorkspaceGraphExploration,\n useWorkspaceGraphFilter,\n} from \"../../hooks/useWorkspaceStores\";\nimport NodeHoverInfo from \"./NodeHoverInfo\";\nimport { useReagraphData } from \"../../hooks/useReagraphData\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport useGraphFocus from \"../../stores/GraphFocus\";\nimport ReaContextMenu from \"./ReaContextMenu\";\nimport type {\n VisualGraphNode,\n VisualGraphEdge,\n} from \"../../models/visual-graph\";\nimport { toast } from \"sonner\";\nimport type { SelectionStore } from \"../../stores/Selection\";\n\ntype ElementType = \"node\" | \"edge\";\n\ninterface FoundElement {\n element: GraphNode | GraphEdge;\n actualElementType: ElementType;\n}\n\n/** Look up an element by ID, falling back to the other collection on type mismatch. */\nfunction findElementInGraphData(\n elementId: string,\n elementType: ElementType,\n nodes: GraphNode[],\n edges: GraphEdge[],\n): FoundElement | null {\n if (elementType === \"node\") {\n const node = nodes.find((n) => n.id === elementId);\n if (node) return { element: node, actualElementType: \"node\" };\n const edge = edges.find((e) => e.id === elementId);\n if (edge) {\n devLog(\"[ReGraph] ID mismatch: requested as node but found as edge\", {\n elementId,\n });\n return { element: edge, actualElementType: \"edge\" };\n }\n } else {\n const edge = edges.find((e) => e.id === elementId);\n if (edge) return { element: edge, actualElementType: \"edge\" };\n const node = nodes.find((n) => n.id === elementId);\n if (node) {\n devLog(\"[ReGraph] ID mismatch: requested as edge but found as node\", {\n elementId,\n });\n return { element: node, actualElementType: \"node\" };\n }\n }\n return null;\n}\n\n/** Execute a single focus action: find the element, pan to it, optionally select it. */\nfunction processFocusAction(\n focusAction: { elementId: string; elementType: ElementType; action: string },\n canvasRef: GraphCanvasRef,\n nodes: GraphNode[],\n edges: GraphEdge[],\n setSelectedNodeIds: (ids: string[]) => void,\n setSelectedEdge: (edge: VisualGraphEdge | null) => void,\n): boolean {\n const { elementId, elementType, action } = focusAction;\n const found = findElementInGraphData(elementId, elementType, nodes, edges);\n\n if (!found) {\n devLog(\"[ReGraph] Element not found in current Reagraph data\", {\n elementId,\n elementType,\n availableNodes: nodes.length,\n availableEdges: edges.length,\n nodeIds: nodes.slice(0, 5).map((n) => n.id),\n edgeIds: edges.slice(0, 5).map((e) => e.id),\n });\n return false;\n }\n\n const { element, actualElementType } = found;\n devLog(\"[ReGraph] Element found, focusing\", {\n elementId,\n elementType: actualElementType,\n });\n\n if (actualElementType === \"node\") {\n canvasRef.fitNodesInView([elementId]);\n } else {\n const edge = element as GraphEdge;\n canvasRef.fitNodesInView([edge.source, edge.target]);\n }\n\n if (action === \"focus-and-select\") {\n if (actualElementType === \"node\") {\n setSelectedNodeIds([elementId]);\n } else {\n const edgeForFocus = edges.find((e) => e.id === elementId);\n setSelectedEdge(\n edgeForFocus ? (edgeForFocus.data as VisualGraphEdge) : null,\n );\n }\n }\n\n return true;\n}\n\ninterface ReaGraphProps {\n /** Callback when a node is copied from context menu. */\n onCopyNode?: (node: VisualGraphNode) => void;\n /** Extra toolbar content (e.g. clipboard UI) injected into the toolbar. */\n extraToolbarContent?: ReactNode;\n}\n\nfunction ReaGraph({ onCopyNode, extraToolbarContent }: ReaGraphProps) {\n const isMountedRef = useRef(false);\n const { nodes, edges } = useReagraphData();\n const { normalized } = useLiveGraphData();\n\n useEffect(() => {\n devLog(\"[ReGraph] counts\", { nodes: nodes.length, edges: edges.length });\n if (nodes.length > 0) devLog(\"[ReGraph] sample node\", nodes[0]);\n if (edges.length > 0) devLog(\"[ReGraph] sample edge\", edges[0]);\n }, [nodes, edges]);\n\n const canvas = useRef<GraphCanvasRef>(null);\n const [hoveredNode, setHoveredNode] = useState<GraphNode | undefined>(\n undefined,\n );\n const [layout, setLayout] = useState<LayoutTypes>(\"forceDirected2d\");\n const [fullscreen, setFullscreen] = useState(false);\n const [pathSelectionType, setPathSelectionType] =\n useState<PathSelectionTypes>(\"direct\");\n\n // Get workspace-scoped stores\n const useGraphSelection = useWorkspaceSelection();\n const useGraphFilter = useWorkspaceGraphFilter();\n const useGraphExploration = useWorkspaceGraphExploration();\n\n // Subscribe to exploration state for toolbar visibility\n const hiddenElementIds = useGraphExploration((s) => s.hiddenElementIds);\n const isFocusMode = useGraphExploration((s) => s.isFocusMode);\n const hasHiddenElements = hiddenElementIds.size > 0;\n\n const { setSelectedNodeIds, setSelectedEdge } = useGraphSelection(\n (s: SelectionStore) => s,\n );\n\n // Get data-change timestamp to detect query re-runs\n const lastDataChangeTime = useGraphFilter((s) => s.lastDataChangeTime);\n\n // --- Selection Handling (no re-render on selection change) ---\n // Access setter functions once (stable in Zustand) to avoid subscribing component render\n const { clear: clearSelectionStore } = useGraphSelection.getState();\n\n const {\n selections,\n actives,\n onNodeClick,\n onCanvasClick,\n clearSelections,\n setSelections,\n } = useSelection({\n ref: canvas,\n nodes,\n edges,\n pathSelectionType,\n type: \"multi\",\n });\n\n // Subscribe to GraphFocus store for focus requests from tools\n useEffect(() => {\n const unsubscribe = useGraphFocus.subscribe((state) => {\n const focusAction = state.focusAction;\n if (!focusAction || !canvas.current) return;\n\n devLog(\"[ReGraph] Processing focus action\", {\n elementId: focusAction.elementId,\n elementType: focusAction.elementType,\n action: focusAction.action,\n timestamp: focusAction.timestamp,\n });\n\n const handled = processFocusAction(\n focusAction,\n canvas.current,\n nodes,\n edges,\n setSelectedNodeIds,\n setSelectedEdge,\n );\n\n if (handled) {\n useGraphFocus.setState({ focusAction: null });\n }\n // Don't clear the focus action if not handled - let it persist in case the element appears later\n });\n\n return unsubscribe;\n }, [nodes, edges, setSelectedNodeIds, setSelectedEdge]);\n\n // Mirror ReGraph behavior: clear selections when query is executed (prevents stale selections)\n // Don't clear on every node change (e.g., override additions), only on query execution\n useEffect(() => {\n if (!canvas.current) return;\n clearSelections();\n clearSelectionStore();\n }, [lastDataChangeTime, clearSelections, clearSelectionStore]);\n\n const fitToScreen = useCallback(\n (reason?: string) => {\n if (!isMountedRef.current) return;\n if (nodes.length === 0) return;\n // Two nested rAFs ensure reagraph has completed its own layout paint\n // before we call fitNodesInView. One rAF is not enough because reagraph\n // schedules its own geometry update in the first frame after data changes.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (!isMountedRef.current) return;\n const ref = canvas.current;\n if (!ref) return;\n try {\n ref.fitNodesInView();\n devLog(\"[ReGraph] fitToScreen\", {\n reason,\n nodeCount: nodes.length,\n });\n } catch (e) {\n devLog(\"[ReGraph] fitToScreen failed\", {\n reason,\n error: (e as Error).message,\n });\n }\n });\n });\n },\n [nodes.length],\n );\n\n // Mounted state\n useEffect(() => {\n isMountedRef.current = true;\n fitToScreen(\"mount\");\n\n // Subscribe to external selection changes (e.g., from Cytoscape renderer) and update Reagraph visuals\n // One-time initial visual sync from existing store selection when mounting\n const state = useGraphSelection.getState();\n if (state.selectedNodeIds.length || state.selectedEdge) {\n devLog(\"[ReGraph] Initial sync of selection store\", {\n selectedNodeIds: state.selectedNodeIds,\n selectedEdge: state.selectedEdge,\n });\n\n // Apply existing selection to Reagraph\n if (state.selectedNodeIds.length > 0) {\n setSelections(state.selectedNodeIds);\n }\n if (state.selectedEdge) {\n setSelectedEdge(state.selectedEdge);\n }\n }\n\n return () => {\n isMountedRef.current = false;\n };\n }, [fitToScreen, setSelections, setSelectedEdge, useGraphSelection]);\n\n // Re-fit when counts change\n useEffect(() => {\n if (isMountedRef.current) fitToScreen(\"counts-changed\");\n }, [nodes.length, edges.length, fitToScreen]);\n\n function updateLayout(next: LayoutTypes) {\n setLayout(next);\n fitToScreen(\"layout-change\");\n }\n\n function handleNodeClick(node: GraphNode) {\n setSelectedEdge(null);\n if (selections.length < 2 && onNodeClick) onNodeClick(node);\n }\n\n function handleEdgeClick(edge: GraphEdge) {\n const startNode = normalized.nodesById[edge.data.start_id_ + \"\"];\n const endNode = normalized.nodesById[edge.data.end_id_ + \"\"];\n\n if (!startNode || !endNode) return;\n\n const startNodeId = String(startNode.id_);\n const endNodeId = String(endNode.id_);\n\n // Get currently selected nodes from global store\n const currentSelectedIds = useGraphSelection.getState().selectedNodeIds;\n\n // CASE 1: One node already selected AND it's an endpoint of this edge\n // Keep only that node selected + select edge (enables directional operations)\n if (currentSelectedIds.length === 1) {\n const selectedNodeId = currentSelectedIds[0];\n\n if (selectedNodeId === startNodeId || selectedNodeId === endNodeId) {\n devLog(\"[ReGraph] handleEdgeClick - node+edge selection\", {\n edgeId: edge.id,\n selectedNode: selectedNodeId,\n direction: selectedNodeId === startNodeId ? \"outgoing\" : \"incoming\",\n });\n\n // Keep only the selected node (selection is already in place from node click)\n setSelectedEdge(edge.data as VisualGraphEdge);\n return; // Early exit\n }\n }\n\n // CASE 2: Default behavior (no node selected, or node not an endpoint)\n // Select BOTH endpoints + edge (traditional behavior)\n devLog(\"[ReGraph] handleEdgeClick - default (both endpoints)\", {\n edgeId: edge.id,\n });\n\n // Use setSelections to directly set both node IDs at once\n setSelections([startNodeId, endNodeId]);\n setSelectedEdge(edge.data as VisualGraphEdge);\n }\n\n function handleCanvasClick(e: MouseEvent) {\n clearSelections();\n setSelectedNodeIds([]);\n setSelectedEdge(null);\n if (onCanvasClick) onCanvasClick(e);\n }\n\n // Sync outward selections\n useEffect(() => {\n if (!isMountedRef.current) return;\n if (selections.length > 0 && selections.length <= 2) {\n const selectedNodes = selections\n .map((id) => nodes.find((n: GraphNode) => n.id === id))\n .filter(Boolean) as GraphNode[];\n setSelectedNodeIds(selectedNodes.map((n) => n.id));\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selections, nodes]);\n\n // Remove selections if nodes disappear\n useEffect(() => {\n if (!isMountedRef.current) return;\n const currentSelectedIds: string[] =\n useGraphSelection.getState().selectedNodeIds;\n if (!currentSelectedIds.length) return;\n const stillPresentIds = currentSelectedIds.filter((id: string) =>\n nodes.find((n: GraphNode) => n.id === id),\n );\n if (stillPresentIds.length !== currentSelectedIds.length) {\n clearSelections();\n setSelectedNodeIds(stillPresentIds);\n if (stillPresentIds.length < 2) setSelectedEdge(null);\n }\n }, [\n nodes,\n clearSelections,\n setSelectedNodeIds,\n setSelectedEdge,\n useGraphSelection,\n ]);\n\n // Reconcile global selection store (preserve visible)\n useEffect(() => {\n if (!isMountedRef.current) return;\n const currentSelectedIds: string[] =\n useGraphSelection.getState().selectedNodeIds;\n if (!currentSelectedIds.length) return;\n const stillPresentIds = currentSelectedIds.filter((id: string) =>\n nodes.find((n: GraphNode) => n.id === id),\n );\n if (stillPresentIds.length !== currentSelectedIds.length) {\n setSelectedNodeIds(stillPresentIds);\n if (stillPresentIds.length < 2) setSelectedEdge(null);\n }\n }, [nodes, setSelectedNodeIds, setSelectedEdge, useGraphSelection]);\n\n // Fullscreen side-effects\n useEffect(() => {\n if (!fullscreen) return;\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n fitToScreen(\"enter-fullscreen\");\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setFullscreen(false);\n };\n window.addEventListener(\"keydown\", handleKey);\n return () => {\n document.body.style.overflow = prevOverflow;\n window.removeEventListener(\"keydown\", handleKey);\n };\n }, [fullscreen, fitToScreen]);\n\n // When entering fullscreen ensure Reagraph recalculates size\n useEffect(() => {\n if (!fullscreen) return;\n // Delay to allow DOM classes/layout to apply\n const id = setTimeout(() => {\n if (canvas.current) {\n fitToScreen(\"fullscreen-resize-delay\");\n }\n }, 50);\n return () => clearTimeout(id);\n }, [fullscreen, fitToScreen]);\n\n // Handle window resize events only when component is mounted\n useEffect(() => {\n if (!isMountedRef.current) return;\n\n const handleResize = () => {\n if (isMountedRef.current && canvas.current) {\n fitToScreen(\"window-resize\");\n }\n };\n\n window.addEventListener(\"resize\", handleResize);\n return () => {\n window.removeEventListener(\"resize\", handleResize);\n };\n }, [fitToScreen]);\n\n // First data arrival fit\n const firstDataRef = useRef(true);\n useEffect(() => {\n if (!isMountedRef.current) return;\n if (nodes.length > 0) {\n if (firstDataRef.current) {\n fitToScreen(\"first-data\");\n firstDataRef.current = false;\n }\n } else {\n firstDataRef.current = true;\n }\n }, [nodes.length, fitToScreen]);\n\n if (nodes.length === 0) {\n devLog(\"[ReGraph] empty state render\");\n return (\n <Card className=\"relative w-full h-full items-center justify-center text-slate-500 gap-2 shadow-xs p-4\">\n <div>No data to display.</div>\n <div>\n Please{\" \"}\n <span className=\"font-semibold\">\n run a query, check filters, or add a node\n </span>{\" \"}\n to the workbench to populate the graph.\n </div>\n </Card>\n );\n }\n\n return (\n <div\n className={cn(\n \"bg-white\",\n fullscreen\n ? \"fixed inset-0 z-50 w-screen h-screen p-0 m-0\"\n : \"relative w-full h-full\",\n )}\n >\n <Card className=\"h-full shadow-xs p-4\">\n <GraphCanvas\n ref={canvas}\n theme={theme}\n nodes={nodes}\n edges={edges}\n draggable\n layoutType={layout}\n selections={selections}\n actives={actives}\n onCanvasClick={handleCanvasClick}\n onNodeClick={(e) => handleNodeClick(e)}\n edgeArrowPosition=\"end\"\n edgeLabelPosition=\"natural\"\n labelType=\"all\"\n onNodePointerOver={setHoveredNode}\n onNodePointerOut={() => setHoveredNode(undefined)}\n onEdgeClick={handleEdgeClick}\n contextMenu={({ data, onClose }) => {\n const elementType = \"source\" in data ? \"edge\" : \"node\";\n devLog(\"[ReGraph] Context menu opened\", {\n elementId: data.id,\n elementType,\n });\n return (\n <ReaContextMenu\n data={data}\n onClose={onClose}\n elementType={elementType}\n useGraphExploration={useGraphExploration}\n onCopyNode={onCopyNode}\n />\n );\n }}\n />\n </Card>\n\n {hoveredNode && <NodeHoverInfo node={hoveredNode} />}\n\n <LayoutAndCameraControls\n fitToScreen={fitToScreen}\n fullscreen={fullscreen}\n toggleFullscreen={() => setFullscreen((prev) => !prev)}\n updateLayout={updateLayout}\n setPathSelectionType={setPathSelectionType}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n onResetView={() => {\n useGraphExploration.getState().resetView();\n toast.success(\n isFocusMode ? \"Focus mode cleared\" : \"Hidden elements restored\",\n );\n }}\n extraToolbarContent={extraToolbarContent}\n />\n </div>\n );\n}\n\nexport default ReaGraph;\n","import { lightTheme } from \"reagraph\";\n\nconst highlightColor = \"#ffb512\";\nconst highlightColorText = \"#c98a02\";\nconst theme = {\n ...lightTheme,\n node: {\n ...lightTheme.node,\n activeFill: highlightColor,\n label: {\n ...lightTheme.node.label,\n activeColor: highlightColorText,\n },\n },\n ring: {\n ...lightTheme.ring,\n activeFill: highlightColor,\n },\n edge: {\n ...lightTheme.edge,\n activeFill: highlightColor,\n label: {\n ...lightTheme.edge.label,\n activeColor: highlightColorText,\n },\n },\n arrow: {\n ...lightTheme.arrow,\n activeFill: highlightColor,\n },\n};\n\nexport { theme };\n","import {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n SimpleTooltip,\n} from \"@petrarca/sonnet-ui\";\nimport { LayoutPanelTop, Maximize, Shrink, ArrowUp, Eye } from \"lucide-react\";\nimport { LayoutTypes, PathSelectionTypes } from \"reagraph\";\nimport { type ReactNode, useState } from \"react\";\nimport { RendererDropdown } from \"../shared/RendererDropdown\";\n\ntype Props = {\n updateLayout: (layout: LayoutTypes) => void;\n fitToScreen: () => void;\n toggleFullscreen: () => void;\n fullscreen: boolean;\n setPathSelectionType: (type: PathSelectionTypes) => void;\n hasHiddenElements?: boolean;\n isFocusMode?: boolean;\n onResetView?: () => void;\n extraToolbarContent?: ReactNode;\n};\n\n/* ------------------------------------------------------------------ */\n/* PathSelectionDropdown */\n/* ------------------------------------------------------------------ */\n\ntype PathSelectionDropdownProps = {\n setPathSelectionType: (type: PathSelectionTypes) => void;\n};\n\nfunction PathSelectionDropdown({\n setPathSelectionType,\n}: PathSelectionDropdownProps) {\n return (\n <DropdownMenu>\n <SimpleTooltip label=\"Path Selection Type\" side=\"left\">\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <ArrowUp />\n </Button>\n </DropdownMenuTrigger>\n </SimpleTooltip>\n\n <DropdownMenuContent side=\"left\" align=\"start\">\n <DropdownMenuItem onClick={() => setPathSelectionType(\"direct\")}>\n None\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setPathSelectionType(\"all\")}>\n All Paths\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setPathSelectionType(\"in\")}>\n Inbound\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => setPathSelectionType(\"out\")}>\n Outbound\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* LayoutDropdown */\n/* ------------------------------------------------------------------ */\n\ntype LayoutDropdownProps = {\n updateLayout: (layout: LayoutTypes) => void;\n};\n\nfunction LayoutDropdown({ updateLayout }: LayoutDropdownProps) {\n const [showTooltip, setShowTooltip] = useState(true);\n\n const handleSelect = (layout: LayoutTypes) => {\n updateLayout(layout);\n setShowTooltip(false);\n // Re-enable tooltip after a short delay\n setTimeout(() => setShowTooltip(true), 500);\n };\n\n const trigger = (\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <LayoutPanelTop />\n </Button>\n </DropdownMenuTrigger>\n );\n\n return (\n <DropdownMenu>\n {showTooltip ? (\n <SimpleTooltip label=\"Layout\" side=\"left\">\n {trigger}\n </SimpleTooltip>\n ) : (\n trigger\n )}\n\n <DropdownMenuContent side=\"left\" align=\"start\">\n <DropdownMenuLabel>Force-directed Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"forceDirected2d\")}>\n Force Directed\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"forceatlas2\")}>\n Force Atlas 2\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Tree Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"treeTd2d\")}>\n Tree Top-Down\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"treeLr2d\")}>\n Tree Left-Right\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Circular & Radial Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"circular2d\")}>\n Circular\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"radialOut2d\")}>\n Radial Out\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => handleSelect(\"concentric2d\")}>\n Concentric\n </DropdownMenuItem>\n\n <DropdownMenuSeparator />\n <DropdownMenuLabel>Utility Layouts</DropdownMenuLabel>\n <DropdownMenuItem onClick={() => handleSelect(\"nooverlap\")}>\n No Overlap\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* ViewControls */\n/* ------------------------------------------------------------------ */\n\ntype ViewControlsProps = {\n fullscreen: boolean;\n toggleFullscreen: () => void;\n fitToScreen: () => void;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n onResetView?: () => void;\n};\n\nfunction ViewControls({\n fullscreen,\n toggleFullscreen,\n fitToScreen,\n hasHiddenElements,\n isFocusMode,\n onResetView,\n}: ViewControlsProps) {\n return (\n <>\n <SimpleTooltip label=\"Fullscreen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleFullscreen}>\n {!fullscreen ? <Maximize /> : <Shrink />}\n </Button>\n </SimpleTooltip>\n\n <SimpleTooltip label=\"Fit to screen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={fitToScreen}>\n <Shrink />\n </Button>\n </SimpleTooltip>\n\n {(hasHiddenElements || isFocusMode) && onResetView && (\n <SimpleTooltip\n label={isFocusMode ? \"Reset Focus\" : \"Show All Hidden\"}\n side=\"left\"\n >\n <Button variant=\"ghost\" size=\"icon\" onClick={onResetView}>\n <Eye />\n </Button>\n </SimpleTooltip>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* LayoutAndCameraControls (composed) */\n/* ------------------------------------------------------------------ */\n\nfunction LayoutAndCameraControls({\n fitToScreen,\n fullscreen,\n toggleFullscreen,\n updateLayout,\n setPathSelectionType,\n hasHiddenElements = false,\n isFocusMode = false,\n onResetView,\n extraToolbarContent,\n}: Props) {\n return (\n <div className=\"absolute right-2 top-2 flex flex-col border\">\n <RendererDropdown />\n\n <ViewControls\n fullscreen={fullscreen}\n toggleFullscreen={toggleFullscreen}\n fitToScreen={fitToScreen}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n onResetView={onResetView}\n />\n\n <PathSelectionDropdown setPathSelectionType={setPathSelectionType} />\n\n {extraToolbarContent}\n\n <LayoutDropdown updateLayout={updateLayout} />\n </div>\n );\n}\n\nexport default LayoutAndCameraControls;\n","import {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n SimpleTooltip,\n} from \"@petrarca/sonnet-ui\";\nimport { useGraphRenderer } from \"../../hooks/useGraphRenderer\";\n\n/**\n * Shared renderer selection dropdown used by both rea and cyto toolbars.\n * Reads and sets the active renderer (reagraph vs cytoscape) from context.\n */\nexport function RendererDropdown() {\n const { renderer, setRenderer } = useGraphRenderer();\n\n return (\n <DropdownMenu>\n <SimpleTooltip label=\"Renderer\" side=\"left\">\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n {renderer === \"reagraph\" ? \"RG\" : \"CY\"}\n </Button>\n </DropdownMenuTrigger>\n </SimpleTooltip>\n <DropdownMenuContent side=\"left\" align=\"start\">\n <DropdownMenuItem\n onClick={() => setRenderer(\"reagraph\")}\n className={renderer === \"reagraph\" ? \"text-blue-600\" : \"\"}\n >\n Reagraph\n </DropdownMenuItem>\n <DropdownMenuItem\n onClick={() => setRenderer(\"cytoscape\")}\n className={renderer === \"cytoscape\" ? \"text-blue-600\" : \"\"}\n >\n Cytoscape\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","import { Card, Separator } from \"@petrarca/sonnet-ui\";\nimport { GraphNode } from \"reagraph\";\n\ntype Props = {\n node: GraphNode;\n};\n\nfunction NodeHoverInfo({ node }: Props) {\n return (\n <Card className=\"absolute top-2 left-1/2 -translate-x-1/2 bg-white shadow-md p-2\">\n <div className=\"flex flex-row items-center gap-2\">\n <Separator\n orientation=\"vertical\"\n decorative\n className=\"h-10 w-1\"\n style={{ backgroundColor: node.fill as string }}\n />\n <div>\n <p>\n <strong>{node.data.label_}: </strong>\n {node.label}\n </p>\n <p className=\"text-sm text-muted-foreground\">{node.data.id_}</p>\n </div>\n </div>\n </Card>\n );\n}\n\nexport default NodeHoverInfo;\n","import React from \"react\";\nimport { devLog } from \"@petrarca/sonnet-core\";\nimport type { GraphNode, GraphEdge } from \"reagraph\";\nimport type { StoreApi, UseBoundStore } from \"zustand\";\nimport type { VisualGraphNode } from \"../../models/visual-graph\";\nimport type { GraphExplorationStore } from \"../../stores/GraphExploration\";\n\ntype Props = Readonly<{\n data: GraphNode | GraphEdge;\n onClose: () => void;\n elementType: \"node\" | \"edge\";\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n onCopyNode?: (node: VisualGraphNode) => void;\n}>;\n\nfunction ReaContextMenu({\n data,\n onClose,\n elementType,\n useGraphExploration,\n onCopyNode,\n}: Props) {\n const handleFocus = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Focus on node and neighborhood:\", nodeId);\n useGraphExploration.getState().setFocusModeWithNeighborhood(nodeId);\n } else {\n // For edges, focus on the start node\n const startNodeId = data.data.start_id_;\n devLog(\"[ReaContextMenu] Focus on edge start node:\", startNodeId);\n useGraphExploration.getState().setFocusModeWithNeighborhood(startNodeId);\n }\n onClose();\n };\n\n const handleCopy = () => {\n devLog(\"[ReaContextMenu] Copy to clipboard\");\n\n if (elementType === \"node\") {\n const visualGraph = data.data?.visualGraph;\n if (visualGraph && onCopyNode) {\n onCopyNode(visualGraph);\n } else if (!visualGraph) {\n // Fallback: use browser clipboard for basic text\n const nodeText = `Node: ${data.label || data.id}`;\n navigator.clipboard.writeText(nodeText);\n }\n } else {\n // For edges, copy the edge info as text\n const edgeText = `Edge: ${data.data.start_id_} -> ${data.data.end_id_}`;\n navigator.clipboard.writeText(edgeText);\n }\n onClose();\n };\n\n const handleHideNode = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Hide node:\", nodeId);\n useGraphExploration.getState().hideElements([nodeId]);\n }\n onClose();\n };\n\n const handleHideIncoming = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Hide incoming edges:\", nodeId);\n useGraphExploration.getState().hideNodeIncoming(nodeId);\n }\n onClose();\n };\n\n const handleHideOutgoing = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Hide outgoing edges:\", nodeId);\n useGraphExploration.getState().hideNodeOutgoing(nodeId);\n }\n onClose();\n };\n\n const handleExpand = () => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Expand node:\", nodeId);\n useGraphExploration.getState().expandNode(nodeId);\n }\n onClose();\n };\n\n const handleHideForwardPath = () => {\n if (elementType === \"edge\") {\n const edgeId = data.id;\n devLog(\"[ReaContextMenu] Hide forward path from edge:\", edgeId);\n useGraphExploration.getState().hideEdgeForwardPath(edgeId);\n }\n onClose();\n };\n\n const handleHideReversePath = () => {\n if (elementType === \"edge\") {\n const edgeId = data.id;\n devLog(\"[ReaContextMenu] Hide reverse path from edge:\", edgeId);\n useGraphExploration.getState().hideEdgeReversePath(edgeId);\n }\n onClose();\n };\n\n const handleFocusOnEdgeType = () => {\n if (elementType === \"edge\") {\n const edgeId = data.id;\n const edgeLabel = data.data?.label_ || \"edge\";\n devLog(\"[ReaContextMenu] Focus on edge type:\", edgeId, edgeLabel);\n useGraphExploration.getState().focusOnEdgeType(edgeId);\n }\n onClose();\n };\n\n // Menu items for nodes - identical to Cytoscape\n const nodeMenuItems = [\n { label: \"Focus\", action: handleFocus },\n { label: \"Copy\", action: handleCopy },\n { label: \"Hide Node\", action: handleHideNode },\n { label: \"Hide Incoming\", action: handleHideIncoming },\n { label: \"Hide Outgoing\", action: handleHideOutgoing },\n { label: \"Expand\", action: handleExpand },\n ];\n\n // Menu items for edges - consistent with Cytoscape\n const edgeMenuItems = [\n { label: \"Focus\", action: handleFocus },\n { label: \"Focus Edge Type\", action: handleFocusOnEdgeType },\n { label: \"Copy\", action: handleCopy },\n { label: \"Hide Forward Path\", action: handleHideForwardPath },\n { label: \"Hide Reverse Path\", action: handleHideReversePath },\n ];\n\n const menuItems = elementType === \"node\" ? nodeMenuItems : edgeMenuItems;\n\n // Simple div-based menu (Reagraph handles positioning)\n return (\n <div className=\"bg-white border border-gray-200 rounded-md shadow-lg py-1 min-w-48\">\n {menuItems.map((item, index) => (\n <React.Fragment key={item.label}>\n <button\n className=\"w-full text-left px-3 py-2 text-sm hover:bg-gray-100 cursor-pointer\"\n onClick={item.action}\n >\n {item.label}\n </button>\n {index === 1 && <div className=\"border-t border-gray-200 my-1\" />}\n </React.Fragment>\n ))}\n </div>\n );\n}\n\nexport default ReaContextMenu;\n","import {\n type ReactNode,\n useEffect,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport { devLog, errorLog } from \"@petrarca/sonnet-core\";\nimport cytoscape from \"cytoscape\";\ntype Core = cytoscape.Core;\ntype LayoutOptions = cytoscape.LayoutOptions;\nimport fcose from \"cytoscape-fcose\";\nimport cola from \"cytoscape-cola\";\nimport dagre from \"cytoscape-dagre\";\nimport klay from \"cytoscape-klay\";\nimport elk from \"cytoscape-elk\";\nimport cise from \"cytoscape-cise\";\nimport cxtmenu from \"cytoscape-cxtmenu\";\nimport { useCytoscapeData } from \"../../hooks/useCytoscapeData\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport {\n useWorkspaceSelection,\n useWorkspaceGraphFilter,\n useWorkspaceGraphExploration,\n} from \"../../hooks/useWorkspaceStores\";\nimport useGraphFocus, { type GraphFocusAction } from \"../../stores/GraphFocus\";\nimport CytoscapeControls from \"./CytoscapeControls\";\nimport { StandardLayout, getLayoutPreset } from \"./layoutPresets\";\nimport type {\n VisualGraphNode,\n VisualGraphEdge,\n} from \"../../models/visual-graph\";\nimport {\n createNodeContextMenu,\n createEdgeContextMenu,\n} from \"./contextMenuConfig\";\nimport { toast } from \"sonner\";\n\n// Register extensions once (cytoscape guards duplicates)\ntry {\n cytoscape.use(fcose);\n cytoscape.use(cola);\n cytoscape.use(dagre);\n cytoscape.use(klay);\n cytoscape.use(elk);\n cytoscape.use(cise);\n cxtmenu(cytoscape); // Register cxtmenu extension\n} catch {\n /* ignore */\n}\n\ninterface CytoscapeGraphProps {\n layout?: StandardLayout; // chosen standard layout or 'auto'\n fitPadding?: number; // padding when fitting after layout\n /** Callback when a node is copied from context menu. */\n onCopyNode?: (node: VisualGraphNode) => void;\n /** Extra toolbar content (e.g. clipboard UI) injected into the toolbar. */\n extraToolbarContent?: ReactNode;\n}\n\n// --- Extracted helpers for data-update useEffect (reduces cyclomatic complexity) ---\n\n/** Valid layouts for the update effect */\nconst ALLOWED_LAYOUTS: StandardLayout[] = [\n \"auto\",\n \"fcose\",\n \"cola\",\n \"dagre\",\n \"klay\",\n \"elk\",\n \"cise\",\n \"grid\",\n \"cose\",\n \"concentric\",\n \"breadthfirst\",\n \"tree\",\n \"circle\",\n \"random\",\n];\n\ninterface SkipUpdateParams {\n cy: Core;\n currentIds: string;\n elementIdsRef: React.MutableRefObject<string>;\n lastLayoutRef: React.MutableRefObject<string>;\n lastFitPaddingRef: React.MutableRefObject<number>;\n currentLayout: string;\n fitPadding: number;\n nodeCount: number;\n edgeCount: number;\n}\n\n/** Returns 'skip' if the update can be skipped entirely, 'refit' if only a refit is needed, or 'update' for a full redraw. */\nfunction classifyUpdate({\n cy,\n currentIds,\n elementIdsRef,\n lastLayoutRef,\n lastFitPaddingRef,\n currentLayout,\n fitPadding,\n nodeCount,\n edgeCount,\n}: SkipUpdateParams): \"skip\" | \"refit\" | \"update\" {\n const paddingChanged = fitPadding !== lastFitPaddingRef.current;\n const cyHasElements =\n cy.nodes().length === nodeCount && cy.edges().length === edgeCount;\n const layoutChanged = currentLayout !== lastLayoutRef.current;\n\n // If only padding changed, just refit without redrawing\n if (\n paddingChanged &&\n currentIds === elementIdsRef.current &&\n cyHasElements &&\n !layoutChanged\n ) {\n return \"refit\";\n }\n\n // Skip if actual data hasn't changed AND Cytoscape has the elements AND layout hasn't changed\n if (currentIds === elementIdsRef.current && cyHasElements && !layoutChanged) {\n return \"skip\";\n }\n\n return \"update\";\n}\n\ninterface ApplyLayoutParams {\n cy: Core;\n chosen: StandardLayout;\n nodeCount: number;\n nodesForLayout: Array<{ id: string; data: { label_: string } }>;\n fitPadding: number;\n}\n\n/** Apply layout to cytoscape instance with error fallbacks. */\nfunction applyLayout({\n cy,\n chosen,\n nodeCount,\n nodesForLayout,\n fitPadding,\n}: ApplyLayoutParams): void {\n const layoutOpts = getLayoutPreset({\n layoutName: chosen,\n count: nodeCount,\n nodeData: nodesForLayout,\n }) as LayoutOptions & { fit?: boolean; roots?: unknown };\n\n if (chosen === \"tree\") {\n const cyNodes = cy.nodes();\n const rootCandidates = cyNodes.filter((n) => n.indegree(false) === 0);\n if (rootCandidates.length > 0) {\n (layoutOpts as unknown as { [k: string]: unknown }).roots =\n rootCandidates;\n } else if (cyNodes.length) {\n (layoutOpts as unknown as { [k: string]: unknown }).roots = cyNodes[0];\n }\n }\n\n const getPreset = (name: StandardLayout) =>\n getLayoutPreset({\n layoutName: name,\n count: nodeCount,\n nodeData: nodesForLayout,\n });\n\n try {\n cy.layout(layoutOpts).run();\n } catch (e) {\n errorLog(\"Layout error, falling back to dagre:\", e);\n if (chosen === \"klay\") {\n try {\n cy.layout(getPreset(\"dagre\")).run();\n } catch (inner) {\n errorLog(\"Fallback layout also failed, using grid:\", inner);\n cy.layout(getPreset(\"grid\")).run();\n }\n } else {\n cy.layout(getPreset(\"grid\")).run();\n }\n }\n\n // Perform a single external fit only if layout didn't already handle fitting\n if (!layoutOpts.fit) {\n cy.fit(undefined, fitPadding);\n }\n}\n\ninterface ProcessPendingFocusParams {\n cy: Core;\n pendingFocus: NonNullable<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n pendingFocusActionRef: React.MutableRefObject<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n}\n\n/** Process a pending focus action after graph data is updated. */\nfunction processPendingFocus({\n cy,\n pendingFocus,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n pendingFocusActionRef,\n}: ProcessPendingFocusParams): void {\n devLog(\"[CytoscapeGraph] Processing pending focus action\", {\n elementId: pendingFocus.elementId,\n elementType: pendingFocus.elementType,\n });\n\n setTimeout(() => {\n const element = cy.$id(pendingFocus.elementId);\n\n if (element.length === 0) {\n devLog(\n \"[CytoscapeGraph] Focus requested but element not found after graph update\",\n {\n elementId: pendingFocus.elementId,\n elementType: pendingFocus.elementType,\n },\n );\n pendingFocusActionRef.current = null;\n useGraphFocus.setState({ focusAction: null });\n return;\n }\n\n // Animate focus with explicit zoom and center\n cy.animate(\n { zoom: 2.0, center: { eles: element } },\n { duration: 500, easing: \"ease-in-out-cubic\" },\n );\n\n // If focus-and-select, also trigger selection\n if (pendingFocus.action === \"focus-and-select\") {\n selectFocusedElement({\n cy,\n pendingFocus,\n element,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n });\n }\n\n pendingFocusActionRef.current = null;\n useGraphFocus.setState({ focusAction: null });\n }, 100);\n}\n\ninterface SelectFocusedElementParams {\n cy: Core;\n pendingFocus: NonNullable<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n element: ReturnType<Core[\"$id\"]>;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n}\n\n/** Handle selection for a focused element (node or edge). */\nfunction selectFocusedElement({\n cy,\n pendingFocus,\n element,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n}: SelectFocusedElementParams): void {\n if (pendingFocus.elementType === \"node\") {\n cy.batch(() => {\n cy.elements().unselect();\n element.select();\n });\n setSelectedNodeIdsStore([pendingFocus.elementId]);\n selectedNodeIdsRef.current = [pendingFocus.elementId];\n setSelectedEdgeStore(null);\n selectedEdgeRef.current = null;\n } else {\n const edgeObj = edgesRef.current.find(\n (e) => String(e.id_) === pendingFocus.elementId,\n );\n if (edgeObj) {\n const sourceId = String(edgeObj.start_id_);\n const targetId = String(edgeObj.end_id_);\n cy.batch(() => {\n cy.elements().unselect();\n cy.$id(sourceId).select();\n cy.$id(targetId).select();\n element.select();\n });\n setSelectedNodeIdsStore([sourceId, targetId]);\n selectedNodeIdsRef.current = [sourceId, targetId];\n setSelectedEdgeStore(edgeObj);\n selectedEdgeRef.current = edgeObj;\n }\n }\n}\n\n// --- Helper: handle a single GraphFocus store state change ---\n\ninterface HandleFocusStateChangeParams {\n focusAction: GraphFocusAction | null;\n cyRef: React.MutableRefObject<Core | null>;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n pendingFocusActionRef: React.MutableRefObject<\n ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]\n >;\n baseNormalized: { edgesById: Record<string, VisualGraphEdge> };\n}\n\nfunction handleFocusStateChange({\n focusAction,\n cyRef,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n pendingFocusActionRef,\n baseNormalized,\n}: HandleFocusStateChangeParams): void {\n if (!focusAction || !cyRef.current) return;\n\n devLog(\"[CytoscapeGraph] Processing focus action\", {\n elementId: focusAction.elementId,\n timestamp: focusAction.timestamp,\n });\n\n const cy = cyRef.current;\n const elementId = focusAction.elementId;\n const element = cy.$id(elementId);\n\n // CASE 1: Element already exists in Cytoscape -> focus immediately\n if (element.length > 0) {\n handleImmediateFocus({\n cy,\n element,\n focusAction,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n });\n return;\n }\n\n // CASE 2: Element NOT in Cytoscape -> needs override\n devLog(\"[CytoscapeGraph] Element not visible, setting up override\", {\n elementId,\n elementType: focusAction.elementType,\n });\n\n pendingFocusActionRef.current = focusAction;\n\n useGraphFocus.setState((state) => {\n const overrides = new Set(state.overrideElementIds);\n overrides.add(elementId);\n\n if (focusAction.elementType === \"edge\") {\n let edgeObj = edgesRef.current.find((e) => String(e.id_) === elementId);\n if (!edgeObj) {\n edgeObj = baseNormalized.edgesById[elementId];\n }\n if (edgeObj) {\n overrides.add(String(edgeObj.start_id_));\n overrides.add(String(edgeObj.end_id_));\n devLog(\"[CytoscapeGraph] Added edge and endpoints to overrides\", {\n edgeId: elementId,\n startId: edgeObj.start_id_,\n endId: edgeObj.end_id_,\n });\n }\n } else {\n devLog(\"[CytoscapeGraph] Added node to overrides\", { nodeId: elementId });\n }\n\n return { overrideElementIds: overrides };\n });\n}\n\ninterface HandleImmediateFocusParams {\n cy: Core;\n element: ReturnType<Core[\"$id\"]>;\n focusAction: GraphFocusAction;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n}\n\nfunction handleImmediateFocus({\n cy,\n element,\n focusAction,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n}: HandleImmediateFocusParams): void {\n const elementId = focusAction.elementId;\n\n devLog(\"[CytoscapeGraph] Element already visible, focusing immediately\", {\n elementId,\n elementType: focusAction.elementType,\n });\n\n cy.animate(\n { zoom: 2.0, center: { eles: element } },\n { duration: 500, easing: \"ease-in-out-cubic\" },\n );\n\n if (focusAction.action === \"focus-and-select\") {\n selectFocusedElement({\n cy,\n pendingFocus: focusAction,\n element,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n });\n }\n\n useGraphFocus.setState({ focusAction: null });\n}\n\n// --- Helper: compute view state flags and CSS classes ---\n\ninterface GraphViewStateInput {\n hasNodes: boolean;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n fullscreen: boolean;\n}\n\nfunction computeGraphViewState({\n hasNodes,\n hasHiddenElements,\n isFocusMode,\n fullscreen,\n}: GraphViewStateInput) {\n const hasExplorationState = hasHiddenElements || isFocusMode;\n return {\n showEmptyMessage: !hasNodes && !hasExplorationState,\n showFilteredMessage: !hasNodes && hasExplorationState,\n showControls: hasNodes || hasExplorationState,\n outerClass: fullscreen\n ? \"fixed inset-0 z-50 w-screen h-screen bg-white flex flex-col\"\n : \"w-full h-full flex flex-col relative\",\n innerClass: fullscreen\n ? \"flex-1 relative overflow-hidden bg-white\"\n : \"flex-1 relative border border-gray-300 rounded-md overflow-hidden bg-white\",\n };\n}\n\n// --- Custom hook: fullscreen state + ESC handler + body scroll lock ---\n\nfunction useFullscreen(\n fitToScreen: () => void,\n cyRef: React.MutableRefObject<Core | null>,\n) {\n const [fullscreen, setFullscreen] = useState(false);\n\n // Handle body scroll lock & ESC to exit fullscreen\n useEffect(() => {\n if (fullscreen) {\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n fitToScreen();\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setFullscreen(false);\n };\n window.addEventListener(\"keydown\", handleKey);\n return () => {\n document.body.style.overflow = prevOverflow;\n window.removeEventListener(\"keydown\", handleKey);\n };\n }\n }, [fullscreen, fitToScreen]);\n\n // When entering fullscreen ensure Cytoscape recalculates size\n useEffect(() => {\n if (!fullscreen) return;\n const id = setTimeout(() => {\n if (cyRef.current) {\n cyRef.current.resize();\n fitToScreen();\n }\n }, 50);\n return () => clearTimeout(id);\n }, [fullscreen, fitToScreen, cyRef]);\n\n return {\n fullscreen,\n setFullscreen,\n toggleFullscreen: useCallback(() => setFullscreen((f) => !f), []),\n };\n}\n\n// --- Helper: set up all Cytoscape event handlers ---\n\ninterface SetupEventHandlersParams {\n cy: Core;\n edgesRef: React.MutableRefObject<VisualGraphEdge[]>;\n selectedNodeIdsRef: React.MutableRefObject<string[]>;\n selectedEdgeRef: React.MutableRefObject<VisualGraphEdge | null>;\n setSelectedNodeIdsStore: (ids: string[]) => void;\n setSelectedEdgeStore: (edge: VisualGraphEdge | null) => void;\n clearSelectionStore: () => void;\n useGraphExploration: ReturnType<typeof useWorkspaceGraphExploration>;\n onCopyNode?: (node: VisualGraphNode) => void;\n}\n\nfunction setupCytoscapeEventHandlers({\n cy,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n clearSelectionStore,\n useGraphExploration,\n onCopyNode,\n}: SetupEventHandlersParams): void {\n const updateSelectedNodeIds = (nodeIds: string[]) => {\n setSelectedNodeIdsStore(nodeIds);\n selectedNodeIdsRef.current = nodeIds;\n };\n const updateSelectedEdge = (edgeToSet: VisualGraphEdge | null) => {\n setSelectedEdgeStore(edgeToSet);\n selectedEdgeRef.current = edgeToSet;\n };\n\n const clearAll = () => {\n cy.batch(() => {\n cy.elements().unselect();\n });\n clearSelectionStore();\n selectedNodeIdsRef.current = [];\n selectedEdgeRef.current = null;\n };\n\n cy.on(\"select\", \"node\", (evt) => {\n const nodeEle = evt.target;\n const evtCy = evt.cy;\n const id = nodeEle.id();\n\n devLog(\"[CytoscapeGraph] node selected\", { id });\n\n if (selectedEdgeRef.current) {\n devLog(\"[CytoscapeGraph] clearing edge due to node selection\", {\n edgeId: selectedEdgeRef.current.id_,\n });\n updateSelectedEdge(null);\n }\n\n let selectedIds = evtCy.$(\"node:selected\").map((e) => e.id());\n\n if (selectedIds.length > 2) {\n const currentOrder = [...selectedNodeIdsRef.current];\n const updatedOrder = [...currentOrder.filter((cid) => cid !== id), id];\n const keep = updatedOrder.slice(-2);\n evtCy.batch(() => {\n evtCy.$(\"node:selected\").unselect();\n keep.forEach((kid) => evtCy.$id(kid).select());\n });\n selectedIds = keep;\n\n devLog(\"[CytoscapeGraph] enforced max 2 after select\", { keep });\n }\n updateSelectedNodeIds(selectedIds);\n });\n\n cy.on(\"unselect\", \"node\", (evt) => {\n devLog(\"[CytoscapeGraph] node unselected\", { id: evt.target.id() });\n const selectedIds = evt.cy.$(\"node:selected\").map((e) => e.id());\n updateSelectedNodeIds(selectedIds);\n });\n\n cy.on(\"tap\", \"edge\", (evt) => {\n const edgeEle = evt.target;\n const edgeId = edgeEle.id();\n const edgeObj = edgesRef.current.find((e) => String(e.id_) === edgeId);\n if (!edgeObj) return;\n\n const sourceId = edgeEle.data(\"source\");\n const targetId = edgeEle.data(\"target\");\n const evtCy = evt.cy;\n const currentlySelectedNodes = evtCy.$(\"node:selected\").toArray();\n\n if (currentlySelectedNodes.length === 1) {\n const selectedNodeId = currentlySelectedNodes[0].id();\n if (selectedNodeId === sourceId || selectedNodeId === targetId) {\n devLog(\"[CytoscapeGraph] tap edge - node+edge selection\", {\n edgeId,\n selectedNode: selectedNodeId,\n direction: selectedNodeId === sourceId ? \"outgoing\" : \"incoming\",\n });\n evtCy.batch(() => {\n evtCy.elements().unselect();\n evtCy.$id(selectedNodeId).select();\n edgeEle.select();\n });\n updateSelectedNodeIds([selectedNodeId]);\n updateSelectedEdge(edgeObj);\n return;\n }\n }\n\n devLog(\"[CytoscapeGraph] tap edge - default (both endpoints)\", { edgeId });\n evtCy.batch(() => {\n evtCy.elements().unselect();\n evtCy.$id(sourceId).select();\n evtCy.$id(targetId).select();\n edgeEle.select();\n });\n updateSelectedNodeIds([sourceId, targetId]);\n updateSelectedEdge(edgeObj);\n });\n\n cy.on(\"tap\", (evt) => {\n if (evt.target === cy) clearAll();\n });\n\n createNodeContextMenu({ cy, useGraphExploration, onCopyNode });\n createEdgeContextMenu({ cy, useGraphExploration });\n}\n\nfunction CytoscapeGraph({\n layout: initialLayout = \"auto\",\n fitPadding = 30,\n onCopyNode,\n extraToolbarContent,\n}: CytoscapeGraphProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const cyRef = useRef<Core | null>(null);\n const isInitializedRef = useRef<boolean>(false);\n const [currentLayout, setCurrentLayout] =\n useState<StandardLayout>(initialLayout);\n // Refs to always have latest nodes/edges inside event handlers\n const nodesRef = useRef<VisualGraphNode[]>([]);\n const edgesRef = useRef<VisualGraphEdge[]>([]);\n // Ref to track pending focus action (processed after graph update)\n const pendingFocusActionRef =\n useRef<ReturnType<typeof useGraphFocus.getState>[\"focusAction\"]>(null);\n\n const cytoData = useCytoscapeData();\n const live = useLiveGraphData();\n const nodes = live.nodes; // VisualGraphNode[]\n const edges = live.edges; // VisualGraphEdge[]\n const baseNormalized = live.baseNormalized; // All nodes/edges (unfiltered)\n\n // Get workspace-scoped stores\n const useGraphFilter = useWorkspaceGraphFilter();\n const useGraphExploration = useWorkspaceGraphExploration();\n const useSelection = useWorkspaceSelection();\n\n // Get data-change timestamp to detect query re-runs\n const lastDataChangeTime = useGraphFilter((s) => s.lastDataChangeTime);\n\n // Graph exploration store\n const resetView = useGraphExploration((s) => s.resetView);\n const hasHiddenElements = useGraphExploration(\n (s) => s.hiddenElementIds.size > 0,\n );\n const isFocusMode = useGraphExploration((s) => s.isFocusMode);\n\n // --- Selection Handling (no re-render on selection change) ---\n // Access setter functions once (stable in Zustand) to avoid subscribing component render\n const {\n setSelectedNodeIds: setSelectedNodeIdsStore,\n setSelectedEdge: setSelectedEdgeStore,\n clear: clearSelectionStore,\n } = useSelection.getState();\n\n // Internal refs mirror selection state without causing React renders\n const selectedNodeIdsRef = useRef<string[]>(\n useSelection.getState().selectedNodeIds,\n );\n const selectedEdgeRef = useRef<VisualGraphEdge | null>(\n useSelection.getState().selectedEdge,\n );\n\n // Subscribe to external selection changes (e.g., from Reagraph renderer) and update Cytoscape visuals\n // One-time initial visual sync from existing store selection when mounting\n useEffect(() => {\n const state = useSelection.getState();\n selectedNodeIdsRef.current = state.selectedNodeIds;\n selectedEdgeRef.current = state.selectedEdge;\n const cy = cyRef.current;\n if (cy && (state.selectedNodeIds.length || state.selectedEdge)) {\n cy.batch(() => {\n cy.elements().unselect();\n state.selectedNodeIds.forEach((id: string) => cy.$id(id).select());\n if (state.selectedEdge) {\n const edge = cy.$id(String(state.selectedEdge.id_));\n if (edge) {\n edge.select();\n cy.$id(edge.data(\"source\")).select();\n cy.$id(edge.data(\"target\")).select();\n }\n }\n });\n }\n }, [useSelection]);\n\n // Keep graph data refs current (used in event handlers)\n useEffect(() => {\n nodesRef.current = nodes;\n }, [nodes]);\n useEffect(() => {\n edgesRef.current = edges;\n }, [edges]);\n\n useEffect(() => {\n if (!containerRef.current || cyRef.current) return;\n isInitializedRef.current = true;\n cyRef.current = cytoscape({\n container: containerRef.current,\n elements: [],\n selectionType: \"additive\", // allow clicking multiple nodes without modifier\n style: [\n // Base node style with data mappers for dynamic properties\n {\n selector: \"node\",\n style: {\n \"background-color\": \"data(color)\", // Read color from element data\n \"background-opacity\": 0.9,\n width: \"data(size)\", // Read size from element data\n height: \"data(size)\",\n shape: \"ellipse\",\n label: \"data(label)\",\n // Dark gray text for readability on subtle gray background\n color: \"#374151\",\n \"font-size\": \"11px\", // Increased from 10px\n \"font-weight\": \"bold\",\n \"text-valign\": \"bottom\",\n \"text-halign\": \"center\",\n \"text-wrap\": \"wrap\",\n \"text-max-width\": \"120px\", // Increased from 100px for longer labels\n \"text-margin-y\": 5,\n // Subtle light gray label background\n \"text-background-color\": \"#e5e7eb\", // gray-200\n \"text-background-opacity\": 1,\n \"text-background-padding\": \"3px\",\n \"text-background-shape\": \"roundrectangle\",\n \"border-width\": 1,\n \"border-color\": \"#ffffff\",\n \"border-opacity\": 0.8,\n } as Record<string, unknown>,\n },\n // Override background color only when fill data is present\n {\n selector: \"node[fill]\",\n style: {\n \"background-color\": \"data(fill)\",\n },\n },\n {\n selector: \"edge\",\n style: {\n width: \"data(size)\", // Read width from element data\n \"line-color\": \"data(color)\", // Read color from element data\n \"target-arrow-color\": \"data(color)\",\n \"target-arrow-shape\": \"triangle\",\n \"curve-style\": \"bezier\",\n \"control-point-step-size\": 40,\n \"control-point-weight\": 0.5,\n opacity: 0.8,\n \"arrow-scale\": 0.8,\n \"mid-target-arrow-shape\": \"none\",\n \"source-endpoint\": \"outside-to-node-or-label\",\n \"target-endpoint\": \"outside-to-node-or-label\",\n },\n },\n // Dashed edges (when dashed property is true)\n {\n selector: \"edge[dashed]\",\n style: {\n \"line-style\": \"dashed\",\n },\n },\n // Show edge labels by default with good styling\n {\n selector: \"edge[label]\",\n style: {\n label: \"data(label)\",\n \"font-size\": \"10px\", // Increased from 8px for better readability\n \"font-weight\": \"500\", // Semi-bold for better visibility\n \"text-background-color\": \"#ffffff\",\n \"text-background-opacity\": 0.9, // Increased from 0.8 for better contrast\n \"text-background-padding\": \"3px\", // Increased from 2px\n \"text-background-shape\": \"roundrectangle\",\n \"text-rotation\": \"autorotate\",\n \"text-margin-y\": -8, // Adjusted for larger font\n color: \"#1a1a1a\", // Darker for better contrast\n },\n },\n {\n selector: \"edge:selected\",\n style: {\n \"line-color\": \"#ff1a1a\",\n \"target-arrow-color\": \"#ff1a1a\",\n width: 8, // even thicker\n \"z-index\": 999,\n \"font-size\": \"11px\",\n \"font-weight\": \"bold\",\n \"text-background-opacity\": 1,\n \"text-background-color\": \"#ffffff\",\n \"text-background-padding\": \"3px\",\n \"arrow-scale\": 1.35,\n opacity: 1,\n \"overlay-color\": \"#ff1a1a\",\n \"overlay-opacity\": 0.08,\n },\n },\n {\n selector: \"node:selected\",\n style: {\n \"border-width\": 10, // thicker circle outline\n \"border-color\": \"#ff1a1a\",\n \"border-opacity\": 1,\n \"background-opacity\": 1,\n \"text-background-opacity\": 1,\n \"text-background-color\": \"#ffffff\",\n \"text-background-padding\": \"4px\",\n \"overlay-color\": \"#ff1a1a\",\n \"overlay-opacity\": 0.18,\n width: 48, // slight size bump from 40\n height: 48,\n } as Record<string, unknown>,\n },\n ],\n layout: { name: \"grid\", fit: true, avoidOverlap: true, condense: true }, // initial quick layout\n wheelSensitivity: 0.2,\n });\n const cy = cyRef.current;\n if (cy) {\n setupCytoscapeEventHandlers({\n cy,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n clearSelectionStore,\n useGraphExploration,\n onCopyNode,\n });\n }\n return () => {\n cyRef.current?.destroy();\n cyRef.current = null;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Track element IDs to detect actual data changes (not just array reference changes)\n const elementIdsRef = useRef<string>(\"\");\n const lastLayoutRef = useRef<string>(\"\");\n const lastFitPaddingRef = useRef<number>(fitPadding);\n\n useEffect(() => {\n // Only process data changes when component is mounted and initialized\n const cy = cyRef.current;\n if (!cy || !isInitializedRef.current) return;\n\n // Create a stable key from element IDs to detect actual data changes\n const currentIds =\n nodes\n .map((n) => n.id_)\n .sort()\n .join(\",\") +\n \"|\" +\n edges\n .map((e) => e.id_)\n .sort()\n .join(\",\");\n\n // Classify whether we need a full update, just a refit, or can skip entirely\n const action = classifyUpdate({\n cy,\n currentIds,\n elementIdsRef,\n lastLayoutRef,\n lastFitPaddingRef,\n currentLayout,\n fitPadding,\n nodeCount: nodes.length,\n edgeCount: edges.length,\n });\n\n if (action === \"refit\") {\n lastFitPaddingRef.current = fitPadding;\n cy.fit(undefined, fitPadding);\n return;\n }\n if (action === \"skip\") {\n return;\n }\n\n // Full update path\n elementIdsRef.current = currentIds;\n lastLayoutRef.current = currentLayout;\n lastFitPaddingRef.current = fitPadding;\n\n // Use cytoscape-formatted elements from the adapter\n const { nodes: nodeElements, edges: edgeElements } = cytoData.elements;\n\n // Batch operations for better performance\n cy.batch(() => {\n cy.elements().remove();\n cy.add([...nodeElements, ...edgeElements]);\n });\n\n // Apply current selection state (initial mount / data refresh) without triggering re-render\n if (selectedNodeIdsRef.current.length > 0 || selectedEdgeRef.current) {\n cy.batch(() => {\n cy.elements().unselect();\n selectedNodeIdsRef.current.forEach((id: string) => cy.$id(id).select());\n if (selectedEdgeRef.current) {\n const edge = cy.$id(String(selectedEdgeRef.current.id_));\n if (edge) {\n edge.select();\n cy.$id(edge.data(\"source\")).select();\n cy.$id(edge.data(\"target\")).select();\n }\n }\n });\n }\n\n // Validate and resolve layout\n const chosen: StandardLayout = (ALLOWED_LAYOUTS as string[]).includes(\n currentLayout,\n )\n ? currentLayout\n : \"auto\";\n\n // Convert VisualGraphNode to format expected by getLayoutPreset (for CiSE clustering by label)\n const nodesForLayout = nodes.map((n) => ({\n id: String(n.id_),\n data: { label_: n.label_ },\n }));\n\n applyLayout({\n cy,\n chosen,\n nodeCount: nodes.length,\n nodesForLayout,\n fitPadding,\n });\n\n // Process pending focus action AFTER graph data is updated\n const pendingFocus = pendingFocusActionRef.current;\n if (pendingFocus) {\n processPendingFocus({\n cy,\n pendingFocus,\n edgesRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n selectedNodeIdsRef,\n selectedEdgeRef,\n pendingFocusActionRef,\n });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [nodes, edges, currentLayout, fitPadding]); // fitPadding tracked via ref to avoid full redraw\n\n // Mirror ReGraph behavior: clear selections when query is executed (prevents stale selections)\n // Don't clear on every node change (e.g., override additions), only on query execution\n useEffect(() => {\n if (!cyRef.current) return;\n cyRef.current.elements().unselect();\n clearSelectionStore();\n }, [lastDataChangeTime, clearSelectionStore]);\n\n // Subscribe to GraphFocus store\n useEffect(() => {\n const unsubscribe = useGraphFocus.subscribe((state) => {\n handleFocusStateChange({\n focusAction: state.focusAction,\n cyRef,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n pendingFocusActionRef,\n baseNormalized,\n });\n });\n\n return unsubscribe;\n }, [baseNormalized, setSelectedEdgeStore, setSelectedNodeIdsStore]);\n\n // Function to update the layout\n const updateLayout = (newLayout: StandardLayout) => {\n setCurrentLayout(newLayout);\n };\n\n // Function to fit the graph to the screen\n const fitToScreen = useCallback(() => {\n if (cyRef.current) {\n cyRef.current.fit(undefined, fitPadding);\n }\n }, [fitPadding]);\n\n // Re-fit when node set size changes (post cutover)\n useEffect(() => {\n fitToScreen();\n }, [nodes.length, fitToScreen]);\n\n // Handle window resize events only when component is mounted\n useEffect(() => {\n if (!isInitializedRef.current) return;\n\n const handleResize = () => cyRef.current?.resize();\n window.addEventListener(\"resize\", handleResize);\n return () => window.removeEventListener(\"resize\", handleResize);\n }, []);\n\n // Fullscreen state + ESC handler + body scroll lock + resize\n const { fullscreen, toggleFullscreen } = useFullscreen(fitToScreen, cyRef);\n\n // Pre-compute visibility flags and CSS classes to reduce JSX complexity\n const {\n outerClass,\n innerClass,\n showEmptyMessage,\n showFilteredMessage,\n showControls,\n } = computeGraphViewState({\n hasNodes: nodes.length > 0,\n hasHiddenElements,\n isFocusMode,\n fullscreen,\n });\n\n return (\n <div className={outerClass}>\n <div className={innerClass}>\n <div ref={containerRef} className=\"absolute inset-0\" />\n {showEmptyMessage && (\n <div className=\"absolute inset-0 flex items-center justify-center text-xs text-gray-500 pointer-events-none select-none\">\n No graph data to visualize (run a query or check the filters)\n </div>\n )}\n {showFilteredMessage && (\n <div className=\"absolute inset-0 flex items-center justify-center text-xs text-gray-500 pointer-events-none select-none\">\n All elements are hidden or filtered (click \"Reset Focus\" to restore)\n </div>\n )}\n {showControls && (\n <CytoscapeControls\n updateLayout={updateLayout}\n fitToScreen={fitToScreen}\n onResetView={() => {\n resetView();\n toast.success(\n isFocusMode ? \"Focus mode cleared\" : \"Hidden elements restored\",\n );\n }}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n extraToolbarContent={extraToolbarContent}\n zoomIn={() => {\n if (cyRef.current) {\n const z = cyRef.current.zoom();\n cyRef.current.zoom({\n level: Math.min(z * 1.2, 5),\n renderedPosition: {\n x: cyRef.current.width() / 2,\n y: cyRef.current.height() / 2,\n },\n });\n }\n }}\n zoomOut={() => {\n if (cyRef.current) {\n const z = cyRef.current.zoom();\n cyRef.current.zoom({\n level: Math.max(z / 1.2, 0.1),\n renderedPosition: {\n x: cyRef.current.width() / 2,\n y: cyRef.current.height() / 2,\n },\n });\n }\n }}\n currentLayout={currentLayout}\n fullscreen={fullscreen}\n toggleFullscreen={toggleFullscreen}\n />\n )}\n </div>\n </div>\n );\n}\n\nexport default CytoscapeGraph;\n","import { type ReactNode } from \"react\";\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n SimpleTooltip,\n} from \"@petrarca/sonnet-ui\";\nimport { LayoutPanelTop, Monitor, Frame, Eye, Minus } from \"lucide-react\";\nimport { StandardLayout } from \"./layoutPresets\";\nimport { RendererDropdown } from \"../shared/RendererDropdown\";\n\ntype Props = {\n updateLayout: (layout: StandardLayout) => void;\n fitToScreen: () => void;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n zoomIn: () => void;\n zoomOut: () => void;\n currentLayout: StandardLayout;\n fullscreen: boolean;\n toggleFullscreen: () => void;\n /** Optional callback when the user resets the view (show hidden / exit focus). */\n onResetView?: () => void;\n /** Optional extra toolbar content (e.g. clipboard UI) injected by the host app. */\n extraToolbarContent?: ReactNode;\n};\n\n/* ------------------------------------------------------------------ */\n/* ViewControls */\n/* ------------------------------------------------------------------ */\n\ntype ViewControlsProps = {\n zoomIn: () => void;\n zoomOut: () => void;\n fullscreen: boolean;\n toggleFullscreen: () => void;\n fitToScreen: () => void;\n hasHiddenElements: boolean;\n isFocusMode: boolean;\n onResetView?: () => void;\n};\n\nfunction ViewControls({\n zoomIn,\n zoomOut,\n fullscreen,\n toggleFullscreen,\n fitToScreen,\n hasHiddenElements,\n isFocusMode,\n onResetView,\n}: ViewControlsProps) {\n return (\n <>\n <SimpleTooltip label=\"Zoom In\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={zoomIn}>\n <span style={{ fontWeight: 600 }}>+</span>\n </Button>\n </SimpleTooltip>\n <SimpleTooltip label=\"Zoom Out\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={zoomOut}>\n <Minus />\n </Button>\n </SimpleTooltip>\n <SimpleTooltip label=\"Fullscreen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleFullscreen}>\n {!fullscreen ? <Monitor /> : <Frame />}\n </Button>\n </SimpleTooltip>\n <SimpleTooltip label=\"Fit to screen\" side=\"left\">\n <Button variant=\"ghost\" size=\"icon\" onClick={fitToScreen}>\n <Frame />\n </Button>\n </SimpleTooltip>\n {(hasHiddenElements || isFocusMode) && onResetView && (\n <SimpleTooltip\n label={isFocusMode ? \"Reset Focus\" : \"Show All Hidden\"}\n side=\"left\"\n >\n <Button variant=\"ghost\" size=\"icon\" onClick={onResetView}>\n <Eye />\n </Button>\n </SimpleTooltip>\n )}\n </>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* LayoutDropdown */\n/* ------------------------------------------------------------------ */\n\ntype LayoutGroup = {\n label: string;\n items: { layout: StandardLayout; name: string }[];\n};\n\nconst LAYOUT_GROUPS: LayoutGroup[] = [\n {\n label: \"Force-directed Layouts\",\n items: [\n { layout: \"cola\", name: \"Cola (Best for Knowledge Graphs)\" },\n { layout: \"fcose\", name: \"F-CoSE (Large Graphs)\" },\n { layout: \"cise\", name: \"CiSE (Clustered Circles)\" },\n { layout: \"cose\", name: \"CoSE\" },\n ],\n },\n {\n label: \"Hierarchical Layouts\",\n items: [\n { layout: \"dagre\", name: \"Dagre (Left to Right)\" },\n { layout: \"klay\", name: \"KLay (Layered)\" },\n { layout: \"elk\", name: \"ELK (Layered)\" },\n { layout: \"breadthfirst\", name: \"Breadth-first\" },\n { layout: \"tree\", name: \"Tree (Top-Down)\" },\n ],\n },\n {\n label: \"Other Layouts\",\n items: [\n { layout: \"concentric\", name: \"Concentric\" },\n { layout: \"circle\", name: \"Circle\" },\n { layout: \"grid\", name: \"Grid\" },\n ],\n },\n];\n\ntype LayoutDropdownProps = {\n currentLayout: StandardLayout;\n updateLayout: (layout: StandardLayout) => void;\n};\n\nfunction LayoutDropdown({ currentLayout, updateLayout }: LayoutDropdownProps) {\n return (\n <DropdownMenu>\n <SimpleTooltip label=\"Layout\" side=\"left\">\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <LayoutPanelTop />\n </Button>\n </DropdownMenuTrigger>\n </SimpleTooltip>\n\n <DropdownMenuContent side=\"left\" align=\"start\">\n {LAYOUT_GROUPS.map((group, groupIdx) => (\n <div key={group.label}>\n {groupIdx > 0 && <DropdownMenuSeparator />}\n <DropdownMenuLabel>{group.label}</DropdownMenuLabel>\n {group.items.map((item) => (\n <DropdownMenuItem\n key={item.layout}\n onClick={() => updateLayout(item.layout)}\n className={currentLayout === item.layout ? \"text-blue-600\" : \"\"}\n >\n {item.name}\n </DropdownMenuItem>\n ))}\n </div>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* CytoscapeControls (composed) */\n/* ------------------------------------------------------------------ */\n\nfunction CytoscapeControls({\n fitToScreen,\n hasHiddenElements,\n isFocusMode,\n updateLayout,\n zoomIn,\n zoomOut,\n currentLayout,\n fullscreen,\n toggleFullscreen,\n onResetView,\n extraToolbarContent,\n}: Props) {\n return (\n <div className=\"absolute right-2 top-2 flex flex-col border bg-white rounded-md shadow-sm z-10\">\n <RendererDropdown />\n <ViewControls\n zoomIn={zoomIn}\n zoomOut={zoomOut}\n fullscreen={fullscreen}\n toggleFullscreen={toggleFullscreen}\n fitToScreen={fitToScreen}\n hasHiddenElements={hasHiddenElements}\n isFocusMode={isFocusMode}\n onResetView={onResetView}\n />\n {extraToolbarContent}\n <LayoutDropdown\n currentLayout={currentLayout}\n updateLayout={updateLayout}\n />\n </div>\n );\n}\n\nexport default CytoscapeControls;\n","/**\n * Cytoscape Layout Presets\n *\n * Provides optimized layout configurations for knowledge graphs.\n * Each layout is tuned based on graph size (node count) for best performance and visual quality.\n */\n\nimport type cytoscape from \"cytoscape\";\ntype LayoutOptions = cytoscape.LayoutOptions;\n\nexport type StandardLayout =\n | \"auto\"\n | \"fcose\"\n | \"cola\"\n | \"dagre\"\n | \"klay\"\n | \"elk\"\n | \"cise\"\n | \"cose\"\n | \"concentric\"\n | \"breadthfirst\"\n | \"tree\"\n | \"circle\"\n | \"grid\"\n | \"random\";\n\nexport interface LayoutPresetOptions {\n layoutName: StandardLayout;\n count: number;\n /** Node data for cluster-based layouts (e.g., CiSE) */\n nodeData?: Array<{ id: string; data?: { label_?: string } }>;\n}\n\ntype NodeDataItem = { id: string; data?: { label_?: string } };\ntype LayoutFactory = (count: number, nodeData: NodeDataItem[]) => LayoutOptions;\n\n// --- Individual layout factory functions ---\n\nfunction buildColaLayout(count: number): LayoutOptions {\n return {\n name: \"cola\",\n // Always animate regardless of node count for better user experience\n animate: true,\n // Increase refresh rate for smoother animation\n refresh: 2,\n // Limit simulation time to prevent hanging with large graphs\n maxSimulationTime: 2000,\n // Prevent grabbing during simulation for better performance\n ungrabifyWhileSimulating: true,\n fit: true,\n padding: 50,\n // Scale spacing based on node count for better distribution\n nodeSpacing: () => Math.max(10, 30 - Math.log(count) * 3),\n edgeLength: () => Math.max(80, 150 - Math.log(count) * 10),\n // Always avoid node overlap\n avoidOverlap: true,\n // Prevent infinite running\n infinite: false,\n // Add convergence threshold for faster completion with large graphs\n convergenceThreshold: 0.01,\n // Add randomize false to maintain consistent layouts\n randomize: false,\n } as unknown as LayoutOptions;\n}\n\nfunction buildDagreLayout(count: number): LayoutOptions {\n return {\n name: \"dagre\",\n rankDir: \"LR\", // Left to right\n // Much more compact separation for tree-like hierarchical layouts\n rankSep: Math.min(80, 50 + Math.sqrt(count) * 1.5), // Further reduced\n nodeSep: Math.min(40, 25 + Math.sqrt(count) * 0.8), // Further reduced\n edgeSep: Math.min(10, 5 + Math.log(count) * 0.5), // Further reduced\n // Always animate for better user experience\n animate: true,\n fit: true,\n padding: 30, // Reduced for more compact layout\n } as unknown as LayoutOptions;\n}\n\nfunction buildTreeLayout(count: number): LayoutOptions {\n // Tree (top-down) using breadthfirst; roots auto-detected later (indegree 0)\n return {\n name: \"breadthfirst\",\n fit: true,\n padding: 30, // Reduced for more compact layout\n animate: true,\n directed: true,\n spacingFactor: Math.min(0.9, 0.7 + 60 / (count + 50)), // Compact spacing: 0.7 to 0.9\n circle: false,\n } as LayoutOptions;\n}\n\nfunction buildKlayLayout(count: number): LayoutOptions {\n // NOTE: cytoscape-klay only supports a well-defined subset of options.\n // Passing unknown props inside the nested `klay` object (like nodeSpacing / edgeSpacing)\n // can cause runtime errors in some builds (observed as generic [object Object]).\n // We therefore keep to documented options: direction, spacing, layoutHierarchy,\n // nodeLayering, thoroughness, edgeRouting, mergeEdges, crossingMinimization.\n return {\n name: \"klay\",\n nodeDimensionsIncludeLabels: true,\n fit: true,\n padding: 30, // Reduced for more compact layout\n animate: true,\n animationDuration: 500,\n klay: {\n direction: \"RIGHT\",\n spacing: Math.min(30, 12 + Math.sqrt(count) * 1.5), // Further reduced for much denser layout\n nodeLayering: \"NETWORK_SIMPLEX\",\n layoutHierarchy: true,\n // Increase thoroughness a bit for nicer layering on medium graphs\n thoroughness: count < 400 ? 30 : 10,\n },\n } as unknown as LayoutOptions;\n}\n\nfunction buildFcoseLayout(count: number): LayoutOptions {\n return {\n name: \"fcose\",\n animate: true,\n animationDuration: 600,\n fit: true,\n padding: 50,\n // Scale edge length based on node count\n idealEdgeLength: Math.min(150, 80 + Math.sqrt(count) * 3),\n // Scale repulsion based on node count\n nodeRepulsion: Math.min(30000, 4000 + count * 50),\n // Scale separation based on node count\n nodeSeparation: Math.min(100, 50 + Math.sqrt(count) * 2),\n // Adjust gravity based on node count\n gravity: 0.3,\n // Never randomize for consistent layouts\n randomize: false,\n // Consistent energy for all graph sizes\n initialEnergyOnIncremental: 0.5,\n // Always use sampling for better performance\n samplingType: true,\n // Use default quality for best balance\n quality: \"default\",\n // Limit iterations for large graphs\n numIter: Math.min(2500, 1000 + count * 5),\n // Use consistent cooling factor\n coolingFactor: 0.95,\n // Prevent infinite running\n infinite: false,\n } as unknown as LayoutOptions;\n}\n\nfunction buildCiseLayout(\n count: number,\n nodeData: NodeDataItem[],\n): LayoutOptions {\n // Cluster nodes by label for CiSE layout\n const labelToIds: Record<string, string[]> = {};\n nodeData.forEach((n) => {\n const label = n.data?.label_ || \"Unknown\";\n if (!labelToIds[label]) labelToIds[label] = [];\n labelToIds[label].push(n.id);\n });\n const clusters = Object.values(labelToIds).filter((arr) => arr.length > 0);\n return {\n name: \"cise\",\n animate: true,\n animationDuration: 600,\n clusters,\n nodeSeparation: Math.min(40, 20 + Math.sqrt(count)),\n idealInterClusterEdgeLengthCoefficient: 1.2,\n allowNodesInsideCircle: false,\n maxRatioOfNodesInsideCircle: 0.1,\n springCoeff: 0.45,\n nodeRepulsion: 4500,\n gravity: 0.25,\n gravityRange: 3.8,\n fit: true,\n padding: 50,\n } as unknown as LayoutOptions;\n}\n\nfunction buildElkLayout(count: number): LayoutOptions {\n // ELK (Eclipse Layout Kernel) good for layered + constraint aware layouts.\n // Keep config minimal to avoid large bundle of options; adjust spacing dynamically.\n return {\n name: \"elk\",\n // elk algorithm options under `elk` key\n elk: {\n algorithm: \"layered\",\n \"elk.direction\": \"RIGHT\",\n \"elk.layered.spacing.nodeNodeBetweenLayers\": Math.min(\n 150,\n 60 + Math.sqrt(count) * 10,\n ),\n \"elk.spacing.nodeNode\": Math.min(120, 40 + Math.sqrt(count) * 8),\n \"elk.layered.crossingMinimization.semiInteractive\": \"true\",\n },\n fit: true,\n padding: 50,\n animate: true,\n animationDuration: 500,\n } as unknown as LayoutOptions;\n}\n\nfunction buildCoseLayout(count: number): LayoutOptions {\n return {\n name: \"cose\",\n // Always animate for better user experience\n animate: true,\n fit: true,\n padding: 50,\n // Scale overlap based on node count\n nodeOverlap: Math.min(30, 15 + Math.sqrt(count)),\n // Scale spacing based on node count\n componentSpacing: Math.min(150, 80 + Math.sqrt(count) * 2),\n // Increase refresh for smoother animation\n refresh: 10,\n // Scale parameters based on node count\n idealEdgeLength: () => Math.min(150, 80 + Math.sqrt(count) * 2),\n edgeElasticity: () => Math.min(150, 80 + Math.sqrt(count) * 2),\n nodeRepulsion: () => Math.min(600000, 200000 + count * 1000),\n nestingFactor: 1.2,\n // Adjust gravity based on node count\n gravity: Math.min(100, 60 + Math.sqrt(count)),\n // Limit iterations for large graphs\n numIter: Math.min(2500, 1000 + count * 5),\n // Use consistent cooling factor\n coolingFactor: 0.95,\n };\n}\n\nfunction buildConcentricLayout(count: number): LayoutOptions {\n return {\n name: \"concentric\",\n fit: true,\n padding: 50,\n // Always animate for better user experience\n animate: true,\n // Scale spacing based on node count\n minNodeSpacing: Math.min(60, 40 + Math.log(count) * 3),\n // Adjust level width based on node count\n levelWidth: () => Math.max(1, 3 - Math.log(count) * 0.3),\n // Use degree for concentric layout\n concentric: (node: cytoscape.NodeSingular) => node.degree(),\n // Start from outside for better distribution\n startAngle: Math.PI * 1.5,\n } as LayoutOptions;\n}\n\nfunction buildBreadthfirstLayout(count: number): LayoutOptions {\n return {\n name: \"breadthfirst\",\n fit: true,\n padding: 50,\n // Always animate for better user experience\n animate: true,\n directed: true,\n // Scale spacing based on node count\n spacingFactor: Math.min(1.8, 1.2 + 100 / (count + 50)),\n // Add circle option for better distribution with smaller graphs\n circle: count < 100,\n } as LayoutOptions;\n}\n\nfunction buildCircleLayout(count: number): LayoutOptions {\n return {\n name: \"circle\",\n fit: true,\n padding: 50,\n // Always animate for better user experience\n animate: true,\n // Scale radius based on node count\n radius: Math.min(500, count * 3 + 50),\n // Add startAngle for consistent layout\n startAngle: Math.PI / 2,\n };\n}\n\nfunction buildGridLayout(count: number): LayoutOptions {\n // Optimized grid: favor a wider layout (common landscape viewport) and add\n // extra overlap padding so long wrapped labels don't collide.\n const approxCols = Math.ceil(Math.sqrt(count * 1.5)); // widen vs square\n const cols = Math.max(approxCols, 1);\n const rows = Math.max(Math.ceil(count / cols), 1);\n return {\n name: \"grid\",\n fit: true,\n padding: 40,\n avoidOverlap: true,\n // Extra space around each node beyond actual dimensions\n avoidOverlapPadding: Math.min(80, 20 + Math.log(count + 1) * 10),\n // Do NOT condense; we want uniform padding for labels\n condense: false,\n animate: true,\n animationDuration: 400,\n rows,\n cols,\n } as unknown as LayoutOptions;\n}\n\n// --- Layout registry ---\n\nconst layoutFactories: Record<string, LayoutFactory> = {\n cola: buildColaLayout,\n dagre: buildDagreLayout,\n tree: buildTreeLayout,\n klay: buildKlayLayout,\n fcose: buildFcoseLayout,\n cise: buildCiseLayout,\n elk: buildElkLayout,\n cose: buildCoseLayout,\n concentric: buildConcentricLayout,\n breadthfirst: buildBreadthfirstLayout,\n circle: buildCircleLayout,\n grid: buildGridLayout,\n};\n\n/**\n * Get optimized layout configuration for cytoscape based on layout type and graph size.\n *\n * @param options - Layout configuration options\n * @returns Cytoscape LayoutOptions\n */\nexport function getLayoutPreset(options: LayoutPresetOptions): LayoutOptions {\n let { layoutName } = options;\n const { count, nodeData = [] } = options;\n\n // Always use cola for knowledge graphs regardless of size\n // It provides the best balance of performance and quality\n if (layoutName === \"auto\") {\n layoutName = \"cola\";\n }\n\n const factory = layoutFactories[layoutName] ?? layoutFactories.grid;\n return factory(count, nodeData);\n}\n","import type cytoscape from \"cytoscape\";\ntype Core = cytoscape.Core;\nimport { VisualGraphNode } from \"../../models/visual-graph\";\nimport { devLog, errorLog } from \"@petrarca/sonnet-core\";\nimport type { StoreApi, UseBoundStore } from \"zustand\";\nimport type { GraphExplorationStore } from \"../../stores/GraphExploration\";\nimport { toast } from \"sonner\";\n\n/** cytoscape-cxtmenu adds `.cxtmenu()` at runtime but has no official TS types. */\ntype CoreWithCxtmenu = Core & {\n cxtmenu(options: Record<string, unknown>): unknown;\n};\n\ninterface NodeContextMenuOptions {\n cy: Core;\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n onCopyNode?: (node: VisualGraphNode) => void;\n}\n\ninterface EdgeContextMenuOptions {\n cy: Core;\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n}\n\n// Node context menu configuration\nexport const createNodeContextMenu = ({\n cy,\n useGraphExploration,\n onCopyNode,\n}: NodeContextMenuOptions) => {\n devLog(\"[CxtMenu] Initializing node context menu\");\n return (cy as CoreWithCxtmenu).cxtmenu({\n selector: \"node\",\n commands: [\n {\n content: \"Focus\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Focus on node and neighborhood:\", nodeId);\n useGraphExploration.getState().setFocusModeWithNeighborhood(nodeId);\n },\n },\n {\n content: \"Copy\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n devLog(\"[CxtMenu] Copy node to clipboard\");\n\n // Get full VisualGraphNode from element data\n const visualGraph: VisualGraphNode | undefined =\n ele.data(\"visualGraph\");\n\n if (visualGraph) {\n onCopyNode?.(visualGraph);\n } else {\n errorLog(\"[CxtMenu] visualGraph not found in element data\");\n }\n },\n },\n {\n content: \"Hide Node\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Hide node:\", nodeId);\n useGraphExploration.getState().hideElements([nodeId]);\n },\n },\n {\n content: \"Hide Incoming\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Hide incoming (predecessors) of node:\", nodeId);\n useGraphExploration.getState().hideNodeIncoming(nodeId);\n },\n },\n {\n content: \"Hide Outgoing\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Hide outgoing (successors) of node:\", nodeId);\n useGraphExploration.getState().hideNodeOutgoing(nodeId);\n },\n },\n {\n content: \"Expand\",\n select: async (ele: any) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Expanding node:\", nodeId);\n\n try {\n await useGraphExploration.getState().expandNode(nodeId);\n devLog(\"[CxtMenu] Expansion complete\");\n } catch (error) {\n errorLog(\"[CxtMenu] Expansion failed:\", error);\n toast.error(\"Failed to expand node\");\n }\n },\n },\n ],\n menuRadius: 60, // Increased for more items (default is 100)\n fillColor: \"rgba(0, 0, 0, 0.75)\",\n activeFillColor: \"rgba(59, 130, 246, 0.75)\", // blue-500\n activePadding: 10,\n indicatorSize: 12,\n separatorWidth: 2,\n spotlightPadding: 2,\n adaptativeNodeSpotlightRadius: true,\n minSpotlightRadius: 12,\n maxSpotlightRadius: 20,\n openMenuEvents: \"cxttapstart taphold\",\n itemColor: \"white\",\n itemTextShadowColor: \"transparent\",\n zIndex: 9999,\n atMouse: false,\n });\n};\n\n// Edge context menu configuration\nexport const createEdgeContextMenu = ({\n cy,\n useGraphExploration,\n}: EdgeContextMenuOptions) => {\n return (cy as CoreWithCxtmenu).cxtmenu({\n selector: \"edge\",\n commands: [\n {\n content: \"Focus\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\n \"[CxtMenu] Focus on edge (auto-direction based on selection):\",\n edgeId,\n );\n useGraphExploration.getState().focusEdge(edgeId);\n },\n },\n {\n content: \"Focus Edge Type\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\"[CxtMenu] Focus on edge type:\", edgeId);\n useGraphExploration.getState().focusOnEdgeType(edgeId);\n },\n },\n {\n content: \"Hide Forward Path\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\n \"[CxtMenu] Hide forward path (edge + target + downstream):\",\n edgeId,\n );\n useGraphExploration.getState().hideEdgeForwardPath(edgeId);\n },\n },\n {\n content: \"Hide Reverse Path\",\n select: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const edgeId = ele.id();\n devLog(\n \"[CxtMenu] Hide reverse path (edge + source + upstream):\",\n edgeId,\n );\n useGraphExploration.getState().hideEdgeReversePath(edgeId);\n },\n },\n ],\n menuRadius: 90, // Increased for more items\n fillColor: \"rgba(0, 0, 0, 0.75)\",\n activeFillColor: \"rgba(239, 68, 68, 0.75)\", // red-500\n activePadding: 10,\n indicatorSize: 12,\n separatorWidth: 2,\n spotlightPadding: 2,\n openMenuEvents: \"cxttapstart taphold\",\n itemColor: \"white\",\n itemTextShadowColor: \"transparent\",\n zIndex: 9999,\n atMouse: false,\n });\n};\n","import { type ReactNode } from \"react\";\nimport { useGraphRenderer } from \"../hooks/useGraphRenderer\";\nimport ReaGraph from \"./rea/ReaGraph\";\nimport CytoscapeGraph from \"./cyto/CytoscapeGraph\";\nimport type { VisualGraphNode } from \"../models/visual-graph\";\n\nexport interface GraphVisualizerProps {\n /** Callback when a node is copied (e.g. to clipboard). Decouples renderers from clipboard store. */\n onCopyNode?: (node: VisualGraphNode) => void;\n /** Extra toolbar content (e.g. clipboard UI) injected into the renderer toolbar. */\n extraToolbarContent?: ReactNode;\n}\n\nfunction GraphVisualizer({\n onCopyNode,\n extraToolbarContent,\n}: GraphVisualizerProps) {\n const { renderer } = useGraphRenderer();\n\n return (\n <div className=\"relative w-full h-full flex flex-col overflow-hidden\">\n {/* Render only the active graph component */}\n <div className=\"flex-1 h-full\">\n {renderer === \"reagraph\" && (\n <ReaGraph\n key=\"reagraph\"\n onCopyNode={onCopyNode}\n extraToolbarContent={extraToolbarContent}\n />\n )}\n {renderer === \"cytoscape\" && (\n <CytoscapeGraph\n key=\"cytoscape\"\n onCopyNode={onCopyNode}\n extraToolbarContent={extraToolbarContent}\n />\n )}\n </div>\n </div>\n );\n}\n\nexport default GraphVisualizer;\n","import { Card } from \"@petrarca/sonnet-ui\";\nimport NodeInfoCard from \"./NodeInfoCard\";\nimport EdgeInfoCard from \"./EdgeInfoCard\";\nimport Overview from \"./Overview\";\nimport { useWorkspaceSelection } from \"../../hooks/useWorkspaceStores\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport { type ReactNode, useMemo } from \"react\";\nimport type { SelectionStore } from \"../../stores/Selection\";\n\ninterface ActionPanelProps {\n /** Optional actions rendered at the top of the panel (e.g. CRUD buttons) */\n actions?: ReactNode;\n}\n\nfunction ActionPanel({ actions }: ActionPanelProps) {\n // Get workspace-scoped store\n const useSelection = useWorkspaceSelection();\n\n // Select only the specific slices we need from the store to reduce unnecessary re-renders.\n const selectedNodeIds = useSelection(\n (s: SelectionStore) => s.selectedNodeIds,\n );\n const selectedEdge = useSelection((s: SelectionStore) => s.selectedEdge);\n const live = useLiveGraphData();\n\n // Memoize selected node objects so referential identity only changes when inputs change.\n const selectedNodes = useMemo(\n () =>\n selectedNodeIds\n .map((id) => live.normalized.nodesById[id])\n .filter(Boolean),\n [selectedNodeIds, live.normalized],\n );\n\n const firstNode = selectedNodes[0];\n const secondNode = selectedNodes?.[1];\n const hasEdge = !!selectedEdge;\n const showOverview = !firstNode && !hasEdge;\n\n return (\n <Card\n className=\"h-full min-w-64 flex flex-col bg-card shadow-none p-4\"\n style={{ maxHeight: \"100%\", overflow: \"hidden\" }}\n >\n {actions && <div className=\"flex-shrink-0 mb-2\">{actions}</div>}\n <div className=\"flex-1 overflow-auto pr-1\">\n <div className=\"flex flex-col gap-3\">\n {firstNode && <NodeInfoCard node={firstNode} />}\n {hasEdge && selectedEdge && <EdgeInfoCard edge={selectedEdge} />}\n {secondNode && <NodeInfoCard node={secondNode} />}\n {showOverview && <Overview />}\n </div>\n </div>\n </Card>\n );\n}\n\nexport default ActionPanel;\n","import { useState } from \"react\";\nimport {\n Card,\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@petrarca/sonnet-ui\";\nimport { VisualGraphNode } from \"../../models/visual-graph\";\nimport { copyTextToClipboard } from \"@petrarca/sonnet-core\";\n\ntype Props = {\n node: VisualGraphNode;\n};\n\nfunction NodeInfoCard({ node }: Props) {\n const [showProperties, setShowProperties] = useState(false);\n\n return (\n <Card\n className=\"w-full rounded-lg overflow-hidden bg-muted/30 border shadow-none p-3\"\n style={{\n borderLeft: `4px solid ${node.visual.color}`,\n }}\n >\n {/* Node type label */}\n <p className=\"text-sm leading-tight font-medium mb-0\">{node.label_}</p>\n\n {/* Display name from visual enrichment */}\n <p className=\"text-sm leading-tight mb-1\">{node.visual.displayName}</p>\n\n {/* Internal node ID */}\n <p\n className=\"text-xs text-muted-foreground cursor-pointer select-all mb-2\"\n onClick={() => copyTextToClipboard(String(node.id_))}\n title=\"Click to copy id\"\n >\n {node.id_}\n </p>\n\n {/* Properties collapsible */}\n <Collapsible open={showProperties} onOpenChange={setShowProperties}>\n <CollapsibleTrigger asChild>\n <button className=\"text-xs cursor-pointer\">\n {showProperties ? \"Hide\" : \"Show more\"}\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <ul className=\"list-none mt-2\">\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1\">\n Properties\n </p>\n {Object.entries(node.properties_ || {}).map(([key, value]) => (\n <li key={key} className=\"mb-2 leading-tight\">\n <p className=\"text-xs text-muted-foreground uppercase tracking-wide\">\n {key}\n </p>\n <p\n className=\"text-sm truncate max-w-[190px] cursor-pointer\"\n onClick={() => copyTextToClipboard(String(value))}\n title=\"Click to copy value\"\n >\n {String(value)}\n </p>\n </li>\n ))}\n </ul>\n </CollapsibleContent>\n </Collapsible>\n </Card>\n );\n}\n\nexport default NodeInfoCard;\n","import { useState } from \"react\";\nimport { VisualGraphEdge } from \"../../models/visual-graph\";\nimport {\n Card,\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"@petrarca/sonnet-ui\";\nimport { ArrowDown } from \"lucide-react\";\nimport { copyTextToClipboard } from \"@petrarca/sonnet-core\";\n\ntype Props = {\n edge: VisualGraphEdge;\n};\n\nfunction EdgeInfoCard({ edge }: Props) {\n const [showProperties, setShowProperties] = useState(false);\n\n return (\n <Card\n className=\"w-full rounded-lg overflow-hidden bg-muted/30 border shadow-none p-3\"\n style={{\n borderLeft: `4px solid ${edge.visual.color}`,\n }}\n >\n {/* Edge type label */}\n <p className=\"text-sm leading-tight mb-1\">\n <ArrowDown className=\"inline-block mr-1 opacity-70 align-middle h-3.5 w-3.5\" />\n <strong className=\"font-medium align-middle\">{edge.label_}</strong>\n </p>\n\n {/* Internal edge ID */}\n {edge.id_ && (\n <p\n className=\"text-xs text-muted-foreground select-all cursor-pointer mt-1 mb-2\"\n title=\"Click to copy edge id\"\n onClick={() => copyTextToClipboard(String(edge.id_))}\n >\n {edge.id_}\n </p>\n )}\n\n {/* Properties display */}\n {edge.properties_ && Object.keys(edge.properties_).length > 0 && (\n <Collapsible open={showProperties} onOpenChange={setShowProperties}>\n <CollapsibleTrigger asChild>\n <button className=\"text-xs cursor-pointer\">\n {showProperties ? \"Hide\" : \"Show more\"}\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent>\n <ul className=\"list-none mt-2\">\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1\">\n Properties\n </p>\n {Object.entries(edge.properties_ || {}).map(([key, value]) => (\n <li key={key} className=\"mb-2 leading-tight\">\n <p className=\"text-xs text-muted-foreground uppercase tracking-wide\">\n {key}\n </p>\n <p\n className=\"text-sm truncate max-w-[190px] cursor-pointer\"\n onClick={() => copyTextToClipboard(String(value))}\n title=\"Click to copy value\"\n >\n {String(value)}\n </p>\n </li>\n ))}\n </ul>\n </CollapsibleContent>\n </Collapsible>\n )}\n </Card>\n );\n}\n\nexport default EdgeInfoCard;\n","import { useWorkspaceGraphFilter } from \"../../hooks/useWorkspaceStores\";\nimport { Badge } from \"@petrarca/sonnet-ui\";\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport { formatNumber, devLog } from \"@petrarca/sonnet-core\";\nimport { useMemo } from \"react\";\n\n/**\n * Compute a mapping from edge labels to the node labels they connect.\n * Uses actual graph data (not schema) to determine which node labels are affected.\n */\nfunction computeEdgeToNodeLabels(\n nodesById: Record<string, { label_: string }>,\n edgesById: Record<\n string,\n { label_: string; start_id_: number; end_id_: number }\n >,\n): Record<string, string[]> {\n const mapping: Record<string, Set<string>> = {};\n\n for (const edge of Object.values(edgesById)) {\n const edgeLabel = edge.label_;\n const startNode = nodesById[String(edge.start_id_)];\n const endNode = nodesById[String(edge.end_id_)];\n\n if (!mapping[edgeLabel]) {\n mapping[edgeLabel] = new Set();\n }\n\n if (startNode) mapping[edgeLabel].add(startNode.label_);\n if (endNode) mapping[edgeLabel].add(endNode.label_);\n }\n\n // Convert Sets to arrays\n const result: Record<string, string[]> = {};\n for (const [edgeLabel, nodeLabels] of Object.entries(mapping)) {\n result[edgeLabel] = Array.from(nodeLabels);\n }\n return result;\n}\n\nfunction resolveBadgeColor(\n isAllDisabled: boolean,\n filters: string[],\n label: string,\n colorPalette: Record<string, string>,\n activeColor: string,\n): string {\n if (isAllDisabled) return colorPalette[\"faded\"];\n if (filters.length === 0 || filters.includes(label))\n return colorPalette[activeColor];\n return colorPalette[\"faded\"];\n}\n\nfunction AllToggleBadge({\n allDisabled,\n colorPalette,\n count,\n onToggle,\n badgeKey,\n}: {\n allDisabled: boolean;\n colorPalette: Record<string, string>;\n count: number;\n onToggle: () => void;\n badgeKey: string;\n}) {\n const bgColor = allDisabled ? colorPalette[\"faded\"] : colorPalette[\"neutral\"];\n return (\n <Badge\n key={badgeKey}\n className=\"cursor-pointer text-xs px-2.5 py-0.5\"\n style={{\n textTransform: \"none\",\n backgroundColor: bgColor,\n borderRadius: \"10px\",\n }}\n onClick={onToggle}\n >\n * ({formatNumber(count)})\n </Badge>\n );\n}\n\nfunction NodeLabelBadges({\n labels,\n labelCounts,\n colorPalette,\n allLabelsDisabled,\n nodeLabelFilters,\n toggleNodeLabelFilter,\n}: {\n labels: string[];\n labelCounts: Record<string, number>;\n colorPalette: Record<string, string>;\n allLabelsDisabled: boolean;\n nodeLabelFilters: string[];\n toggleNodeLabelFilter: (label: string, allLabels: string[]) => void;\n}) {\n return labels.map((label) => {\n const bgColor = resolveBadgeColor(\n allLabelsDisabled,\n nodeLabelFilters,\n label,\n colorPalette,\n label,\n );\n return (\n <Badge\n key={label}\n className=\"cursor-pointer text-xs px-2.5 py-0.5\"\n style={{\n textTransform: \"none\",\n backgroundColor: bgColor,\n borderRadius: \"10px\",\n }}\n onClick={() => toggleNodeLabelFilter(label, labels)}\n >\n {label} ({formatNumber(labelCounts[label])})\n </Badge>\n );\n });\n}\n\nfunction EdgeLabelBadges({\n labels,\n edgeLabelCounts,\n colorPalette,\n allEdgeLabelsDisabled,\n edgeLabelFilters,\n toggleEdgeLabelFilter,\n edgeToNodeLabels,\n}: {\n labels: string[];\n edgeLabelCounts: Record<string, number>;\n colorPalette: Record<string, string>;\n allEdgeLabelsDisabled: boolean;\n edgeLabelFilters: string[];\n toggleEdgeLabelFilter: (\n label: string,\n allLabels: string[],\n mapping: Record<string, string[]>,\n ) => void;\n edgeToNodeLabels: Record<string, string[]>;\n}) {\n return labels.map((label) => {\n const bgColor = resolveBadgeColor(\n allEdgeLabelsDisabled,\n edgeLabelFilters,\n label,\n colorPalette,\n \"neutral\",\n );\n return (\n <Badge\n key={label}\n className=\"cursor-pointer text-xs px-2.5 py-0.5\"\n style={{\n textTransform: \"none\",\n backgroundColor: bgColor,\n borderRadius: \"10px\",\n }}\n onClick={() => toggleEdgeLabelFilter(label, labels, edgeToNodeLabels)}\n >\n {label} ({formatNumber(edgeLabelCounts[label])})\n </Badge>\n );\n });\n}\n\n/** Renders the graph overview with node/edge label filter badges. */\nfunction GraphOverview({\n stats,\n colorPalette,\n labelCounts,\n edgeLabelCounts,\n edgeToNodeLabels,\n}: {\n stats: { nodes: number; edges: number };\n colorPalette: Record<string, string>;\n labelCounts: Record<string, number>;\n edgeLabelCounts: Record<string, number>;\n edgeToNodeLabels: Record<string, string[]>;\n}) {\n const useGraphFilter = useWorkspaceGraphFilter();\n const nodeLabelFilters = useGraphFilter((state) => state.nodeLabelFilters);\n const allLabelsDisabled = useGraphFilter((state) => state.allLabelsDisabled);\n const edgeLabelFilters = useGraphFilter((state) => state.edgeLabelFilters);\n const allEdgeLabelsDisabled = useGraphFilter(\n (state) => state.allEdgeLabelsDisabled,\n );\n const toggleNodeLabelFilter = useGraphFilter(\n (state) => state.toggleNodeLabelFilter,\n );\n const clearNodeLabelFilters = useGraphFilter(\n (state) => state.clearNodeLabelFilters,\n );\n const toggleAllLabelsDisabled = useGraphFilter(\n (state: any) => state.toggleAllLabelsDisabled,\n );\n const toggleEdgeLabelFilter = useGraphFilter(\n (state: any) => state.toggleEdgeLabelFilter,\n );\n const clearEdgeLabelFilters = useGraphFilter(\n (state: any) => state.clearEdgeLabelFilters,\n );\n const toggleAllEdgeLabelsDisabled = useGraphFilter(\n (state: any) => state.toggleAllEdgeLabelsDisabled,\n );\n\n const allLabels = Object.keys(labelCounts).sort();\n devLog(\"[Overview] Rendering labels\", {\n labels: allLabels,\n colorKeys: Object.keys(colorPalette || {}),\n labelCounts: labelCounts,\n stats: stats,\n });\n\n const allEdgeLabels = Object.keys(edgeLabelCounts || {}).sort();\n\n const handleNodeToggle = () => {\n if (allLabelsDisabled) {\n toggleAllLabelsDisabled();\n clearNodeLabelFilters();\n } else {\n toggleAllLabelsDisabled();\n }\n };\n\n const handleEdgeToggle = () => {\n if (allEdgeLabelsDisabled) {\n toggleAllEdgeLabelsDisabled();\n clearEdgeLabelFilters();\n } else {\n toggleAllEdgeLabelsDisabled();\n }\n };\n\n return (\n <>\n <p className=\"mt-2 text-sm font-semibold\">Overview</p>\n\n {allLabels.length > 0 && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2\">\n Node Labels\n </p>\n <div className=\"flex flex-col items-start gap-2\">\n <AllToggleBadge\n allDisabled={allLabelsDisabled}\n colorPalette={colorPalette}\n count={stats.nodes}\n onToggle={handleNodeToggle}\n badgeKey=\"all\"\n />\n <NodeLabelBadges\n labels={allLabels}\n labelCounts={labelCounts}\n colorPalette={colorPalette}\n allLabelsDisabled={allLabelsDisabled}\n nodeLabelFilters={nodeLabelFilters}\n toggleNodeLabelFilter={toggleNodeLabelFilter}\n />\n </div>\n </div>\n )}\n {allEdgeLabels.length > 0 && (\n <div>\n <p className=\"text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2\">\n Edge Types\n </p>\n <div className=\"flex flex-col items-start gap-2\">\n <AllToggleBadge\n allDisabled={allEdgeLabelsDisabled}\n colorPalette={colorPalette}\n count={stats.edges}\n onToggle={handleEdgeToggle}\n badgeKey=\"edge-all\"\n />\n <EdgeLabelBadges\n labels={allEdgeLabels}\n edgeLabelCounts={edgeLabelCounts}\n colorPalette={colorPalette}\n allEdgeLabelsDisabled={allEdgeLabelsDisabled}\n edgeLabelFilters={edgeLabelFilters}\n toggleEdgeLabelFilter={toggleEdgeLabelFilter}\n edgeToNodeLabels={edgeToNodeLabels}\n />\n </div>\n </div>\n )}\n </>\n );\n}\n\nfunction Overview() {\n const { stats, colorPalette, labelCounts, edgeLabelCounts, baseNormalized } =\n useLiveGraphData();\n\n // Compute edge-to-node-labels mapping from actual graph data\n const edgeToNodeLabels = useMemo(() => {\n if (!baseNormalized?.nodesById || !baseNormalized?.edgesById) return {};\n return computeEdgeToNodeLabels(\n baseNormalized.nodesById,\n baseNormalized.edgesById,\n );\n }, [baseNormalized]);\n\n if (stats && stats.values != null && stats.values > 0) {\n return (\n <>\n <p className=\"mt-2 text-sm font-semibold\">Overview</p>\n\n <p className=\"text-sm text-muted-foreground\">\n {formatNumber(stats.values)} Values\n </p>\n </>\n );\n }\n\n if (stats && stats.nodes > 0 && colorPalette) {\n return (\n <GraphOverview\n stats={stats}\n colorPalette={colorPalette}\n labelCounts={labelCounts}\n edgeLabelCounts={edgeLabelCounts}\n edgeToNodeLabels={edgeToNodeLabels}\n />\n );\n }\n\n return null;\n}\n\nexport default Overview;\n","/**\n * GraphA11yList — accessible DOM mirror of the graph's selectable elements.\n *\n * Cytoscape (canvas) and Reagraph (WebGL) draw nodes/edges OUTSIDE the DOM, so\n * they are invisible to screen readers, keyboard users, and DOM-based\n * automation (Playwright, AI agents). This component renders a real,\n * keyboard-focusable list of `<button>`s — one per node and edge — that drives\n * the SAME selection store the canvas reads. Activating a button selects the\n * element; the detail panel (which reads the store) updates exactly as if the\n * user had clicked it on the canvas.\n *\n * Renderer-independent (it drives the store, not the renderer) and\n * **virtualized** (`@tanstack/react-virtual`) so it stays performant for very\n * large result sets — only the visible rows are in the DOM.\n *\n * By default it is visually hidden (`sr-only`-style) but fully present in the\n * a11y tree; pass `visible` to render it on-screen (e.g. an outline panel).\n *\n * Each button carries stable handles for automation/tests:\n * - nodes: `data-graph-node-id`, `data-testid=\"graph-node-<id>\"`\n * - edges: `data-graph-edge-id`, `data-testid=\"graph-edge-<id>\"`\n */\nimport { useMemo, useRef } from \"react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\n\nimport { cn } from \"@petrarca/sonnet-core\";\n\nimport { useLiveGraphData } from \"../../hooks/useLiveGraphData\";\nimport { useWorkspaceSelection } from \"../../hooks/useWorkspaceStores\";\nimport type { SelectionStore } from \"../../stores/Selection\";\nimport type {\n VisualGraphEdge,\n VisualGraphNode,\n} from \"../../models/visual-graph\";\n\ntype Row =\n | { kind: \"node\"; id: string; label: string; node: VisualGraphNode }\n | { kind: \"edge\"; id: string; label: string; edge: VisualGraphEdge };\n\nexport interface GraphA11yListProps {\n /** Render on-screen instead of visually-hidden (still a11y-present). */\n visible?: boolean;\n /** Estimated row height in px (virtualization). Default 28. */\n rowHeight?: number;\n /** Max viewport height in px when visible. Default 320. */\n maxHeight?: number;\n className?: string;\n}\n\nconst SR_ONLY =\n \"absolute h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)] [clip-path:inset(50%)] -m-px\";\n\nexport function GraphA11yList({\n visible = false,\n rowHeight = 28,\n maxHeight = 320,\n className,\n}: GraphA11yListProps) {\n const live = useLiveGraphData();\n const useSelection = useWorkspaceSelection();\n const selectedNodeIds = useSelection(\n (s: SelectionStore) => s.selectedNodeIds,\n );\n const selectedEdge = useSelection((s: SelectionStore) => s.selectedEdge);\n const setSelectedNodeIds = useSelection(\n (s: SelectionStore) => s.setSelectedNodeIds,\n );\n const setSelectedEdge = useSelection(\n (s: SelectionStore) => s.setSelectedEdge,\n );\n\n const rows = useMemo<Row[]>(() => {\n const nodeRows: Row[] = live.nodes.map((n) => ({\n kind: \"node\",\n id: String(n.id_),\n label: n.visual?.displayName || n.label_ || String(n.id_),\n node: n,\n }));\n const edgeRows: Row[] = live.edges.map((e) => ({\n kind: \"edge\",\n id: String(e.id_),\n label: e.label_ || String(e.id_),\n edge: e,\n }));\n return [...nodeRows, ...edgeRows];\n }, [live.nodes, live.edges]);\n\n const parentRef = useRef<HTMLDivElement>(null);\n const virtualizer = useVirtualizer({\n count: rows.length,\n getScrollElement: () => parentRef.current,\n estimateSize: () => rowHeight,\n overscan: 8,\n });\n\n const selectRow = (row: Row) => {\n if (row.kind === \"node\") {\n setSelectedEdge(null);\n setSelectedNodeIds([row.id]);\n } else {\n setSelectedNodeIds([]);\n setSelectedEdge(row.edge);\n }\n };\n\n const isSelected = (row: Row) =>\n row.kind === \"node\"\n ? selectedNodeIds.includes(row.id)\n : selectedEdge?.id_ === row.edge.id_;\n\n return (\n <div\n role=\"listbox\"\n aria-label=\"Graph elements\"\n className={cn(visible ? \"rounded-md border\" : SR_ONLY, className)}\n >\n <div\n ref={parentRef}\n style={{ maxHeight: visible ? maxHeight : undefined, overflow: \"auto\" }}\n >\n <div\n style={{\n height: `${virtualizer.getTotalSize()}px`,\n width: \"100%\",\n position: \"relative\",\n }}\n >\n {virtualizer.getVirtualItems().map((vi) => {\n const row = rows[vi.index];\n if (!row) return null;\n const selected = isSelected(row);\n return (\n <button\n key={vi.key}\n type=\"button\"\n role=\"option\"\n aria-selected={selected}\n aria-label={`${row.kind === \"node\" ? \"Node\" : \"Edge\"} ${row.label}`}\n data-testid={`graph-${row.kind}-${row.id}`}\n {...(row.kind === \"node\"\n ? { \"data-graph-node-id\": row.id }\n : { \"data-graph-edge-id\": row.id })}\n onClick={() => selectRow(row)}\n className={cn(\n \"absolute left-0 top-0 flex w-full items-center px-2 text-left text-sm\",\n visible &&\n \"hover:bg-accent aria-selected:bg-state-selected aria-selected:text-foreground\",\n )}\n style={{\n height: `${vi.size}px`,\n transform: `translateY(${vi.start}px)`,\n }}\n >\n <span className=\"truncate\">{row.label}</span>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["create","devLog","create","create","devLog","devLog","create","create","devLog","create","devLog","buildStore","devLog","useGraphFilter","useGraphData","useMemo","useMemo","useMemo","useMemo","createContext","useContext","useEffect","useState","useCallback","devLog","useSelection","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","SimpleTooltip","useState","jsx","jsx","jsxs","DropdownMenu","SimpleTooltip","DropdownMenuTrigger","Button","DropdownMenuContent","DropdownMenuItem","useState","Card","jsx","jsxs","React","devLog","jsx","jsxs","jsx","jsxs","devLog","useEffect","useState","useGraphFilter","useSelection","useCallback","Card","useEffect","useRef","useState","useCallback","devLog","errorLog","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuLabel","DropdownMenuSeparator","DropdownMenuTrigger","SimpleTooltip","LayoutPanelTop","Eye","Fragment","jsx","jsxs","ViewControls","SimpleTooltip","Button","Eye","LayoutDropdown","DropdownMenu","DropdownMenuTrigger","LayoutPanelTop","DropdownMenuContent","DropdownMenuSeparator","DropdownMenuLabel","DropdownMenuItem","devLog","toast","toast","jsx","jsxs","errorLog","devLog","useState","useEffect","useCallback","useRef","useGraphFilter","useSelection","jsx","jsxs","Card","useState","Card","jsx","jsxs","useState","Card","Collapsible","CollapsibleContent","CollapsibleTrigger","copyTextToClipboard","jsx","jsxs","devLog","useMemo","Fragment","jsx","jsxs","useGraphFilter","useMemo","jsx","jsxs","useSelection","Card","useMemo","useRef","cn","jsx","useSelection","useMemo","useRef","cn"]}
|