-
{key}
+
{key}
{typeof value === "object" ? JSON.stringify(value) : String(value)}
@@ -248,6 +363,8 @@ export function GraphInspectorPanel({
);
}
+/* ─── styles ─────────────────────────────────────────────────────── */
+
const inputStyle: CSSProperties = {
width: "100%",
background: "rgba(4, 10, 18, 0.5)",
@@ -284,19 +401,12 @@ const secondaryActionButtonStyle: CSSProperties = {
const predictionCardStyle: CSSProperties = {
textAlign: "left",
- padding: 12,
+ padding: "10px 12px",
background: "rgba(88, 166, 255, 0.08)",
border: "1px solid rgba(88, 166, 255, 0.12)",
borderRadius: 10,
cursor: "pointer",
-};
-
-const pathStepStyle: CSSProperties = {
- color: "#e6edf3",
- fontSize: 13,
- padding: "8px 10px",
- background: "rgba(255, 255, 255, 0.03)",
- borderRadius: 8,
+ width: "100%",
};
const propertyCardStyle: CSSProperties = {
@@ -338,3 +448,58 @@ const sectionTitleStyle: CSSProperties = {
textTransform: "uppercase",
letterSpacing: "0.08em",
};
+
+const pathFlowContainerStyle: CSSProperties = {
+ display: "flex",
+ alignItems: "center",
+ gap: 0,
+ flexWrap: "wrap",
+ rowGap: 8,
+};
+
+const pathNodeChipStyle: CSSProperties = {
+ display: "inline-flex",
+ alignItems: "center",
+ gap: 6,
+ padding: "5px 10px",
+ borderRadius: 999,
+ background: "rgba(88,166,255,0.1)",
+ border: "1px solid rgba(88,166,255,0.22)",
+ color: "#e6edf3",
+ fontSize: 12,
+ fontWeight: 600,
+ maxWidth: 160,
+};
+
+const pathNodeIndexStyle: CSSProperties = {
+ display: "inline-flex",
+ alignItems: "center",
+ justifyContent: "center",
+ width: 16,
+ height: 16,
+ borderRadius: "50%",
+ background: "rgba(88,166,255,0.22)",
+ color: "#79c0ff",
+ fontSize: 9,
+ fontWeight: 800,
+ flexShrink: 0,
+};
+
+const pathEdgeConnectorStyle: CSSProperties = {
+ display: "inline-flex",
+ alignItems: "center",
+ gap: 2,
+ flexShrink: 0,
+};
+
+const pathEdgeLabelStyle: CSSProperties = {
+ fontSize: 9,
+ fontWeight: 700,
+ color: "#6a7f97",
+ letterSpacing: "0.04em",
+ textTransform: "uppercase",
+ maxWidth: 70,
+ overflow: "hidden",
+ textOverflow: "ellipsis",
+ whiteSpace: "nowrap",
+};
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/GraphLoadingOverlay.tsx b/explorer/src/workspaces/GraphWorkspace/GraphLoadingOverlay.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/GraphLoadingOverlay.tsx
rename to explorer/src/workspaces/GraphWorkspace/GraphLoadingOverlay.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/GraphRuntimeStage.tsx b/explorer/src/workspaces/GraphWorkspace/GraphRuntimeStage.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/GraphRuntimeStage.tsx
rename to explorer/src/workspaces/GraphWorkspace/GraphRuntimeStage.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx b/explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx
similarity index 97%
rename from semantica-explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx
rename to explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx
index a01dd32c..b14a26e8 100644
--- a/semantica-explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx
+++ b/explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx
@@ -1,6 +1,7 @@
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { batchMergeEdges, batchMergeNodes, graph } from "../../store/graphStore";
+import { logEvent } from "../../store/registryStore";
import type { EdgeAttributes, NodeAttributes } from "../../store/graphStore";
import { curveGroupForPair } from "../../store/edgePairKeys.js";
import { InspectorPanel, MetricChip, SurfaceCard } from "../../ui/primitives";
@@ -630,6 +631,7 @@ export function GraphWorkspace() {
const [searchResults, setSearchResults] = useState
([]);
const [searchError, setSearchError] = useState("");
const [predictionType, setPredictionType] = useState("");
+ const [isRunningPredictions, setIsRunningPredictions] = useState(false);
const [predictions, setPredictions] = useState([]);
const [pathTargetId, setPathTargetId] = useState("");
const [pathResult, setPathResult] = useState(null);
@@ -899,6 +901,7 @@ export function GraphWorkspace() {
attributes: buildRealtimeNodeAttributes(payload),
},
]);
+ logEvent("add-node", `Added node ${payload.label ?? payload.id}${payload.nodeType ? ` (${payload.nodeType})` : ""} via realtime ws`, { nodeId: payload.id, nodeType: payload.nodeType });
sceneRef.current?.getRuntime()?.requestRender();
}
if (eventType === "ADD_EDGE") {
@@ -911,6 +914,7 @@ export function GraphWorkspace() {
attributes: buildRealtimeEdgeAttributes(payload),
},
]);
+ logEvent("add-edge", `Added edge ${payload.edgeType ?? payload.id} (${payload.source_id} → ${payload.target_id}) via realtime ws`, { edgeId: payload.id, edgeType: payload.edgeType, source: payload.source_id, target: payload.target_id });
sceneRef.current?.getRuntime()?.requestRender();
}
} catch (socketError) {
@@ -1293,10 +1297,34 @@ export function GraphWorkspace() {
disabled: showLoadingOverlay || !searchQuery.trim(),
onClick: () => void handleSearch(),
},
+ {
+ id: "zoom-in",
+ label: "+ Zoom In",
+ title: "Zoom in (or scroll up on the canvas)",
+ onClick: () => {
+ const runtime = sceneRef.current?.getRuntime();
+ if (runtime?.renderer === "sigma") {
+ const camera = (runtime.scene as import("sigma").default).getCamera();
+ camera.animatedZoom({ duration: 200 });
+ }
+ },
+ },
+ {
+ id: "zoom-out",
+ label: "- Zoom Out",
+ title: "Zoom out (or scroll down on the canvas)",
+ onClick: () => {
+ const runtime = sceneRef.current?.getRuntime();
+ if (runtime?.renderer === "sigma") {
+ const camera = (runtime.scene as import("sigma").default).getCamera();
+ camera.animatedUnzoom({ duration: 200 });
+ }
+ },
+ },
{
id: "fit-view",
label: "Fit View",
- title: "Reset the camera to the current view",
+ title: "Reset the camera to fit the whole graph",
onClick: () => sceneRef.current?.fitView(),
},
{
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/GraphWorkspaceShell.tsx b/explorer/src/workspaces/GraphWorkspace/GraphWorkspaceShell.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/GraphWorkspaceShell.tsx
rename to explorer/src/workspaces/GraphWorkspace/GraphWorkspaceShell.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/SigmaSceneAdapter.tsx b/explorer/src/workspaces/GraphWorkspace/SigmaSceneAdapter.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/SigmaSceneAdapter.tsx
rename to explorer/src/workspaces/GraphWorkspace/SigmaSceneAdapter.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/TimelinePanel.tsx b/explorer/src/workspaces/GraphWorkspace/TimelinePanel.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/TimelinePanel.tsx
rename to explorer/src/workspaces/GraphWorkspace/TimelinePanel.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/clickSelectionBehavior.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/clickSelectionBehavior.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/clickSelectionBehavior.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/clickSelectionBehavior.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/fitViewBehavior.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/fitViewBehavior.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/fitViewBehavior.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/fitViewBehavior.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/focusCameraBehavior.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/focusCameraBehavior.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/focusCameraBehavior.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/focusCameraBehavior.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/hoverActivationBehavior.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/hoverActivationBehavior.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/hoverActivationBehavior.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/hoverActivationBehavior.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/pathHighlightBehavior.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/pathHighlightBehavior.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/pathHighlightBehavior.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/pathHighlightBehavior.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/searchFocusBehavior.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/searchFocusBehavior.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/searchFocusBehavior.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/searchFocusBehavior.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/types.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/types.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/types.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/types.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/behaviors/viewModeSwitchBehavior.ts b/explorer/src/workspaces/GraphWorkspace/behaviors/viewModeSwitchBehavior.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/behaviors/viewModeSwitchBehavior.ts
rename to explorer/src/workspaces/GraphWorkspace/behaviors/viewModeSwitchBehavior.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/graphAnalytics.ts b/explorer/src/workspaces/GraphWorkspace/graphAnalytics.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/graphAnalytics.ts
rename to explorer/src/workspaces/GraphWorkspace/graphAnalytics.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/graphConfig.ts b/explorer/src/workspaces/GraphWorkspace/graphConfig.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/graphConfig.ts
rename to explorer/src/workspaces/GraphWorkspace/graphConfig.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/graphLoading.ts b/explorer/src/workspaces/GraphWorkspace/graphLoading.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/graphLoading.ts
rename to explorer/src/workspaces/GraphWorkspace/graphLoading.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/graphSceneLayers.ts b/explorer/src/workspaces/GraphWorkspace/graphSceneLayers.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/graphSceneLayers.ts
rename to explorer/src/workspaces/GraphWorkspace/graphSceneLayers.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/graphSceneState.ts b/explorer/src/workspaces/GraphWorkspace/graphSceneState.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/graphSceneState.ts
rename to explorer/src/workspaces/GraphWorkspace/graphSceneState.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/graphTheme.ts b/explorer/src/workspaces/GraphWorkspace/graphTheme.ts
similarity index 86%
rename from semantica-explorer/src/workspaces/GraphWorkspace/graphTheme.ts
rename to explorer/src/workspaces/GraphWorkspace/graphTheme.ts
index bce23092..ea033613 100644
--- a/semantica-explorer/src/workspaces/GraphWorkspace/graphTheme.ts
+++ b/explorer/src/workspaces/GraphWorkspace/graphTheme.ts
@@ -265,16 +265,16 @@ export const GRAPH_THEME: GraphTheme = {
],
overview: {
nodeBase: "#0B1320",
- nodeCore: "#435D7A",
+ nodeCore: "#5A7A9E",
nodeMuted: "#121927",
- nodeBorder: "#64758C",
- nodeTintMix: 0.03,
- nodeCoreMix: 0.52,
+ nodeBorder: "#7A92AE",
+ nodeTintMix: 0.14,
+ nodeCoreMix: 0.72,
nodeShellAlpha: 0.97,
nodeCoreAlpha: 1,
- edgeBackbone: "rgba(83, 111, 148, 0.04)",
- edgeStructure: "rgba(72, 90, 118, 0.009)",
- edgeInspection: "rgba(98, 120, 148, 0.026)",
+ edgeBackbone: "rgba(100, 148, 210, 0.38)",
+ edgeStructure: "rgba(88, 140, 200, 0.28)",
+ edgeInspection: "rgba(110, 165, 230, 0.48)",
},
accent: {
selected: "#F2D288",
@@ -285,12 +285,12 @@ export const GRAPH_THEME: GraphTheme = {
inferred: "#D07B4D",
},
muted: {
- fallback: "rgba(96, 112, 136, 0.1)",
- nodeAlpha: 0.085,
- edgeOverview: "rgba(82, 100, 124, 0.009)",
- edgeStructure: "rgba(92, 112, 138, 0.02)",
- edgeInspection: "rgba(124, 148, 176, 0.066)",
- edgeFocus: "rgba(160, 186, 218, 0.16)",
+ fallback: "rgba(96, 112, 136, 0.18)",
+ nodeAlpha: 0.12,
+ edgeOverview: "rgba(82, 100, 124, 0.12)",
+ edgeStructure: "rgba(92, 112, 138, 0.18)",
+ edgeInspection: "rgba(124, 148, 176, 0.26)",
+ edgeFocus: "rgba(160, 186, 218, 0.42)",
},
background: {
canvas: "#07101A",
@@ -305,36 +305,36 @@ export const GRAPH_THEME: GraphTheme = {
zoomTiers: {
overview: {
maxRatio: Number.POSITIVE_INFINITY,
- nodeScale: 0.66,
- labelThreshold: 0.985,
- labelBudget: 10,
- edgePriorityThreshold: 0.72,
+ nodeScale: 0.88,
+ labelThreshold: 0.92,
+ labelBudget: 28,
+ edgePriorityThreshold: 0.55,
arrowPriorityThreshold: Number.POSITIVE_INFINITY,
- edgeSizeScale: 0.34,
+ edgeSizeScale: 0.62,
showBadges: false,
showCurves: false,
showContextualArrows: false,
},
structure: {
maxRatio: 1.2,
- nodeScale: 0.98,
- labelThreshold: 0.88,
- labelBudget: 36,
- edgePriorityThreshold: 0.4,
- arrowPriorityThreshold: 0.75,
- edgeSizeScale: 0.92,
+ nodeScale: 1.02,
+ labelThreshold: 0.82,
+ labelBudget: 60,
+ edgePriorityThreshold: 0.3,
+ arrowPriorityThreshold: 0.65,
+ edgeSizeScale: 1.05,
showBadges: true,
showCurves: true,
showContextualArrows: true,
},
inspection: {
maxRatio: 0.5,
- nodeScale: 1,
- labelThreshold: 0.7,
- labelBudget: 80,
+ nodeScale: 1.08,
+ labelThreshold: 0.6,
+ labelBudget: 120,
edgePriorityThreshold: 0,
- arrowPriorityThreshold: 0.58,
- edgeSizeScale: 1.04,
+ arrowPriorityThreshold: 0.45,
+ edgeSizeScale: 1.18,
showBadges: true,
showCurves: true,
showContextualArrows: true,
@@ -398,13 +398,13 @@ export const GRAPH_THEME: GraphTheme = {
inspection: { base: 1.2, emphasis: 1.7, muted: 0.6 },
},
states: {
- default: { color: "base", sizeMultiplier: 0.72, minSize: 0.68, forceLabel: false, zIndex: 0, borderBoost: -0.42 },
- hovered: { color: "hovered", sizeMultiplier: 1.18, minSize: 12.5, forceLabel: true, zIndex: 4, borderBoost: 0.22 },
- selected: { color: "selected", sizeMultiplier: 1.06, minSize: 10.5, forceLabel: true, zIndex: 3, borderBoost: 0.2 },
- neighbor: { color: "base", sizeMultiplier: 0.84, minSize: 4.8, forceLabel: true, zIndex: 2, borderBoost: -0.08 },
- path: { color: "path", sizeMultiplier: 1.01, minSize: 6.2, forceLabel: true, zIndex: 2, borderBoost: 0.08 },
- inactive: { color: "muted", sizeMultiplier: 0.32, minSize: 0.46, forceLabel: false, zIndex: 0, borderBoost: -0.42 },
- muted: { color: "muted", sizeMultiplier: 0.32, minSize: 0.46, forceLabel: false, zIndex: 0, borderBoost: -0.42 },
+ default: { color: "base", sizeMultiplier: 0.92, minSize: 3.5, forceLabel: false, zIndex: 0, borderBoost: -0.18 },
+ hovered: { color: "hovered", sizeMultiplier: 1.28, minSize: 13.5, forceLabel: true, zIndex: 4, borderBoost: 0.28 },
+ selected: { color: "selected", sizeMultiplier: 1.14, minSize: 11.5, forceLabel: true, zIndex: 3, borderBoost: 0.24 },
+ neighbor: { color: "base", sizeMultiplier: 0.96, minSize: 5.5, forceLabel: true, zIndex: 2, borderBoost: 0.04 },
+ path: { color: "path", sizeMultiplier: 1.08, minSize: 7.0, forceLabel: true, zIndex: 2, borderBoost: 0.12 },
+ inactive: { color: "muted", sizeMultiplier: 0.48, minSize: 1.8, forceLabel: false, zIndex: 0, borderBoost: -0.28 },
+ muted: { color: "muted", sizeMultiplier: 0.48, minSize: 1.8, forceLabel: false, zIndex: 0, borderBoost: -0.28 },
},
variants: {
default: { sizeMultiplier: 1, borderBoost: 0, haloBoost: 0, badgeVisibleFrom: "inspection" },
@@ -437,14 +437,14 @@ export const GRAPH_THEME: GraphTheme = {
},
edges: {
states: {
- default: { color: "structure", sizeMultiplier: 0.74, minSize: 0.18, zIndex: 0, forceArrow: false, hide: false },
- backbone: { color: "backbone", sizeMultiplier: 0.72, minSize: 0.18, zIndex: 1, forceArrow: false, hide: false },
- hovered: { color: "hover", sizeMultiplier: 1.42, minSize: 1.45, zIndex: 3, forceArrow: true, hide: false },
- selected: { color: "hover", sizeMultiplier: 1.42, minSize: 1.45, zIndex: 3, forceArrow: true, hide: false },
- neighbor: { color: "focus", sizeMultiplier: 0.92, minSize: 0.5, zIndex: 1, forceArrow: false, hide: false },
- path: { color: "path", sizeMultiplier: 1.5, minSize: 1.8, zIndex: 4, forceArrow: true, hide: false },
- inactive: { color: "muted", sizeMultiplier: 1, minSize: 0.16, zIndex: 0, forceArrow: false, hide: true },
- muted: { color: "muted", sizeMultiplier: 1, minSize: 0.16, zIndex: 0, forceArrow: false, hide: true },
+ default: { color: "structure", sizeMultiplier: 0.96, minSize: 0.9, zIndex: 0, forceArrow: false, hide: false },
+ backbone: { color: "backbone", sizeMultiplier: 1.0, minSize: 1.0, zIndex: 1, forceArrow: false, hide: false },
+ hovered: { color: "hover", sizeMultiplier: 1.6, minSize: 2.2, zIndex: 3, forceArrow: true, hide: false },
+ selected: { color: "hover", sizeMultiplier: 1.6, minSize: 2.2, zIndex: 3, forceArrow: true, hide: false },
+ neighbor: { color: "focus", sizeMultiplier: 1.1, minSize: 1.2, zIndex: 1, forceArrow: false, hide: false },
+ path: { color: "path", sizeMultiplier: 1.7, minSize: 2.4, zIndex: 4, forceArrow: true, hide: false },
+ inactive: { color: "muted", sizeMultiplier: 0.6, minSize: 0.5, zIndex: 0, forceArrow: false, hide: false },
+ muted: { color: "muted", sizeMultiplier: 0.6, minSize: 0.5, zIndex: 0, forceArrow: false, hide: false },
},
variants: {
line: { baseType: "line", arrowPolicy: "hidden", curveStrength: 0, sizeMultiplier: 1, glowAlpha: 0 },
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPlugin.tsx b/explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPlugin.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPlugin.tsx
rename to explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPlugin.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPluginPhaseC.tsx b/explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPluginPhaseC.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPluginPhaseC.tsx
rename to explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPluginPhaseC.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/plugins/index.ts b/explorer/src/workspaces/GraphWorkspace/plugins/index.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/plugins/index.ts
rename to explorer/src/workspaces/GraphWorkspace/plugins/index.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/plugins/legendPlugin.tsx b/explorer/src/workspaces/GraphWorkspace/plugins/legendPlugin.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/plugins/legendPlugin.tsx
rename to explorer/src/workspaces/GraphWorkspace/plugins/legendPlugin.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/plugins/neighborhoodPanelPlugin.tsx b/explorer/src/workspaces/GraphWorkspace/plugins/neighborhoodPanelPlugin.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/plugins/neighborhoodPanelPlugin.tsx
rename to explorer/src/workspaces/GraphWorkspace/plugins/neighborhoodPanelPlugin.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/plugins/temporalOverlayPlugin.tsx b/explorer/src/workspaces/GraphWorkspace/plugins/temporalOverlayPlugin.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/plugins/temporalOverlayPlugin.tsx
rename to explorer/src/workspaces/GraphWorkspace/plugins/temporalOverlayPlugin.tsx
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/plugins/types.ts b/explorer/src/workspaces/GraphWorkspace/plugins/types.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/plugins/types.ts
rename to explorer/src/workspaces/GraphWorkspace/plugins/types.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/scene.ts b/explorer/src/workspaces/GraphWorkspace/scene.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/scene.ts
rename to explorer/src/workspaces/GraphWorkspace/scene.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/sigmaNativeRendering.ts b/explorer/src/workspaces/GraphWorkspace/sigmaNativeRendering.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/sigmaNativeRendering.ts
rename to explorer/src/workspaces/GraphWorkspace/sigmaNativeRendering.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/types.ts b/explorer/src/workspaces/GraphWorkspace/types.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/types.ts
rename to explorer/src/workspaces/GraphWorkspace/types.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/useGraphData.ts b/explorer/src/workspaces/GraphWorkspace/useGraphData.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/useGraphData.ts
rename to explorer/src/workspaces/GraphWorkspace/useGraphData.ts
diff --git a/semantica-explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts b/explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts
rename to explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts
diff --git a/semantica-explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx b/explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx
similarity index 96%
rename from semantica-explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx
rename to explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx
index abf32aba..44b0df58 100644
--- a/semantica-explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx
+++ b/explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx
@@ -4,6 +4,7 @@
import { useState, useCallback } from "react";
import { useDropzone } from "react-dropzone";
import { UploadCloud, Download, FileJson, FileText, CheckCircle2, AlertCircle, Loader2 } from "lucide-react";
+import { logEvent } from "../../store/registryStore";
const THEME_CSS = `
.glass-panel {
@@ -107,6 +108,11 @@ export function ImportExportWorkspace() {
const data = await res.json();
showToast("success", `Imported ${data.nodes_imported} nodes and ${data.edges_imported} edges!`);
+ logEvent("import", `Imported ${data.nodes_imported} nodes · ${data.edges_imported} edges from ${file.name}`, {
+ file: file.name,
+ nodesImported: data.nodes_imported,
+ edgesImported: data.edges_imported,
+ });
setFile(null);
} catch (err: any) {
showToast("error", err.message || "An error occurred during import");
@@ -142,6 +148,7 @@ export function ImportExportWorkspace() {
document.body.removeChild(a);
showToast("success", "Export complete! Your download should begin shortly.");
+ logEvent("export", `Exported graph as ${exportFormat.toUpperCase()}`, { format: exportFormat });
} catch (err: any) {
showToast("error", err.message || "An error occurred during export");
} finally {
diff --git a/semantica-explorer/src/workspaces/LineageWorkspace/LineageDiagram.tsx b/explorer/src/workspaces/LineageWorkspace/LineageDiagram.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/LineageWorkspace/LineageDiagram.tsx
rename to explorer/src/workspaces/LineageWorkspace/LineageDiagram.tsx
diff --git a/explorer/src/workspaces/ManageWorkspace/KGOverviewTab.tsx b/explorer/src/workspaces/ManageWorkspace/KGOverviewTab.tsx
new file mode 100644
index 00000000..60866143
--- /dev/null
+++ b/explorer/src/workspaces/ManageWorkspace/KGOverviewTab.tsx
@@ -0,0 +1,339 @@
+/**
+ * src/workspaces/ManageWorkspace/KGOverviewTab.tsx
+ *
+ * Quick-view dashboard for the Knowledge Graph: node/edge counts,
+ * type distributions, and top connected nodes.
+ */
+import { useState, useEffect, useCallback } from "react";
+import { Network, RefreshCw, Loader2 } from "lucide-react";
+
+interface KGStats {
+ node_count: number;
+ edge_count: number;
+ node_types?: Record;
+ edge_types?: Record;
+ [key: string]: unknown;
+}
+
+interface NodeItem {
+ id: string;
+ type: string;
+ content: string;
+ properties?: Record;
+}
+
+interface NodeListResponse {
+ nodes: NodeItem[];
+ total: number;
+}
+
+function TypeBar({ label, count, total, color }: { label: string; count: number; total: number; color: string }) {
+ const pct = total > 0 ? Math.round((count / total) * 100) : 0;
+ return (
+
+
+ {label}
+
+
+
+ {count.toLocaleString()}
+ {pct}%
+
+
+ );
+}
+
+const NODE_COLORS = ["#3E79F2", "#149287", "#2F9F61", "#555FD6", "#8A56D8", "#B65473", "#C9922E", "#4aa3ff", "#f2b66d"];
+const EDGE_COLORS = ["#4cc38a", "#79c0ff", "#d2a8ff", "#f2b66d", "#ff7b72", "#58a6ff", "#4aa3ff", "#8A56D8"];
+
+function buildTypeMap(nodes: NodeItem[], key: keyof NodeItem): Record {
+ const map: Record = {};
+ for (const node of nodes) {
+ const val = String(node[key] ?? "unknown");
+ map[val] = (map[val] ?? 0) + 1;
+ }
+ return map;
+}
+
+export function KGOverviewTab() {
+ const [stats, setStats] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState("");
+ const [topNodes, setTopNodes] = useState<{ node: NodeItem; neighborCount: number }[]>([]);
+ const [nodeTypeMap, setNodeTypeMap] = useState>({});
+
+ const fetchOverview = useCallback(async () => {
+ setLoading(true);
+ setError("");
+ try {
+ const [statsRes, nodesRes] = await Promise.all([
+ fetch("/api/graph/stats"),
+ fetch("/api/graph/nodes?limit=500"),
+ ]);
+
+ if (statsRes.ok) {
+ const statsData: KGStats = await statsRes.json();
+ setStats(statsData);
+ }
+
+ if (nodesRes.ok) {
+ const nodesData: NodeListResponse = await nodesRes.json();
+ const nodes = nodesData.nodes ?? [];
+ setNodeTypeMap(buildTypeMap(nodes, "type"));
+
+ // Simulate neighbor counts via edges fetch for top-N
+ const edgesRes = await fetch("/api/graph/edges?limit=2000");
+ if (edgesRes.ok) {
+ const edgesData = await edgesRes.json();
+ const edges: { source: string; target: string }[] = edgesData.edges ?? [];
+ const degreeMap: Record = {};
+ for (const edge of edges) {
+ degreeMap[edge.source] = (degreeMap[edge.source] ?? 0) + 1;
+ degreeMap[edge.target] = (degreeMap[edge.target] ?? 0) + 1;
+ }
+ const sorted = nodes
+ .map((n) => ({ node: n, neighborCount: degreeMap[n.id] ?? 0 }))
+ .sort((a, b) => b.neighborCount - a.neighborCount)
+ .slice(0, 10);
+ setTopNodes(sorted);
+ }
+ }
+ } catch {
+ setError("Failed to load graph overview. Ensure the server is running.");
+ } finally {
+ setLoading(false);
+ }
+ }, []);
+
+ useEffect(() => {
+ void fetchOverview();
+ }, [fetchOverview]);
+
+ const nodeTypeEntries = Object.entries(nodeTypeMap).sort((a, b) => b[1] - a[1]);
+ const edgeTypeEntries = stats?.edge_types
+ ? Object.entries(stats.edge_types).sort((a, b) => b[1] - a[1])
+ : [];
+
+ const totalNodes = stats?.node_count ?? 0;
+ const totalEdges = stats?.edge_count ?? 0;
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
KG Overview
+
Quick view of the Knowledge Graph structure and health
+
+
+
void fetchOverview()} disabled={loading} style={refreshBtnStyle}>
+ {loading ? : }
+ Refresh
+
+
+
+ {error ? (
+
+ {error}
+
+ ) : null}
+
+
+ {/* Stats chips */}
+
+ {[
+ { label: "Nodes", value: totalNodes.toLocaleString(), color: "#4aa3ff", sub: `${nodeTypeEntries.length} types` },
+ { label: "Edges", value: totalEdges.toLocaleString(), color: "#4cc38a", sub: `${edgeTypeEntries.length} relationship types` },
+ { label: "Density", value: totalNodes > 1 ? ((totalEdges / (totalNodes * (totalNodes - 1))) * 100).toFixed(3) + "%" : "—", color: "#d2a8ff", sub: "graph density" },
+ ].map(({ label, value, color, sub }) => (
+
+
{label}
+
{loading ? "—" : value}
+
{sub}
+
+ ))}
+
+
+ {/* Type breakdowns */}
+
+ {/* Node types */}
+
+
Node Type Breakdown
+ {loading ? (
+
+ {[80, 65, 45, 35, 25].map((w, i) => (
+
+ ))}
+
+ ) : nodeTypeEntries.length === 0 ? (
+
No data — load the graph first.
+ ) : (
+ nodeTypeEntries.slice(0, 8).map(([type, count], i) => (
+
+ ))
+ )}
+
+
+ {/* Edge types */}
+
+
Edge Type Breakdown
+ {loading ? (
+
+ {[70, 55, 48, 30, 20].map((w, i) => (
+
+ ))}
+
+ ) : edgeTypeEntries.length === 0 ? (
+
Edge type breakdown requires the stats endpoint to return edge_types.
+ ) : (
+ edgeTypeEntries.slice(0, 8).map(([type, count], i) => (
+
+ ))
+ )}
+
+
+
+ {/* Top connected nodes */}
+ {topNodes.length > 0 ? (
+
+
Top Connected Nodes (by degree)
+
+ {topNodes.map(({ node, neighborCount }, rank) => (
+
+
#{rank + 1}
+
+
+ {node.content || node.id}
+
+
{node.type}
+
+
+ {neighborCount} conn.
+
+
+ ))}
+
+
+ ) : null}
+
+
+ );
+}
+
+/* ─── styles ─────────────────────────────────────────────────────── */
+
+const shellStyle: React.CSSProperties = {
+ display: "flex",
+ flexDirection: "column",
+ width: "100%",
+ height: "100%",
+ background: "#0d1117",
+ overflow: "hidden",
+};
+
+const headerStyle: React.CSSProperties = {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ padding: "20px 24px 16px",
+ borderBottom: "1px solid rgba(88,166,255,0.1)",
+ flexShrink: 0,
+};
+
+const refreshBtnStyle: React.CSSProperties = {
+ display: "inline-flex",
+ alignItems: "center",
+ gap: 6,
+ padding: "6px 12px",
+ borderRadius: 8,
+ border: "1px solid rgba(127,208,255,0.16)",
+ background: "rgba(74,163,255,0.08)",
+ color: "#8fa8c6",
+ fontSize: 12,
+ fontWeight: 600,
+ cursor: "pointer",
+};
+
+const scrollBodyStyle: React.CSSProperties = {
+ flex: 1,
+ overflowY: "auto",
+ padding: "20px 24px",
+ display: "flex",
+ flexDirection: "column",
+ gap: 16,
+};
+
+const statsRowStyle: React.CSSProperties = {
+ display: "grid",
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
+ gap: 12,
+};
+
+const statCardStyle: React.CSSProperties = {
+ padding: "18px 20px",
+ borderRadius: 16,
+ background: "linear-gradient(135deg, rgba(13,17,23,0.8), rgba(22,27,34,0.5))",
+ border: "1px solid rgba(127,208,255,0.1)",
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.04)",
+};
+
+const sectionRowStyle: React.CSSProperties = {
+ display: "grid",
+ gridTemplateColumns: "1fr 1fr",
+ gap: 12,
+};
+
+const breakdownCardStyle: React.CSSProperties = {
+ padding: "16px 18px",
+ borderRadius: 14,
+ background: "linear-gradient(135deg, rgba(13,17,23,0.7), rgba(22,27,34,0.4))",
+ border: "1px solid rgba(255,255,255,0.06)",
+ display: "flex",
+ flexDirection: "column",
+ gap: 8,
+};
+
+const sectionTitleStyle: React.CSSProperties = {
+ color: "#8b949e",
+ fontSize: 11,
+ fontWeight: 700,
+ textTransform: "uppercase",
+ letterSpacing: "0.07em",
+ marginBottom: 4,
+};
+
+const topNodeRowStyle: React.CSSProperties = {
+ display: "flex",
+ alignItems: "center",
+ gap: 10,
+ padding: "8px 10px",
+ borderRadius: 10,
+ background: "rgba(255,255,255,0.025)",
+ border: "1px solid rgba(255,255,255,0.05)",
+};
+
+const skeletonWrapStyle: React.CSSProperties = {
+ display: "flex",
+ flexDirection: "column",
+ gap: 8,
+ marginTop: 4,
+};
+
+const skeletonBarStyle: React.CSSProperties = {
+ height: 12,
+ borderRadius: 999,
+ background: "rgba(255,255,255,0.05)",
+ animation: "skeleton-pulse 1.4s ease-in-out infinite",
+};
diff --git a/explorer/src/workspaces/ManageWorkspace/OntologySummaryTab.tsx b/explorer/src/workspaces/ManageWorkspace/OntologySummaryTab.tsx
new file mode 100644
index 00000000..4bb2e629
--- /dev/null
+++ b/explorer/src/workspaces/ManageWorkspace/OntologySummaryTab.tsx
@@ -0,0 +1,346 @@
+/**
+ * src/workspaces/ManageWorkspace/OntologySummaryTab.tsx
+ *
+ * A compact read-only view of all loaded SKOS ConceptSchemes and their
+ * top-level concepts. Clicking a concept deep-links to the Vocabulary Browser.
+ */
+import { useState } from "react";
+import { BookOpen, ChevronRight, ChevronDown, ExternalLink } from "lucide-react";
+import { useVocabularies, useConceptHierarchy } from "../VocabularyWorkspace/queries";
+import type { ConceptNode, VocabularyScheme } from "../VocabularyWorkspace/types";
+
+function countConcepts(nodes: ConceptNode[]): number {
+ return nodes.reduce((acc, node) => {
+ return acc + 1 + countConcepts(node.children ?? []);
+ }, 0);
+}
+
+function ConceptRow({
+ concept,
+ depth,
+ onSelect,
+}: {
+ concept: ConceptNode;
+ depth: number;
+ onSelect: (concept: ConceptNode) => void;
+}) {
+ const [expanded, setExpanded] = useState(false);
+ const children = concept.children ?? [];
+ const hasChildren = children.length > 0;
+
+ return (
+ <>
+ { (e.currentTarget as HTMLDivElement).style.background = "rgba(74,163,255,0.07)"; }}
+ onMouseLeave={(e) => { (e.currentTarget as HTMLDivElement).style.background = "transparent"; }}
+ >
+ {hasChildren ? (
+ setExpanded((v) => !v)}
+ style={{ background: "transparent", border: "none", color: "#8b949e", cursor: "pointer", padding: 0, display: "flex", alignItems: "center" }}
+ >
+ {expanded ? : }
+
+ ) : (
+
+ )}
+ onSelect(concept)}
+ style={{ flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}
+ >
+ {concept.pref_label || concept.uri}
+
+ {children.length > 0 ? (
+ {children.length}
+ ) : null}
+
+ {expanded && hasChildren
+ ? children.map((child) => (
+
+ ))
+ : null}
+ >
+ );
+}
+
+function SchemePanel({
+ scheme,
+ onSelectConcept,
+}: {
+ scheme: VocabularyScheme;
+ onSelectConcept: (concept: ConceptNode) => void;
+}) {
+ const [expanded, setExpanded] = useState(true);
+ const { data: hierarchy = [], isLoading } = useConceptHierarchy(scheme.uri);
+ const totalConcepts = countConcepts(hierarchy);
+
+ return (
+
+ {/* Scheme header */}
+
setExpanded((v) => !v)}
+ style={schemeHeaderStyle}
+ >
+
+ {expanded ? : }
+ {scheme.label}
+
+
+ {isLoading ? "…" : `${totalConcepts} concept${totalConcepts !== 1 ? "s" : ""}`}
+
+
+
+ {/* Concept tree */}
+ {expanded ? (
+
+ {isLoading ? (
+
Loading concepts…
+ ) : hierarchy.length === 0 ? (
+
+ No concepts found in this scheme.
+
+ ) : (
+ hierarchy.map((concept) => (
+
+ ))
+ )}
+
+ ) : null}
+
+ );
+}
+
+export function OntologySummaryTab({
+ onOpenVocabularyBrowser,
+}: {
+ onOpenVocabularyBrowser?: () => void;
+}) {
+ const { data: schemes = [], isLoading } = useVocabularies();
+ const [selectedConcept, setSelectedConcept] = useState(null);
+
+ return (
+
+ {/* Header */}
+
+
+
+
+
Ontology Summary
+
+ {isLoading
+ ? "Loading schemes…"
+ : `${schemes.length} vocabulary scheme${schemes.length !== 1 ? "s" : ""} loaded`}
+
+
+
+ {onOpenVocabularyBrowser ? (
+
+
+ Open Full Browser
+
+ ) : null}
+
+
+
+ {/* Scheme tree column */}
+
+ {isLoading ? (
+
+ {[90, 75, 60].map((w, i) => (
+
+ ))}
+
+ ) : schemes.length === 0 ? (
+
+
+
No vocabulary schemes loaded
+
+ Import a .ttl or .rdf file via the Vocabulary Browser to see your ontology here.
+
+
+ ) : (
+
+ {schemes.map((scheme) => (
+
+ ))}
+
+ )}
+
+
+ {/* Concept detail panel */}
+ {selectedConcept ? (
+
+
+
+ Concept Detail
+
+
setSelectedConcept(null)} style={{ background: "transparent", border: "none", color: "#8b949e", cursor: "pointer", fontSize: 16 }}>×
+
+
+
+ {selectedConcept.pref_label}
+
+ {selectedConcept.notation ? (
+
Notation: {selectedConcept.notation}
+ ) : null}
+
+ {selectedConcept.uri}
+
+
+ {selectedConcept.description ? (
+
+
Description
+
{selectedConcept.description}
+
+ ) : null}
+
+ {selectedConcept.alt_labels?.length ? (
+
+
Alternative Labels
+
+ {selectedConcept.alt_labels.map((label) => (
+ {label}
+ ))}
+
+
+ ) : null}
+
+ {(selectedConcept.children?.length ?? 0) > 0 ? (
+
+
Narrower Concepts ({selectedConcept.children!.length})
+
+ {selectedConcept.children!.slice(0, 8).map((child) => (
+
setSelectedConcept(child)}
+ style={{ color: "#79c0ff", fontSize: 12, cursor: "pointer", padding: "3px 0" }}
+ >
+ → {child.pref_label}
+
+ ))}
+ {selectedConcept.children!.length > 8 ? (
+
+{selectedConcept.children!.length - 8} more
+ ) : null}
+
+
+ ) : null}
+
+ ) : null}
+
+
+ );
+}
+
+/* ─── styles ─────────────────────────────────────────────────────── */
+
+const shellStyle: React.CSSProperties = {
+ display: "flex",
+ flexDirection: "column",
+ width: "100%",
+ height: "100%",
+ background: "#0d1117",
+ overflow: "hidden",
+};
+
+const headerStyle: React.CSSProperties = {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ padding: "20px 24px 16px",
+ borderBottom: "1px solid rgba(88,166,255,0.1)",
+ flexShrink: 0,
+};
+
+const openBrowserBtnStyle: React.CSSProperties = {
+ display: "inline-flex",
+ alignItems: "center",
+ gap: 6,
+ padding: "6px 12px",
+ borderRadius: 8,
+ border: "1px solid rgba(210,168,255,0.22)",
+ background: "rgba(210,168,255,0.08)",
+ color: "#d2a8ff",
+ fontSize: 12,
+ fontWeight: 600,
+ cursor: "pointer",
+};
+
+const treeColumnStyle: React.CSSProperties = {
+ flex: 1,
+ overflowY: "auto",
+ borderRight: "1px solid rgba(255,255,255,0.06)",
+};
+
+const schemeCardStyle: React.CSSProperties = {
+ borderRadius: 10,
+ border: "1px solid rgba(210,168,255,0.1)",
+ background: "rgba(255,255,255,0.02)",
+ overflow: "hidden",
+};
+
+const schemeHeaderStyle: React.CSSProperties = {
+ width: "100%",
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ padding: "10px 14px",
+ background: "transparent",
+ border: "none",
+ cursor: "pointer",
+ borderBottom: "1px solid rgba(255,255,255,0.05)",
+};
+
+const detailPanelStyle: React.CSSProperties = {
+ width: 300,
+ padding: "20px",
+ overflowY: "auto",
+ borderLeft: "1px solid rgba(255,255,255,0.06)",
+ flexShrink: 0,
+};
+
+const detailSectionStyle: React.CSSProperties = {
+ marginTop: 14,
+ paddingTop: 12,
+ borderTop: "1px solid rgba(255,255,255,0.06)",
+};
+
+const detailLabelStyle: React.CSSProperties = {
+ color: "#8b949e",
+ fontSize: 10,
+ fontWeight: 700,
+ textTransform: "uppercase",
+ letterSpacing: "0.07em",
+ marginBottom: 6,
+};
+
+const altLabelChipStyle: React.CSSProperties = {
+ padding: "3px 8px",
+ borderRadius: 999,
+ background: "rgba(255,255,255,0.05)",
+ border: "1px solid rgba(255,255,255,0.08)",
+ color: "#8fa8c6",
+ fontSize: 11,
+};
+
+const emptyStateStyle: React.CSSProperties = {
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ justifyContent: "center",
+ padding: 40,
+ height: "100%",
+};
diff --git a/semantica-explorer/src/workspaces/ReasoningWorkspace.tsx b/explorer/src/workspaces/ReasoningWorkspace.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/ReasoningWorkspace.tsx
rename to explorer/src/workspaces/ReasoningWorkspace.tsx
diff --git a/semantica-explorer/src/workspaces/SparqlWorkspace/SparqlWorkspace.tsx b/explorer/src/workspaces/SparqlWorkspace/SparqlWorkspace.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/SparqlWorkspace/SparqlWorkspace.tsx
rename to explorer/src/workspaces/SparqlWorkspace/SparqlWorkspace.tsx
diff --git a/semantica-explorer/src/workspaces/VocabularyWorkspace/ConceptTree.tsx b/explorer/src/workspaces/VocabularyWorkspace/ConceptTree.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/VocabularyWorkspace/ConceptTree.tsx
rename to explorer/src/workspaces/VocabularyWorkspace/ConceptTree.tsx
diff --git a/semantica-explorer/src/workspaces/VocabularyWorkspace/ImportDropzone.tsx b/explorer/src/workspaces/VocabularyWorkspace/ImportDropzone.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/VocabularyWorkspace/ImportDropzone.tsx
rename to explorer/src/workspaces/VocabularyWorkspace/ImportDropzone.tsx
diff --git a/semantica-explorer/src/workspaces/VocabularyWorkspace/PropertyPanel.tsx b/explorer/src/workspaces/VocabularyWorkspace/PropertyPanel.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/VocabularyWorkspace/PropertyPanel.tsx
rename to explorer/src/workspaces/VocabularyWorkspace/PropertyPanel.tsx
diff --git a/semantica-explorer/src/workspaces/VocabularyWorkspace/Sidebar.tsx b/explorer/src/workspaces/VocabularyWorkspace/Sidebar.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/VocabularyWorkspace/Sidebar.tsx
rename to explorer/src/workspaces/VocabularyWorkspace/Sidebar.tsx
diff --git a/semantica-explorer/src/workspaces/VocabularyWorkspace/VocabularyWorkspace.tsx b/explorer/src/workspaces/VocabularyWorkspace/VocabularyWorkspace.tsx
similarity index 100%
rename from semantica-explorer/src/workspaces/VocabularyWorkspace/VocabularyWorkspace.tsx
rename to explorer/src/workspaces/VocabularyWorkspace/VocabularyWorkspace.tsx
diff --git a/semantica-explorer/src/workspaces/VocabularyWorkspace/queries.ts b/explorer/src/workspaces/VocabularyWorkspace/queries.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/VocabularyWorkspace/queries.ts
rename to explorer/src/workspaces/VocabularyWorkspace/queries.ts
diff --git a/semantica-explorer/src/workspaces/VocabularyWorkspace/types.ts b/explorer/src/workspaces/VocabularyWorkspace/types.ts
similarity index 100%
rename from semantica-explorer/src/workspaces/VocabularyWorkspace/types.ts
rename to explorer/src/workspaces/VocabularyWorkspace/types.ts
diff --git a/semantica-explorer/tests/graphStore.multi-edge.test.mjs b/explorer/tests/graphStore.multi-edge.test.mjs
similarity index 100%
rename from semantica-explorer/tests/graphStore.multi-edge.test.mjs
rename to explorer/tests/graphStore.multi-edge.test.mjs
diff --git a/semantica-explorer/tsconfig.app.json b/explorer/tsconfig.app.json
similarity index 100%
rename from semantica-explorer/tsconfig.app.json
rename to explorer/tsconfig.app.json
diff --git a/semantica-explorer/tsconfig.json b/explorer/tsconfig.json
similarity index 100%
rename from semantica-explorer/tsconfig.json
rename to explorer/tsconfig.json
diff --git a/semantica-explorer/tsconfig.node.json b/explorer/tsconfig.node.json
similarity index 100%
rename from semantica-explorer/tsconfig.node.json
rename to explorer/tsconfig.node.json
diff --git a/semantica-explorer/vite.config.ts b/explorer/vite.config.ts
similarity index 89%
rename from semantica-explorer/vite.config.ts
rename to explorer/vite.config.ts
index f741d247..2f87b55c 100644
--- a/semantica-explorer/vite.config.ts
+++ b/explorer/vite.config.ts
@@ -1,13 +1,15 @@
import { defineConfig } from 'vite'
-import react, { reactCompilerPreset } from '@vitejs/plugin-react'
-import babel from '@rolldown/plugin-babel'
+import react from '@vitejs/plugin-react'
import path from 'path'
// https://vite.dev/config/
export default defineConfig({
plugins: [
- react(),
- babel({ presets: [reactCompilerPreset()] })
+ react({
+ babel: {
+ plugins: ['babel-plugin-react-compiler'],
+ },
+ }),
],
base: '/',
diff --git a/semantica-explorer/src/workspaces/DecisionWorkspace/DecisionWorkspace.tsx b/semantica-explorer/src/workspaces/DecisionWorkspace/DecisionWorkspace.tsx
deleted file mode 100644
index 07b38f82..00000000
--- a/semantica-explorer/src/workspaces/DecisionWorkspace/DecisionWorkspace.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * src/workspaces/DecisionWorkspace/DecisionWorkspace.tsx
- */
-import { useState, useEffect } from "react";
-
-const THEME_CSS = `
- .glass-panel {
- background: linear-gradient(135deg, rgba(13,17,23,0.75), rgba(22,27,34,0.6));
- backdrop-filter: blur(16px) saturate(1.2);
- -webkit-backdrop-filter: blur(16px) saturate(1.2);
- border: 1px solid rgba(88,166,255,0.2);
- box-shadow: 0 8px 32px rgba(0,0,0,0.5), inset 1px 1px 0 rgba(255,255,255,0.05);
- }
-`;
-
-
-
-function CausalChainNode({ hop, title, desc }: { hop: number, title: string, desc: string }) {
- return (
-
- );
-}
-
-export function DecisionWorkspace() {
- const [decisions, setDecisions] = useState([]);
- const [selectedDecision, setSelectedDecision] = useState(null);
- const [chain, setChain] = useState([]);
- const [loading, setLoading] = useState(false);
-
- useEffect(() => {
- fetch("/api/decisions")
- .then(res => res.json())
- .then(data => {
- setDecisions(data);
- if (data.length > 0) handleSelectDecision(data[0]);
- })
- .catch(console.error);
- }, []);
-
- const handleSelectDecision = async (d: any) => {
- setSelectedDecision(d);
- setLoading(true);
- try {
- const res = await fetch(`/api/decisions/${d.decision_id}/chain`);
- const data = await res.json();
- setChain(data.chain || []);
- } catch (e) {
- console.error(e);
- } finally {
- setLoading(false);
- }
- };
-
- return (
-
-
-
- {/* Left Column: Decisions List */}
-
-
- Decision Tree
-
-
- {decisions.map(d => (
-
handleSelectDecision(d)}
- style={{
- textAlign: "left", padding: "12px 16px", borderRadius: 8, cursor: "pointer",
- background: selectedDecision?.decision_id === d.decision_id ? "rgba(88,166,255,0.15)" : "transparent",
- border: `1px solid ${selectedDecision?.decision_id === d.decision_id ? "#58a6ff" : "rgba(255,255,255,0.1)"}`,
- color: selectedDecision?.decision_id === d.decision_id ? "#ffffff" : "#c9d1d9",
- transition: "all 0.2s"
- }}
- >
- {d.decision_id}
- {d.category || 'Uncategorized'}
-
- ))}
-
-
-
- {/* Right Column: Causal Chains */}
-
-
-
- {selectedDecision ? (
- <>
-
{selectedDecision.decision_id}
-
Outcome: {selectedDecision.outcome}
-
-
-
Causal Chain
- {loading ? (
-
Loading chain...
- ) : chain.length > 0 ? (
- chain.map((c, i) => (
-
- ))
- ) : (
-
No causal chain found.
- )}
-
- >
- ) : (
-
Select a decision to view details
- )}
-
-
- );
-}