@petrarca/sonnet-graph 0.4.2 → 0.5.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/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/rea/ExpandOptionsPanel.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, errorLog } from \"@petrarca/sonnet-core\";\nimport { toast } from \"sonner\";\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/** Options for bounded node expansion. */\nexport interface ExpandOptions {\n direction?: \"both\" | \"out\" | \"in\";\n relTypes?: string[];\n limit?: number;\n}\n\n/** Result shape returned by the expand backend call. */\nexport interface ExpandResult {\n nodes: RawGraphNode[];\n edges: RawGraphEdge[];\n has_more: boolean;\n}\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: (id: number, options?: ExpandOptions) => Promise<ExpandResult>;\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\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 * @param options - Optional expand parameters (direction, relTypes, limit)\n * @returns Promise that resolves when expansion is complete\n */\n expandNode: (nodeId: string, options?: ExpandOptions) => 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// Ensures expanded node labels are included in active filters so they are not hidden\nfunction mergeExpandedLabelsIntoFilters(\n stores: GraphExplorationDeps,\n enrichedNodes: { label_: string }[],\n nodeId: string,\n): void {\n const graphFilterState = stores.graphFilter.getState();\n const currentFilters = graphFilterState.nodeLabelFilters;\n\n if (currentFilters.length === 0 || enrichedNodes.length === 0) return;\n\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(\"[GraphExploration] Adding expanded node labels to active filters\", {\n nodeId,\n labelsToAdd,\n currentFilters,\n });\n stores.graphFilter\n .getState()\n .setNodeLabelFilters([...currentFilters, ...labelsToAdd]);\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, options) => {\n devLog(\"[GraphExploration] expandNode\", { nodeId, options });\n\n try {\n // Fetch connected nodes and edges via injected backend provider\n const result = await stores.expandNode(Number(nodeId), options);\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 mergeExpandedLabelsIntoFilters(stores, enrichedNodes, nodeId);\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 // Inform user when expansion was truncated (has_more = limit was hit).\n if (result.has_more) {\n toast.info(\n `Showing first ${enrichedNodes.length} neighbors — more exist. Refine filters or increase the limit.`,\n );\n }\n\n devLog(\"[GraphExploration] Expansion complete\", {\n nodeId,\n addedNodes: enrichedNodes.length,\n addedEdges: enrichedEdges.length,\n hasMore: result.has_more,\n });\n } catch (error) {\n errorLog(\"[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 /** Fetch distinct edge types for a node (for expand options panel). */\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n}\n\nfunction ReaGraph({\n onCopyNode,\n extraToolbarContent,\n getNodeEdgeTypes,\n}: 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 getNodeEdgeTypes={getNodeEdgeTypes}\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, { useState } 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 {\n GraphExplorationStore,\n ExpandOptions,\n} from \"../../stores/GraphExploration\";\nimport ExpandOptionsPanel from \"./ExpandOptionsPanel\";\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 getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n}>;\n\nfunction ReaContextMenu({\n data,\n onClose,\n elementType,\n useGraphExploration,\n onCopyNode,\n getNodeEdgeTypes,\n}: Props) {\n const [showExpandPanel, setShowExpandPanel] = useState(false);\n\n // Dismiss on Escape\n React.useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKey);\n return () => document.removeEventListener(\"keydown\", handleKey);\n }, [onClose]);\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 handleExpandWithOptions = (options: ExpandOptions) => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Expand node with options:\", nodeId, options);\n useGraphExploration.getState().expandNode(nodeId, options);\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: () => setShowExpandPanel(true) },\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 // Show expand options panel if user selected \"Expand...\"\n if (showExpandPanel && elementType === \"node\") {\n const nodeLabel = data.label || data.id;\n return (\n <ExpandOptionsPanel\n nodeLabel={String(nodeLabel)}\n onExpand={handleExpandWithOptions}\n onBack={() => setShowExpandPanel(false)}\n getEdgeTypes={\n getNodeEdgeTypes ? () => getNodeEdgeTypes(Number(data.id)) : undefined\n }\n />\n );\n }\n\n // Simple div-based menu (Reagraph handles positioning)\n return (\n <div className=\"bg-background border border-border 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-muted/50 cursor-pointer\"\n onClick={item.action}\n >\n {item.label}\n </button>\n {index === 1 && <div className=\"border-t border-border my-1\" />}\n </React.Fragment>\n ))}\n <div className=\"border-t border-border my-1\" />\n <button\n className=\"w-full text-left px-3 py-1.5 text-xs text-muted-foreground hover:bg-muted/50 cursor-pointer\"\n onClick={onClose}\n >\n Cancel\n </button>\n </div>\n );\n}\n\nexport default ReaContextMenu;\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Checkbox, Input, Label } from \"@petrarca/sonnet-ui\";\nimport type { ExpandOptions } from \"../../stores/GraphExploration\";\n\n// Derive Direction from the ExpandOptions type (I-3: single source of truth).\ntype Direction = NonNullable<ExpandOptions[\"direction\"]>;\n\ntype Props = Readonly<{\n nodeLabel: string;\n onExpand: (options: ExpandOptions) => void;\n onBack: () => void;\n getEdgeTypes?: () => Promise<string[]>;\n}>;\n\n/**\n * Inline panel for configuring expand options (direction, rel-types, limit).\n * Shown in place of the context menu when the user selects \"Expand...\".\n */\nfunction ExpandOptionsPanel({\n nodeLabel,\n onExpand,\n onBack,\n getEdgeTypes,\n}: Props) {\n const [direction, setDirection] = useState<Direction>(\"both\");\n const [limit, setLimit] = useState(100);\n const [edgeTypes, setEdgeTypes] = useState<string[]>([]);\n const [selectedTypes, setSelectedTypes] = useState<string[]>([]);\n const [loading, setLoading] = useState(!!getEdgeTypes);\n const [offset, setOffset] = useState({ x: 0, y: 0 });\n const expandBtnRef = useRef<HTMLButtonElement>(null);\n const dragRef = useRef<{\n startX: number;\n startY: number;\n origX: number;\n origY: number;\n } | null>(null);\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent) => {\n // Only drag from the header area, not from buttons\n if ((e.target as HTMLElement).closest(\"button\")) return;\n e.preventDefault();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n origX: offset.x,\n origY: offset.y,\n };\n },\n [offset],\n );\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragRef.current) return;\n const dx = e.clientX - dragRef.current.startX;\n const dy = e.clientY - dragRef.current.startY;\n setOffset({ x: dragRef.current.origX + dx, y: dragRef.current.origY + dy });\n }, []);\n\n const onPointerUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n useEffect(() => {\n if (!getEdgeTypes) return;\n setLoading(true);\n getEdgeTypes()\n .then((types) => {\n setEdgeTypes(types);\n setSelectedTypes(types); // all selected by default\n })\n .finally(() => setLoading(false));\n }, [getEdgeTypes]);\n\n const handleToggleType = (type: string) => {\n setSelectedTypes((prev) =>\n prev.includes(type) ? prev.filter((t) => t !== type) : [...prev, type],\n );\n };\n\n const handleExpand = () => {\n const options: ExpandOptions = {};\n if (direction !== \"both\") options.direction = direction;\n // M-1: clamp limit to valid server range before sending\n const clampedLimit = Math.max(1, Math.min(10_000, limit));\n if (clampedLimit !== 100) options.limit = clampedLimit;\n // Only pass relTypes when the user has deselected at least one type.\n // I-1: guard selectedTypes.length === 0 (all deselected) — handled by\n // disabling the Expand button below so this branch is unreachable.\n if (selectedTypes.length > 0 && selectedTypes.length < edgeTypes.length) {\n options.relTypes = selectedTypes;\n }\n onExpand(options);\n };\n\n const allSelected = selectedTypes.length === edgeTypes.length;\n // I-1: disable expand when the user has deselected all rel types.\n const noneSelected = edgeTypes.length > 0 && selectedTypes.length === 0;\n\n // Auto-focus the Expand button once ready so Enter submits.\n useEffect(() => {\n if (!loading && !noneSelected) {\n expandBtnRef.current?.focus();\n }\n }, [loading, noneSelected]);\n\n return (\n <div\n className=\"bg-background border border-border rounded-md shadow-md p-2.5 min-w-48 space-y-2\"\n style={{ transform: `translate(${offset.x}px, ${offset.y}px)` }}\n >\n <div\n className=\"flex items-center justify-between gap-2 cursor-grab active:cursor-grabbing select-none\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n >\n <button\n className=\"text-[11px] text-muted-foreground hover:text-foreground cursor-pointer\"\n onClick={onBack}\n >\n Back\n </button>\n <span className=\"text-[11px] font-medium text-foreground truncate max-w-32\">\n {nodeLabel}\n </span>\n </div>\n\n {/* Direction */}\n <div className=\"space-y-1\">\n <Label className=\"text-[11px] text-muted-foreground\">Direction</Label>\n <div className=\"flex gap-0.5\">\n {([\"both\", \"out\", \"in\"] as const).map((dir) => (\n <button\n key={dir}\n className={`flex-1 px-2 py-1 text-[11px] capitalize rounded border cursor-pointer ${\n direction === dir\n ? \"bg-primary/10 text-primary border-primary/40 font-medium\"\n : \"bg-background text-muted-foreground border-border hover:bg-muted\"\n }`}\n onClick={() => setDirection(dir)}\n >\n {dir}\n </button>\n ))}\n </div>\n </div>\n\n {/* Relationship Types (only shown once loaded and >1 type exists) */}\n {!loading && edgeTypes.length > 1 && (\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-[11px] text-muted-foreground\">\n Rel Types\n </Label>\n {/* M-2: removed redundant inner edgeTypes.length > 1 guard */}\n <button\n className=\"text-[10px] text-muted-foreground hover:text-foreground cursor-pointer\"\n onClick={() =>\n setSelectedTypes(allSelected ? [] : [...edgeTypes])\n }\n >\n {allSelected ? \"None\" : \"All\"}\n </button>\n </div>\n <div className=\"space-y-0.5 max-h-32 overflow-y-auto\">\n {edgeTypes.map((type) => (\n <label\n key={type}\n className=\"flex items-center gap-1.5 text-[11px] cursor-pointer\"\n >\n <Checkbox\n checked={selectedTypes.includes(type)}\n onCheckedChange={() => handleToggleType(type)}\n className=\"h-3 w-3\"\n />\n <span className=\"truncate\">{type}</span>\n </label>\n ))}\n </div>\n </div>\n )}\n\n {/* Limit */}\n <div className=\"space-y-1\">\n <Label className=\"text-[11px] text-muted-foreground\">Limit</Label>\n <Input\n type=\"number\"\n min={1}\n max={10000}\n value={limit}\n onChange={(e) => {\n const v = Number(e.target.value);\n // M-1: clamp immediately so the displayed value stays in range\n if (!Number.isNaN(v)) setLimit(Math.max(1, Math.min(10_000, v)));\n }}\n className=\"h-6 text-[11px]\"\n />\n </div>\n\n {/* I-1: disabled when all rel types are deselected */}\n <button\n ref={expandBtnRef}\n className=\"w-full py-1.5 text-[11px] font-medium rounded bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer\"\n onClick={handleExpand}\n disabled={loading || noneSelected}\n title={\n noneSelected ? \"Select at least one relationship type\" : undefined\n }\n >\n Expand\n </button>\n </div>\n );\n}\n\nexport default ExpandOptionsPanel;\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 type ExpandRequest,\n} from \"./contextMenuConfig\";\nimport { toast } from \"sonner\";\nimport ExpandOptionsPanel from \"../rea/ExpandOptionsPanel\";\nimport type { ExpandOptions } from \"../../stores/GraphExploration\";\n\n// Expand overlay shown after radial menu \"Expand\" selection\nfunction CytoscapeExpandOverlay({\n expandRequest,\n containerRef,\n useGraphExploration,\n getNodeEdgeTypes,\n onClose,\n}: {\n expandRequest: ExpandRequest;\n containerRef: React.RefObject<HTMLDivElement | null>;\n useGraphExploration: ReturnType<typeof useWorkspaceGraphExploration>;\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n onClose: () => void;\n}): React.JSX.Element {\n return (\n <div\n className=\"absolute z-50\"\n style={{\n left: Math.min(\n Math.max(expandRequest.x, 120),\n (containerRef.current?.clientWidth ?? 800) - 120,\n ),\n top: Math.min(\n Math.max(expandRequest.y, 10),\n (containerRef.current?.clientHeight ?? 600) - 260,\n ),\n transform: \"translate(-50%, 12px)\",\n }}\n >\n <ExpandOptionsPanel\n nodeLabel={expandRequest.nodeLabel}\n onExpand={(options: ExpandOptions) => {\n const { nodeId } = expandRequest;\n onClose();\n useGraphExploration\n .getState()\n .expandNode(nodeId, options)\n .catch((err: unknown) => {\n errorLog(\"[CxtMenu] Expansion failed:\", err);\n toast.error(\"Failed to expand node\");\n });\n }}\n onBack={onClose}\n getEdgeTypes={\n getNodeEdgeTypes\n ? () => getNodeEdgeTypes(Number(expandRequest.nodeId))\n : undefined\n }\n />\n </div>\n );\n}\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 /** Fetch distinct edge types for a node (for expand options panel). */\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\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 onExpandRequest?: (req: ExpandRequest) => void;\n}\n\nfunction setupCytoscapeEventHandlers({\n cy,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n clearSelectionStore,\n useGraphExploration,\n onCopyNode,\n onExpandRequest,\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({\n cy,\n useGraphExploration,\n onCopyNode,\n onExpandRequest,\n });\n createEdgeContextMenu({ cy, useGraphExploration });\n}\n\nfunction CytoscapeGraph({\n layout: initialLayout = \"auto\",\n fitPadding = 30,\n onCopyNode,\n extraToolbarContent,\n getNodeEdgeTypes,\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 const [expandRequest, setExpandRequest] = useState<ExpandRequest | null>(\n null,\n );\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 onExpandRequest: setExpandRequest,\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 {expandRequest && (\n <CytoscapeExpandOverlay\n expandRequest={expandRequest}\n containerRef={containerRef}\n useGraphExploration={useGraphExploration}\n getNodeEdgeTypes={getNodeEdgeTypes}\n onClose={() => setExpandRequest(null)}\n />\n )}\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\n/** Info passed when user selects \"Expand\" from the radial menu. */\nexport interface ExpandRequest {\n nodeId: string;\n nodeLabel: string;\n x: number;\n y: number;\n}\n\ninterface NodeContextMenuOptions {\n cy: Core;\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n onCopyNode?: (node: VisualGraphNode) => void;\n onExpandRequest?: (req: ExpandRequest) => 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 onExpandRequest,\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: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Expand request for node:\", nodeId);\n if (onExpandRequest) {\n const pos = ele.renderedPosition();\n const label = (ele.data(\"label\") as string) || nodeId;\n onExpandRequest({ nodeId, nodeLabel: label, x: pos.x, y: pos.y });\n } else {\n useGraphExploration\n .getState()\n .expandNode(nodeId)\n .catch((error: unknown) => {\n errorLog(\"[CxtMenu] Expansion failed:\", error);\n toast.error(\"Failed to expand node\");\n });\n }\n },\n },\n ],\n menuRadius: 60,\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 /** Fetch distinct edge types for a node (for expand options panel). */\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n}\n\nfunction GraphVisualizer({\n onCopyNode,\n extraToolbarContent,\n getNodeEdgeTypes,\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 getNodeEdgeTypes={getNodeEdgeTypes}\n />\n )}\n {renderer === \"cytoscape\" && (\n <CytoscapeGraph\n key=\"cytoscape\"\n onCopyNode={onCopyNode}\n extraToolbarContent={extraToolbarContent}\n getNodeEdgeTypes={getNodeEdgeTypes}\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 PropertyList,\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 <div className=\"mt-2\">\n <PropertyList properties={node.properties_ || {}} showHeader />\n </div>\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 PropertyList,\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 <div className=\"mt-2\">\n <PropertyList properties={edge.properties_ || {}} showHeader />\n </div>\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","useRef","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","useState","devLog","useCallback","useEffect","useState","jsx","jsxs","jsx","jsxs","useState","React","devLog","toast","jsx","jsxs","devLog","useRef","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","errorLog","toast","toast","jsx","jsxs","errorLog","toast","devLog","useState","useEffect","useCallback","useRef","useGraphFilter","useSelection","jsx","jsxs","Card","useState","Card","jsx","jsxs","useState","Card","Collapsible","CollapsibleContent","CollapsibleTrigger","PropertyList","copyTextToClipboard","jsx","jsxs","devLog","useMemo","Fragment","jsx","jsxs","useGraphFilter","useMemo","jsx","jsxs","useSelection","Card","useMemo","useRef","cn","jsx","useSelection","useMemo","useRef","cn"]}
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/useStableRef.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/rea/ExpandOptionsPanel.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","../src/graph-model/types.ts","../src/graph-model/converter.ts","../src/graph-model/filter.ts","../src/graph-model/GraphModelEditor.tsx","../src/graph-model/ModelActionPanel.tsx","../src/graph-model/TypeDetailPanel.tsx","../src/graph-model/view.ts","../src/graph-model/mutate.ts","../src/graph-model/PropertyFormSheet.tsx","../src/graph-model/RelationFormSheet.tsx","../src/graph-model/NodeTypeNameSheet.tsx","../src/graph-model/capabilities.ts","../src/graph-edit/capabilities.ts","../src/graph-edit/relationFields.ts","../src/graph-edit/GraphEditToolbar.tsx","../src/graph-edit/NodeFormSheet.tsx","../src/graph-edit/EdgeFormSheet.tsx","../src/graph-edit/DeleteNodeDialog.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 * The single selection-highlight colour, shared by every renderer (Cytoscape,\n * Reagraph) so selection looks identical across them.\n *\n * It is a blue -- the design system's primary/ring colour (`--primary`\n * `hsl(220 65% 50%)` resolved to hex, since canvas renderers need a static\n * value and cannot read CSS variables). Blue is deliberately chosen for\n * accessibility: it stays distinguishable under red/green colour-vision\n * deficiency and does not collide with the red/green/orange data-node palette\n * (BASE_COLORS), unlike the previous red/amber highlights. Selection is also\n * signalled by non-colour means (thicker border/line + overlay), satisfying\n * WCAG 1.4.1 (use of colour).\n */\nexport const SELECTION_COLOR = \"#2d64d2\";\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 setAllLabelsDisabled: (disabled: boolean) => void;\n /** Atomically update both allLabelsDisabled and nodeLabelFilters in one write. */\n setNodeFilterState: (disabled: boolean, filters: string[]) => 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 setAllLabelsDisabled: (disabled) => set({ allLabelsDisabled: disabled }),\n setNodeFilterState: (disabled, filters) =>\n set({ allLabelsDisabled: disabled, nodeLabelFilters: filters }),\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, errorLog } from \"@petrarca/sonnet-core\";\nimport { toast } from \"sonner\";\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/** Options for bounded node expansion. */\nexport interface ExpandOptions {\n direction?: \"both\" | \"out\" | \"in\";\n relTypes?: string[];\n limit?: number;\n}\n\n/** Result shape returned by the expand backend call. */\nexport interface ExpandResult {\n nodes: RawGraphNode[];\n edges: RawGraphEdge[];\n has_more: boolean;\n}\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: (id: number, options?: ExpandOptions) => Promise<ExpandResult>;\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\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 * @param options - Optional expand parameters (direction, relTypes, limit)\n * @returns Promise that resolves when expansion is complete\n */\n expandNode: (nodeId: string, options?: ExpandOptions) => 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// Ensures expanded node labels are included in active filters so they are not hidden\nfunction mergeExpandedLabelsIntoFilters(\n stores: GraphExplorationDeps,\n enrichedNodes: { label_: string }[],\n nodeId: string,\n): void {\n const graphFilterState = stores.graphFilter.getState();\n const currentFilters = graphFilterState.nodeLabelFilters;\n\n if (currentFilters.length === 0 || enrichedNodes.length === 0) return;\n\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(\"[GraphExploration] Adding expanded node labels to active filters\", {\n nodeId,\n labelsToAdd,\n currentFilters,\n });\n stores.graphFilter\n .getState()\n .setNodeLabelFilters([...currentFilters, ...labelsToAdd]);\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, options) => {\n devLog(\"[GraphExploration] expandNode\", { nodeId, options });\n\n try {\n // Fetch connected nodes and edges via injected backend provider\n const result = await stores.expandNode(Number(nodeId), options);\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 mergeExpandedLabelsIntoFilters(stores, enrichedNodes, nodeId);\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 // Inform user when expansion was truncated (has_more = limit was hit).\n if (result.has_more) {\n toast.info(\n `Showing first ${enrichedNodes.length} neighbors — more exist. Refine filters or increase the limit.`,\n );\n }\n\n devLog(\"[GraphExploration] Expansion complete\", {\n nodeId,\n addedNodes: enrichedNodes.length,\n addedEdges: enrichedEdges.length,\n hasMore: result.has_more,\n });\n } catch (error) {\n errorLog(\"[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., a graph explorer or consumer app).\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","/**\n * useStableRef -- returns a stable function identity that always delegates to\n * the latest `fn` reference.\n *\n * Use when a parent callback is an inline arrow (new reference every render)\n * and would otherwise pollute `useCallback` dependency arrays, causing\n * unnecessary re-creation of handlers.\n *\n * Two overloads: required callback returns `T`; optional callback returns\n * `T | undefined`.\n */\nimport { useCallback, useRef } from \"react\";\n\nexport function useStableRef<T extends (...args: never[]) => unknown>(fn: T): T;\nexport function useStableRef<T extends (...args: never[]) => unknown>(\n fn: T | undefined,\n): T | undefined;\nexport function useStableRef<T extends (...args: never[]) => unknown>(\n fn: T | undefined,\n): T | undefined {\n const ref = useRef(fn);\n ref.current = fn;\n return useCallback(\n ((...args: Parameters<T>) => ref.current?.(...args)) as T,\n [],\n );\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 /** Fetch distinct edge types for a node (for expand options panel). */\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n}\n\nfunction ReaGraph({\n onCopyNode,\n extraToolbarContent,\n getNodeEdgeTypes,\n}: 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 // Track Reagraph's own current selection so the store subscriber can tell\n // whether the canvas is already in sync and skip re-applying (which would\n // fight reagraph's own selection on a canvas-originated change).\n const selectionsRef = useRef<string[]>(selections);\n selectionsRef.current = selections;\n\n // Reflect store selection on the Reagraph canvas (a11y list, other renderer).\n // Only applies when the canvas is actually out of sync, so canvas-originated\n // changes (already reflected) are no-ops and do not loop.\n useEffect(() => {\n const inSync = (nodeIds: string[]): boolean => {\n const cur = selectionsRef.current;\n return (\n cur.length === nodeIds.length && nodeIds.every((id) => cur.includes(id))\n );\n };\n const unsubscribe = useGraphSelection.subscribe((state) => {\n // Reflect node selection only; edge reflection on the canvas is driven by\n // reagraph's own handlers. (setSelectedEdge here is the store setter, not\n // a canvas API, so writing it from a store subscriber would be a no-op\n // self-write.)\n if (!inSync(state.selectedNodeIds)) {\n setSelections(state.selectedNodeIds);\n }\n });\n return unsubscribe;\n }, [useGraphSelection, setSelections]);\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 getNodeEdgeTypes={getNodeEdgeTypes}\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\";\nimport { SELECTION_COLOR } from \"../../graph/enrichment\";\n\n// Shared selection-highlight colour (DS primary blue), chosen for colour-vision\n// accessibility and consistency with the Cytoscape renderer. See SELECTION_COLOR.\nconst highlightColor = SELECTION_COLOR;\n// Darker blue for label text rendered on/near the highlight (readable contrast).\nconst highlightColorText = \"#1d4ed8\";\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, { useState } 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 {\n GraphExplorationStore,\n ExpandOptions,\n} from \"../../stores/GraphExploration\";\nimport ExpandOptionsPanel from \"./ExpandOptionsPanel\";\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 getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n}>;\n\nfunction ReaContextMenu({\n data,\n onClose,\n elementType,\n useGraphExploration,\n onCopyNode,\n getNodeEdgeTypes,\n}: Props) {\n const [showExpandPanel, setShowExpandPanel] = useState(false);\n\n // Dismiss on Escape\n React.useEffect(() => {\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKey);\n return () => document.removeEventListener(\"keydown\", handleKey);\n }, [onClose]);\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 handleExpandWithOptions = (options: ExpandOptions) => {\n if (elementType === \"node\") {\n const nodeId = data.id;\n devLog(\"[ReaContextMenu] Expand node with options:\", nodeId, options);\n useGraphExploration.getState().expandNode(nodeId, options);\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: () => setShowExpandPanel(true) },\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 // Show expand options panel if user selected \"Expand...\"\n if (showExpandPanel && elementType === \"node\") {\n const nodeLabel = data.label || data.id;\n return (\n <ExpandOptionsPanel\n nodeLabel={String(nodeLabel)}\n onExpand={handleExpandWithOptions}\n onBack={() => setShowExpandPanel(false)}\n getEdgeTypes={\n getNodeEdgeTypes ? () => getNodeEdgeTypes(Number(data.id)) : undefined\n }\n />\n );\n }\n\n // Simple div-based menu (Reagraph handles positioning)\n return (\n <div className=\"bg-background border border-border 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-muted/50 cursor-pointer\"\n onClick={item.action}\n >\n {item.label}\n </button>\n {index === 1 && <div className=\"border-t border-border my-1\" />}\n </React.Fragment>\n ))}\n <div className=\"border-t border-border my-1\" />\n <button\n className=\"w-full text-left px-3 py-1.5 text-xs text-muted-foreground hover:bg-muted/50 cursor-pointer\"\n onClick={onClose}\n >\n Cancel\n </button>\n </div>\n );\n}\n\nexport default ReaContextMenu;\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Checkbox, Input, Label } from \"@petrarca/sonnet-ui\";\nimport type { ExpandOptions } from \"../../stores/GraphExploration\";\n\n// Derive Direction from the ExpandOptions type (I-3: single source of truth).\ntype Direction = NonNullable<ExpandOptions[\"direction\"]>;\n\ntype Props = Readonly<{\n nodeLabel: string;\n onExpand: (options: ExpandOptions) => void;\n onBack: () => void;\n getEdgeTypes?: () => Promise<string[]>;\n}>;\n\n/**\n * Inline panel for configuring expand options (direction, rel-types, limit).\n * Shown in place of the context menu when the user selects \"Expand...\".\n */\nfunction ExpandOptionsPanel({\n nodeLabel,\n onExpand,\n onBack,\n getEdgeTypes,\n}: Props) {\n const [direction, setDirection] = useState<Direction>(\"both\");\n const [limit, setLimit] = useState(100);\n const [edgeTypes, setEdgeTypes] = useState<string[]>([]);\n const [selectedTypes, setSelectedTypes] = useState<string[]>([]);\n const [loading, setLoading] = useState(!!getEdgeTypes);\n const [offset, setOffset] = useState({ x: 0, y: 0 });\n const expandBtnRef = useRef<HTMLButtonElement>(null);\n const dragRef = useRef<{\n startX: number;\n startY: number;\n origX: number;\n origY: number;\n } | null>(null);\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent) => {\n // Only drag from the header area, not from buttons\n if ((e.target as HTMLElement).closest(\"button\")) return;\n e.preventDefault();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n dragRef.current = {\n startX: e.clientX,\n startY: e.clientY,\n origX: offset.x,\n origY: offset.y,\n };\n },\n [offset],\n );\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n if (!dragRef.current) return;\n const dx = e.clientX - dragRef.current.startX;\n const dy = e.clientY - dragRef.current.startY;\n setOffset({ x: dragRef.current.origX + dx, y: dragRef.current.origY + dy });\n }, []);\n\n const onPointerUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n useEffect(() => {\n if (!getEdgeTypes) return;\n setLoading(true);\n getEdgeTypes()\n .then((types) => {\n setEdgeTypes(types);\n setSelectedTypes(types); // all selected by default\n })\n .finally(() => setLoading(false));\n }, [getEdgeTypes]);\n\n const handleToggleType = (type: string) => {\n setSelectedTypes((prev) =>\n prev.includes(type) ? prev.filter((t) => t !== type) : [...prev, type],\n );\n };\n\n const handleExpand = () => {\n const options: ExpandOptions = {};\n if (direction !== \"both\") options.direction = direction;\n // M-1: clamp limit to valid server range before sending\n const clampedLimit = Math.max(1, Math.min(10_000, limit));\n if (clampedLimit !== 100) options.limit = clampedLimit;\n // Only pass relTypes when the user has deselected at least one type.\n // I-1: guard selectedTypes.length === 0 (all deselected) — handled by\n // disabling the Expand button below so this branch is unreachable.\n if (selectedTypes.length > 0 && selectedTypes.length < edgeTypes.length) {\n options.relTypes = selectedTypes;\n }\n onExpand(options);\n };\n\n const allSelected = selectedTypes.length === edgeTypes.length;\n // I-1: disable expand when the user has deselected all rel types.\n const noneSelected = edgeTypes.length > 0 && selectedTypes.length === 0;\n\n // Auto-focus the Expand button once ready so Enter submits.\n useEffect(() => {\n if (!loading && !noneSelected) {\n expandBtnRef.current?.focus();\n }\n }, [loading, noneSelected]);\n\n return (\n <div\n className=\"bg-background border border-border rounded-md shadow-md p-2.5 min-w-48 space-y-2\"\n style={{ transform: `translate(${offset.x}px, ${offset.y}px)` }}\n >\n <div\n className=\"flex items-center justify-between gap-2 cursor-grab active:cursor-grabbing select-none\"\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n >\n <button\n className=\"text-[11px] text-muted-foreground hover:text-foreground cursor-pointer\"\n onClick={onBack}\n >\n Back\n </button>\n <span className=\"text-[11px] font-medium text-foreground truncate max-w-32\">\n {nodeLabel}\n </span>\n </div>\n\n {/* Direction */}\n <div className=\"space-y-1\">\n <Label className=\"text-[11px] text-muted-foreground\">Direction</Label>\n <div className=\"flex gap-0.5\">\n {([\"both\", \"out\", \"in\"] as const).map((dir) => (\n <button\n key={dir}\n className={`flex-1 px-2 py-1 text-[11px] capitalize rounded border cursor-pointer ${\n direction === dir\n ? \"bg-primary/10 text-primary border-primary/40 font-medium\"\n : \"bg-background text-muted-foreground border-border hover:bg-muted\"\n }`}\n onClick={() => setDirection(dir)}\n >\n {dir}\n </button>\n ))}\n </div>\n </div>\n\n {/* Relationship Types (only shown once loaded and >1 type exists) */}\n {!loading && edgeTypes.length > 1 && (\n <div className=\"space-y-1\">\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-[11px] text-muted-foreground\">\n Rel Types\n </Label>\n {/* M-2: removed redundant inner edgeTypes.length > 1 guard */}\n <button\n className=\"text-[10px] text-muted-foreground hover:text-foreground cursor-pointer\"\n onClick={() =>\n setSelectedTypes(allSelected ? [] : [...edgeTypes])\n }\n >\n {allSelected ? \"None\" : \"All\"}\n </button>\n </div>\n <div className=\"space-y-0.5 max-h-32 overflow-y-auto\">\n {edgeTypes.map((type) => (\n <label\n key={type}\n className=\"flex items-center gap-1.5 text-[11px] cursor-pointer\"\n >\n <Checkbox\n checked={selectedTypes.includes(type)}\n onCheckedChange={() => handleToggleType(type)}\n className=\"h-3 w-3\"\n />\n <span className=\"truncate\">{type}</span>\n </label>\n ))}\n </div>\n </div>\n )}\n\n {/* Limit */}\n <div className=\"space-y-1\">\n <Label className=\"text-[11px] text-muted-foreground\">Limit</Label>\n <Input\n type=\"number\"\n min={1}\n max={10000}\n value={limit}\n onChange={(e) => {\n const v = Number(e.target.value);\n // M-1: clamp immediately so the displayed value stays in range\n if (!Number.isNaN(v)) setLimit(Math.max(1, Math.min(10_000, v)));\n }}\n className=\"h-6 text-[11px]\"\n />\n </div>\n\n {/* I-1: disabled when all rel types are deselected */}\n <button\n ref={expandBtnRef}\n className=\"w-full py-1.5 text-[11px] font-medium rounded bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer\"\n onClick={handleExpand}\n disabled={loading || noneSelected}\n title={\n noneSelected ? \"Select at least one relationship type\" : undefined\n }\n >\n Expand\n </button>\n </div>\n );\n}\n\nexport default ExpandOptionsPanel;\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 type ExpandRequest,\n} from \"./contextMenuConfig\";\nimport { toast } from \"sonner\";\nimport ExpandOptionsPanel from \"../rea/ExpandOptionsPanel\";\nimport type { ExpandOptions } from \"../../stores/GraphExploration\";\nimport { SELECTION_COLOR } from \"../../graph/enrichment\";\n\n// Expand overlay shown after radial menu \"Expand\" selection\nfunction CytoscapeExpandOverlay({\n expandRequest,\n containerRef,\n useGraphExploration,\n getNodeEdgeTypes,\n onClose,\n}: {\n expandRequest: ExpandRequest;\n containerRef: React.RefObject<HTMLDivElement | null>;\n useGraphExploration: ReturnType<typeof useWorkspaceGraphExploration>;\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n onClose: () => void;\n}): React.JSX.Element {\n return (\n <div\n className=\"absolute z-50\"\n style={{\n left: Math.min(\n Math.max(expandRequest.x, 120),\n (containerRef.current?.clientWidth ?? 800) - 120,\n ),\n top: Math.min(\n Math.max(expandRequest.y, 10),\n (containerRef.current?.clientHeight ?? 600) - 260,\n ),\n transform: \"translate(-50%, 12px)\",\n }}\n >\n <ExpandOptionsPanel\n nodeLabel={expandRequest.nodeLabel}\n onExpand={(options: ExpandOptions) => {\n const { nodeId } = expandRequest;\n onClose();\n useGraphExploration\n .getState()\n .expandNode(nodeId, options)\n .catch((err: unknown) => {\n errorLog(\"[CxtMenu] Expansion failed:\", err);\n toast.error(\"Failed to expand node\");\n });\n }}\n onBack={onClose}\n getEdgeTypes={\n getNodeEdgeTypes\n ? () => getNodeEdgeTypes(Number(expandRequest.nodeId))\n : undefined\n }\n />\n </div>\n );\n}\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 /** Fetch distinct edge types for a node (for expand options panel). */\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\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 onExpandRequest?: (req: ExpandRequest) => void;\n}\n\nfunction setupCytoscapeEventHandlers({\n cy,\n edgesRef,\n selectedNodeIdsRef,\n selectedEdgeRef,\n setSelectedNodeIdsStore,\n setSelectedEdgeStore,\n clearSelectionStore,\n useGraphExploration,\n onCopyNode,\n onExpandRequest,\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({\n cy,\n useGraphExploration,\n onCopyNode,\n onExpandRequest,\n });\n createEdgeContextMenu({ cy, useGraphExploration });\n}\n\nfunction CytoscapeGraph({\n layout: initialLayout = \"auto\",\n fitPadding = 30,\n onCopyNode,\n extraToolbarContent,\n getNodeEdgeTypes,\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 const [expandRequest, setExpandRequest] = useState<ExpandRequest | null>(\n null,\n );\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 // Reflect store selection on the canvas (a11y list, other renderer, mount).\n //\n // This is a DIFF, not a blanket unselect+reselect: it only selects nodes the\n // store wants but the canvas lacks, and unselects nodes the canvas has but the\n // store dropped. When the canvas already matches the store (a canvas-originated\n // change), the diff is empty and cytoscape is not touched at all -- so this\n // never fires spurious select/unselect events and never fights the canvas's\n // own selection. Only genuinely external changes (e.g. the a11y list) produce\n // a non-empty diff and get applied.\n useEffect(() => {\n const applyStoreSelection = (\n nodeIds: string[],\n edge: VisualGraphEdge | null,\n ) => {\n selectedNodeIdsRef.current = nodeIds;\n selectedEdgeRef.current = edge;\n const cy = cyRef.current;\n if (!cy) return;\n\n const want = new Set(nodeIds);\n const haveNodes = cy.$(\"node:selected\");\n const have = new Set(haveNodes.map((e) => e.id()));\n const wantEdgeId = edge ? String(edge.id_) : null;\n const haveEdge = cy.$(\"edge:selected\");\n const haveEdgeId = haveEdge.length ? haveEdge[0].id() : null;\n\n const nodesInSync =\n want.size === have.size && [...want].every((id) => have.has(id));\n const edgeInSync = wantEdgeId === haveEdgeId;\n if (nodesInSync && edgeInSync) return; // canvas already matches -- no-op\n\n cy.batch(() => {\n // Unselect only what is no longer wanted.\n haveNodes.forEach((ele) => {\n if (!want.has(ele.id())) ele.unselect();\n });\n if (haveEdgeId && haveEdgeId !== wantEdgeId) haveEdge.unselect();\n // Select only what is newly wanted.\n nodeIds.forEach((id) => {\n if (!have.has(id)) cy.$id(id).select();\n });\n if (wantEdgeId && wantEdgeId !== haveEdgeId) {\n const edgeEle = cy.$id(wantEdgeId);\n if (edgeEle) {\n edgeEle.select();\n cy.$id(edgeEle.data(\"source\")).select();\n cy.$id(edgeEle.data(\"target\")).select();\n }\n }\n });\n };\n\n const initial = useSelection.getState();\n applyStoreSelection(initial.selectedNodeIds, initial.selectedEdge);\n\n const unsubscribe = useSelection.subscribe((state) => {\n applyStoreSelection(state.selectedNodeIds, state.selectedEdge);\n });\n return unsubscribe;\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 // Plain click selects a single node (replaces the selection); hold\n // Shift/Cmd to add a second node (e.g. for the two-node edge action).\n // This matches the conventional canvas-selection expectation.\n selectionType: \"single\",\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\": SELECTION_COLOR,\n \"target-arrow-color\": SELECTION_COLOR,\n // Modest bump over the base width (~3); selection is conveyed mainly\n // by colour + overlay, not a slab. (Was 8, which looked oversized.)\n width: 4,\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\": 0.9,\n opacity: 1,\n \"overlay-color\": SELECTION_COLOR,\n \"overlay-opacity\": 0.08,\n },\n },\n {\n selector: \"node:selected\",\n style: {\n \"border-width\": 10, // thicker circle outline\n \"border-color\": SELECTION_COLOR,\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\": SELECTION_COLOR,\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 onExpandRequest: setExpandRequest,\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 {expandRequest && (\n <CytoscapeExpandOverlay\n expandRequest={expandRequest}\n containerRef={containerRef}\n useGraphExploration={useGraphExploration}\n getNodeEdgeTypes={getNodeEdgeTypes}\n onClose={() => setExpandRequest(null)}\n />\n )}\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\n/** Info passed when user selects \"Expand\" from the radial menu. */\nexport interface ExpandRequest {\n nodeId: string;\n nodeLabel: string;\n x: number;\n y: number;\n}\n\ninterface NodeContextMenuOptions {\n cy: Core;\n useGraphExploration: UseBoundStore<StoreApi<GraphExplorationStore>>;\n onCopyNode?: (node: VisualGraphNode) => void;\n onExpandRequest?: (req: ExpandRequest) => 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 onExpandRequest,\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: (ele: cytoscape.NodeSingular & cytoscape.EdgeSingular) => {\n const nodeId = ele.id();\n devLog(\"[CxtMenu] Expand request for node:\", nodeId);\n if (onExpandRequest) {\n const pos = ele.renderedPosition();\n const label = (ele.data(\"label\") as string) || nodeId;\n onExpandRequest({ nodeId, nodeLabel: label, x: pos.x, y: pos.y });\n } else {\n useGraphExploration\n .getState()\n .expandNode(nodeId)\n .catch((error: unknown) => {\n errorLog(\"[CxtMenu] Expansion failed:\", error);\n toast.error(\"Failed to expand node\");\n });\n }\n },\n },\n ],\n menuRadius: 60,\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 /** Fetch distinct edge types for a node (for expand options panel). */\n getNodeEdgeTypes?: (id: number) => Promise<string[]>;\n}\n\nfunction GraphVisualizer({\n onCopyNode,\n extraToolbarContent,\n getNodeEdgeTypes,\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 getNodeEdgeTypes={getNodeEdgeTypes}\n />\n )}\n {renderer === \"cytoscape\" && (\n <CytoscapeGraph\n key=\"cytoscape\"\n onCopyNode={onCopyNode}\n extraToolbarContent={extraToolbarContent}\n getNodeEdgeTypes={getNodeEdgeTypes}\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 PropertyList,\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 <div className=\"mt-2\">\n <PropertyList properties={node.properties_ || {}} showHeader />\n </div>\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 PropertyList,\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 <div className=\"mt-2\">\n <PropertyList properties={edge.properties_ || {}} showHeader />\n </div>\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 shown,\n onToggleLabel,\n}: {\n labels: string[];\n labelCounts: Record<string, number>;\n colorPalette: Record<string, string>;\n /** Set of node labels currently visible. */\n shown: Set<string>;\n onToggleLabel: (label: string) => void;\n}) {\n return labels.map((label) => {\n const bgColor = shown.has(label)\n ? colorPalette[label]\n : colorPalette[\"faded\"];\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={() => onToggleLabel(label)}\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/** A named group of node labels shown as its own legend sub-section. */\nexport interface NodeLabelBucket {\n title: string;\n /** Node labels in this bucket; only those present in the graph are shown. */\n labels: string[];\n}\n\nfunction bucketCount(\n labels: string[],\n labelCounts: Record<string, number>,\n): number {\n return labels.reduce((sum, l) => sum + (labelCounts[l] ?? 0), 0);\n}\n\n// The set of node labels currently visible, resolving the flat-filter\n// \"empty == all shown\" convention into an explicit set. This is the single\n// source of truth for both rendering and toggling when the node section is\n// split into multiple buckets, so toggling one bucket never changes another's\n// visibility.\nfunction effectiveShownNodeLabels(\n allLabels: string[],\n allLabelsDisabled: boolean,\n nodeLabelFilters: string[],\n): Set<string> {\n if (allLabelsDisabled) return new Set();\n if (nodeLabelFilters.length === 0) return new Set(allLabels);\n return new Set(nodeLabelFilters);\n}\n\n// Whether every label in the bucket is currently hidden.\nfunction isBucketAllOff(bucketLabels: string[], shown: Set<string>): boolean {\n return bucketLabels.every((l) => !shown.has(l));\n}\n\n// Persist an explicit shown-set back to the flat filter store in one atomic\n// write, preserving the \"all shown\" convention: when every label is shown,\n// use empty filter list + disabled=false (canonical form).\nfunction commitShownNodeLabels(\n shown: Set<string>,\n allLabels: string[],\n setNodeFilterState: (disabled: boolean, filters: string[]) => void,\n): void {\n if (shown.size === 0) {\n setNodeFilterState(true, []);\n } else {\n // All shown -> empty filter list (canonical \"all shown\" form).\n setNodeFilterState(\n false,\n shown.size === allLabels.length ? [] : [...shown],\n );\n }\n}\n\n// Toggle visibility of a whole bucket, preserving every label outside it.\nfunction toggleBucketAll(\n bucketLabels: string[],\n allLabels: string[],\n shown: Set<string>,\n setNodeFilterState: (disabled: boolean, filters: string[]) => void,\n): void {\n const next = new Set(shown);\n if (isBucketAllOff(bucketLabels, next)) {\n for (const l of bucketLabels) next.add(l);\n } else {\n for (const l of bucketLabels) next.delete(l);\n }\n commitShownNodeLabels(next, allLabels, setNodeFilterState);\n}\n\n// Toggle a single node label, preserving every other label's visibility.\nfunction toggleNodeLabelScoped(\n label: string,\n allLabels: string[],\n shown: Set<string>,\n setNodeFilterState: (disabled: boolean, filters: string[]) => void,\n): void {\n const next = new Set(shown);\n if (next.has(label)) {\n next.delete(label);\n } else {\n next.add(label);\n }\n commitShownNodeLabels(next, allLabels, setNodeFilterState);\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 nodeBuckets,\n edgeSectionTitle = \"Relations\",\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 /** Split the node section into named buckets (default: one \"Node Labels\"). */\n nodeBuckets?: NodeLabelBucket[];\n /** Heading for the edge (arrow) section. Default \"Relations\". */\n edgeSectionTitle?: 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 toggleEdgeLabelFilter = useGraphFilter(\n (state) => state.toggleEdgeLabelFilter,\n );\n const toggleAllEdgeLabelsDisabled = useGraphFilter(\n (state) => state.toggleAllEdgeLabelsDisabled,\n );\n const setNodeFilterState = useGraphFilter(\n (state) => state.setNodeFilterState,\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 // Resolve node-label buckets. Default: one \"Node Labels\" bucket with every\n // node label. When provided, each bucket keeps only labels present in the\n // graph; the \"All\" toggle and filtering are unchanged.\n const buckets: NodeLabelBucket[] = nodeBuckets\n ? nodeBuckets.map((b) => ({\n title: b.title,\n labels: b.labels.filter((l) => l in labelCounts).sort(),\n }))\n : [{ title: \"Node Labels\", labels: allLabels }];\n\n // Single source of truth for node visibility, shared by every bucket. All\n // node-label toggles (per-label and per-bucket \"All\") read and write this\n // set, preserving labels outside the bucket being toggled -- so toggling one\n // bucket never changes another bucket's state.\n const shownNodeLabels = effectiveShownNodeLabels(\n allLabels,\n allLabelsDisabled,\n nodeLabelFilters,\n );\n\n // toggleAllEdgeLabelsDisabled already clears edgeLabelFilters internally.\n const handleEdgeToggle = toggleAllEdgeLabelsDisabled;\n\n return (\n <>\n <p className=\"mt-2 heading-component\">Overview</p>\n\n {allLabels.length > 0 && (\n <div>\n {buckets.map((bucket) => {\n if (bucket.labels.length === 0) return null;\n // Every bucket's \"All\" and per-label badges resolve against the\n // shared shown set and write back preserving other buckets, so a\n // bucket toggle is fully scoped to its own labels.\n const bucketAllDisabled = isBucketAllOff(\n bucket.labels,\n shownNodeLabels,\n );\n const onBucketAll = () =>\n toggleBucketAll(\n bucket.labels,\n allLabels,\n shownNodeLabels,\n setNodeFilterState,\n );\n return (\n <div key={bucket.title} className=\"mb-2\">\n <p className=\"heading-meta mb-2\">{bucket.title}</p>\n <div className=\"flex flex-col items-start gap-2\">\n <AllToggleBadge\n allDisabled={bucketAllDisabled}\n colorPalette={colorPalette}\n count={bucketCount(bucket.labels, labelCounts)}\n onToggle={onBucketAll}\n badgeKey={`all-${bucket.title}`}\n />\n <NodeLabelBadges\n labels={bucket.labels}\n labelCounts={labelCounts}\n colorPalette={colorPalette}\n shown={shownNodeLabels}\n onToggleLabel={(label) =>\n toggleNodeLabelScoped(\n label,\n allLabels,\n shownNodeLabels,\n setNodeFilterState,\n )\n }\n />\n </div>\n </div>\n );\n })}\n </div>\n )}\n {allEdgeLabels.length > 0 && (\n <div>\n <p className=\"heading-meta mb-2\">{edgeSectionTitle}</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\nexport interface OverviewProps {\n /** Split the node section into named buckets (default: one \"Node Labels\"). */\n nodeBuckets?: NodeLabelBucket[];\n /** Heading for the edge (arrow) section. Default \"Relations\". */\n edgeSectionTitle?: string;\n}\n\nfunction Overview({ nodeBuckets, edgeSectionTitle }: OverviewProps = {}) {\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 heading-component\">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 nodeBuckets={nodeBuckets}\n edgeSectionTitle={edgeSectionTitle}\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 * **Node selection supports up to two nodes** (the cap that makes the \"Edges\"\n * action actionable): a plain click replaces the selection (jump-to); holding\n * Cmd/Ctrl/Shift toggles a node into a multi-selection, evicting the oldest\n * past the cap (FIFO). Edge rows remain single-select.\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 { useCallback, 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\n// Two is the meaningful cap: the edge action needs exactly two nodes, node\n// edit/delete need one, add-node needs none. Anything beyond two produces a\n// non-actionable selection. Module-level constant -- never varies at runtime.\nconst MAX_NODE_SELECTION = 2;\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 // Activating a node row. A plain activation replaces the selection with that\n // single node (jump-to). Holding a modifier (Cmd/Ctrl/Shift) toggles the node\n // into a multi-selection capped at MAX_NODE_SELECTION, evicting the oldest\n // (FIFO) past the cap -- so two nodes can be selected without the canvas,\n // which is what the edge action requires. Modifiers are available on both\n // mouse clicks and keyboard activation (Enter/Space), so this stays\n // keyboard-accessible.\n const activateNode = useCallback(\n (id: string, additive: boolean) => {\n setSelectedEdge(null);\n if (!additive) {\n setSelectedNodeIds([id]);\n return;\n }\n if (selectedNodeIds.includes(id)) {\n setSelectedNodeIds(selectedNodeIds.filter((x) => x !== id));\n return;\n }\n // FIFO evict from the front so the most recently added two remain.\n setSelectedNodeIds([...selectedNodeIds, id].slice(-MAX_NODE_SELECTION));\n },\n [selectedNodeIds, setSelectedNodeIds, setSelectedEdge],\n );\n\n const selectRow = useCallback(\n (row: Row, e: React.MouseEvent | React.KeyboardEvent) => {\n if (row.kind === \"node\") {\n activateNode(row.id, e.metaKey || e.ctrlKey || e.shiftKey);\n } else {\n setSelectedNodeIds([]);\n setSelectedEdge(row.edge);\n }\n },\n [activateNode, setSelectedNodeIds, setSelectedEdge],\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 aria-multiselectable={true}\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={(e) => selectRow(row, e)}\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","/**\n * Graph model (metamodel) types.\n *\n * A graph model is a list of type schemas, each a JSON Schema carrying an\n * `x-graph` extension that declares whether it is a node or edge type, its\n * graph label, and (for node types) the valid outbound relations. This mirrors\n * the shape consumed by cypher-graphdb-core, so a model authored here is a\n * valid model there.\n *\n * The model is the source of truth. It is rendered as a graph of node-types and\n * relation-edges via `modelToGraph` + `GraphVisualizer`; there is no reverse\n * conversion.\n */\n\n/** Relation cardinality. Binary only, matching the core model. */\nexport type Cardinality = \"ONE_TO_ONE\" | \"ONE_TO_MANY\";\n\n/**\n * A valid outbound relation from a node type. Directional: the triple is\n * (owning type, rel_type_name, to_type_name). Asymmetry is the default --\n * declare the reverse relation explicitly if it is also valid.\n */\nexport interface GraphRelation {\n /** Relation/edge label, e.g. \"partOf\". */\n rel_type_name: string;\n /** Target node-type label. */\n to_type_name: string;\n /** Binary cardinality. Defaults to ONE_TO_MANY when omitted. */\n cardinality?: Cardinality;\n /** Whether the relation is surfaced as a form field (consumer hint). */\n form_field?: boolean;\n description?: string;\n}\n\n/** Optional display configuration for a type (how instances are labelled). */\nexport interface GraphModelDisplay {\n labelTemplate?: string;\n labelProperty?: string;\n fallbackProperty?: string;\n sortProperty?: string;\n sortOrder?: \"ASC\" | \"DESC\";\n filterProperty?: string;\n}\n\n/** The `x-graph` extension on a type schema. */\nexport interface XGraph {\n /** NODE types carry relations; EDGE types define relationship properties. */\n type: \"NODE\" | \"EDGE\";\n /** The authoritative graph label, e.g. \"Hospital\" or \"partOf\". */\n label: string;\n /** Allowed outbound relations (node types only). */\n relations?: GraphRelation[];\n /** Parent type labels this type inherits from. */\n inherits_from?: string[];\n display?: GraphModelDisplay;\n /** Free-form metadata preserved on round-trip. */\n metadata?: Record<string, unknown>;\n source?: string;\n}\n\n/**\n * A single property definition within a type schema. A pragmatic subset of\n * JSON Schema; unknown keys are preserved.\n */\nexport interface GraphModelProperty {\n type?: string | string[];\n title?: string;\n description?: string;\n enum?: Array<string | number>;\n format?: string;\n default?: unknown;\n items?: GraphModelProperty;\n [key: string]: unknown;\n}\n\n/**\n * One type in the model: a JSON Schema object with an `x-graph` extension.\n * Additional `x-*` extension keys are allowed and preserved.\n */\nexport interface GraphTypeSchema {\n title?: string;\n type: \"object\";\n properties?: Record<string, GraphModelProperty>;\n required?: string[];\n \"x-graph\": XGraph;\n [key: string]: unknown;\n}\n\n/** A graph model: the list of node/edge type schemas. */\nexport type GraphModel = GraphTypeSchema[];\n\n/** Type guard: is this type schema a node type (vs an edge type). */\nexport function isNodeType(schema: GraphTypeSchema): boolean {\n return schema[\"x-graph\"].type !== \"EDGE\";\n}\n\n/** Type guard: is this type schema an edge type (vs a node type). */\nexport function isEdgeType(schema: GraphTypeSchema): boolean {\n return schema[\"x-graph\"].type === \"EDGE\";\n}\n\n/** The graph label of a type schema (x-graph.label, falling back to title). */\nexport function typeLabel(schema: GraphTypeSchema): string {\n return schema[\"x-graph\"].label || schema.title || \"Unknown\";\n}\n","/**\n * Convert a graph model (metamodel) into renderable nodes and edges.\n *\n * Forward conversion only: a `GraphModel` becomes a graph of node-type nodes\n * and relation/inheritance edges, suitable for `enrichNodes` / `enrichEdges`\n * and `GraphVisualizer`. The model JSON is the source of truth; there is no\n * reverse conversion.\n *\n * Ports cypher-graphdb-core's `json_schemas_to_graph` with two deliberate\n * differences:\n * - Node/edge ids are derived deterministically from type/relation names so\n * the same model always yields the same ids (required for visualizer merge,\n * dedup, and stable selection).\n * - A node's `label_` is the type label itself (e.g. \"Hospital\"), so the\n * legend colours and filters by type. `x-graph.type` still distinguishes\n * node from edge type schemas.\n */\n\nimport type { RawGraphNode, RawGraphEdge } from \"../models/graph-types\";\nimport {\n type GraphModel,\n type GraphTypeSchema,\n isNodeType,\n typeLabel,\n} from \"./types\";\n\n/** The output of modelToGraph: renderable nodes + edges. */\nexport interface ModelGraph {\n nodes: RawGraphNode[];\n edges: RawGraphEdge[];\n}\n\n// Deterministic 31-bit hash of a string (FNV-1a variant), so ids are stable\n// and positive across runs and processes.\nfunction stableId(seed: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < seed.length; i++) {\n h ^= seed.charCodeAt(i);\n h = Math.imul(h, 0x01000193);\n }\n // Mask to a positive 31-bit integer.\n return (h & 0x7fffffff) >>> 0;\n}\n\nfunction nodeId(typeName: string): number {\n return stableId(`schema.node.${typeName}`);\n}\n\nfunction edgeId(source: string, target: string, rel: string): number {\n return stableId(`schema.edge.${source}.${target}.${rel}`);\n}\n\n// Convert a hyphenated extension key to camelCase, e.g. \"x-graph\" -> \"xGraph\".\nfunction toCamelCase(key: string): string {\n const parts = key.split(\"-\");\n return (\n parts[0] +\n parts\n .slice(1)\n .map((w) => (w ? w[0].toUpperCase() + w.slice(1) : \"\"))\n .join(\"\")\n );\n}\n\nfunction buildNode(schema: GraphTypeSchema): RawGraphNode {\n const name = typeLabel(schema);\n const properties: Record<string, unknown> = {\n gid_: `schema:${name}`,\n name,\n type: schema.type ?? \"object\",\n propertyDefinitions: schema.properties ?? {},\n required: schema.required ?? [],\n };\n // Preserve all x-* extensions (xGraph, etc.) for downstream use.\n for (const key of Object.keys(schema)) {\n if (key.startsWith(\"x-\")) {\n properties[toCamelCase(key)] = schema[key];\n }\n }\n return {\n id_: nodeId(name),\n // Type label drives legend colour/filtering; node vs edge type is in xGraph.\n label_: name,\n properties_: properties as RawGraphNode[\"properties_\"],\n };\n}\n\nfunction buildRelationEdges(\n schema: GraphTypeSchema,\n knownTypes: Set<string>,\n): RawGraphEdge[] {\n const source = typeLabel(schema);\n const sourceId = nodeId(source);\n const edges: RawGraphEdge[] = [];\n for (const relation of schema[\"x-graph\"].relations ?? []) {\n const target = relation.to_type_name;\n if (!target || !knownTypes.has(target)) continue;\n const rel = relation.rel_type_name || \"RELATED_TO\";\n // Use \"\\0\" as separator so labels containing colons parse unambiguously.\n const properties: Record<string, unknown> = {\n gid_: `schema:rel:${source}\\0${target}`,\n name: rel,\n cardinality: relation.cardinality ?? \"ONE_TO_MANY\",\n };\n if (relation.form_field !== undefined)\n properties.form_field = relation.form_field;\n if (relation.description !== undefined)\n properties.description = relation.description;\n edges.push({\n id_: edgeId(source, target, rel),\n label_: rel,\n start_id_: sourceId,\n end_id_: nodeId(target),\n properties_: properties as RawGraphEdge[\"properties_\"],\n });\n }\n return edges;\n}\n\nfunction buildInheritanceEdges(\n schema: GraphTypeSchema,\n knownTypes: Set<string>,\n): RawGraphEdge[] {\n const source = typeLabel(schema);\n const sourceId = nodeId(source);\n const edges: RawGraphEdge[] = [];\n for (const parent of schema[\"x-graph\"].inherits_from ?? []) {\n if (!knownTypes.has(parent)) continue;\n edges.push({\n id_: edgeId(source, parent, \"INHERITS_FROM_\"),\n label_: \"INHERITS_FROM_\",\n start_id_: sourceId,\n end_id_: nodeId(parent),\n properties_: {\n gid_: `schema:rel:${source}\\0${parent}`,\n name: \"INHERITS_FROM_\",\n parent,\n } as RawGraphEdge[\"properties_\"],\n });\n }\n return edges;\n}\n\n/**\n * Convert a graph model into renderable nodes and edges.\n *\n * Both node types and edge types become canvas nodes. Node types carry the\n * `x-graph.relations[*]` arrows between them (plus `inherits_from` arrows).\n * Edge types are rendered as standalone nodes (the catalog of relationship\n * types); they are not connected by arrows. Relation arrows only connect node\n * types, so relations whose target is not a node type are skipped.\n */\nexport function modelToGraph(model: GraphModel): ModelGraph {\n const nodeTypes = model.filter(isNodeType);\n const knownTypes = new Set(nodeTypes.map(typeLabel));\n const nodes = model.map(buildNode);\n const edges: RawGraphEdge[] = [];\n for (const schema of nodeTypes) {\n edges.push(...buildRelationEdges(schema, knownTypes));\n edges.push(...buildInheritanceEdges(schema, knownTypes));\n }\n return { nodes, edges };\n}\n","/**\n * Canvas label-filter reconciliation for the model editor.\n *\n * The graph filter is an allowlist of node labels: empty = show all; non-empty\n * = show only those labels. The model editor uses it to optionally hide\n * edge-type nodes (showEdgeTypes) while keeping the user's show/hide choices\n * stable across model edits.\n */\n\nimport { type GraphModel, isNodeType, typeLabel } from \"./types\";\n\n/**\n * Reconcile the node-label allowlist after a model load.\n *\n * - baselineReset (first load or showEdgeTypes toggled): set the baseline --\n * show all (empty) when showEdgeTypes is true, otherwise allow only\n * node-type labels so edge types are hidden.\n * - Otherwise (a model edit): preserve the user's current filter, but drop\n * labels that no longer exist and add any new node-type labels so a\n * just-created node type is visible. An empty filter (\"show all\") stays\n * empty -- we never spontaneously start hiding what the user chose to show.\n */\nexport function reconcileFilter(\n current: string[],\n model: GraphModel,\n baselineReset: boolean,\n showEdgeTypes: boolean,\n): string[] {\n const nodeTypeLabels = model.filter(isNodeType).map(typeLabel);\n\n if (baselineReset) {\n return showEdgeTypes ? [] : nodeTypeLabels;\n }\n\n if (current.length === 0) return [];\n\n const allLabels = new Set(model.map(typeLabel));\n const kept = current.filter((l) => allLabels.has(l));\n const keptSet = new Set(kept);\n const added = nodeTypeLabels.filter((l) => !keptSet.has(l));\n return added.length > 0 ? [...kept, ...added] : kept;\n}\n","/**\n * GraphModelEditor -- view and edit a graph model (metamodel).\n *\n * A controlled component over the model JSON: pass a `GraphModel` in, render it\n * as a graph of node-types and relation-edges via `GraphVisualizer`, and (when\n * authoring lands) emit an edited model through `onChange`. Read-only is a mode\n * of the same component.\n *\n * Rendering reuses the existing visualizer: the model is converted with\n * `modelToGraph`, enriched, and pushed into a per-instance workspace store.\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { ResizeHandle } from \"@petrarca/sonnet-ui\";\nimport GraphVisualizer from \"../components/GraphVisualizer\";\nimport { ModelActionPanel } from \"./ModelActionPanel\";\nimport { GraphStoresContext } from \"../hooks/useWorkspaceStores\";\nimport { GraphRendererProvider } from \"../hooks/graphRendererProvider\";\nimport { createGraphDataStore } from \"../stores/GraphData\";\nimport { createGraphFilterStore } from \"../stores/GraphFilter\";\nimport { createSelectionStore } from \"../stores/Selection\";\nimport { createGraphFocusStore } from \"../stores/GraphFocus\";\nimport { createGraphExplorationStore } from \"../stores/GraphExploration\";\nimport type { WorkspaceStores } from \"../stores/types\";\nimport { buildColorPalette } from \"../graph/enrichment\";\nimport { enrichNodes, enrichEdges } from \"../graph/enrichment\";\nimport { modelToGraph } from \"./converter\";\nimport type { GraphModel } from \"./types\";\nimport { reconcileFilter } from \"./filter\";\nimport {\n type GraphModelCapabilities,\n resolveCapabilities,\n} from \"./capabilities\";\nimport type { GraphRenderer } from \"../hooks/useGraphRendererContext\";\n\nexport interface GraphModelEditorProps {\n /** The graph model to view/edit. Controlled. */\n value: GraphModel;\n /**\n * Called with the edited model. Omit (or set readOnly) for a view-only\n * editor.\n */\n onChange?: (model: GraphModel) => void;\n /** View-only: no edit affordances, onChange never fires. Shorthand for\n * fully-locked capabilities. */\n readOnly?: boolean;\n /** Fine-grained gating of what can be edited. Merged onto full-edit\n * defaults; readOnly overrides to fully locked. */\n capabilities?: GraphModelCapabilities;\n /** Allowed x-ui-widget values offered when editing a property. */\n widgetOptions?: string[];\n /** Default graph renderer. */\n defaultRenderer?: GraphRenderer;\n /** Hide the side panel (node/edge detail + overview legend). */\n hideActionPanel?: boolean;\n}\n\n// Build a fresh set of workspace stores for one editor instance. The model is\n// static (no server expansion), so the exploration backend is stubbed.\nfunction createEditorStores(): WorkspaceStores {\n const graphFilter = createGraphFilterStore();\n const graphData = createGraphDataStore();\n const selection = createSelectionStore();\n const graphFocus = createGraphFocusStore();\n const graphExploration = createGraphExplorationStore({\n graphData,\n selection,\n graphFocus,\n graphFilter,\n expandNode: async () => ({ nodes: [], edges: [], has_more: false }),\n getNodes: async () => [],\n });\n return { graphFilter, graphData, graphExploration, selection };\n}\n\nfunction loadModel(stores: WorkspaceStores, model: GraphModel): void {\n const { nodes: rawNodes, edges: rawEdges } = modelToGraph(model);\n const labelCounts: Record<string, number> = {};\n for (const n of rawNodes) {\n labelCounts[n.label_] = (labelCounts[n.label_] ?? 0) + 1;\n }\n const palette = buildColorPalette(labelCounts);\n const nodes = enrichNodes(rawNodes, palette);\n const edges = enrichEdges(rawEdges, palette);\n // Do NOT reset filters here: editing the model flows through onChange and\n // re-runs this loader, and a reset would wipe the user's current label\n // filter on every property/relation edit. notifyDataChange reconciles the\n // filter store with the new data (added/removed labels) without clobbering\n // the user's choices.\n stores.graphData\n .getState()\n .setQueryData(nodes, edges, { nodes: nodes.length, edges: edges.length });\n stores.graphFilter.getState().notifyDataChange();\n}\n\nexport function GraphModelEditor({\n value,\n readOnly,\n capabilities,\n onChange,\n widgetOptions,\n defaultRenderer = \"cytoscape\",\n hideActionPanel = false,\n}: GraphModelEditorProps): React.ReactElement {\n // One store bundle per editor instance, stable across renders.\n const storesRef = useRef<WorkspaceStores | null>(null);\n if (!storesRef.current) storesRef.current = createEditorStores();\n const stores = storesRef.current;\n\n const caps = resolveCapabilities(capabilities, readOnly);\n const showEdgeTypes = caps.showEdgeTypes;\n\n // Re-render the model graph whenever the model changes, reconciling the\n // canvas label filter so edits preserve the user's show/hide choices while\n // newly added types appear and removed types drop out. See reconcileFilter.\n // A \"baseline reset\" happens on first load and whenever the showEdgeTypes\n // capability is toggled; otherwise the user's filter is preserved.\n const firstLoadRef = useRef(true);\n const prevShowEdgeTypesRef = useRef(showEdgeTypes);\n useEffect(() => {\n loadModel(stores, value);\n const filter = stores.graphFilter.getState();\n const baselineReset =\n firstLoadRef.current || prevShowEdgeTypesRef.current !== showEdgeTypes;\n const next = reconcileFilter(\n filter.nodeLabelFilters,\n value,\n baselineReset,\n showEdgeTypes,\n );\n filter.setNodeLabelFilters(next);\n firstLoadRef.current = false;\n prevShowEdgeTypesRef.current = showEdgeTypes;\n }, [stores, value, showEdgeTypes]);\n\n // Resizable right panel.\n const rowRef = useRef<HTMLDivElement>(null);\n const [panelWidth, setPanelWidth] = useState(380);\n const startResize = useCallback((e: React.PointerEvent) => {\n e.preventDefault();\n const target = e.currentTarget as HTMLElement;\n target.setPointerCapture(e.pointerId);\n const move = (ev: PointerEvent) => {\n const right = rowRef.current?.getBoundingClientRect().right ?? 0;\n setPanelWidth(Math.min(640, Math.max(300, right - ev.clientX)));\n };\n const up = () => {\n window.removeEventListener(\"pointermove\", move);\n window.removeEventListener(\"pointerup\", up);\n };\n window.addEventListener(\"pointermove\", move);\n window.addEventListener(\"pointerup\", up);\n }, []);\n\n return (\n <GraphStoresContext.Provider value={stores}>\n <GraphRendererProvider defaultRenderer={defaultRenderer}>\n <div ref={rowRef} className=\"flex w-full h-full overflow-hidden\">\n <div className=\"flex-1 min-w-0\">\n <GraphVisualizer />\n </div>\n {!hideActionPanel && (\n <>\n <ResizeHandle\n orientation=\"vertical\"\n aria-valuenow={panelWidth}\n aria-valuemin={300}\n aria-valuemax={640}\n onPointerDown={startResize}\n onDoubleClick={() => setPanelWidth(380)}\n />\n <div\n style={{ width: panelWidth }}\n className=\"shrink-0 border-l overflow-hidden bg-card\"\n >\n <ModelActionPanel\n model={value}\n onChange={onChange}\n readOnly={readOnly}\n capabilities={capabilities}\n widgetOptions={widgetOptions}\n />\n </div>\n </>\n )}\n </div>\n </GraphRendererProvider>\n </GraphStoresContext.Provider>\n );\n}\n\nexport default GraphModelEditor;\n","/**\n * ModelActionPanel -- selection-aware detail panel for the model editor.\n *\n * Renders, from the current model + workspace selection:\n * - a relation's detail when a relation arrow is selected,\n * - two node types selected => a \"Create relation\" prompt (select-two-then-link),\n * - a single node type's detail when one node is selected,\n * - the Overview legend when nothing is selected.\n *\n * Editing flows through onChange (controlled). Replaces the generic ActionPanel\n * inside GraphModelEditor; the instance-graph ActionPanel is unchanged.\n */\n\nimport React, { useMemo, useState } from \"react\";\nimport { Button, IconButton } from \"@petrarca/sonnet-ui\";\nimport { GitBranchPlus, CirclePlus, Waypoints } from \"lucide-react\";\nimport Overview from \"../components/ActionPanel/Overview\";\nimport { useWorkspaceSelection } from \"../hooks/useWorkspaceStores\";\nimport { useLiveGraphData } from \"../hooks/useLiveGraphData\";\nimport type { SelectionStore } from \"../stores/Selection\";\nimport { TypeDetailPanel, type TypeDetailPanelProps } from \"./TypeDetailPanel\";\nimport { RelationFormSheet } from \"./RelationFormSheet\";\nimport { NodeTypeNameSheet } from \"./NodeTypeNameSheet\";\nimport { resolveRelationEdge, findType } from \"./view\";\nimport {\n addRelation,\n addNodeType,\n addEdgeType,\n type RelationInput,\n} from \"./mutate\";\nimport { type GraphModel, typeLabel, isNodeType, isEdgeType } from \"./types\";\nimport {\n resolveCapabilities,\n type GraphModelCapabilities,\n type ResolvedCapabilities,\n type EdgeTypeMode,\n} from \"./capabilities\";\n\n// Node-type labels (rendered as the node types bucket).\nfunction nodeTypeLabels(model: GraphModel): string[] {\n return model.filter(isNodeType).map(typeLabel);\n}\n\n// Edge-type labels (the catalog of relationship-type definitions).\nfunction edgeTypeLabels(model: GraphModel): string[] {\n return model.filter(isEdgeType).map(typeLabel);\n}\n\nexport interface ModelActionPanelProps {\n model: GraphModel;\n onChange?: (model: GraphModel) => void;\n readOnly?: boolean;\n capabilities?: GraphModelCapabilities;\n widgetOptions?: string[];\n}\n\n// Two node types selected: prompt to create a relation between them.\nfunction CreateRelationPrompt({\n nodeA,\n nodeB,\n model,\n edgeTypeMode,\n onChange,\n}: {\n nodeA: string;\n nodeB: string;\n model: GraphModel;\n edgeTypeMode: EdgeTypeMode;\n onChange: (model: GraphModel) => void;\n}): React.ReactElement {\n const [open, setOpen] = useState(false);\n return (\n <div>\n <div className=\"text-sm\">\n <span className=\"font-medium\">{nodeA}</span>\n {\" and \"}\n <span className=\"font-medium\">{nodeB}</span>\n {\" selected.\"}\n </div>\n <Button size=\"sm\" className=\"mt-3 gap-1.5\" onClick={() => setOpen(true)}>\n <GitBranchPlus className=\"h-4 w-4\" />\n Create relation\n </Button>\n <RelationFormSheet\n open={open}\n onOpenChange={setOpen}\n nodeA={nodeA}\n nodeB={nodeB}\n edgeTypeOptions={edgeTypeLabels(model)}\n edgeTypeMode={edgeTypeMode}\n onSave={(source, _target, input: RelationInput) =>\n onChange(addRelation(model, source, input))\n }\n />\n </div>\n );\n}\n\nexport function ModelActionPanel({\n model,\n onChange,\n readOnly,\n capabilities,\n widgetOptions,\n}: ModelActionPanelProps): React.ReactElement {\n const caps = resolveCapabilities(capabilities, readOnly);\n const useSelection = useWorkspaceSelection();\n const selectedNodeIds = useSelection(\n (s: SelectionStore) => s.selectedNodeIds,\n );\n const selectedEdge = useSelection((s: SelectionStore) => s.selectedEdge);\n const live = useLiveGraphData();\n\n const labelsById = (ids: string[]): string[] =>\n ids\n .map((id) => live.normalized.nodesById[id]?.label_)\n .filter((l): l is string => !!l);\n\n const selection = useMemo<TypeDetailPanelProps[\"selection\"] | null>(() => {\n if (selectedEdge) {\n const r = resolveRelationEdge(selectedEdge);\n if (r) {\n return {\n kind: \"relation\",\n source: r.source,\n relType: r.relType,\n target: r.target,\n };\n }\n }\n const firstId = selectedNodeIds[0];\n if (selectedNodeIds.length === 1 && firstId != null) {\n const node = live.normalized.nodesById[firstId];\n if (node) {\n // An edge-type node (e.g. OWNS) resolves to the edge-type detail; a\n // node-type node to the node detail. Distinguish by the model.\n const schema = findType(model, node.label_);\n const kind = schema && isEdgeType(schema) ? \"edge\" : \"node\";\n return { kind, label: node.label_ };\n }\n }\n return null;\n }, [selectedEdge, selectedNodeIds, live.normalized, model]);\n\n // Only offer the create-relation prompt when both selected nodes are node\n // types, not edge types. Edge-type nodes share the canvas but are not valid\n // relation endpoints.\n const twoLabels =\n selectedNodeIds.length === 2 && !selectedEdge\n ? labelsById(selectedNodeIds).filter((l) => {\n const schema = findType(model, l);\n return schema ? isNodeType(schema) : false;\n })\n : [];\n\n return (\n <div className=\"h-full overflow-auto p-4\">\n <PanelBody\n model={model}\n onChange={onChange}\n readOnly={readOnly}\n caps={caps}\n widgetOptions={widgetOptions}\n selection={selection}\n twoLabels={twoLabels}\n />\n </div>\n );\n}\n\n// Decides which view the panel shows: a selected element's detail, the\n// create-relation prompt (two node types selected), or the Overview (with an\n// optional Add node type affordance).\nfunction PanelBody({\n model,\n onChange,\n readOnly,\n caps,\n widgetOptions,\n selection,\n twoLabels,\n}: {\n model: GraphModel;\n onChange?: (model: GraphModel) => void;\n readOnly?: boolean;\n caps: ResolvedCapabilities;\n widgetOptions?: string[];\n selection: TypeDetailPanelProps[\"selection\"] | null;\n twoLabels: string[];\n}): React.ReactElement {\n if (selection) {\n return (\n <TypeDetailPanel\n model={model}\n selection={selection}\n onChange={onChange}\n readOnly={readOnly}\n capabilities={caps}\n widgetOptions={widgetOptions}\n />\n );\n }\n const canEdit = !readOnly && !!onChange;\n if (twoLabels.length === 2 && canEdit && caps.relations === \"edit\") {\n return (\n <CreateRelationPrompt\n nodeA={twoLabels[0]}\n nodeB={twoLabels[1]}\n model={model}\n edgeTypeMode={caps.edgeTypes}\n onChange={onChange!}\n />\n );\n }\n return (\n <>\n {canEdit && (\n <AddTypeToolbar\n model={model}\n onChange={onChange!}\n canAddNode={caps.nodeTypes === \"edit\"}\n canAddEdge={caps.edgeTypes === \"edit\"}\n />\n )}\n <Overview\n nodeBuckets={[\n { title: \"Node types\", labels: nodeTypeLabels(model) },\n { title: \"Edge types\", labels: edgeTypeLabels(model) },\n ]}\n edgeSectionTitle=\"Relations\"\n />\n </>\n );\n}\n\n// A compact icon button that opens a name sheet to add a node or edge type.\n// Icon-only with a tooltip; the glyph conveys the type (node vs edge).\nfunction AddTypeIconButton({\n tooltip,\n icon,\n noun,\n existing,\n onSave,\n}: {\n tooltip: string;\n icon: React.ReactNode;\n noun: \"node\" | \"edge\";\n existing: string[];\n onSave: (name: string) => void;\n}): React.ReactElement {\n const [open, setOpen] = useState(false);\n return (\n <>\n <IconButton\n label={tooltip}\n variant=\"outline\"\n onClick={() => setOpen(true)}\n >\n {icon}\n </IconButton>\n <NodeTypeNameSheet\n open={open}\n onOpenChange={setOpen}\n existing={existing}\n noun={noun}\n onSave={onSave}\n />\n </>\n );\n}\n\n// Add-type affordances: compact icon buttons on a single row above the\n// Overview. The node/edge glyphs and tooltips convey what each adds.\nfunction AddTypeToolbar({\n model,\n onChange,\n canAddNode,\n canAddEdge,\n}: {\n model: GraphModel;\n onChange: (model: GraphModel) => void;\n canAddNode: boolean;\n canAddEdge: boolean;\n}): React.ReactElement | null {\n if (!canAddNode && !canAddEdge) return null;\n const existing = model.map(typeLabel);\n return (\n <div className=\"mb-3 flex gap-1.5\">\n {canAddNode && (\n <AddTypeIconButton\n tooltip=\"Add node type\"\n icon={<CirclePlus />}\n noun=\"node\"\n existing={existing}\n onSave={(name) => onChange(addNodeType(model, name))}\n />\n )}\n {canAddEdge && (\n <AddTypeIconButton\n tooltip=\"Add edge type\"\n icon={<Waypoints />}\n noun=\"edge\"\n existing={existing}\n onSave={(name) => onChange(addEdgeType(model, name))}\n />\n )}\n </div>\n );\n}\n\nexport default ModelActionPanel;\n","/**\n * TypeDetailPanel -- detail for a selected metamodel element.\n *\n * Renders either a node type (Identity + Properties + Relations) or a relation\n * arrow (Identity + endpoints + Properties joined from the relation's hidden\n * edge type). Uniform Properties presentation for both. When not readOnly and\n * capabilities allow, properties can be added / edited / deleted; mutations\n * edit the model and are emitted via onChange.\n */\n\nimport React, { useState } from \"react\";\nimport { Badge, IconButton } from \"@petrarca/sonnet-ui\";\nimport { Plus, Pencil, Trash2 } from \"lucide-react\";\nimport type { GraphModel } from \"./types\";\nimport {\n nodeTypeView,\n edgeTypeView,\n relationView,\n cardinalityLabel,\n type NodeTypeView,\n type EdgeTypeView,\n type RelationDetailView,\n type PropertyView,\n type RelationView,\n} from \"./view\";\nimport {\n setNodeProperty,\n deleteNodeProperty,\n setRelationProperty,\n deleteRelationProperty,\n setEdgeTypeProperty,\n deleteEdgeTypeProperty,\n updateRelation,\n deleteRelation,\n renameNodeType,\n deleteNodeType,\n renameEdgeType,\n deleteEdgeType,\n type PropertyInput,\n type RelationInput,\n} from \"./mutate\";\nimport { PropertyFormSheet } from \"./PropertyFormSheet\";\nimport { RelationFormSheet } from \"./RelationFormSheet\";\nimport { NodeTypeNameSheet } from \"./NodeTypeNameSheet\";\nimport { typeLabel, isEdgeType } from \"./types\";\nimport type {\n ResolvedCapabilities,\n EditMode,\n EdgeTypeMode,\n} from \"./capabilities\";\n\n// Build the RelationView (the shape used by the node-type relations list) from\n// a selected relation arrow, so edit/delete from the arrow reuse exactly the\n// same handlers as the list.\nfunction relationViewOf(view: RelationDetailView): RelationView {\n return {\n relType: view.relType,\n target: view.target,\n cardinality: view.cardinality,\n description: view.description,\n };\n}\n\nfunction SectionTitle({\n children,\n action,\n}: {\n children: React.ReactNode;\n action?: React.ReactNode;\n}): React.ReactElement {\n return (\n <div className=\"mt-4 mb-2 flex items-center gap-2\">\n <span className=\"heading-meta\">{children}</span>\n {action && <span className=\"ml-auto\">{action}</span>}\n </div>\n );\n}\n\nfunction PropertyRows({\n properties,\n emptyText,\n editable,\n onEdit,\n onDelete,\n}: {\n properties: PropertyView[];\n emptyText: string;\n editable: boolean;\n onEdit: (p: PropertyView) => void;\n onDelete: (p: PropertyView) => void;\n}): React.ReactElement {\n if (properties.length === 0) {\n return <p className=\"text-xs text-muted-foreground\">{emptyText}</p>;\n }\n return (\n <div className=\"rounded-lg border divide-y\">\n {properties.map((p) => (\n <div\n key={p.name}\n className=\"group/row flex items-center gap-2 px-3 py-2\"\n >\n <span className=\"text-sm font-medium min-w-24\">{p.name}</span>\n <span className=\"flex-1 font-mono text-xs text-muted-foreground\">\n {p.type}\n {p.widget ? ` \\u00b7 ${p.widget}` : \"\"}\n </span>\n {p.required && <Badge badgeColor=\"orange\">required</Badge>}\n {editable && (\n <span className=\"flex gap-1\">\n <IconButton\n label=\"Edit property\"\n revealOnHover\n onClick={() => onEdit(p)}\n >\n <Pencil />\n </IconButton>\n <IconButton\n label=\"Delete property\"\n tone=\"destructive\"\n revealOnHover\n onClick={() => onDelete(p)}\n >\n <Trash2 />\n </IconButton>\n </span>\n )}\n </div>\n ))}\n </div>\n );\n}\n\ninterface SheetState {\n open: boolean;\n property?: PropertyView;\n}\n\n// Resolve gating from capabilities. The Properties section follows the\n// nodeProperties mode for a node type and the edgeProperties mode for a\n// relation; node-type rename/delete follow the nodeTypes mode.\ninterface Gating {\n propsHidden: boolean;\n propsEditable: boolean;\n nodeTypeEditable: boolean;\n edgeTypeEditable: boolean;\n relationsEditable: boolean;\n}\n\n// Whether an area is editable: editable session AND the area's mode is \"edit\".\nfunction areaEditable(editable: boolean, mode: EditMode | undefined): boolean {\n return editable && (mode ?? \"edit\") === \"edit\";\n}\n\nfunction resolveGating(\n kind: \"node\" | \"relation\" | \"edge\",\n editable: boolean,\n c: ResolvedCapabilities | undefined,\n): Gating {\n // Node-type properties follow nodeProperties; relation and edge-type\n // properties (the same data, keyed by edge-type label) follow edgeProperties.\n const propsMode =\n (kind === \"node\" ? c?.nodeProperties : c?.edgeProperties) ?? \"edit\";\n // Edge-type rename/delete follow the edgeTypes capability; only \"edit\"\n // allows structural changes (\"catalog\" is select-only, \"readonly\" locks).\n const edgeTypeEditable = editable && (c?.edgeTypes ?? \"edit\") === \"edit\";\n return {\n propsHidden: propsMode === \"hidden\",\n propsEditable: areaEditable(editable, propsMode),\n nodeTypeEditable: areaEditable(editable, c?.nodeTypes),\n edgeTypeEditable,\n relationsEditable: areaEditable(editable, c?.relations),\n };\n}\n\nexport interface TypeDetailPanelProps {\n model: GraphModel;\n /** The selected element: a node type, an edge type, or a relation arrow. */\n selection:\n | { kind: \"node\"; label: string }\n | { kind: \"edge\"; label: string }\n | { kind: \"relation\"; source: string; relType: string; target: string };\n onChange?: (model: GraphModel) => void;\n readOnly?: boolean;\n /** Resolved capabilities (gating per area). */\n capabilities?: ResolvedCapabilities;\n /** Allowed x-ui-widget values offered in the property form. */\n widgetOptions?: string[];\n}\n\n// Resolve a selection into the matching detail view (node / edge / relation).\nfunction resolveView(\n model: GraphModel,\n selection: TypeDetailPanelProps[\"selection\"],\n): NodeTypeView | EdgeTypeView | RelationDetailView | null {\n if (selection.kind === \"node\") return nodeTypeView(model, selection.label);\n if (selection.kind === \"edge\") return edgeTypeView(model, selection.label);\n return relationView(\n model,\n selection.source,\n selection.relType,\n selection.target,\n );\n}\n\ntype DetailView = NodeTypeView | EdgeTypeView | RelationDetailView;\n\n// Add/update a property on the selected element, routing to the right store:\n// node-type, edge-type (selected directly), or relation (lazy edge type).\nfunction applySaveProperty(\n model: GraphModel,\n view: DetailView,\n input: PropertyInput,\n prevName?: string,\n): GraphModel {\n if (view.kind === \"node\")\n return setNodeProperty(model, view.label, input, prevName);\n if (view.kind === \"edge\")\n return setEdgeTypeProperty(model, view.label, input, prevName);\n return setRelationProperty(model, view.relType, input, prevName);\n}\n\n// Delete a property from the selected element (same routing as applySaveProperty).\nfunction applyRemoveProperty(\n model: GraphModel,\n view: DetailView,\n name: string,\n): GraphModel {\n if (view.kind === \"node\") return deleteNodeProperty(model, view.label, name);\n if (view.kind === \"edge\")\n return deleteEdgeTypeProperty(model, view.label, name);\n return deleteRelationProperty(model, view.relType, name);\n}\n\nexport function TypeDetailPanel({\n model,\n selection,\n onChange,\n readOnly,\n capabilities,\n widgetOptions,\n}: TypeDetailPanelProps): React.ReactElement | null {\n const [sheet, setSheet] = useState<SheetState>({ open: false });\n const [relSheet, setRelSheet] = useState<RelationView | null>(null);\n const [renameOpen, setRenameOpen] = useState(false);\n\n const view = resolveView(model, selection);\n if (!view) return null;\n\n const editable = !readOnly && !!onChange;\n const ownerLabel = view.kind === \"relation\" ? view.relType : view.label;\n const {\n propsHidden,\n propsEditable,\n nodeTypeEditable,\n edgeTypeEditable,\n relationsEditable,\n } = resolveGating(view.kind, editable, capabilities);\n\n const saveProperty = (input: PropertyInput, prevName?: string): void => {\n if (onChange) onChange(applySaveProperty(model, view, input, prevName));\n };\n\n const removeProperty = (p: PropertyView): void => {\n if (onChange) onChange(applyRemoveProperty(model, view, p.name));\n };\n\n // Delete a relation. Works the same whether triggered from a node type's\n // relations list (source = the node type) or from a selected relation arrow\n // (source = the arrow's source). Identical mutation in both cases.\n const removeRelation = (r: RelationView): void => {\n if (!onChange || view.kind === \"edge\") return;\n const source = view.kind === \"node\" ? view.label : view.source;\n onChange(deleteRelation(model, source, r.relType, r.target));\n };\n\n const saveRelation = (\n source: string,\n _target: string,\n input: RelationInput,\n prev: RelationView,\n ): void => {\n if (!onChange) return;\n onChange(updateRelation(model, source, prev.relType, prev.target, input));\n };\n\n const propertiesSection = propsHidden ? null : (\n <PropertiesSection\n view={view}\n editable={propsEditable}\n onAdd={() => setSheet({ open: true, property: undefined })}\n onEdit={(p) => setSheet({ open: true, property: p })}\n onDelete={removeProperty}\n />\n );\n\n return (\n <div>\n {view.kind === \"node\" ? (\n <NodeDetail\n view={view}\n nodeTypeEditable={nodeTypeEditable}\n relationsEditable={relationsEditable}\n onRename={() => setRenameOpen(true)}\n onDelete={() => onChange?.(deleteNodeType(model, view.label))}\n onEditRelation={setRelSheet}\n onDeleteRelation={removeRelation}\n >\n {propertiesSection}\n </NodeDetail>\n ) : view.kind === \"edge\" ? (\n <EdgeDetail\n view={view}\n editable={edgeTypeEditable}\n onRename={() => setRenameOpen(true)}\n onDelete={() => onChange?.(deleteEdgeType(model, view.label))}\n >\n {propertiesSection}\n </EdgeDetail>\n ) : (\n <RelationDetail\n view={view}\n editable={relationsEditable}\n onEdit={() => setRelSheet(relationViewOf(view))}\n onDelete={() => removeRelation(relationViewOf(view))}\n >\n {propertiesSection}\n </RelationDetail>\n )}\n\n {editable && (\n <DetailSheets\n model={model}\n view={view}\n ownerLabel={ownerLabel}\n widgetOptions={widgetOptions}\n edgeTypeMode={capabilities?.edgeTypes ?? \"edit\"}\n sheet={sheet}\n setSheet={setSheet}\n relSheet={relSheet}\n setRelSheet={setRelSheet}\n renameOpen={renameOpen}\n setRenameOpen={setRenameOpen}\n onSaveProperty={saveProperty}\n onSaveRelation={saveRelation}\n onRename={(label) => {\n if (!onChange) return;\n if (view.kind === \"node\")\n onChange(renameNodeType(model, view.label, label));\n else if (view.kind === \"edge\")\n onChange(renameEdgeType(model, view.label, label));\n }}\n />\n )}\n </div>\n );\n}\n\n// All edit sheets for the panel, kept out of the main component to bound its\n// complexity. Only rendered when editable.\nfunction DetailSheets({\n model,\n view,\n ownerLabel,\n widgetOptions,\n edgeTypeMode,\n sheet,\n setSheet,\n relSheet,\n setRelSheet,\n renameOpen,\n setRenameOpen,\n onSaveProperty,\n onSaveRelation,\n onRename,\n}: {\n model: GraphModel;\n view: NodeTypeView | EdgeTypeView | RelationDetailView;\n ownerLabel: string;\n widgetOptions?: string[];\n edgeTypeMode: EdgeTypeMode;\n sheet: SheetState;\n setSheet: React.Dispatch<React.SetStateAction<SheetState>>;\n relSheet: RelationView | null;\n setRelSheet: (r: RelationView | null) => void;\n renameOpen: boolean;\n setRenameOpen: (open: boolean) => void;\n onSaveProperty: (input: PropertyInput, prevName?: string) => void;\n onSaveRelation: (\n source: string,\n target: string,\n input: RelationInput,\n prev: RelationView,\n ) => void;\n onRename: (label: string) => void;\n}): React.ReactElement {\n const edgeTypeOptions = model.filter(isEdgeType).map(typeLabel);\n return (\n <>\n <PropertyFormSheet\n open={sheet.open}\n onOpenChange={(o) => setSheet((s) => ({ ...s, open: o }))}\n property={sheet.property}\n ownerLabel={ownerLabel}\n widgetOptions={widgetOptions}\n onSave={onSaveProperty}\n />\n {relSheet && (view.kind === \"node\" || view.kind === \"relation\") && (\n <RelationFormSheet\n key={`${relSheet.relType}:${relSheet.target}`}\n open={!!relSheet}\n onOpenChange={(o) => !o && setRelSheet(null)}\n nodeA={view.kind === \"node\" ? view.label : view.source}\n nodeB={relSheet.target}\n initial={{\n relType: relSheet.relType,\n cardinality: relSheet.cardinality,\n }}\n edgeTypeOptions={edgeTypeOptions}\n edgeTypeMode={edgeTypeMode}\n onSave={(source, target, input) =>\n onSaveRelation(source, target, input, relSheet)\n }\n />\n )}\n {(view.kind === \"node\" || view.kind === \"edge\") && renameOpen && (\n <NodeTypeNameSheet\n key={view.label}\n open={renameOpen}\n onOpenChange={setRenameOpen}\n initial={view.label}\n existing={model.map(typeLabel)}\n noun={view.kind === \"edge\" ? \"edge\" : \"node\"}\n onSave={onRename}\n />\n )}\n </>\n );\n}\n\nfunction PropertiesSection({\n view,\n editable,\n onAdd,\n onEdit,\n onDelete,\n}: {\n view: NodeTypeView | EdgeTypeView | RelationDetailView;\n editable: boolean;\n onAdd: () => void;\n onEdit: (p: PropertyView) => void;\n onDelete: (p: PropertyView) => void;\n}): React.ReactElement {\n return (\n <>\n <SectionTitle\n action={\n editable ? (\n <IconButton label=\"Add property\" onClick={onAdd}>\n <Plus />\n </IconButton>\n ) : undefined\n }\n >\n Properties\n </SectionTitle>\n <PropertyRows\n properties={view.properties}\n emptyText=\"No properties yet.\"\n editable={editable}\n onEdit={onEdit}\n onDelete={onDelete}\n />\n </>\n );\n}\n\nfunction NodeDetail({\n view,\n nodeTypeEditable,\n relationsEditable,\n onRename,\n onDelete,\n onEditRelation,\n onDeleteRelation,\n children,\n}: {\n view: NodeTypeView;\n nodeTypeEditable: boolean;\n relationsEditable: boolean;\n onRename: () => void;\n onDelete: () => void;\n onEditRelation: (r: RelationView) => void;\n onDeleteRelation: (r: RelationView) => void;\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-base font-semibold\">{view.label}</span>\n <Badge>NODE TYPE</Badge>\n {nodeTypeEditable && (\n <RenameDeleteActions\n noun=\"node type\"\n onRename={onRename}\n onDelete={onDelete}\n />\n )}\n </div>\n {view.description && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{view.description}</p>\n )}\n {children}\n <SectionTitle>Relations</SectionTitle>\n {view.relations.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\">No relations.</p>\n ) : (\n <div className=\"rounded-lg border divide-y\">\n {view.relations.map((r) => (\n <div\n key={`${r.relType}:${r.target}`}\n className=\"group/row flex items-center gap-2 px-3 py-2\"\n >\n <span className=\"text-sm font-medium min-w-24\">{r.relType}</span>\n <span className=\"flex-1 font-mono text-xs text-muted-foreground\">\n {\"\\u2192\"} {r.target} {\"\\u00b7\"}{\" \"}\n {cardinalityLabel(r.cardinality)}\n </span>\n {relationsEditable && (\n <span className=\"flex gap-1\">\n <IconButton\n label=\"Edit relation\"\n revealOnHover\n onClick={() => onEditRelation(r)}\n >\n <Pencil />\n </IconButton>\n <IconButton\n label=\"Delete relation\"\n tone=\"destructive\"\n revealOnHover\n onClick={() => onDeleteRelation(r)}\n >\n <Trash2 />\n </IconButton>\n </span>\n )}\n </div>\n ))}\n </div>\n )}\n </>\n );\n}\n\n// A short explanatory note that the properties shown belong to the edge type\n// (and are therefore shared by every relation of this type), not to a single\n// relation. Shown above the Properties section on relation and edge details.\nfunction EdgeTypeNote({\n children,\n}: {\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <p className=\"mt-3 rounded-md bg-muted/50 px-3 py-2 text-xs text-muted-foreground\">\n {children}\n </p>\n );\n}\n\n// Edit/rename + delete icon buttons shown in a type detail header when\n// editable. `editVerb` is \"Rename\" for node/edge types and \"Edit\" for a\n// relation (which has no name to rename, only properties to edit).\nfunction RenameDeleteActions({\n noun,\n editVerb = \"Rename\",\n onRename,\n onDelete,\n}: {\n noun: string;\n editVerb?: string;\n onRename: () => void;\n onDelete: () => void;\n}): React.ReactElement {\n return (\n <span className=\"ml-auto flex gap-1\">\n <IconButton label={`${editVerb} ${noun}`} onClick={onRename}>\n <Pencil />\n </IconButton>\n <IconButton\n label={`Delete ${noun}`}\n tone=\"destructive\"\n onClick={onDelete}\n >\n <Trash2 />\n </IconButton>\n </span>\n );\n}\n\nfunction EdgeDetail({\n view,\n editable,\n onRename,\n onDelete,\n children,\n}: {\n view: EdgeTypeView;\n editable: boolean;\n onRename: () => void;\n onDelete: () => void;\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-base font-semibold\">{view.label}</span>\n <Badge>EDGE TYPE</Badge>\n {editable && (\n <RenameDeleteActions\n noun=\"edge type\"\n onRename={onRename}\n onDelete={onDelete}\n />\n )}\n </div>\n {view.description && (\n <p className=\"mt-1 text-sm text-muted-foreground\">{view.description}</p>\n )}\n <EdgeTypeNote>\n These properties belong to the{\" \"}\n <span className=\"font-medium\">{view.label}</span> edge type and are\n shared by every relation of this type.\n </EdgeTypeNote>\n {children}\n </>\n );\n}\n\nfunction RelationDetail({\n view,\n editable,\n onEdit,\n onDelete,\n children,\n}: {\n view: RelationDetailView;\n editable: boolean;\n onEdit: () => void;\n onDelete: () => void;\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-base font-semibold\">{view.relType}</span>\n <Badge>RELATION</Badge>\n {editable && (\n <RenameDeleteActions\n noun=\"relation\"\n editVerb=\"Edit\"\n onRename={onEdit}\n onDelete={onDelete}\n />\n )}\n </div>\n <p className=\"mt-1 text-sm text-muted-foreground\">\n <span className=\"font-medium text-foreground\">{view.source}</span>\n {\" \\u2192 \"}\n <span className=\"font-medium text-foreground\">{view.target}</span>\n {\" \\u00b7 \"}\n {cardinalityLabel(view.cardinality)}\n </p>\n <EdgeTypeNote>\n Properties are defined on the{\" \"}\n <span className=\"font-medium\">{view.relType}</span> edge type, shared by\n every relation of this type -- not on this single relation.\n </EdgeTypeNote>\n {children}\n </>\n );\n}\n\nexport default TypeDetailPanel;\n","/**\n * Type-view parser: turn a graph model + a selection into clean, readable\n * structured data for the detail panel.\n *\n * The model JSON is low-level (JSON Schema + x-graph). This module resolves a\n * selected node type or relation arrow into a flat shape the panel renders --\n * hiding mechanics (gid_, raw nested schema) and joining a relation arrow to\n * its hidden edge type so the relation's properties surface on the arrow.\n */\n\nimport {\n type GraphModel,\n type GraphTypeSchema,\n type GraphModelProperty,\n type GraphRelation,\n type Cardinality,\n isNodeType,\n typeLabel,\n} from \"./types\";\n\n/** One property of a type, flattened for display. */\nexport interface PropertyView {\n /** Property key. */\n name: string;\n /** JSON Schema type (e.g. \"string\", \"integer\"); \"object\" when absent. */\n type: string;\n required: boolean;\n title?: string;\n description?: string;\n /** x-ui-widget, if set on the property. */\n widget?: string;\n enum?: Array<string | number>;\n}\n\n/** One relation declared on a node type, flattened for display. */\nexport interface RelationView {\n relType: string;\n target: string;\n cardinality: Cardinality;\n description?: string;\n}\n\n/** View of a selected node type. */\nexport interface NodeTypeView {\n kind: \"node\";\n label: string;\n description?: string;\n properties: PropertyView[];\n relations: RelationView[];\n}\n\n/**\n * View of a selected edge type (a catalog entry). An edge type carries only\n * identity and properties -- it has no relations of its own (relations are\n * declared on node types and reference an edge type by label).\n */\nexport interface EdgeTypeView {\n kind: \"edge\";\n label: string;\n description?: string;\n properties: PropertyView[];\n}\n\n/**\n * View of a selected relation arrow. Properties are joined from the relation's\n * hidden edge type (the edge-type schema whose label === relType), if one\n * exists; otherwise the relation simply has no properties yet.\n */\nexport interface RelationDetailView {\n kind: \"relation\";\n relType: string;\n source: string;\n target: string;\n cardinality: Cardinality;\n description?: string;\n /** Whether a hidden edge type backs this relation's properties. */\n hasEdgeType: boolean;\n properties: PropertyView[];\n}\n\n/** Human-readable label for a cardinality value. */\nexport function cardinalityLabel(c: Cardinality): string {\n return c === \"ONE_TO_ONE\" ? \"one-to-one\" : \"one-to-many\";\n}\n\nfunction propTypeOf(prop: GraphModelProperty): string {\n if (Array.isArray(prop.type)) return prop.type.join(\" | \");\n return prop.type ?? \"object\";\n}\n\nfunction toPropertyViews(schema: GraphTypeSchema | undefined): PropertyView[] {\n if (!schema?.properties) return [];\n const required = new Set(schema.required ?? []);\n return Object.entries(schema.properties).map(([name, prop]) => ({\n name,\n type: propTypeOf(prop),\n required: required.has(name),\n title: typeof prop.title === \"string\" ? prop.title : undefined,\n description:\n typeof prop.description === \"string\" ? prop.description : undefined,\n widget:\n typeof prop[\"x-ui-widget\"] === \"string\" ? prop[\"x-ui-widget\"] : undefined,\n enum: prop.enum,\n }));\n}\n\nfunction toRelationViews(schema: GraphTypeSchema): RelationView[] {\n const relations = schema[\"x-graph\"].relations ?? [];\n return relations.map((r: GraphRelation) => ({\n relType: r.rel_type_name,\n target: r.to_type_name,\n cardinality: r.cardinality ?? \"ONE_TO_MANY\",\n description: r.description,\n }));\n}\n\n/** Find a type schema by its graph label. */\nexport function findType(\n model: GraphModel,\n label: string,\n): GraphTypeSchema | undefined {\n return model.find((s) => typeLabel(s) === label);\n}\n\n/** Find the (hidden) edge type backing a relation type, if any. */\nexport function findEdgeType(\n model: GraphModel,\n relType: string,\n): GraphTypeSchema | undefined {\n return model.find(\n (s) => s[\"x-graph\"].type === \"EDGE\" && typeLabel(s) === relType,\n );\n}\n\n/**\n * Resolve a selected relation edge into (source, relType, target).\n *\n * The converter sets each relation edge's `label_` to the relation type and its\n * `gid_` to `schema:rel:<source>\\0<target>`, using NUL as a separator so node\n * type labels that contain colons parse unambiguously. INHERITS_FROM_ edges are\n * not relations and resolve to null.\n */\nexport function resolveRelationEdge(edge: {\n label_: string;\n properties_?: Record<string, unknown>;\n}): { source: string; relType: string; target: string } | null {\n if (edge.label_ === \"INHERITS_FROM_\") return null;\n const gid = edge.properties_?.gid_;\n if (typeof gid !== \"string\" || !gid.startsWith(\"schema:rel:\")) return null;\n const rest = gid.slice(\"schema:rel:\".length);\n const sep = rest.indexOf(\"\\0\");\n if (sep < 0) return null;\n return {\n source: rest.slice(0, sep),\n relType: edge.label_,\n target: rest.slice(sep + 1),\n };\n}\n\n/** Build the view for a selected node type. Returns null if not a node type. */\nexport function nodeTypeView(\n model: GraphModel,\n label: string,\n): NodeTypeView | null {\n const schema = findType(model, label);\n if (!schema || !isNodeType(schema)) return null;\n return {\n kind: \"node\",\n label: typeLabel(schema),\n description:\n typeof schema.description === \"string\" ? schema.description : undefined,\n properties: toPropertyViews(schema),\n relations: toRelationViews(schema),\n };\n}\n\n/**\n * Build the view for a selected edge type. Returns null if the label does not\n * resolve to an edge type. An edge type's properties are the relation\n * properties shared by every relation of this type.\n */\nexport function edgeTypeView(\n model: GraphModel,\n label: string,\n): EdgeTypeView | null {\n const schema = findType(model, label);\n if (!schema || isNodeType(schema)) return null;\n return {\n kind: \"edge\",\n label: typeLabel(schema),\n description:\n typeof schema.description === \"string\" ? schema.description : undefined,\n properties: toPropertyViews(schema),\n };\n}\n\n/**\n * Build the view for a selected relation arrow. `source` is the owning node\n * type label, `relType` the relation type, `target` the target node label.\n * Properties are joined from the hidden edge type, if present.\n */\nexport function relationView(\n model: GraphModel,\n source: string,\n relType: string,\n target: string,\n): RelationDetailView | null {\n const sourceSchema = findType(model, source);\n if (!sourceSchema || !isNodeType(sourceSchema)) return null;\n const relation = (sourceSchema[\"x-graph\"].relations ?? []).find(\n (r) => r.rel_type_name === relType && r.to_type_name === target,\n );\n if (!relation) return null;\n const edgeType = findEdgeType(model, relType);\n return {\n kind: \"relation\",\n relType,\n source,\n target,\n cardinality: relation.cardinality ?? \"ONE_TO_MANY\",\n description: relation.description,\n hasEdgeType: !!edgeType,\n properties: toPropertyViews(edgeType),\n };\n}\n","/**\n * Pure model mutations. Each takes a GraphModel and returns a new GraphModel\n * (immutable); GraphModelEditor is controlled, so callers pass the result to\n * onChange. No mutation touches the input.\n *\n * Properties live on a type schema's `properties` (+ `required`). A relation's\n * properties live on its hidden edge type (the EDGE schema whose label === the\n * relation type); that edge type is created lazily when a relation gains its\n * first property and removed when it loses its last.\n */\n\nimport {\n type GraphModel,\n type GraphTypeSchema,\n type GraphModelProperty,\n type GraphRelation,\n type Cardinality,\n typeLabel,\n isEdgeType,\n} from \"./types\";\nimport { findType, findEdgeType } from \"./view\";\n\n/** A property definition as edited in the form. */\nexport interface PropertyInput {\n name: string;\n type: string;\n required: boolean;\n title?: string;\n description?: string;\n widget?: string;\n enum?: Array<string | number>;\n}\n\n// Build a JSON Schema property object from form input.\nfunction toSchemaProperty(input: PropertyInput): GraphModelProperty {\n const prop: GraphModelProperty = { type: input.type };\n if (input.title) prop.title = input.title;\n if (input.description) prop.description = input.description;\n if (input.widget && input.widget !== \"default\")\n prop[\"x-ui-widget\"] = input.widget;\n if (input.enum && input.enum.length) prop.enum = input.enum;\n return prop;\n}\n\n// Replace a single schema in the model by label, returning a new model.\nfunction replaceSchema(\n model: GraphModel,\n label: string,\n next: GraphTypeSchema,\n): GraphModel {\n return model.map((s) => (typeLabel(s) === label ? next : s));\n}\n\n// Apply a property add/update/delete to a type schema's properties + required.\nfunction withProperty(\n schema: GraphTypeSchema,\n input: PropertyInput | null,\n prevName?: string,\n): GraphTypeSchema {\n const properties: Record<string, GraphModelProperty> = {\n ...(schema.properties ?? {}),\n };\n const required = new Set(schema.required ?? []);\n // Remove the previous key (rename or delete).\n if (prevName) {\n delete properties[prevName];\n required.delete(prevName);\n }\n // Add/update.\n if (input) {\n properties[input.name] = toSchemaProperty(input);\n if (input.required) required.add(input.name);\n else required.delete(input.name);\n }\n const next: GraphTypeSchema = { ...schema, properties };\n if (required.size) next.required = [...required];\n else delete next.required;\n return next;\n}\n\n/**\n * Add or update a property on a node type. `prevName` set => rename/update that\n * property; omitted => add `input.name`.\n */\nexport function setNodeProperty(\n model: GraphModel,\n typeLabel_: string,\n input: PropertyInput,\n prevName?: string,\n): GraphModel {\n const schema = findType(model, typeLabel_);\n if (!schema) return model;\n return replaceSchema(\n model,\n typeLabel_,\n withProperty(schema, input, prevName),\n );\n}\n\n/** Delete a property from a node type. */\nexport function deleteNodeProperty(\n model: GraphModel,\n typeLabel_: string,\n name: string,\n): GraphModel {\n const schema = findType(model, typeLabel_);\n if (!schema) return model;\n return replaceSchema(model, typeLabel_, withProperty(schema, null, name));\n}\n\n// Make a fresh hidden edge type for a relation that is gaining its first prop.\nfunction newEdgeType(relType: string): GraphTypeSchema {\n return {\n title: relType,\n type: \"object\",\n properties: {},\n \"x-graph\": { type: \"EDGE\", label: relType },\n };\n}\n\n/**\n * Add or update a property on a relation. Properties are stored on the\n * relation's hidden edge type, which is created lazily here if absent.\n */\nexport function setRelationProperty(\n model: GraphModel,\n relType: string,\n input: PropertyInput,\n prevName?: string,\n): GraphModel {\n const existing = findEdgeType(model, relType);\n const base = existing ?? newEdgeType(relType);\n const next = withProperty(base, input, prevName);\n return existing ? replaceSchema(model, relType, next) : [...model, next];\n}\n\n/**\n * Delete a property from a relation. If that was the relation's last property,\n * the now-empty hidden edge type is removed entirely.\n */\nexport function deleteRelationProperty(\n model: GraphModel,\n relType: string,\n name: string,\n): GraphModel {\n const existing = findEdgeType(model, relType);\n if (!existing) return model;\n const next = withProperty(existing, null, name);\n const empty = Object.keys(next.properties ?? {}).length === 0;\n if (empty) return model.filter((s) => s !== existing);\n return replaceSchema(model, relType, next);\n}\n\n/**\n * Add or update a property on an edge type selected directly (by its label).\n * Unlike setRelationProperty this never creates the edge type -- it must\n * already exist -- and is used when an edge-type node is selected on the canvas.\n */\nexport function setEdgeTypeProperty(\n model: GraphModel,\n edgeLabel: string,\n input: PropertyInput,\n prevName?: string,\n): GraphModel {\n const existing = findEdgeType(model, edgeLabel);\n if (!existing) return model;\n return replaceSchema(\n model,\n edgeLabel,\n withProperty(existing, input, prevName),\n );\n}\n\n/**\n * Delete a property from an edge type selected directly. Unlike\n * deleteRelationProperty this keeps the edge type even when it becomes empty:\n * an explicitly-created edge type stays in the catalog with no properties.\n */\nexport function deleteEdgeTypeProperty(\n model: GraphModel,\n edgeLabel: string,\n name: string,\n): GraphModel {\n const existing = findEdgeType(model, edgeLabel);\n if (!existing) return model;\n return replaceSchema(model, edgeLabel, withProperty(existing, null, name));\n}\n\n/** Add a new, empty edge type to the catalog. No-op if the label exists. */\nexport function addEdgeType(model: GraphModel, label: string): GraphModel {\n const name = label.trim();\n if (!name || model.some((s) => typeLabel(s) === name)) return model;\n return [...model, newEdgeType(name)];\n}\n\n/** A relation definition as edited in the form. */\nexport interface RelationInput {\n relType: string;\n target: string;\n cardinality: Cardinality;\n description?: string;\n}\n\n/**\n * Add a relation to a node type's x-graph.relations. No-op if an identical\n * (relType, target) relation already exists on that source.\n */\nexport function addRelation(\n model: GraphModel,\n source: string,\n input: RelationInput,\n): GraphModel {\n const schema = findType(model, source);\n if (!schema) return model;\n const relations = schema[\"x-graph\"].relations ?? [];\n if (\n relations.some(\n (r) =>\n r.rel_type_name === input.relType && r.to_type_name === input.target,\n )\n ) {\n return model;\n }\n const rel: GraphRelation = {\n rel_type_name: input.relType,\n to_type_name: input.target,\n cardinality: input.cardinality,\n };\n if (input.description) rel.description = input.description;\n const next: GraphTypeSchema = {\n ...schema,\n \"x-graph\": { ...schema[\"x-graph\"], relations: [...relations, rel] },\n };\n return replaceSchema(model, source, next);\n}\n\n/** Update an existing relation (matched by source + prev relType/target). */\nexport function updateRelation(\n model: GraphModel,\n source: string,\n prevRelType: string,\n prevTarget: string,\n input: RelationInput,\n): GraphModel {\n const schema = findType(model, source);\n if (!schema) return model;\n const relations = (schema[\"x-graph\"].relations ?? []).map((r) =>\n r.rel_type_name === prevRelType && r.to_type_name === prevTarget\n ? {\n rel_type_name: input.relType,\n to_type_name: input.target,\n cardinality: input.cardinality,\n ...(input.description ? { description: input.description } : {}),\n }\n : r,\n );\n const next: GraphTypeSchema = {\n ...schema,\n \"x-graph\": { ...schema[\"x-graph\"], relations },\n };\n return replaceSchema(model, source, next);\n}\n\n/** Add a new, empty node type. No-op if the label already exists. */\nexport function addNodeType(model: GraphModel, label: string): GraphModel {\n const name = label.trim();\n if (!name || model.some((s) => typeLabel(s) === name)) return model;\n const schema: GraphTypeSchema = {\n title: name,\n type: \"object\",\n properties: {},\n \"x-graph\": { type: \"NODE\", label: name },\n };\n return [...model, schema];\n}\n\n/**\n * Rename a node type, updating every reference: the type's own label/title and\n * any relation `to_type_name` (and `inherits_from`) that pointed at the old\n * label. No-op if newLabel already exists.\n */\nexport function renameNodeType(\n model: GraphModel,\n oldLabel: string,\n newLabel: string,\n): GraphModel {\n const name = newLabel.trim();\n if (!name || name === oldLabel) return model;\n if (model.some((s) => typeLabel(s) === name)) return model;\n return model.map((s) => {\n const xg = s[\"x-graph\"];\n const isTarget = typeLabel(s) === oldLabel;\n const relations = xg.relations?.map((r) =>\n r.to_type_name === oldLabel ? { ...r, to_type_name: name } : r,\n );\n const inherits = xg.inherits_from?.map((p) => (p === oldLabel ? name : p));\n return {\n ...s,\n ...(isTarget && s.title ? { title: name } : {}),\n \"x-graph\": {\n ...xg,\n ...(isTarget ? { label: name } : {}),\n ...(relations ? { relations } : {}),\n ...(inherits ? { inherits_from: inherits } : {}),\n },\n };\n });\n}\n\n/**\n * Delete a node type and clean up references: removes the type, plus any\n * relations (on other types) that target it and any inherits_from entries.\n */\nexport function deleteNodeType(model: GraphModel, label: string): GraphModel {\n return model\n .filter((s) => typeLabel(s) !== label)\n .map((s) => {\n const xg = s[\"x-graph\"];\n const relations = xg.relations?.filter((r) => r.to_type_name !== label);\n const inherits = xg.inherits_from?.filter((p) => p !== label);\n return {\n ...s,\n \"x-graph\": {\n ...xg,\n ...(relations ? { relations } : {}),\n ...(inherits ? { inherits_from: inherits } : {}),\n },\n };\n });\n}\n\n/** Remove a relation from a node type. */\nexport function deleteRelation(\n model: GraphModel,\n source: string,\n relType: string,\n target: string,\n): GraphModel {\n const schema = findType(model, source);\n if (!schema) return model;\n const relations = (schema[\"x-graph\"].relations ?? []).filter(\n (r) => !(r.rel_type_name === relType && r.to_type_name === target),\n );\n const next: GraphTypeSchema = {\n ...schema,\n \"x-graph\": { ...schema[\"x-graph\"], relations },\n };\n return replaceSchema(model, source, next);\n}\n\n/**\n * Rename an edge type, updating every relation `rel_type_name` that referenced\n * the old label so those relations keep pointing at the (now renamed) edge\n * type. No-op if newLabel already exists or there is no such edge type.\n */\nexport function renameEdgeType(\n model: GraphModel,\n oldLabel: string,\n newLabel: string,\n): GraphModel {\n const name = newLabel.trim();\n if (!name || name === oldLabel) return model;\n if (model.some((s) => typeLabel(s) === name)) return model;\n const edgeType = findEdgeType(model, oldLabel);\n if (!edgeType) return model;\n return model.map((s) => {\n const xg = s[\"x-graph\"];\n const isTarget = s === edgeType;\n const relations = xg.relations?.map((r) =>\n r.rel_type_name === oldLabel ? { ...r, rel_type_name: name } : r,\n );\n return {\n ...s,\n ...(isTarget && s.title ? { title: name } : {}),\n \"x-graph\": {\n ...xg,\n ...(isTarget ? { label: name } : {}),\n ...(relations ? { relations } : {}),\n },\n };\n });\n}\n\n/**\n * Delete an edge type from the catalog. Relations that referenced it remain as\n * bare-label relations (edge types are optional); only the catalog entry and\n * its shared properties are removed.\n */\nexport function deleteEdgeType(model: GraphModel, label: string): GraphModel {\n return model.filter((s) => !(isEdgeType(s) && typeLabel(s) === label));\n}\n","/**\n * PropertyFormSheet -- add/edit a single property definition.\n *\n * A property definition (name, type, required, title, description, widget) is\n * itself a small object, so it is edited with a schema-driven form\n * (JsonSchemaFormRenderer) over a property meta-schema, inside a Sheet. The\n * widget choice (x-ui-widget) is the extensibility hook; consumers can extend\n * the allowed widget list via `widgetOptions`.\n */\n\nimport React, { useMemo } from \"react\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetTitle,\n SheetDescription,\n} from \"@petrarca/sonnet-ui\";\nimport { JsonSchemaFormRenderer } from \"@petrarca/sonnet-forms\";\nimport type { JsonSchema } from \"@petrarca/sonnet-core/schema\";\nimport type { PropertyView } from \"./view\";\nimport type { PropertyInput } from \"./mutate\";\n\nconst TYPE_OPTIONS = [\n \"string\",\n \"integer\",\n \"number\",\n \"boolean\",\n \"array\",\n \"object\",\n];\nconst DEFAULT_WIDGETS = [\"default\"];\n\n// Build the meta-schema describing a property definition (the form fields).\nfunction buildSchema(widgetOptions: string[]): JsonSchema {\n return {\n type: \"object\",\n properties: {\n name: {\n type: \"string\",\n title: \"Property name\",\n description: \"The JSON Schema property key.\",\n },\n type: { type: \"string\", title: \"Type\", enum: TYPE_OPTIONS },\n required: { type: \"boolean\", title: \"Required\" },\n title: { type: \"string\", title: \"Title\" },\n description: {\n type: \"string\",\n title: \"Description\",\n \"x-ui-widget\": \"textarea\",\n },\n widget: {\n type: \"string\",\n title: \"Widget\",\n description:\n \"x-ui-widget -- render this property with a specific widget.\",\n enum: widgetOptions,\n },\n enumValues: {\n type: \"array\",\n title: \"Allowed values\",\n description:\n \"Restrict the property to a fixed set of values (leave empty for free input).\",\n items: { type: \"string\" },\n \"x-ui-widget\": \"tags\",\n },\n },\n required: [\"name\", \"type\"],\n } as unknown as JsonSchema;\n}\n\nfunction toFormData(prop: PropertyView | undefined): Record<string, unknown> {\n if (!prop)\n return {\n type: \"string\",\n required: false,\n widget: \"default\",\n enumValues: [],\n };\n return {\n name: prop.name,\n type: prop.type,\n required: prop.required,\n title: prop.title ?? \"\",\n description: prop.description ?? \"\",\n widget: prop.widget ?? \"default\",\n enumValues: prop.enum ? prop.enum.map(String) : [],\n };\n}\n\nfunction toInput(data: Record<string, unknown>): PropertyInput {\n const raw = data.enumValues;\n const enumValues = Array.isArray(raw)\n ? raw.map(String).filter((v) => v.length > 0)\n : undefined;\n return {\n name: String(data.name ?? \"\").trim(),\n type: String(data.type ?? \"string\"),\n required: Boolean(data.required),\n title: data.title ? String(data.title) : undefined,\n description: data.description ? String(data.description) : undefined,\n widget: data.widget ? String(data.widget) : undefined,\n enum: enumValues && enumValues.length ? enumValues : undefined,\n };\n}\n\nexport interface PropertyFormSheetProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The property being edited; omit for add. */\n property?: PropertyView;\n /** Owner label for the title (a type or relation name). */\n ownerLabel: string;\n /** Allowed x-ui-widget values; \"default\" is always included first. */\n widgetOptions?: string[];\n /** Called with the property input on save; the sheet closes after. */\n onSave: (input: PropertyInput, prevName?: string) => void;\n}\n\nexport function PropertyFormSheet({\n open,\n onOpenChange,\n property,\n ownerLabel,\n widgetOptions,\n onSave,\n}: PropertyFormSheetProps): React.ReactElement {\n const widgets = useMemo(\n () => [...DEFAULT_WIDGETS, ...(widgetOptions ?? [])],\n [widgetOptions],\n );\n const schema = useMemo(() => buildSchema(widgets), [widgets]);\n const data = useMemo(() => toFormData(property), [property]);\n const isEdit = !!property;\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>\n {isEdit ? \"Edit property\" : \"Add property\"} {\"\\u2014\"} {ownerLabel}\n </SheetTitle>\n <SheetDescription>\n Define the property and how it is rendered.\n </SheetDescription>\n </SheetHeader>\n <SheetBody>\n <JsonSchemaFormRenderer\n schema={schema}\n data={data}\n showActions\n saveLabel={isEdit ? \"Save\" : \"Add\"}\n showExtraProperties={false}\n onUpdate={(d) => {\n onSave(toInput(d), property?.name);\n onOpenChange(false);\n }}\n onCancel={() => onOpenChange(false)}\n />\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\nexport default PropertyFormSheet;\n","/**\n * RelationFormSheet -- create or edit a relation between two node types.\n *\n * Used by the select-two-then-link flow (create) and the relation edit action.\n * The endpoints are fixed by the selection / existing relation; the form edits\n * the relation type, direction (swap source/target), and cardinality.\n */\n\nimport React, { useState } from \"react\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetTitle,\n SheetDescription,\n Button,\n} from \"@petrarca/sonnet-ui\";\nimport { FormSelect } from \"@petrarca/sonnet-forms\";\nimport { ArrowRight } from \"lucide-react\";\nimport type { Cardinality } from \"./types\";\nimport { cardinalityLabel } from \"./view\";\nimport type { RelationInput } from \"./mutate\";\nimport type { EdgeTypeMode } from \"./capabilities\";\n\nexport interface RelationFormSheetProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The two endpoints; the first is the initial source. */\n nodeA: string;\n nodeB: string;\n /** Existing relation values when editing. */\n initial?: { relType: string; cardinality: Cardinality };\n /**\n * Existing edge-type labels (the catalog) offered for the relation type.\n * The user selects one of these; in \"edit\" mode a new one can be created.\n */\n edgeTypeOptions: string[];\n /**\n * Edge-type governance. \"edit\": select or create; \"catalog\": select only\n * from edgeTypeOptions; \"readonly\": no create. Default \"edit\".\n */\n edgeTypeMode?: EdgeTypeMode;\n /** Save handler: (source, target, input). Sheet closes after. */\n onSave: (source: string, target: string, input: RelationInput) => void;\n}\n\nconst CARDINALITIES: Cardinality[] = [\"ONE_TO_MANY\", \"ONE_TO_ONE\"];\n\n// The relation type field: a catalog combobox over existing edge types.\n// In \"edit\" mode a new edge type can be created from the typed text.\nfunction RelationTypeField({\n relType,\n setRelType,\n edgeTypeOptions,\n edgeTypeMode,\n}: {\n relType: string;\n setRelType: (v: string) => void;\n edgeTypeOptions: string[];\n edgeTypeMode: EdgeTypeMode;\n}): React.ReactElement {\n // Include the current value so an edited relation whose type is not in the\n // catalog still renders as selected.\n const labels = Array.from(\n new Set([...edgeTypeOptions, ...(relType ? [relType] : [])]),\n );\n const options = labels.map((l) => ({ value: l, label: l }));\n const canCreate = edgeTypeMode === \"edit\";\n return (\n <FormSelect\n label=\"Relation type\"\n options={options}\n value={relType || null}\n onChange={(v) => setRelType(v ?? \"\")}\n allowCreate={canCreate}\n onCreate={setRelType}\n clearable={false}\n placeholder=\"Select an edge type\"\n searchPlaceholder={\n canCreate ? \"Search or type to create...\" : \"Search edge types...\"\n }\n emptyMessage={\n canCreate\n ? \"Type a name to create a new edge type.\"\n : \"No matching edge type.\"\n }\n />\n );\n}\n\nfunction DirectionField({\n source,\n target,\n canSwap,\n onSwap,\n}: {\n source: string;\n target: string;\n canSwap: boolean;\n onSwap: () => void;\n}): React.ReactElement {\n return (\n <div>\n <label className=\"mb-1 block text-xs font-medium\">Direction</label>\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"font-medium\">{source}</span>\n <ArrowRight className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">{target}</span>\n {canSwap && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"ml-auto\"\n onClick={onSwap}\n >\n Swap\n </Button>\n )}\n </div>\n </div>\n );\n}\n\nfunction CardinalityField({\n cardinality,\n onChange,\n}: {\n cardinality: Cardinality;\n onChange: (c: Cardinality) => void;\n}): React.ReactElement {\n return (\n <div>\n <label className=\"mb-1 block text-xs font-medium\">Cardinality</label>\n <div className=\"flex gap-2\">\n {CARDINALITIES.map((c) => (\n <Button\n key={c}\n variant={c === cardinality ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={() => onChange(c)}\n >\n {cardinalityLabel(c)}\n </Button>\n ))}\n </div>\n </div>\n );\n}\n\nexport function RelationFormSheet({\n open,\n onOpenChange,\n nodeA,\n nodeB,\n initial,\n edgeTypeOptions,\n edgeTypeMode = \"edit\",\n onSave,\n}: RelationFormSheetProps): React.ReactElement {\n const [relType, setRelType] = useState(initial?.relType ?? \"\");\n const [swapped, setSwapped] = useState(false);\n const [cardinality, setCardinality] = useState<Cardinality>(\n initial?.cardinality ?? \"ONE_TO_MANY\",\n );\n\n const source = swapped ? nodeB : nodeA;\n const target = swapped ? nodeA : nodeB;\n const isEdit = !!initial;\n const canSave = relType.trim().length > 0;\n\n const handleSave = (): void => {\n if (!canSave) return;\n onSave(source, target, {\n relType: relType.trim(),\n target,\n cardinality,\n });\n onOpenChange(false);\n };\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>\n {isEdit ? \"Edit relation\" : \"Create relation\"}\n </SheetTitle>\n <SheetDescription>\n A relation is stored on the source node type.\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"flex flex-col gap-4\">\n <RelationTypeField\n relType={relType}\n setRelType={setRelType}\n edgeTypeOptions={edgeTypeOptions}\n edgeTypeMode={edgeTypeMode}\n />\n\n <DirectionField\n source={source}\n target={target}\n canSwap={!isEdit}\n onSwap={() => setSwapped((s) => !s)}\n />\n\n <CardinalityField\n cardinality={cardinality}\n onChange={setCardinality}\n />\n\n <div className=\"flex justify-end gap-2 pt-2\">\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button disabled={!canSave} onClick={handleSave}>\n {isEdit ? \"Save\" : \"Create relation\"}\n </Button>\n </div>\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\nexport default RelationFormSheet;\n","/**\n * NodeTypeNameSheet -- name input for adding or renaming a node type.\n */\n\nimport React, { useState } from \"react\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetTitle,\n SheetDescription,\n Button,\n Input,\n} from \"@petrarca/sonnet-ui\";\n\nexport interface NodeTypeNameSheetProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Current label when renaming; omit for add. */\n initial?: string;\n /** Existing labels, to prevent duplicates. */\n existing: string[];\n /** The kind of type being named (affects wording). Default \"node\". */\n noun?: \"node\" | \"edge\";\n onSave: (label: string) => void;\n}\n\nexport function NodeTypeNameSheet({\n open,\n onOpenChange,\n initial,\n existing,\n noun = \"node\",\n onSave,\n}: NodeTypeNameSheetProps): React.ReactElement {\n const [name, setName] = useState(initial ?? \"\");\n const isEdit = initial !== undefined;\n const trimmed = name.trim();\n const duplicate = trimmed !== initial && existing.includes(trimmed);\n const canSave = trimmed.length > 0 && !duplicate;\n const typeNoun = noun === \"edge\" ? \"edge type\" : \"node type\";\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>\n {isEdit ? `Rename ${typeNoun}` : `Add ${typeNoun}`}\n </SheetTitle>\n <SheetDescription>\n The label identifies this type and its instances.\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"flex flex-col gap-4\">\n <div>\n <label className=\"mb-1 block text-xs font-medium\">Label</label>\n <Input\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Hospital\"\n autoFocus\n />\n {duplicate && (\n <p className=\"mt-1 text-xs text-destructive\">\n A type with this label already exists.\n </p>\n )}\n </div>\n <div className=\"flex justify-end gap-2\">\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button\n disabled={!canSave}\n onClick={() => {\n onSave(trimmed);\n onOpenChange(false);\n }}\n >\n {isEdit ? \"Rename\" : \"Add\"}\n </Button>\n </div>\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\nexport default NodeTypeNameSheet;\n","/**\n * GraphModelEditor capabilities -- a single structure that gates what can be\n * edited. Consumers pass `capabilities` to tailor the editor (e.g. an\n * organization-model profile that hides node properties). `readOnly` is a\n * shorthand for the fully-locked capabilities.\n *\n * This module is the single source of truth: the Zod schema below defines the\n * shape, the TypeScript type is inferred from it (`z.infer`), the JSON Schema\n * is generated from it (see `capabilities.schema.ts` / the generate script),\n * and `validateCapabilities` validates hand-authored / external JSON at the\n * boundary. Every field is optional and defaults to the most permissive value,\n * so adding a new capability never tightens an existing consumer's profile\n * (forward compatible).\n */\n\nimport { z } from \"zod\";\nimport { warnLog } from \"@petrarca/sonnet-core\";\n\n/**\n * Mode for a section that can be edited, shown read-only, or dropped entirely.\n * \"hidden\" omits the section (meaningful only where there is a section to drop,\n * e.g. properties -- not for node types, which are the canvas nodes).\n */\nexport type EditMode = \"edit\" | \"readonly\" | \"hidden\";\n\n/** Mode for a structural area that is always present (cannot be hidden). */\nexport type EditableMode = \"edit\" | \"readonly\";\n\n/**\n * Mode for the edge-type catalog when creating relations.\n * - \"edit\": pick an existing edge type or create a new one inline.\n * - \"catalog\": pick only from existing edge types (the catalog passed in the\n * model); creating new edge types is not allowed.\n * - \"readonly\": no changes (view only).\n */\nexport type EdgeTypeMode = \"edit\" | \"catalog\" | \"readonly\";\n\n/**\n * The capabilities schema. Each field is optional with a permissive default;\n * `.meta({ description })` is carried through to the generated JSON Schema.\n */\nexport const capabilitiesSchema = z\n .object({\n nodeTypes: z.enum([\"edit\", \"readonly\"]).default(\"edit\").meta({\n description:\n \"Node types (add / rename / delete). 'edit' (default): add new types, rename and delete from the panel. 'readonly': types are shown but cannot be added, renamed, or deleted. No 'hidden': node types are the canvas nodes and are always present.\",\n }),\n edgeTypes: z.enum([\"edit\", \"catalog\", \"readonly\"]).default(\"edit\").meta({\n description:\n \"Edge-type catalog governance for relation creation. 'edit' (default): select an existing edge type or create one inline, plus 'Add edge type' and edge-type rename/delete. 'catalog': select only from existing edge types; no create/rename/delete. 'readonly': no edge-type changes.\",\n }),\n nodeProperties: z\n .enum([\"edit\", \"readonly\", \"hidden\"])\n .default(\"edit\")\n .meta({\n description:\n \"Node-type properties. 'edit' (default): add / edit / delete. 'readonly': shown, but no add / edit / delete affordances. 'hidden': the Properties section is not rendered.\",\n }),\n edgeProperties: z\n .enum([\"edit\", \"readonly\", \"hidden\"])\n .default(\"edit\")\n .meta({\n description:\n \"Edge-type / relation properties (defined on the edge type, shared by every relation of that type). 'edit' (default): add / edit / delete. 'readonly': shown, but not editable. 'hidden': the Properties section is not rendered.\",\n }),\n relations: z.enum([\"edit\", \"readonly\"]).default(\"edit\").meta({\n description:\n \"Relations between node types (create / edit / delete). 'edit' (default): create (select two nodes), edit, and delete relations. 'readonly': relations are shown but cannot be changed. How the relation type is chosen is governed by edgeTypes.\",\n }),\n showEdgeTypes: z.boolean().default(false).meta({\n description:\n \"Whether edge-type nodes (the catalog of relationship types) are shown on the canvas initially. false (default): edge types start filtered out (re-enable from the Edge types legend). true: shown from the start.\",\n }),\n })\n .meta({\n id: \"GraphModelCapabilities\",\n title: \"GraphModelCapabilities\",\n description:\n \"Capability profile for GraphModelEditor. Gates what a consumer can edit. Every field is optional and defaults to the most permissive value (forward-compatible). Passing readOnly to the editor overrides this object to a fully-locked profile.\",\n });\n\n/**\n * The capabilities a consumer may pass. Inferred from the schema; with all\n * fields optional on input (defaults are applied by resolveCapabilities).\n */\nexport type GraphModelCapabilities = z.input<typeof capabilitiesSchema>;\n\n/** The fully-resolved capabilities (every field present). */\nexport type ResolvedCapabilities = z.output<typeof capabilitiesSchema>;\n\n/** Fully-locked capabilities (readOnly). Locking edits does not hide edge\n * types (visibility is a display concern, not an edit gate). */\nconst LOCKED: ResolvedCapabilities = {\n nodeTypes: \"readonly\",\n edgeTypes: \"readonly\",\n nodeProperties: \"readonly\",\n edgeProperties: \"readonly\",\n relations: \"readonly\",\n showEdgeTypes: false,\n};\n\n/**\n * Resolve the effective capabilities: readOnly wins (everything locked),\n * otherwise parse the provided capabilities (applying per-field defaults).\n * Invalid input falls back to the permissive defaults rather than throwing --\n * use validateCapabilities to surface errors at a boundary.\n */\nexport function resolveCapabilities(\n capabilities: GraphModelCapabilities | undefined,\n readOnly: boolean | undefined,\n): ResolvedCapabilities {\n if (readOnly) return LOCKED;\n const parsed = capabilitiesSchema.safeParse(capabilities ?? {});\n if (!parsed.success) {\n warnLog(\n \"[GraphModelEditor] Invalid capabilities — falling back to defaults.\",\n parsed.error.issues,\n );\n return capabilitiesSchema.parse({});\n }\n return parsed.data;\n}\n\n/** Result of validating an untrusted capabilities object. */\nexport type CapabilitiesValidation =\n | { ok: true; value: ResolvedCapabilities }\n | { ok: false; errors: string[] };\n\n/**\n * Validate a hand-authored / external capabilities object (e.g. parsed from a\n * per-tenant config JSON). Returns the resolved value or a list of readable\n * error messages. Does not throw.\n */\nexport function validateCapabilities(input: unknown): CapabilitiesValidation {\n const parsed = capabilitiesSchema.safeParse(input);\n if (parsed.success) return { ok: true, value: parsed.data };\n const errors = parsed.error.issues.map((i) => {\n const path = i.path.length ? i.path.join(\".\") : \"(root)\";\n return `${path}: ${i.message}`;\n });\n return { ok: false, errors };\n}\n","/**\n * Graph instance-editing capabilities -- a single structure that gates what a\n * consumer can do with a live data graph. Distinct from `GraphModelCapabilities`\n * (which gates the metamodel/schema editor): this profile governs the viewer +\n * instance editor (editing node/edge DATA, not types).\n *\n * This profile is the RBAC/ABAC seam: the host resolves a user's\n * role/attributes into a `GraphCapabilities` object and passes it in; the\n * library enables only what the resolved capabilities allow and never sees\n * roles, policies, or auth.\n *\n * This module is the single source of truth: the Zod schema below defines the\n * shape, the TypeScript types are inferred from it (`z.input` / `z.output`),\n * and `validateGraphCapabilities` validates hand-authored / external JSON at\n * the boundary. Every field is optional and defaults to `\"readonly\"` (no\n * editing affordances) so existing viewers are unaffected until a consumer\n * opts in by passing a capabilities profile. The viewer areas are reserved for\n * a follow-on refactor and default fully permissive; v1 ships the editing\n * areas.\n */\n\nimport { z } from \"zod\";\nimport { warnLog } from \"@petrarca/sonnet-core\";\n\n/** Mode for an editable area: allow the action or not. */\nexport type EditMode = \"edit\" | \"readonly\";\n\n/**\n * The capabilities schema. Each field is optional with a permissive default;\n * `.meta({ description })` is carried through to any generated JSON Schema.\n *\n * Editing areas (v1): node CRUD, edge CRUD, property editing. Viewer areas are\n * reserved (designed-for, not yet wired) so they slot in without a breaking\n * change.\n */\nexport const graphCapabilitiesSchema = z\n .object({\n createNode: z.enum([\"edit\", \"readonly\"]).default(\"readonly\").meta({\n description:\n \"Create new nodes. 'edit': the add-node affordance is shown. 'readonly' (default): hidden.\",\n }),\n updateNode: z.enum([\"edit\", \"readonly\"]).default(\"readonly\").meta({\n description:\n \"Edit existing nodes (properties and relations). 'edit': the edit-node affordance is shown. 'readonly' (default): hidden.\",\n }),\n deleteNode: z.enum([\"edit\", \"readonly\"]).default(\"readonly\").meta({\n description:\n \"Delete nodes. 'edit': the delete-node affordance is shown. 'readonly' (default): hidden.\",\n }),\n createEdge: z.enum([\"edit\", \"readonly\"]).default(\"readonly\").meta({\n description:\n \"Create edges between two selected nodes. 'edit': the add-edge affordance is shown. 'readonly' (default): hidden.\",\n }),\n updateEdge: z.enum([\"edit\", \"readonly\"]).default(\"readonly\").meta({\n description:\n \"Edit edge properties. 'edit': the edit-edge affordance is shown. 'readonly' (default): hidden.\",\n }),\n deleteEdge: z.enum([\"edit\", \"readonly\"]).default(\"readonly\").meta({\n description:\n \"Delete edges. 'edit': the delete-edge affordance is shown. 'readonly' (default): hidden.\",\n }),\n })\n .meta({\n id: \"GraphCapabilities\",\n title: \"GraphCapabilities\",\n description:\n \"Capability profile for the graph viewer + instance editor. Gates what a consumer can do with a live data graph. Every field is optional and defaults to read-only (no editing affordances) so existing viewers are unaffected until a consumer opts in. Passing readOnly to the editor overrides this object to a fully read-only profile.\",\n });\n\n/**\n * The capabilities a consumer may pass. Inferred from the schema; with all\n * fields optional on input (defaults are applied by resolveGraphCapabilities).\n */\nexport type GraphCapabilities = z.input<typeof graphCapabilitiesSchema>;\n\n/** The fully-resolved capabilities (every field present). */\nexport type ResolvedGraphCapabilities = z.output<\n typeof graphCapabilitiesSchema\n>;\n\n/** Fully read-only capabilities (readOnly shorthand). */\nconst READ_ONLY: ResolvedGraphCapabilities = {\n createNode: \"readonly\",\n updateNode: \"readonly\",\n deleteNode: \"readonly\",\n createEdge: \"readonly\",\n updateEdge: \"readonly\",\n deleteEdge: \"readonly\",\n};\n\n/**\n * Resolve the effective capabilities: readOnly wins (everything read-only),\n * otherwise parse the provided capabilities (applying per-field defaults of\n * \"readonly\"). Invalid input falls back to the read-only defaults rather than\n * throwing -- use validateGraphCapabilities to surface errors at a boundary.\n */\nexport function resolveGraphCapabilities(\n capabilities: GraphCapabilities | undefined,\n readOnly: boolean | undefined,\n): ResolvedGraphCapabilities {\n if (readOnly) return READ_ONLY;\n const parsed = graphCapabilitiesSchema.safeParse(capabilities ?? {});\n if (!parsed.success) {\n warnLog(\n \"[GraphEditor] Invalid capabilities — falling back to defaults.\",\n parsed.error.issues,\n );\n return graphCapabilitiesSchema.parse({});\n }\n return parsed.data;\n}\n\n/** Result of validating an untrusted capabilities object. */\nexport type GraphCapabilitiesValidation =\n | { ok: true; value: ResolvedGraphCapabilities }\n | { ok: false; errors: string[] };\n\n/**\n * Validate a hand-authored / external capabilities object (e.g. parsed from a\n * per-tenant config JSON or produced by an authorization layer). Returns the\n * resolved value or a list of readable error messages. Does not throw.\n */\nexport function validateGraphCapabilities(\n input: unknown,\n): GraphCapabilitiesValidation {\n const parsed = graphCapabilitiesSchema.safeParse(input);\n if (parsed.success) return { ok: true, value: parsed.data };\n const errors = parsed.error.issues.map((i) => {\n const path = i.path.length ? i.path.join(\".\") : \"(root)\";\n return `${path}: ${i.message}`;\n });\n return { ok: false, errors };\n}\n","/**\n * Relation form-field utilities.\n *\n * The schema-driven node form represents editable relations as synthetic\n * `__rel_<type>__` fields (a multi-select of target node ids). These helpers\n * convert between that flat form shape and the structured\n * `{ properties, relations }` the mutation port expects.\n *\n * Relocated from the cypher-graphdb explorer (`services/nodeFormUtils.ts`) so\n * every consumer of the shared editor gets the same relation handling. The\n * functions are pure -- no I/O. Reads of a node's existing relations go through\n * the injected `GraphMutationPort` (getInboundEdges / getOutboundEdges), not a\n * hardcoded backend call.\n */\n\nimport type { JsonSchema, UISchema } from \"@petrarca/sonnet-core/schema\";\nimport type { GraphProperties, RawGraphEdge } from \"../models/graph-types\";\nimport type { RelationMap } from \"./port\";\nimport type { RelationDef } from \"./schemaProvider\";\n\n/** A per-field UI schema map, as JsonSchemaFormRenderer's `uiSchema` prop. */\nexport type FieldUiSchema = { [fieldName: string]: UISchema };\n\n/** The synthetic form-field prefix/suffix for an editable relation. */\nconst REL_PREFIX = \"__rel_\";\nconst REL_SUFFIX = \"__\";\n\n/** Whether a form key is a synthetic relation field. */\nexport function isRelationField(key: string): boolean {\n return key.startsWith(REL_PREFIX) && key.endsWith(REL_SUFFIX);\n}\n\n/** The form-field name for a relation type (`USES` -> `__rel_uses__`). */\nexport function relationFieldName(relationType: string): string {\n return `${REL_PREFIX}${relationType.toLowerCase()}${REL_SUFFIX}`;\n}\n\n/** The relation type for a form-field name (`__rel_uses__` -> `USES`). */\nexport function relationTypeFromField(fieldName: string): string {\n return fieldName.slice(REL_PREFIX.length, -REL_SUFFIX.length).toUpperCase();\n}\n\n/**\n * Group a node's edges into a relation map (rel_type -> target node ids),\n * relative to the node. The target is the other end of each edge.\n */\nexport function groupEdgesByRelation(\n nodeId: number,\n edges: RawGraphEdge[],\n): RelationMap {\n const relations: RelationMap = {};\n for (const edge of edges) {\n const targetId = edge.start_id_ === nodeId ? edge.end_id_ : edge.start_id_;\n (relations[edge.label_] ??= []).push(targetId);\n }\n return relations;\n}\n\n/**\n * Build initial form data from a node's properties and its relations, including\n * a `__rel_*` field for every editable relation type. `editableRelationTypes`\n * is the set of relation types that should appear as form fields (typically\n * those marked `form_field` in the model); an empty list yields properties\n * only.\n */\nexport function initializeFormData(\n properties: GraphProperties,\n relations: RelationMap,\n editableRelationTypes: string[],\n): Record<string, unknown> {\n const formData: Record<string, unknown> = { ...properties };\n for (const relationType of editableRelationTypes) {\n const ids = relations[relationType] ?? [];\n // String values: the select widgets operate on string ids.\n formData[relationFieldName(relationType)] = ids.map(String);\n }\n return formData;\n}\n\n/**\n * Split form data into `{ properties, relations }`, converting `__rel_*` fields\n * back to relation type names and numeric ids.\n */\nexport function extractRelationFields(formData: Record<string, unknown>): {\n properties: GraphProperties;\n relations: RelationMap;\n} {\n const properties: GraphProperties = {};\n const relations: RelationMap = {};\n\n for (const [key, value] of Object.entries(formData)) {\n if (isRelationField(key)) {\n const relationType = relationTypeFromField(key);\n if (Array.isArray(value)) {\n relations[relationType] = value.map(Number);\n } else if (value != null) {\n relations[relationType] = [Number(value)];\n } else {\n relations[relationType] = [];\n }\n } else {\n // The form always produces string | number | Array values for non-relation\n // fields, matching GraphProperties[string]. The cast is safe at this seam.\n properties[key] = value as unknown as GraphProperties[string];\n }\n }\n\n return { properties, relations };\n}\n\n/** Whether any form key is a relation field (decides the atomic save path). */\nexport function hasRelationFields(formData: Record<string, unknown>): boolean {\n return Object.keys(formData).some(isRelationField);\n}\n\n/** Title-case a relation type for a default field title (\"USES_TECHNOLOGY\" ->\n * \"Uses Technology\"). Matches the explorer's formatting. */\nexport function relationTitle(relationType: string): string {\n return relationType\n .toLowerCase()\n .split(\"_\")\n .map((w) => (w ? w.charAt(0).toUpperCase() + w.slice(1) : w))\n .join(\" \");\n}\n\n/** A relation is editable (becomes a form field) when form_field === true,\n * matching the explorer. */\nexport function editableRelations(relations: RelationDef[]): RelationDef[] {\n return relations.filter((r) => r.form_field === true);\n}\n\n/** Whether a node/edge schema declares any properties (gates \"Edit edge\" the\n * same way the explorer's hasProperties does). */\nexport function hasProperties(schema: JsonSchema | null | undefined): boolean {\n return !!schema && Object.keys(schema.properties ?? {}).length > 0;\n}\n\n/** The widget hint for a relation field (x-ui-widget). Defaults to\n * \"entity-select\"; consumers can override per relation. */\nconst DEFAULT_RELATION_WIDGET = \"entity-select\";\n\n/**\n * Enrich a node schema with a `__rel_*` field per editable relation, returning\n * a new `{ schema, uiSchema }`. Mirrors the explorer's enrichment:\n * - field type is `array of integer` (multi) for ONE_TO_MANY / unset\n * cardinality, or `integer` (single) for ONE_TO_ONE;\n * - the field title is the relation's title or a Title-Cased label;\n * - the uiSchema carries `x-ui-widget` (default \"entity-select\") plus\n * `x-ui-options` describing the target type and selection mode.\n *\n * The widget COMPONENT stays app-level (supplied via the form widget registry);\n * this only produces the schema/uiSchema that drives it.\n */\nexport function enrichSchemaWithRelations(\n baseSchema: JsonSchema,\n relations: RelationDef[],\n): { schema: JsonSchema; uiSchema: FieldUiSchema } {\n const editable = editableRelations(relations);\n if (editable.length === 0) {\n return { schema: baseSchema, uiSchema: {} };\n }\n\n const properties: Record<string, unknown> = {\n ...(baseSchema.properties ?? {}),\n };\n const uiSchema: FieldUiSchema = {};\n\n for (const rel of editable) {\n const fieldName = relationFieldName(rel.rel_type_name);\n const multiple = rel.cardinality !== \"ONE_TO_ONE\";\n const title = rel.title ?? relationTitle(rel.rel_type_name);\n\n properties[fieldName] = multiple\n ? { type: \"array\", items: { type: \"integer\" }, title }\n : { type: \"integer\", title };\n\n uiSchema[fieldName] = {\n \"x-ui-widget\": rel.widget ?? DEFAULT_RELATION_WIDGET,\n \"x-ui-options\": {\n targetType: rel.to_type_name,\n multiple,\n relationType: rel.rel_type_name,\n },\n };\n }\n\n const schema: JsonSchema = {\n ...baseSchema,\n properties,\n } as JsonSchema;\n return { schema, uiSchema };\n}\n","/**\n * GraphEditToolbar -- the selection-driven CRUD toolbar for instance editing.\n *\n * Reads the current selection from the workspace selection store (the same\n * store the viewer owns), gates each action behind the resolved\n * `GraphCapabilities`, and owns the edit dialogs (node form, edge form, delete\n * confirm). Relocated from the explorer's `CrudActions`, but library-native:\n * it drives everything through the injected `GraphMutationPort` +\n * `GraphSchemaProvider` and is slot-injectable via `ActionPanel actions={...}`.\n *\n * Override tiers: pass your own toolbar into `ActionPanel` to replace it\n * entirely (tier 3), or drive the exported dialogs / port directly (tier 4).\n */\n\nimport React, { useCallback, useMemo, useState } from \"react\";\nimport { IconButton } from \"@petrarca/sonnet-ui\";\nimport { Plus, Edit, Link, Trash2 } from \"lucide-react\";\nimport type { WidgetRegistry } from \"@petrarca/sonnet-forms\";\nimport { useWorkspaceSelection } from \"../hooks/useWorkspaceStores\";\nimport { useLiveGraphData } from \"../hooks/useLiveGraphData\";\nimport type { SelectionStore } from \"../stores/Selection\";\nimport type { RawGraphNode } from \"../models/graph-types\";\nimport type { GraphMutationPort } from \"./port\";\nimport type { GraphSchemaProvider } from \"./schemaProvider\";\nimport { useStableRef } from \"../hooks/useStableRef\";\nimport {\n resolveGraphCapabilities,\n type GraphCapabilities,\n type ResolvedGraphCapabilities,\n} from \"./capabilities\";\nimport { NodeFormSheet } from \"./NodeFormSheet\";\nimport { EdgeFormSheet } from \"./EdgeFormSheet\";\nimport { DeleteNodeDialog } from \"./DeleteNodeDialog\";\n\nexport interface GraphEditToolbarProps {\n port: GraphMutationPort;\n schemaProvider: GraphSchemaProvider;\n /** Capability profile. Defaults to read-only (no affordances shown). */\n capabilities?: GraphCapabilities;\n /** Force read-only regardless of capabilities. */\n readOnly?: boolean;\n /** Form widgets shared by the node + edge forms. */\n widgets?: WidgetRegistry;\n /** Called after any successful mutation so the consumer can refresh. */\n onMutated?: () => void;\n}\n\ntype ActiveDialog = \"node-create\" | \"node-edit\" | \"edge\" | \"delete\" | null;\n\n/** Which CRUD affordances the resolved capabilities allow. */\ninterface ToolbarPerms {\n canCreateNode: boolean;\n canUpdateNode: boolean;\n canDeleteNode: boolean;\n canEditEdges: boolean;\n anyEditable: boolean;\n}\n\nfunction toPerms(caps: ResolvedGraphCapabilities): ToolbarPerms {\n const canCreateNode = caps.createNode === \"edit\";\n const canUpdateNode = caps.updateNode === \"edit\";\n const canDeleteNode = caps.deleteNode === \"edit\";\n const canEditEdges =\n caps.createEdge === \"edit\" ||\n caps.updateEdge === \"edit\" ||\n caps.deleteEdge === \"edit\";\n return {\n canCreateNode,\n canUpdateNode,\n canDeleteNode,\n canEditEdges,\n anyEditable:\n canCreateNode || canUpdateNode || canDeleteNode || canEditEdges,\n };\n}\n\n// The toolbar buttons; each gated by the resolved permissions + selection count.\nfunction ToolbarButtons({\n perms,\n count,\n onOpen,\n}: {\n perms: ToolbarPerms;\n count: number;\n onOpen: (d: ActiveDialog) => void;\n}): React.ReactElement {\n return (\n <div className=\"flex gap-0.5\">\n {perms.canCreateNode && (\n <IconButton\n label=\"Add node\"\n variant=\"outline\"\n disabled={count > 0}\n onClick={() => onOpen(\"node-create\")}\n >\n <Plus />\n </IconButton>\n )}\n {perms.canUpdateNode && (\n <IconButton\n label=\"Edit node\"\n variant=\"outline\"\n disabled={count !== 1}\n onClick={() => onOpen(\"node-edit\")}\n >\n <Edit />\n </IconButton>\n )}\n {perms.canEditEdges && (\n <IconButton\n label=\"Edges\"\n variant=\"outline\"\n disabled={count !== 2}\n onClick={() => onOpen(\"edge\")}\n >\n <Link />\n </IconButton>\n )}\n {perms.canDeleteNode && (\n <IconButton\n label=\"Delete node\"\n variant=\"outline\"\n tone=\"destructive\"\n disabled={count !== 1}\n onClick={() => onOpen(\"delete\")}\n >\n <Trash2 />\n </IconButton>\n )}\n </div>\n );\n}\n\n// The dialogs owned by the toolbar, each gated by permissions + selection.\nfunction ToolbarDialogs({\n perms,\n dialog,\n firstNode,\n secondNode,\n port,\n schemaProvider,\n widgets,\n onClose,\n onMutated,\n}: {\n perms: ToolbarPerms;\n dialog: ActiveDialog;\n firstNode?: RawGraphNode;\n secondNode?: RawGraphNode;\n port: GraphMutationPort;\n schemaProvider: GraphSchemaProvider;\n widgets?: WidgetRegistry;\n onClose: () => void;\n onMutated?: () => void;\n}): React.ReactElement {\n const onChange = useCallback(\n (o: boolean): void => {\n if (!o) onClose();\n },\n [onClose],\n );\n return (\n <>\n {(perms.canCreateNode || perms.canUpdateNode) && (\n <NodeFormSheet\n open={dialog === \"node-create\" || dialog === \"node-edit\"}\n onOpenChange={onChange}\n node={dialog === \"node-edit\" ? firstNode : null}\n port={port}\n schemaProvider={schemaProvider}\n widgets={widgets}\n onSaved={onMutated}\n />\n )}\n {perms.canEditEdges && firstNode && secondNode && (\n <EdgeFormSheet\n open={dialog === \"edge\"}\n onOpenChange={onChange}\n nodeA={firstNode}\n nodeB={secondNode}\n port={port}\n schemaProvider={schemaProvider}\n widgets={widgets}\n onChanged={onMutated}\n />\n )}\n {perms.canDeleteNode && firstNode && (\n <DeleteNodeDialog\n open={dialog === \"delete\"}\n onOpenChange={onChange}\n node={firstNode}\n port={port}\n onDeleted={onMutated}\n />\n )}\n </>\n );\n}\n\nexport function GraphEditToolbar({\n port,\n schemaProvider,\n capabilities,\n readOnly,\n widgets,\n onMutated,\n}: GraphEditToolbarProps): React.ReactElement | null {\n const useSelection = useWorkspaceSelection();\n const selectedNodeIds = useSelection(\n (s: SelectionStore) => s.selectedNodeIds,\n );\n const live = useLiveGraphData();\n const [dialog, setDialog] = useState<ActiveDialog>(null);\n\n const perms = useMemo(\n () => toPerms(resolveGraphCapabilities(capabilities, readOnly)),\n [capabilities, readOnly],\n );\n\n const selectedNodes = useMemo<RawGraphNode[]>(\n () =>\n selectedNodeIds\n .map((id) => live.normalized.nodesById[id])\n .filter(Boolean),\n [selectedNodeIds, live.normalized],\n );\n\n // Stabilise the optional onMutated callback so ToolbarDialogs never receives\n // a new reference on every parent render.\n const stableOnMutated = useStableRef(onMutated);\n\n if (!perms.anyEditable) return null;\n\n return (\n <>\n <ToolbarButtons\n perms={perms}\n count={selectedNodes.length}\n onOpen={setDialog}\n />\n <ToolbarDialogs\n perms={perms}\n dialog={dialog}\n firstNode={selectedNodes[0]}\n secondNode={selectedNodes[1]}\n port={port}\n schemaProvider={schemaProvider}\n widgets={widgets}\n onClose={() => setDialog(null)}\n onMutated={stableOnMutated}\n />\n </>\n );\n}\n\nexport default GraphEditToolbar;\n","/**\n * NodeFormSheet -- create or edit a graph node (instance data).\n *\n * Schema-driven: the node's JSON Schema and editable relations come from the\n * injected `GraphSchemaProvider`; the form is rendered with\n * `JsonSchemaFormRenderer`. Editable relations are surfaced as `__rel_*` form\n * fields (see relationFields.ts). Saving goes through the injected\n * `GraphMutationPort`: when relations are present the atomic\n * create/updateNodeWithRelations methods are used, otherwise the plain\n * create/updateNode methods.\n *\n * The component is I/O-free beyond the port + provider it is given, and emits\n * no events: it `await`s the port and calls `onSaved` so the consumer can patch\n * its own cache.\n */\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetTitle,\n SheetDescription,\n Alert,\n} from \"@petrarca/sonnet-ui\";\nimport {\n FormSelect,\n FormCheckbox,\n JsonSchemaFormRenderer,\n type WidgetRegistry,\n} from \"@petrarca/sonnet-forms\";\nimport type { JsonSchema } from \"@petrarca/sonnet-core/schema\";\nimport { errorLog } from \"@petrarca/sonnet-core\";\nimport type { RawGraphNode, GraphProperties } from \"../models/graph-types\";\nimport type { GraphMutationPort } from \"./port\";\nimport type { GraphSchemaProvider } from \"./schemaProvider\";\nimport { useStableRef } from \"../hooks/useStableRef\";\nimport {\n initializeFormData,\n extractRelationFields,\n groupEdgesByRelation,\n editableRelations,\n enrichSchemaWithRelations,\n type FieldUiSchema,\n} from \"./relationFields\";\n\nexport interface NodeFormSheetProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The node being edited; omit for create. */\n node?: RawGraphNode | null;\n port: GraphMutationPort;\n schemaProvider: GraphSchemaProvider;\n /** Form widgets (e.g. a product reference-select). Defaults to the built-ins. */\n widgets?: WidgetRegistry;\n /** Called with the saved node after a successful create/update. */\n onSaved?: (node: RawGraphNode) => void;\n}\n\n/** The schema + uiSchema for the form, plus the editable relation types. */\ninterface ResolvedNodeSchema {\n schema: JsonSchema | null;\n uiSchema: FieldUiSchema;\n relationTypes: string[];\n}\n\nconst EMPTY_RESOLVED: ResolvedNodeSchema = {\n schema: null,\n uiSchema: {},\n relationTypes: [],\n};\n\n/**\n * Build a temporary schema from a node's own data when the provider has no\n * schema for its label (mirrors the explorer's createTemporarySchema): infer a\n * string/number/boolean field per non-internal property so the node is still\n * editable. Internal keys (ending in \"_\") are skipped.\n */\nfunction temporarySchema(properties: GraphProperties): JsonSchema {\n const props: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(properties)) {\n if (key.endsWith(\"_\")) continue;\n const type = Array.isArray(value) ? \"array\" : typeof value;\n props[key] = { type, title: key };\n }\n return { type: \"object\", properties: props } as JsonSchema;\n}\n\n/** Resolve the base schema: the provider's, or a temporary one inferred from\n * the node's data, or an empty object schema (still creatable). */\nfunction resolveBaseSchema(\n provided: JsonSchema | null,\n node: RawGraphNode | null | undefined,\n): JsonSchema {\n if (provided) return provided;\n const properties = node?.properties_;\n if (properties && Object.keys(properties).length > 0) {\n return temporarySchema(properties);\n }\n return { type: \"object\", properties: {} } as JsonSchema;\n}\n\n// Load the schema + editable relations for a label, enrich it with __rel_*\n// fields, and fall back to a temporary / empty schema so the form always\n// renders. `node` supplies data for the temporary-schema fallback (edit mode).\nfunction useNodeSchema(\n schemaProvider: GraphSchemaProvider,\n label: string | null,\n node: RawGraphNode | null | undefined,\n): ResolvedNodeSchema {\n const [resolved, setResolved] = useState<ResolvedNodeSchema>(EMPTY_RESOLVED);\n const nodeRef = useRef(node);\n nodeRef.current = node;\n\n useEffect(() => {\n let cancelled = false;\n if (!label) {\n setResolved(EMPTY_RESOLVED);\n return;\n }\n void (async () => {\n try {\n const [provided, rels] = await Promise.all([\n schemaProvider.getNodeSchema(label),\n schemaProvider.relationsFor(label),\n ]);\n if (cancelled) return;\n const base = resolveBaseSchema(provided, nodeRef.current);\n const editable = editableRelations(rels);\n const { schema, uiSchema } = enrichSchemaWithRelations(base, editable);\n setResolved({\n schema,\n uiSchema,\n relationTypes: editable.map((r) => r.rel_type_name),\n });\n } catch (e) {\n if (cancelled) return;\n errorLog(\"[NodeFormSheet] failed to load node schema\", e);\n setResolved({\n schema: resolveBaseSchema(null, nodeRef.current),\n uiSchema: {},\n relationTypes: [],\n });\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [schemaProvider, label]);\n\n return resolved;\n}\n\n// Load existing form data (properties + relation fields) for an edited node.\nfunction useExistingFormData(\n port: GraphMutationPort,\n node: RawGraphNode | null | undefined,\n relationTypes: string[],\n): Record<string, unknown> | null {\n const [data, setData] = useState<Record<string, unknown> | null>(null);\n\n // Dep on stable primitives (nodeId, relationTypes, port), not the node\n // object reference. The properties are read via a ref so the effect always\n // sees the latest value without it becoming a reactive dependency: the dialog\n // is opened for one specific node and closed on save, so the properties do\n // not change while the form is open.\n const nodeId = node?.id_;\n const propertiesRef = useRef(node?.properties_);\n propertiesRef.current = node?.properties_;\n\n useEffect(() => {\n let cancelled = false;\n if (nodeId == null) {\n setData(null);\n return;\n }\n const properties = propertiesRef.current ?? {};\n if (relationTypes.length === 0) {\n setData({ ...properties });\n return;\n }\n void (async () => {\n try {\n const [inbound, outbound] = await Promise.all([\n port.getInboundEdges(nodeId),\n port.getOutboundEdges(nodeId),\n ]);\n if (cancelled) return;\n const relations = groupEdgesByRelation(nodeId, [\n ...inbound,\n ...outbound,\n ]);\n setData(initializeFormData(properties, relations, relationTypes));\n } catch (e) {\n if (cancelled) return;\n errorLog(\"[NodeFormSheet] failed to load node relations\", e);\n setData({ ...properties });\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [port, nodeId, relationTypes]);\n\n return data;\n}\n\n// The label: a read-only value when editing, a selector when creating.\nfunction LabelField({\n isEdit,\n selectedLabel,\n labels,\n onSelect,\n}: {\n isEdit: boolean;\n selectedLabel: string | null;\n labels: string[];\n onSelect: (v: string | null) => void;\n}): React.ReactElement {\n if (isEdit) {\n return (\n <div>\n <span className=\"heading-meta block\">Label</span>\n <span className=\"text-sm text-muted-foreground\">{selectedLabel}</span>\n </div>\n );\n }\n return (\n <FormSelect\n label=\"Label\"\n options={labels.map((l) => ({ value: l, label: l }))}\n clearable={false}\n value={selectedLabel}\n onChange={onSelect}\n />\n );\n}\n\n// Load the node labels offered in the create-mode selector.\nfunction useCreateModeLabels(\n schemaProvider: GraphSchemaProvider,\n open: boolean,\n isEdit: boolean,\n): string[] {\n const [labels, setLabels] = useState<string[]>([]);\n useEffect(() => {\n let cancelled = false;\n if (!open || isEdit) return;\n void schemaProvider.listNodeLabels().then((ls) => {\n if (!cancelled) setLabels(ls);\n });\n return () => {\n cancelled = true;\n };\n }, [open, isEdit, schemaProvider]);\n return labels;\n}\n\n// The schema-driven property + relations form for the selected node.\nfunction NodeForm({\n formKey,\n schema,\n uiSchema,\n data,\n widgets,\n isEdit,\n onSave,\n onCancel,\n}: {\n formKey: string;\n schema: JsonSchema;\n uiSchema: FieldUiSchema;\n data: Record<string, unknown>;\n widgets?: WidgetRegistry;\n isEdit: boolean;\n onSave: (data: Record<string, unknown>) => void;\n onCancel: () => void;\n}): React.ReactElement {\n return (\n <JsonSchemaFormRenderer\n key={formKey}\n schema={schema}\n uiSchema={uiSchema}\n data={data}\n widgets={widgets}\n showActions\n // Create forms submit even when pristine (e.g. a node/edge type with no\n // required properties); edit forms keep the dirty-check.\n allowPristineSave={!isEdit}\n saveLabel={isEdit ? \"Save\" : \"Create\"}\n cancelLabel=\"Cancel\"\n showExtraProperties\n onUpdate={onSave}\n onCancel={onCancel}\n />\n );\n}\n\n// The sheet header + label field + form + error, given resolved data.\nfunction NodeFormSheetBody({\n isEdit,\n selectedLabel,\n labels,\n onSelectLabel,\n schema,\n uiSchema,\n formKey,\n formData,\n widgets,\n error,\n keepOpen,\n onKeepOpenChange,\n onSave,\n onCancel,\n}: {\n isEdit: boolean;\n selectedLabel: string | null;\n labels: string[];\n onSelectLabel: (v: string | null) => void;\n schema: JsonSchema | null;\n uiSchema: FieldUiSchema;\n formKey: string;\n formData: Record<string, unknown>;\n widgets?: WidgetRegistry;\n error: string;\n keepOpen: boolean;\n onKeepOpenChange: (v: boolean) => void;\n onSave: (data: Record<string, unknown>) => void;\n onCancel: () => void;\n}): React.ReactElement {\n return (\n <>\n <SheetHeader>\n <SheetTitle>{isEdit ? \"Edit node\" : \"Add node\"}</SheetTitle>\n <SheetDescription>\n {isEdit\n ? \"Edit this node's properties and relations.\"\n : \"Create a node and (optionally) its relations.\"}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"flex flex-col gap-4\">\n <LabelField\n isEdit={isEdit}\n selectedLabel={selectedLabel}\n labels={labels}\n onSelect={onSelectLabel}\n />\n\n {schema && (\n <NodeForm\n formKey={formKey}\n schema={schema}\n uiSchema={uiSchema}\n data={formData}\n widgets={widgets}\n isEdit={isEdit}\n onSave={onSave}\n onCancel={onCancel}\n />\n )}\n\n {!isEdit && (\n <FormCheckbox\n label=\"Create another node\"\n checked={keepOpen}\n onChange={(c) => onKeepOpenChange(c === true)}\n />\n )}\n\n {error && <Alert variant=\"destructive\">{error}</Alert>}\n </SheetBody>\n </>\n );\n}\n\nexport function NodeFormSheet({\n open,\n onOpenChange,\n node,\n port,\n schemaProvider,\n widgets,\n onSaved,\n}: NodeFormSheetProps): React.ReactElement {\n const isEdit = !!node?.id_;\n const [selectedLabel, setSelectedLabel] = useState<string | null>(\n node?.label_ ?? null,\n );\n const [error, setError] = useState<string>(\"\");\n // \"Create another\" -- keep the sheet open after a create (create mode only),\n // matching the explorer's keepOpen checkbox.\n const [keepOpen, setKeepOpen] = useState(false);\n // Bumped after a kept-open create to remount the form with empty data.\n const [formNonce, setFormNonce] = useState(0);\n const labels = useCreateModeLabels(schemaProvider, open, isEdit);\n\n // Reset all transient state when the sheet opens for a different node/mode.\n useEffect(() => {\n if (open) {\n setSelectedLabel(node?.label_ ?? null);\n setError(\"\");\n setKeepOpen(false);\n setFormNonce(0);\n }\n }, [open, node]);\n\n const { schema, uiSchema, relationTypes } = useNodeSchema(\n schemaProvider,\n selectedLabel,\n node,\n );\n const existingData = useExistingFormData(port, node, relationTypes);\n const formData = useMemo(() => existingData ?? {}, [existingData]);\n\n // Stabilise the parent callbacks so they can be used in useCallback deps\n // without causing the handler to be recreated on every render.\n const stableOnSaved = useStableRef(onSaved); // optional\n const stableOnOpenChange = useStableRef(onOpenChange); // required\n\n const handleSave = useCallback(\n (data: Record<string, unknown>) => {\n if (!selectedLabel) return;\n void (async () => {\n try {\n const saved = await saveNode({\n port,\n label: selectedLabel,\n id: node?.id_,\n data,\n });\n setError(\"\");\n stableOnSaved?.(saved);\n // Create + \"create another\": keep the sheet open and reset the form.\n if (!isEdit && keepOpen) {\n setFormNonce((n) => n + 1);\n } else {\n stableOnOpenChange(false);\n }\n } catch (e) {\n setError(saveErrorMessage(e, isEdit));\n }\n })();\n },\n [\n port,\n selectedLabel,\n node?.id_,\n isEdit,\n keepOpen,\n stableOnSaved,\n stableOnOpenChange,\n ],\n );\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent>\n <NodeFormSheetBody\n isEdit={isEdit}\n selectedLabel={selectedLabel}\n labels={labels}\n onSelectLabel={setSelectedLabel}\n schema={schema}\n uiSchema={uiSchema}\n formKey={`${selectedLabel}:${node?.id_ ?? \"new\"}:${formNonce}`}\n formData={formData}\n widgets={widgets}\n error={error}\n keepOpen={keepOpen}\n onKeepOpenChange={setKeepOpen}\n onSave={handleSave}\n onCancel={() => stableOnOpenChange(false)}\n />\n </SheetContent>\n </Sheet>\n );\n}\n\n// A readable save error, falling back to a mode-specific default.\nfunction saveErrorMessage(e: unknown, isEdit: boolean): string {\n if (e instanceof Error) return e.message;\n return isEdit ? \"Failed to update node\" : \"Failed to create node\";\n}\n\n// Save a node, choosing the atomic relations path when relation fields exist.\n// Always extracts properties via extractRelationFields so we get a typed\n// GraphProperties without casting, even when there are no relation fields.\nasync function saveNode({\n port,\n label,\n id,\n data,\n}: {\n port: GraphMutationPort;\n label: string;\n id?: number;\n data: Record<string, unknown>;\n}): Promise<RawGraphNode> {\n const isEdit = id != null;\n const { properties, relations } = extractRelationFields(data);\n const hasRelations = Object.keys(relations).length > 0;\n\n if (hasRelations) {\n if (isEdit) {\n const res = await port.updateNodeWithRelations({\n id_: id,\n label_: label,\n properties_: properties,\n relations,\n });\n return res.node;\n }\n const res = await port.createNodeWithRelations({\n label_: label,\n properties_: properties,\n relations,\n });\n return res.node;\n }\n\n if (isEdit) {\n return port.updateNode({ id_: id, label_: label, properties_: properties });\n }\n return port.createNode({ label_: label, properties_: properties });\n}\n\nexport default NodeFormSheet;\n","/**\n * EdgeFormSheet -- manage the edges between two selected nodes.\n *\n * Lists the existing edges between the pair (loaded via the port's\n * `getPairEdges`), the edge types that may still be created between them\n * (derived from the schema provider's relations), and renders a schema-driven\n * property form when creating or editing an edge. All writes go through the\n * injected `GraphMutationPort`; the component emits no events and calls\n * `onChanged` so the consumer can patch its own cache and re-read the pair.\n */\n\nimport React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n Sheet,\n SheetContent,\n SheetHeader,\n SheetBody,\n SheetTitle,\n SheetDescription,\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogDescription,\n DialogFooter,\n Button,\n IconButton,\n Alert,\n} from \"@petrarca/sonnet-ui\";\nimport { Pencil, Plus, Trash2, ArrowRight } from \"lucide-react\";\nimport {\n JsonSchemaFormRenderer,\n type WidgetRegistry,\n} from \"@petrarca/sonnet-forms\";\nimport type { JsonSchema } from \"@petrarca/sonnet-core/schema\";\nimport { errorLog } from \"@petrarca/sonnet-core\";\nimport type { RawGraphNode, RawGraphEdge } from \"../models/graph-types\";\nimport { extractDisplayLabel } from \"../graph/extractDisplayLabel\";\nimport type { GraphMutationPort } from \"./port\";\nimport type { GraphSchemaProvider } from \"./schemaProvider\";\nimport { extractRelationFields, hasProperties } from \"./relationFields\";\n\nexport interface EdgeFormSheetProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The two endpoints; the first is the edge source. */\n nodeA: RawGraphNode;\n nodeB: RawGraphNode;\n port: GraphMutationPort;\n schemaProvider: GraphSchemaProvider;\n widgets?: WidgetRegistry;\n /** Called after any edge create / update / delete succeeds. */\n onChanged?: () => void;\n}\n\n/**\n * A relation that can still be created between the selected pair, with the\n * direction it must be created in. The metamodel relations are directional\n * (`partOf` goes Department -> Hospital, not the reverse), so an available edge\n * records which endpoint is the source -- independent of the order in which the\n * two nodes were selected.\n */\ninterface CreatableEdge {\n label: string;\n /** The source node id for this edge (the \"from\" of the relation). */\n sourceId: number;\n /** The target node id for this edge (the \"to\" of the relation). */\n targetId: number;\n}\n\ntype Draft =\n | { mode: \"create\"; entry: CreatableEdge }\n | { mode: \"edit\"; edge: RawGraphEdge }\n | null;\n\n// Load existing edges between the pair plus the edge types still creatable.\n// Deps on stable primitives (ids, labels), not the node objects, so the effect\n// is not re-triggered by parent re-renders that produce new object references.\n//\n// Creatable relations are resolved in BOTH directions (A -> B and B -> A),\n// because the selection order is not guaranteed to match the metamodel's\n// relation direction. Each creatable entry carries its own source/target so the\n// edge is created with the correct orientation regardless of which node the user\n// selected first.\nfunction usePairState(\n port: GraphMutationPort,\n schemaProvider: GraphSchemaProvider,\n open: boolean,\n nodeAId: number | undefined,\n nodeALabel: string,\n nodeBId: number | undefined,\n nodeBLabel: string,\n reloadKey: number,\n): { active: RawGraphEdge[]; available: CreatableEdge[] } {\n const [active, setActive] = useState<RawGraphEdge[]>([]);\n const [available, setAvailable] = useState<CreatableEdge[]>([]);\n\n useEffect(() => {\n let cancelled = false;\n if (!open || nodeAId == null || nodeBId == null) {\n setActive([]);\n setAvailable([]);\n return;\n }\n void (async () => {\n try {\n const [edges, relationsAB, relationsBA] = await Promise.all([\n port.getPairEdges(nodeAId, nodeBId),\n schemaProvider.relationsFor(nodeALabel),\n schemaProvider.relationsFor(nodeBLabel),\n ]);\n if (cancelled) return;\n setActive(edges);\n\n // An edge type is already present if any edge between the pair (either\n // orientation) carries that label, so it is not offered again.\n const present = new Set(edges.map((e) => e.label_));\n const forward = relationsAB\n .filter((r) => r.to_type_name === nodeBLabel)\n .map<CreatableEdge>((r) => ({\n label: r.rel_type_name,\n sourceId: nodeAId,\n targetId: nodeBId,\n }));\n const backward = relationsBA\n .filter((r) => r.to_type_name === nodeALabel)\n .map<CreatableEdge>((r) => ({\n label: r.rel_type_name,\n sourceId: nodeBId,\n targetId: nodeAId,\n }));\n // De-duplicate by label+direction; drop any already present.\n const seen = new Set<string>();\n const creatable: CreatableEdge[] = [];\n for (const entry of [...forward, ...backward]) {\n const key = `${entry.label}:${entry.sourceId}:${entry.targetId}`;\n if (present.has(entry.label) || seen.has(key)) continue;\n seen.add(key);\n creatable.push(entry);\n }\n setAvailable(creatable);\n } catch (e) {\n if (cancelled) return;\n errorLog(\"[EdgeFormSheet] failed to load pair edges\", e);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [\n port,\n schemaProvider,\n open,\n nodeAId,\n nodeALabel,\n nodeBId,\n nodeBLabel,\n reloadKey,\n ]);\n\n return { active, available };\n}\n\n// Derive the edge label from the draft using useMemo so the derived value is\n// stable across re-renders when the draft has not changed.\nfunction draftLabel(draft: Draft): string | null {\n if (!draft) return null;\n return draft.mode === \"create\" ? draft.entry.label : draft.edge.label_;\n}\n\n/** A property-less edge schema -- an edge type with no defined properties is\n * still creatable; the form renders with just the Add / Cancel actions. */\nconst EMPTY_EDGE_SCHEMA: JsonSchema = {\n type: \"object\",\n properties: {},\n} as JsonSchema;\n\n// Resolve the edge schema for the current draft (create label or edited edge).\n// Returns null only when there is no draft; for an active draft whose edge type\n// has no schema, falls back to an empty schema so the form (and its Add/Cancel\n// actions) still render -- otherwise the user is stranded with no way to save.\nfunction useEdgeSchema(\n schemaProvider: GraphSchemaProvider,\n draft: Draft,\n): JsonSchema | null {\n const [schema, setSchema] = useState<JsonSchema | null>(null);\n const label = useMemo(() => draftLabel(draft), [draft]);\n\n useEffect(() => {\n let cancelled = false;\n if (!label) {\n setSchema(null);\n return;\n }\n void schemaProvider\n .getEdgeSchema(label)\n .then((s) => {\n if (!cancelled) setSchema(s ?? EMPTY_EDGE_SCHEMA);\n })\n .catch((e) => {\n if (cancelled) return;\n errorLog(\"[EdgeFormSheet] failed to load edge schema\", e);\n setSchema(EMPTY_EDGE_SCHEMA);\n });\n return () => {\n cancelled = true;\n };\n }, [schemaProvider, label]);\n\n return schema;\n}\n\n// Resolve which active edge LABELS have editable properties, so the Edit\n// affordance is only enabled where there is something to edit (matching the\n// explorer's hasProperties gate). A label not yet resolved defaults to false.\nfunction useEditableEdgeTypes(\n schemaProvider: GraphSchemaProvider,\n active: RawGraphEdge[],\n): Record<string, boolean> {\n const [editable, setEditable] = useState<Record<string, boolean>>({});\n const labelsKey = useMemo(\n () =>\n Array.from(new Set(active.map((e) => e.label_)))\n .sort()\n .join(\"\\u0000\"),\n [active],\n );\n\n useEffect(() => {\n let cancelled = false;\n const labels = labelsKey ? labelsKey.split(\"\\u0000\") : [];\n if (labels.length === 0) {\n setEditable({});\n return;\n }\n void (async () => {\n const entries = await Promise.all(\n labels.map(async (label) => {\n try {\n const schema = await schemaProvider.getEdgeSchema(label);\n return [label, hasProperties(schema)] as const;\n } catch {\n return [label, false] as const;\n }\n }),\n );\n if (!cancelled) setEditable(Object.fromEntries(entries));\n })();\n return () => {\n cancelled = true;\n };\n }, [schemaProvider, labelsKey]);\n\n return editable;\n}\n\n// Section heading for the edge sheet. No top margin -- the parent container\n// controls vertical spacing between sections via gap-4.\nfunction SectionTitle({\n children,\n}: {\n children: React.ReactNode;\n}): React.ReactElement {\n return (\n <div className=\"mb-2\">\n <span className=\"heading-meta\">{children}</span>\n </div>\n );\n}\n\n// A single edge row inside a divided-card list (TypeDetailPanel pattern):\n// label + actions revealed on hover. Edit is shown only when an onEdit handler\n// is given (edge type has editable properties); otherwise it is omitted.\nfunction EdgeRow({\n label,\n onEdit,\n onDelete,\n onAdd,\n}: {\n label: string;\n onEdit?: () => void;\n onDelete?: () => void;\n onAdd?: () => void;\n}): React.ReactElement {\n return (\n <div className=\"group/row flex items-center gap-2 px-3 py-2\">\n <span className=\"flex-1 text-sm font-medium\">{label}</span>\n <span className=\"flex gap-1\">\n {onAdd && (\n <IconButton label=\"Create edge\" revealOnHover onClick={onAdd}>\n <Plus />\n </IconButton>\n )}\n {onEdit && (\n <IconButton label=\"Edit edge\" revealOnHover onClick={onEdit}>\n <Pencil />\n </IconButton>\n )}\n {onDelete && (\n <IconButton\n label=\"Delete edge\"\n tone=\"destructive\"\n revealOnHover\n onClick={onDelete}\n >\n <Trash2 />\n </IconButton>\n )}\n </span>\n </div>\n );\n}\n\n// The active + available edge lists shown when no draft form is open.\nfunction PairLists({\n nodeALabel,\n nodeBLabel,\n nodeAId,\n active,\n available,\n editableTypes,\n onEdit,\n onDelete,\n onCreate,\n}: {\n /** Labels used only for the empty-state message. */\n nodeALabel: string;\n nodeBLabel: string;\n /** Id of nodeA, used to label an available edge's direction. */\n nodeAId: number | undefined;\n active: RawGraphEdge[];\n available: CreatableEdge[];\n editableTypes: Record<string, boolean>;\n onEdit: (edge: RawGraphEdge) => void;\n onDelete: (edge: RawGraphEdge) => void;\n onCreate: (entry: CreatableEdge) => void;\n}): React.ReactElement {\n const empty = active.length === 0 && available.length === 0;\n // When the same label can be created in both directions, suffix the row with\n // its direction so the two options are distinguishable. Otherwise show the\n // bare label.\n const labelCounts = available.reduce<Record<string, number>>((acc, e) => {\n acc[e.label] = (acc[e.label] ?? 0) + 1;\n return acc;\n }, {});\n const rowLabel = (entry: CreatableEdge): string => {\n if (labelCounts[entry.label] <= 1) return entry.label;\n const from = entry.sourceId === nodeAId ? nodeALabel : nodeBLabel;\n const to = entry.sourceId === nodeAId ? nodeBLabel : nodeALabel;\n return `${entry.label} (${from} -> ${to})`;\n };\n return (\n <div className=\"flex flex-col gap-4\">\n {empty && (\n <p className=\"text-xs text-muted-foreground\">\n No edges are defined between {nodeALabel} and {nodeBLabel}.\n </p>\n )}\n {active.length > 0 && (\n <div>\n <SectionTitle>Active edges</SectionTitle>\n <div className=\"rounded-lg border divide-y\">\n {active.map((edge) => (\n <EdgeRow\n key={edge.id_}\n label={edge.label_}\n onEdit={\n editableTypes[edge.label_] ? () => onEdit(edge) : undefined\n }\n onDelete={() => onDelete(edge)}\n />\n ))}\n </div>\n </div>\n )}\n {available.length > 0 && (\n <div>\n <SectionTitle>Available edges</SectionTitle>\n <div className=\"rounded-lg border divide-y\">\n {available.map((entry) => (\n <EdgeRow\n key={`${entry.label}:${entry.sourceId}:${entry.targetId}`}\n label={rowLabel(entry)}\n onAdd={() => onCreate(entry)}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// The schema-driven property form for the current create/edit draft.\nfunction DraftForm({\n draft,\n schema,\n widgets,\n onSave,\n onCancel,\n}: {\n draft: Exclude<Draft, null>;\n schema: JsonSchema;\n widgets?: WidgetRegistry;\n onSave: (properties: Record<string, unknown>) => void;\n onCancel: () => void;\n}): React.ReactElement {\n const label = draft.mode === \"create\" ? draft.entry.label : draft.edge.label_;\n const data = draft.mode === \"edit\" ? (draft.edge.properties_ ?? {}) : {};\n return (\n <div>\n <SectionTitle>\n {draft.mode === \"create\" ? \"Add\" : \"Edit\"} {label}\n </SectionTitle>\n <JsonSchemaFormRenderer\n key={label}\n schema={schema}\n data={data}\n widgets={widgets}\n showActions\n // Creating an edge submits even when its type has no properties; editing\n // keeps the dirty-check.\n allowPristineSave={draft.mode === \"create\"}\n saveLabel={draft.mode === \"create\" ? \"Add\" : \"Save\"}\n cancelLabel=\"Cancel\"\n showExtraProperties\n onUpdate={onSave}\n onCancel={onCancel}\n />\n </div>\n );\n}\n\nexport function EdgeFormSheet({\n open,\n onOpenChange,\n nodeA,\n nodeB,\n port,\n schemaProvider,\n widgets,\n onChanged,\n}: EdgeFormSheetProps): React.ReactElement {\n const [reloadKey, setReloadKey] = useState(0);\n const [draft, setDraft] = useState<Draft>(null);\n const [error, setError] = useState<string>(\"\");\n // The edge pending delete confirmation (confirmed before executing).\n const [pendingDelete, setPendingDelete] = useState<RawGraphEdge | null>(null);\n const { active, available } = usePairState(\n port,\n schemaProvider,\n open,\n nodeA.id_,\n nodeA.label_,\n nodeB.id_,\n nodeB.label_,\n reloadKey,\n );\n const schema = useEdgeSchema(schemaProvider, draft);\n const editableTypes = useEditableEdgeTypes(schemaProvider, active);\n\n // Dep on stable primitives, not node objects, so a parent re-render that\n // produces new object references with the same ids does not reset mid-session.\n const nodeAId = nodeA.id_;\n const nodeBId = nodeB.id_;\n useEffect(() => {\n if (open) {\n setDraft(null);\n setError(\"\");\n setPendingDelete(null);\n }\n }, [open, nodeAId, nodeBId]);\n\n const reload = useCallback(() => {\n setReloadKey((k) => k + 1);\n onChanged?.();\n }, [onChanged]);\n\n const handleSave = useCallback(\n (formData: Record<string, unknown>): void => {\n if (!draft) return;\n // Extract typed properties (edge forms have no relation fields, but using\n // extractRelationFields gives us GraphProperties without a cast).\n const { properties } = extractRelationFields(formData);\n void (async () => {\n try {\n if (draft.mode === \"create\") {\n await port.createEdge({\n label_: draft.entry.label,\n start_id_: draft.entry.sourceId,\n end_id_: draft.entry.targetId,\n properties_: properties,\n });\n } else {\n await port.updateEdge({\n id_: draft.edge.id_!,\n label_: draft.edge.label_,\n start_id_: draft.edge.start_id_,\n end_id_: draft.edge.end_id_,\n properties_: properties,\n });\n }\n setDraft(null);\n setError(\"\");\n reload();\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Failed to save edge\");\n }\n })();\n },\n [draft, port, reload],\n );\n\n const confirmDelete = useCallback(async () => {\n const edge = pendingDelete;\n if (!edge || edge.id_ == null) return;\n try {\n await port.deleteEdge(edge.id_);\n setError(\"\");\n setPendingDelete(null);\n reload();\n } catch (e) {\n setPendingDelete(null);\n setError(e instanceof Error ? e.message : \"Failed to delete edge\");\n }\n }, [pendingDelete, port, reload]);\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent>\n <SheetHeader>\n <SheetTitle>Edges</SheetTitle>\n <SheetDescription>\n Manage the edges between the two selected nodes.\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-2 text-sm\">\n <span className=\"font-medium\">{extractDisplayLabel(nodeA)}</span>\n <ArrowRight className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">{extractDisplayLabel(nodeB)}</span>\n </div>\n\n {!draft && (\n <PairLists\n nodeALabel={nodeA.label_}\n nodeBLabel={nodeB.label_}\n nodeAId={nodeA.id_}\n active={active}\n available={available}\n editableTypes={editableTypes}\n onEdit={(edge) => setDraft({ mode: \"edit\", edge })}\n onDelete={(edge) => setPendingDelete(edge)}\n onCreate={(entry) => setDraft({ mode: \"create\", entry })}\n />\n )}\n\n {draft && schema && (\n <DraftForm\n draft={draft}\n schema={schema}\n widgets={widgets}\n onSave={handleSave}\n onCancel={() => setDraft(null)}\n />\n )}\n\n {error && <Alert variant=\"destructive\">{error}</Alert>}\n </SheetBody>\n </SheetContent>\n\n <DeleteEdgeConfirm\n edge={pendingDelete}\n onCancel={() => setPendingDelete(null)}\n onConfirm={() => void confirmDelete()}\n />\n </Sheet>\n );\n}\n\n// Confirm deleting an edge (matching the explorer's delete confirmation).\nfunction DeleteEdgeConfirm({\n edge,\n onCancel,\n onConfirm,\n}: {\n edge: RawGraphEdge | null;\n onCancel: () => void;\n onConfirm: () => void;\n}): React.ReactElement {\n return (\n <Dialog open={!!edge} onOpenChange={(o) => !o && onCancel()}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Delete edge</DialogTitle>\n <DialogDescription>\n Delete the edge <strong>{edge?.label_}</strong>? This removes the\n relationship between the two nodes.\n </DialogDescription>\n </DialogHeader>\n <DialogFooter>\n <Button variant=\"outline\" onClick={onCancel}>\n Cancel\n </Button>\n <Button variant=\"destructive\" onClick={onConfirm}>\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport default EdgeFormSheet;\n","/**\n * DeleteNodeDialog -- confirm deleting a node, warning about dependent edges.\n *\n * Loads the node's inbound/outbound edges through the injected\n * `GraphMutationPort` so the user sees what will be removed. Deleting goes\n * through `port.deleteNode`; the component emits no events and calls\n * `onDeleted` so the consumer can patch its own cache.\n */\n\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogDescription,\n DialogFooter,\n Button,\n Alert,\n} from \"@petrarca/sonnet-ui\";\nimport { errorLog } from \"@petrarca/sonnet-core\";\nimport type { RawGraphNode, RawGraphEdge } from \"../models/graph-types\";\nimport { extractDisplayLabel } from \"../graph/extractDisplayLabel\";\nimport type { GraphMutationPort } from \"./port\";\n\n/** Resolved dependent edges plus a map of neighbour-node id -> display name. */\ninterface DependentEdges {\n inbound: RawGraphEdge[];\n outbound: RawGraphEdge[];\n names: Record<number, string>;\n}\n\nexport interface DeleteNodeDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n node: RawGraphNode;\n port: GraphMutationPort;\n /** Called with the deleted node id after a successful delete. */\n onDeleted?: (id: number) => void;\n}\n\nconst EMPTY_DEPENDENT: DependentEdges = {\n inbound: [],\n outbound: [],\n names: {},\n};\n\n// Load the node's dependent edges (and the neighbour node names) so the user\n// sees what will be removed, with the same name -> relType detail the explorer\n// shows.\nfunction useDependentEdges(\n port: GraphMutationPort,\n open: boolean,\n node: RawGraphNode,\n): DependentEdges {\n const [dependent, setDependent] = useState<DependentEdges>(EMPTY_DEPENDENT);\n\n useEffect(() => {\n // Fetch each time the dialog opens (not on close) so there is no stale\n // flash if it is reopened for the same node.\n if (!open) return;\n if (node.id_ == null) {\n setDependent(EMPTY_DEPENDENT);\n return;\n }\n let cancelled = false;\n void (async () => {\n try {\n const [inbound, outbound] = await Promise.all([\n port.getInboundEdges(node.id_!),\n port.getOutboundEdges(node.id_!),\n ]);\n if (cancelled) return;\n const neighbourIds = Array.from(\n new Set([\n ...inbound.map((e) => e.start_id_),\n ...outbound.map((e) => e.end_id_),\n ]),\n );\n const names = await resolveNames(port, neighbourIds);\n if (cancelled) return;\n setDependent({ inbound, outbound, names });\n } catch (e) {\n if (cancelled) return;\n errorLog(\"[DeleteNodeDialog] failed to load dependent edges\", e);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [port, open, node.id_]);\n\n return dependent;\n}\n\n// Resolve neighbour node display names; tolerant of a port without rich data.\nasync function resolveNames(\n port: GraphMutationPort,\n ids: number[],\n): Promise<Record<number, string>> {\n if (ids.length === 0) return {};\n const nodes = await port.getNodes(ids);\n const names: Record<number, string> = {};\n for (const n of nodes) {\n if (n.id_ != null) names[n.id_] = extractDisplayLabel(n);\n }\n return names;\n}\n\n// One dependent-edge row: \"Neighbour -> relType\" (inbound) or\n// \"relType -> Neighbour\" (outbound). Falls back to the edge label when the\n// neighbour name is unknown.\nfunction EdgeList({\n title,\n edges,\n names,\n direction,\n}: {\n title: string;\n edges: RawGraphEdge[];\n names: Record<number, string>;\n direction: \"inbound\" | \"outbound\";\n}): React.ReactElement | null {\n if (edges.length === 0) return null;\n return (\n <div className=\"mb-2\">\n <span className=\"heading-meta block\">{title}</span>\n <ul className=\"list-disc pl-6 text-sm\">\n {edges.map((edge) => {\n const neighbour =\n direction === \"inbound\"\n ? names[edge.start_id_]\n : names[edge.end_id_];\n const text =\n direction === \"inbound\"\n ? `${neighbour ?? \"?\"} \\u2192 ${edge.label_}`\n : `${edge.label_} \\u2192 ${neighbour ?? \"?\"}`;\n return <li key={edge.id_}>{neighbour ? text : edge.label_}</li>;\n })}\n </ul>\n </div>\n );\n}\n\nexport function DeleteNodeDialog({\n open,\n onOpenChange,\n node,\n port,\n onDeleted,\n}: DeleteNodeDialogProps): React.ReactElement {\n const { inbound, outbound, names } = useDependentEdges(port, open, node);\n const [error, setError] = useState<string>(\"\");\n const hasEdges = inbound.length > 0 || outbound.length > 0;\n\n const handleDelete = useCallback((): void => {\n if (node.id_ == null) return;\n void (async () => {\n try {\n await port.deleteNode(node.id_!);\n setError(\"\");\n onDeleted?.(node.id_!);\n onOpenChange(false);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Unable to delete node\");\n }\n })();\n }, [port, node.id_, onDeleted, onOpenChange]);\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Delete node</DialogTitle>\n <DialogDescription>\n Delete the node <strong>{extractDisplayLabel(node)}</strong>?\n </DialogDescription>\n </DialogHeader>\n\n {!hasEdges && (\n <p className=\"text-sm text-muted-foreground\">No connected edges.</p>\n )}\n <EdgeList\n title=\"Inbound edges\"\n edges={inbound}\n names={names}\n direction=\"inbound\"\n />\n <EdgeList\n title=\"Outbound edges\"\n edges={outbound}\n names={names}\n direction=\"outbound\"\n />\n\n {error && <Alert variant=\"destructive\">{error}</Alert>}\n\n <DialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button variant=\"destructive\" onClick={handleDelete}>\n Delete\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\nexport default DeleteNodeDialog;\n"],"mappings":"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","names":["create","devLog","create","create","devLog","edgeId","devLog","nodeId","create","create","devLog","create","devLog","buildStore","devLog","useGraphFilter","useGraphData","useMemo","useMemo","useMemo","useMemo","createContext","useContext","useCallback","useCallback","useEffect","useRef","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","useState","devLog","useCallback","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useState","React","nodeId","devLog","edgeId","toast","jsx","jsxs","devLog","useRef","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","errorLog","toast","nodeId","edgeId","toast","jsx","jsxs","nodeId","errorLog","toast","devLog","useState","useEffect","useCallback","edgeId","useRef","useGraphFilter","useSelection","z","jsx","jsxs","Card","useState","Card","jsx","jsxs","useState","Card","Collapsible","CollapsibleContent","CollapsibleTrigger","PropertyList","copyTextToClipboard","jsx","jsxs","devLog","useMemo","Fragment","jsx","jsxs","useGraphFilter","useMemo","jsx","jsxs","useSelection","Card","useCallback","useMemo","useRef","cn","jsx","useSelection","useMemo","useRef","useCallback","cn","nodeTypeLabels","useCallback","useEffect","useRef","useState","useMemo","useState","Button","IconButton","useState","Badge","useMemo","jsx","jsxs","useState","Sheet","SheetContent","SheetHeader","SheetBody","SheetTitle","SheetDescription","Button","jsx","jsxs","Button","useState","Sheet","SheetContent","SheetHeader","SheetTitle","SheetDescription","SheetBody","useState","Sheet","SheetContent","SheetHeader","SheetBody","SheetTitle","SheetDescription","Button","Input","jsx","jsxs","Fragment","jsx","jsxs","Badge","useState","Fragment","jsx","jsxs","useState","Button","useSelection","useMemo","IconButton","Fragment","jsx","jsxs","useRef","useEffect","useState","useCallback","z","warnLog","nodeId","useCallback","useMemo","useState","IconButton","Plus","Trash2","useCallback","useEffect","useMemo","useRef","useState","Sheet","SheetContent","SheetHeader","SheetBody","SheetTitle","SheetDescription","FormSelect","JsonSchemaFormRenderer","errorLog","Fragment","jsx","jsxs","useState","useRef","useEffect","errorLog","nodeId","FormSelect","JsonSchemaFormRenderer","SheetHeader","SheetTitle","SheetDescription","SheetBody","useMemo","useCallback","Sheet","SheetContent","res","useCallback","useEffect","useMemo","useState","Sheet","SheetContent","SheetHeader","SheetBody","SheetTitle","SheetDescription","Button","IconButton","Alert","Pencil","Plus","Trash2","ArrowRight","JsonSchemaFormRenderer","errorLog","jsx","jsxs","useState","useEffect","errorLog","useMemo","SectionTitle","IconButton","Plus","Pencil","Trash2","JsonSchemaFormRenderer","useCallback","Sheet","SheetContent","SheetHeader","SheetTitle","SheetDescription","SheetBody","ArrowRight","Alert","Button","useCallback","useEffect","useState","Dialog","DialogContent","DialogHeader","DialogTitle","DialogDescription","DialogFooter","Button","Alert","errorLog","jsx","jsxs","useState","useEffect","errorLog","useCallback","Dialog","DialogContent","DialogHeader","DialogTitle","DialogDescription","Alert","DialogFooter","Button","Fragment","jsx","jsxs","IconButton","Plus","Trash2","useCallback","useSelection","useState","useMemo"]}