@ltm-blueverse/alpha-semantic-hub 0.7.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.
Files changed (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1674 -0
  3. package/explorer/README.md +282 -0
  4. package/explorer/src/App.css +0 -0
  5. package/explorer/src/App.tsx +2035 -0
  6. package/explorer/src/ErrorBoundary.tsx +112 -0
  7. package/explorer/src/ExploreWorkspaceTabs.tsx +29 -0
  8. package/explorer/src/assets/hero.png +0 -0
  9. package/explorer/src/assets/react.svg +1 -0
  10. package/explorer/src/assets/vite.svg +1 -0
  11. package/explorer/src/explorerCapabilities.ts +24 -0
  12. package/explorer/src/index.css +71 -0
  13. package/explorer/src/main.tsx +7 -0
  14. package/explorer/src/store/edgePairKeys.d.ts +2 -0
  15. package/explorer/src/store/edgePairKeys.js +7 -0
  16. package/explorer/src/store/graphStore.ts +183 -0
  17. package/explorer/src/store/registryStore.ts +78 -0
  18. package/explorer/src/types.d.ts +16 -0
  19. package/explorer/src/ui/primitives.css +414 -0
  20. package/explorer/src/ui/primitives.tsx +170 -0
  21. package/explorer/src/workspaces/DecisionWorkspace/DecisionWorkspace.tsx +279 -0
  22. package/explorer/src/workspaces/DiffMergeWorkspace/DiffMergeWorkspace.tsx +121 -0
  23. package/explorer/src/workspaces/EnrichWorkspace/EntityResolutionTab.tsx +454 -0
  24. package/explorer/src/workspaces/EnrichWorkspace/RegistryTab.tsx +285 -0
  25. package/explorer/src/workspaces/GraphWorkspace/GraphCanvas.tsx +2673 -0
  26. package/explorer/src/workspaces/GraphWorkspace/GraphInspectorPanel.tsx +771 -0
  27. package/explorer/src/workspaces/GraphWorkspace/GraphLoadingOverlay.tsx +410 -0
  28. package/explorer/src/workspaces/GraphWorkspace/GraphWorkspace.tsx +3584 -0
  29. package/explorer/src/workspaces/GraphWorkspace/MarkdownContentViewer.tsx +705 -0
  30. package/explorer/src/workspaces/GraphWorkspace/SigmaSceneAdapter.tsx +55 -0
  31. package/explorer/src/workspaces/GraphWorkspace/TimelinePanel.tsx +193 -0
  32. package/explorer/src/workspaces/GraphWorkspace/behaviors/clickSelectionBehavior.ts +29 -0
  33. package/explorer/src/workspaces/GraphWorkspace/behaviors/fitViewBehavior.ts +15 -0
  34. package/explorer/src/workspaces/GraphWorkspace/behaviors/focusCameraBehavior.ts +25 -0
  35. package/explorer/src/workspaces/GraphWorkspace/behaviors/hoverActivationBehavior.ts +15 -0
  36. package/explorer/src/workspaces/GraphWorkspace/behaviors/pathHighlightBehavior.ts +52 -0
  37. package/explorer/src/workspaces/GraphWorkspace/behaviors/searchFocusBehavior.ts +36 -0
  38. package/explorer/src/workspaces/GraphWorkspace/behaviors/types.ts +41 -0
  39. package/explorer/src/workspaces/GraphWorkspace/behaviors/viewModeSwitchBehavior.ts +29 -0
  40. package/explorer/src/workspaces/GraphWorkspace/graphAnalytics.ts +779 -0
  41. package/explorer/src/workspaces/GraphWorkspace/graphColorLegend.ts +36 -0
  42. package/explorer/src/workspaces/GraphWorkspace/graphConfig.ts +102 -0
  43. package/explorer/src/workspaces/GraphWorkspace/graphEntityShape.ts +34 -0
  44. package/explorer/src/workspaces/GraphWorkspace/graphLoading.ts +84 -0
  45. package/explorer/src/workspaces/GraphWorkspace/graphSceneLayers.ts +775 -0
  46. package/explorer/src/workspaces/GraphWorkspace/graphSceneState.ts +2753 -0
  47. package/explorer/src/workspaces/GraphWorkspace/graphStructureLayer.ts +335 -0
  48. package/explorer/src/workspaces/GraphWorkspace/graphTheme.ts +1078 -0
  49. package/explorer/src/workspaces/GraphWorkspace/graphViewCopy.ts +41 -0
  50. package/explorer/src/workspaces/GraphWorkspace/localGraphTransition.ts +9 -0
  51. package/explorer/src/workspaces/GraphWorkspace/markdownEditorState.ts +114 -0
  52. package/explorer/src/workspaces/GraphWorkspace/markdownResourceClient.ts +103 -0
  53. package/explorer/src/workspaces/GraphWorkspace/markdownUrlSafety.ts +29 -0
  54. package/explorer/src/workspaces/GraphWorkspace/nodeMarkdownSync.ts +81 -0
  55. package/explorer/src/workspaces/GraphWorkspace/pluginRegistryPredicates.ts +24 -0
  56. package/explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPlugin.tsx +353 -0
  57. package/explorer/src/workspaces/GraphWorkspace/plugins/explorationEffectsPluginPhaseC.tsx +522 -0
  58. package/explorer/src/workspaces/GraphWorkspace/plugins/index.ts +16 -0
  59. package/explorer/src/workspaces/GraphWorkspace/plugins/legendPlugin.tsx +120 -0
  60. package/explorer/src/workspaces/GraphWorkspace/plugins/neighborhoodPanelPlugin.tsx +231 -0
  61. package/explorer/src/workspaces/GraphWorkspace/plugins/temporalOverlayPlugin.tsx +142 -0
  62. package/explorer/src/workspaces/GraphWorkspace/plugins/types.ts +106 -0
  63. package/explorer/src/workspaces/GraphWorkspace/realtimeGraphAttributes.ts +50 -0
  64. package/explorer/src/workspaces/GraphWorkspace/scene.ts +79 -0
  65. package/explorer/src/workspaces/GraphWorkspace/sigmaNativeRendering.ts +421 -0
  66. package/explorer/src/workspaces/GraphWorkspace/smallGraphLayout.ts +135 -0
  67. package/explorer/src/workspaces/GraphWorkspace/temporalLifecyclePredicates.ts +31 -0
  68. package/explorer/src/workspaces/GraphWorkspace/temporalScrubberBounds.ts +46 -0
  69. package/explorer/src/workspaces/GraphWorkspace/temporalSnapshotGuards.ts +113 -0
  70. package/explorer/src/workspaces/GraphWorkspace/types.ts +395 -0
  71. package/explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts +746 -0
  72. package/explorer/src/workspaces/GraphWorkspace/useMarkdownEditor.ts +177 -0
  73. package/explorer/src/workspaces/ImportExportWorkspace/ImportExportWorkspace.tsx +196 -0
  74. package/explorer/src/workspaces/LineageWorkspace/LineageDiagram.tsx +177 -0
  75. package/explorer/src/workspaces/ManageWorkspace/KGOverviewTab.tsx +291 -0
  76. package/explorer/src/workspaces/ManageWorkspace/OntologySummaryTab.tsx +346 -0
  77. package/explorer/src/workspaces/MemoryWorkspace.tsx +464 -0
  78. package/explorer/src/workspaces/OntologyWorkspace/AlignmentsTab.tsx +437 -0
  79. package/explorer/src/workspaces/OntologyWorkspace/HealthTab.tsx +214 -0
  80. package/explorer/src/workspaces/OntologyWorkspace/OntologyEditor.tsx +770 -0
  81. package/explorer/src/workspaces/OntologyWorkspace/OntologyLoader.tsx +913 -0
  82. package/explorer/src/workspaces/OntologyWorkspace/OntologyManager.tsx +930 -0
  83. package/explorer/src/workspaces/OntologyWorkspace/OntologySearch.tsx +590 -0
  84. package/explorer/src/workspaces/OntologyWorkspace/ProposalReview.tsx +429 -0
  85. package/explorer/src/workspaces/OntologyWorkspace/SKOSVocabularyManager.tsx +696 -0
  86. package/explorer/src/workspaces/OntologyWorkspace/ShaclStudio.tsx +363 -0
  87. package/explorer/src/workspaces/OntologyWorkspace/VersionsTab.tsx +546 -0
  88. package/explorer/src/workspaces/OntologyWorkspace/api.ts +164 -0
  89. package/explorer/src/workspaces/OntologyWorkspace/index.tsx +101 -0
  90. package/explorer/src/workspaces/OntologyWorkspace/ontologyEditorModel.ts +87 -0
  91. package/explorer/src/workspaces/OntologyWorkspace/ontologyUrlState.ts +94 -0
  92. package/explorer/src/workspaces/OntologyWorkspace/types.ts +119 -0
  93. package/explorer/src/workspaces/ReasoningWorkspace.tsx +243 -0
  94. package/explorer/src/workspaces/SparqlWorkspace/SparqlWorkspace.tsx +271 -0
  95. package/explorer/src/workspaces/VocabularyWorkspace/ConceptTree.tsx +97 -0
  96. package/explorer/src/workspaces/VocabularyWorkspace/ImportDropzone.tsx +95 -0
  97. package/explorer/src/workspaces/VocabularyWorkspace/PropertyPanel.tsx +116 -0
  98. package/explorer/src/workspaces/VocabularyWorkspace/Sidebar.tsx +112 -0
  99. package/explorer/src/workspaces/VocabularyWorkspace/VocabularyWorkspace.tsx +70 -0
  100. package/explorer/src/workspaces/VocabularyWorkspace/queries.ts +52 -0
  101. package/explorer/src/workspaces/VocabularyWorkspace/types.ts +24 -0
  102. package/package.json +31 -0
  103. package/plugins/.claude-plugin/README.md +262 -0
  104. package/plugins/.claude-plugin/marketplace.json +20 -0
  105. package/plugins/.claude-plugin/plugin.json +33 -0
  106. package/plugins/.cline-plugin/README.md +32 -0
  107. package/plugins/.cline-plugin/marketplace.json +17 -0
  108. package/plugins/.cline-plugin/plugin.json +35 -0
  109. package/plugins/.codex-plugin/marketplace.json +21 -0
  110. package/plugins/.codex-plugin/plugin.json +35 -0
  111. package/plugins/.continue-plugin/README.md +34 -0
  112. package/plugins/.continue-plugin/marketplace.json +17 -0
  113. package/plugins/.continue-plugin/plugin.json +33 -0
  114. package/plugins/.cursor-plugin/marketplace.json +18 -0
  115. package/plugins/.cursor-plugin/plugin.json +32 -0
  116. package/plugins/.openclaw-plugin/README.md +62 -0
  117. package/plugins/.openclaw-plugin/marketplace.json +18 -0
  118. package/plugins/.openclaw-plugin/plugin.json +46 -0
  119. package/plugins/.pi-plugin/README.md +35 -0
  120. package/plugins/.vscode-plugin/README.md +48 -0
  121. package/plugins/.vscode-plugin/marketplace.json +17 -0
  122. package/plugins/.vscode-plugin/plugin.json +35 -0
  123. package/plugins/.windsurf-plugin/README.md +39 -0
  124. package/plugins/.windsurf-plugin/marketplace.json +17 -0
  125. package/plugins/.windsurf-plugin/plugin.json +35 -0
  126. package/plugins/agents/decision-advisor.md +126 -0
  127. package/plugins/agents/explainability.md +129 -0
  128. package/plugins/agents/kg-assistant.md +73 -0
  129. package/plugins/hooks/hooks.json +12 -0
  130. package/plugins/skills/causal/SKILL.md +74 -0
  131. package/plugins/skills/change/SKILL.md +80 -0
  132. package/plugins/skills/decision/SKILL.md +197 -0
  133. package/plugins/skills/deduplicate/SKILL.md +41 -0
  134. package/plugins/skills/embed/SKILL.md +230 -0
  135. package/plugins/skills/explain/SKILL.md +44 -0
  136. package/plugins/skills/export/SKILL.md +67 -0
  137. package/plugins/skills/extract/SKILL.md +93 -0
  138. package/plugins/skills/ingest/SKILL.md +38 -0
  139. package/plugins/skills/ontology/SKILL.md +89 -0
  140. package/plugins/skills/policy/SKILL.md +66 -0
  141. package/plugins/skills/provenance/SKILL.md +70 -0
  142. package/plugins/skills/query/SKILL.md +84 -0
  143. package/plugins/skills/reason/SKILL.md +201 -0
  144. package/plugins/skills/temporal/SKILL.md +164 -0
  145. package/plugins/skills/validate/SKILL.md +228 -0
  146. package/plugins/skills/visualize/SKILL.md +249 -0
@@ -0,0 +1,410 @@
1
+ import { useEffect, useRef, useState, type CSSProperties } from "react";
2
+ import { AlertTriangle, RefreshCw } from "lucide-react";
3
+
4
+ import { GRAPH_THEME, withAlpha } from "./graphTheme";
5
+ import { GRAPH_LOAD_STAGE_SEQUENCE, createGraphLoadProgress, getGraphLoadStageLabel } from "./graphLoading";
6
+ import type { GraphLoadProgress } from "./types";
7
+
8
+ const LOADING_OVERLAY_CSS = `
9
+ .graph-stage-loader {
10
+ position: absolute;
11
+ inset: 0;
12
+ z-index: 9;
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ pointer-events: none;
17
+ opacity: 1;
18
+ transition: opacity 220ms ease, transform 220ms ease;
19
+ }
20
+ .graph-stage-loader[data-exiting="true"] {
21
+ opacity: 0;
22
+ transform: scale(0.985);
23
+ }
24
+ .graph-stage-loader-card {
25
+ width: min(540px, calc(100% - 48px));
26
+ border-radius: 24px;
27
+ padding: 20px 20px 18px;
28
+ border: 1px solid rgba(255, 107, 129, 0.18);
29
+ background:
30
+ radial-gradient(circle at top right, rgba(242, 182, 109, 0.12), transparent 28%),
31
+ radial-gradient(circle at top left, rgba(255, 107, 129, 0.14), transparent 30%),
32
+ linear-gradient(145deg, rgba(11, 5, 8, 0.94), rgba(12, 25, 43, 0.82));
33
+ box-shadow: 0 26px 90px rgba(0, 0, 0, 0.34), inset 0 1px 0 rgba(255,255,255,0.05);
34
+ backdrop-filter: blur(18px) saturate(1.08);
35
+ -webkit-backdrop-filter: blur(18px) saturate(1.08);
36
+ }
37
+ .graph-stage-loader-card[data-live="true"] {
38
+ width: min(500px, calc(100% - 56px));
39
+ background:
40
+ radial-gradient(circle at top right, rgba(242, 182, 109, 0.08), transparent 26%),
41
+ radial-gradient(circle at top left, rgba(255, 107, 129, 0.12), transparent 28%),
42
+ linear-gradient(145deg, rgba(11, 5, 8, 0.84), rgba(11, 24, 40, 0.72));
43
+ box-shadow: 0 18px 54px rgba(0, 0, 0, 0.26), inset 0 1px 0 rgba(255,255,255,0.04);
44
+ }
45
+ .graph-stage-loader-beacon {
46
+ position: relative;
47
+ width: 12px;
48
+ height: 12px;
49
+ border-radius: 999px;
50
+ background: linear-gradient(135deg, rgba(255, 107, 129, 0.98), rgba(242, 182, 109, 0.94));
51
+ box-shadow: 0 0 18px rgba(255, 107, 129, 0.4);
52
+ }
53
+ .graph-stage-loader-beacon::after {
54
+ content: "";
55
+ position: absolute;
56
+ inset: -7px;
57
+ border-radius: inherit;
58
+ border: 1px solid rgba(255, 107, 129, 0.18);
59
+ animation: graph-loader-beacon 1.9s ease-out infinite;
60
+ }
61
+ .graph-stage-loader-track {
62
+ display: grid;
63
+ grid-template-columns: repeat(6, minmax(0, 1fr));
64
+ gap: 8px;
65
+ }
66
+ .graph-stage-loader-step {
67
+ border-radius: 999px;
68
+ padding: 7px 0;
69
+ text-align: center;
70
+ font-size: 10px;
71
+ font-weight: 700;
72
+ letter-spacing: 0.08em;
73
+ text-transform: uppercase;
74
+ border: 1px solid rgba(255, 107, 129, 0.08);
75
+ color: rgba(143, 168, 198, 0.72);
76
+ background: rgba(255, 255, 255, 0.02);
77
+ }
78
+ .graph-stage-loader-step[data-state="done"] {
79
+ color: rgba(214, 232, 250, 0.92);
80
+ border-color: rgba(255, 107, 129, 0.18);
81
+ background: rgba(89, 155, 220, 0.14);
82
+ }
83
+ .graph-stage-loader-step[data-state="active"] {
84
+ color: #eff7ff;
85
+ border-color: rgba(242, 182, 109, 0.24);
86
+ background: linear-gradient(135deg, rgba(49, 108, 172, 0.28), rgba(242, 182, 109, 0.16));
87
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
88
+ }
89
+ .graph-stage-loader-bar {
90
+ position: relative;
91
+ width: 100%;
92
+ height: 12px;
93
+ overflow: hidden;
94
+ border-radius: 999px;
95
+ border: 1px solid rgba(255, 107, 129, 0.1);
96
+ background: rgba(255, 255, 255, 0.05);
97
+ }
98
+ .graph-stage-loader-bar-fill {
99
+ display: block;
100
+ height: 100%;
101
+ border-radius: inherit;
102
+ background: linear-gradient(90deg, rgba(255, 45, 75, 0.9), rgba(255, 107, 129, 0.96), rgba(242, 182, 109, 0.92));
103
+ box-shadow: 0 0 30px rgba(255, 45, 75, 0.28);
104
+ transition: width 220ms ease;
105
+ }
106
+ .graph-stage-loader-bar-indeterminate::before {
107
+ content: "";
108
+ position: absolute;
109
+ top: 1px;
110
+ bottom: 1px;
111
+ width: 34%;
112
+ border-radius: 999px;
113
+ background: linear-gradient(90deg, rgba(255, 45, 75, 0), rgba(255, 107, 129, 0.94), rgba(242, 182, 109, 0.82), rgba(255, 45, 75, 0));
114
+ box-shadow: 0 0 26px rgba(255, 107, 129, 0.18);
115
+ animation: graph-loader-sweep 1.5s cubic-bezier(0.22, 1, 0.36, 1) infinite;
116
+ }
117
+ @keyframes graph-loader-beacon {
118
+ 0% { transform: scale(0.72); opacity: 0.6; }
119
+ 100% { transform: scale(1.44); opacity: 0; }
120
+ }
121
+ @keyframes graph-loader-sweep {
122
+ 0% { transform: translateX(-120%); }
123
+ 100% { transform: translateX(360%); }
124
+ }
125
+ .graph-stage-loader-card[data-error="true"] {
126
+ pointer-events: auto;
127
+ border-color: rgba(255, 123, 114, 0.32);
128
+ background:
129
+ radial-gradient(circle at top left, rgba(255, 123, 114, 0.12), transparent 32%),
130
+ linear-gradient(145deg, rgba(11, 5, 8, 0.96), rgba(24, 14, 18, 0.86));
131
+ }
132
+ .graph-stage-loader-error-mark {
133
+ width: 38px;
134
+ height: 38px;
135
+ flex: 0 0 auto;
136
+ border-radius: 12px;
137
+ display: grid;
138
+ place-items: center;
139
+ color: #ff9e97;
140
+ background: rgba(255, 123, 114, 0.12);
141
+ border: 1px solid rgba(255, 123, 114, 0.28);
142
+ }
143
+ .graph-stage-loader-error-detail {
144
+ padding: 10px 12px;
145
+ border-radius: 10px;
146
+ background: rgba(0, 0, 0, 0.32);
147
+ border: 1px solid rgba(255, 123, 114, 0.18);
148
+ color: #ffb4ae;
149
+ font-family: "JetBrains Mono", "Fira Code", Consolas, monospace;
150
+ font-size: 12px;
151
+ line-height: 1.55;
152
+ word-break: break-word;
153
+ }
154
+ .graph-stage-loader-retry {
155
+ display: inline-flex;
156
+ align-items: center;
157
+ gap: 7px;
158
+ padding: 9px 16px;
159
+ border-radius: 8px;
160
+ font-size: 13px;
161
+ font-weight: 700;
162
+ cursor: pointer;
163
+ border: 1px solid rgba(255, 107, 129, 0.4);
164
+ background: linear-gradient(135deg, rgba(255, 45, 75, 0.28), rgba(56, 210, 160, 0.16));
165
+ color: #ffeef1;
166
+ transition: 160ms ease;
167
+ }
168
+ .graph-stage-loader-retry:hover {
169
+ border-color: rgba(255, 107, 129, 0.62);
170
+ background: linear-gradient(135deg, rgba(255, 45, 75, 0.4), rgba(56, 210, 160, 0.24));
171
+ transform: translateY(-1px);
172
+ }
173
+ .graph-stage-loader-retry:focus-visible {
174
+ outline: 2px solid #ff6b81;
175
+ outline-offset: 2px;
176
+ }
177
+ `;
178
+
179
+ function formatLayoutSource(source: GraphLoadProgress["layoutSource"]) {
180
+ switch (source) {
181
+ case "provided":
182
+ return "Persisted layout";
183
+ case "carried":
184
+ return "Preserved layout";
185
+ case "runtime":
186
+ return "Runtime layout";
187
+ default:
188
+ return null;
189
+ }
190
+ }
191
+
192
+ function formatLayoutState(state: GraphLoadProgress["layoutState"]) {
193
+ switch (state) {
194
+ case "bootstrapping":
195
+ return "Bootstrapping";
196
+ case "running":
197
+ return "Settling";
198
+ case "interactive":
199
+ return "Interactive";
200
+ case "stabilized":
201
+ return "Stable";
202
+ case "failed":
203
+ return "Fallback";
204
+ default:
205
+ return null;
206
+ }
207
+ }
208
+
209
+ const loadingMetricStyle = {
210
+ display: "inline-flex",
211
+ alignItems: "center",
212
+ gap: 6,
213
+ padding: "7px 10px",
214
+ borderRadius: 999,
215
+ border: "1px solid rgba(255, 107, 129, 0.12)",
216
+ background: "rgba(255, 255, 255, 0.03)",
217
+ color: "#b8cade",
218
+ fontSize: 11,
219
+ fontWeight: 600,
220
+ } satisfies CSSProperties;
221
+
222
+ export function GraphLoadingOverlay({
223
+ progress,
224
+ visible,
225
+ showGraphBehind,
226
+ error = null,
227
+ onRetry,
228
+ }: {
229
+ progress: GraphLoadProgress | null;
230
+ visible: boolean;
231
+ showGraphBehind: boolean;
232
+ error?: string | null;
233
+ onRetry?: () => void;
234
+ }) {
235
+ const [renderVisible, setRenderVisible] = useState(visible);
236
+ const [exiting, setExiting] = useState(false);
237
+ const [displayProgress, setDisplayProgress] = useState<GraphLoadProgress>(
238
+ progress ?? createGraphLoadProgress({
239
+ phase: "bootstrapping",
240
+ message: "Preparing graph session",
241
+ progressKind: "indeterminate",
242
+ }),
243
+ );
244
+ const exitTimerRef = useRef<number | null>(null);
245
+
246
+ useEffect(() => {
247
+ if (progress) {
248
+ setDisplayProgress(progress);
249
+ }
250
+ }, [progress]);
251
+
252
+ useEffect(() => {
253
+ if (visible) {
254
+ if (exitTimerRef.current !== null) {
255
+ window.clearTimeout(exitTimerRef.current);
256
+ exitTimerRef.current = null;
257
+ }
258
+ setRenderVisible(true);
259
+ setExiting(false);
260
+ return;
261
+ }
262
+
263
+ if (!renderVisible) {
264
+ return;
265
+ }
266
+
267
+ setExiting(true);
268
+ exitTimerRef.current = window.setTimeout(() => {
269
+ setRenderVisible(false);
270
+ setExiting(false);
271
+ exitTimerRef.current = null;
272
+ }, 220);
273
+
274
+ return () => {
275
+ if (exitTimerRef.current !== null) {
276
+ window.clearTimeout(exitTimerRef.current);
277
+ exitTimerRef.current = null;
278
+ }
279
+ };
280
+ }, [renderVisible, visible]);
281
+
282
+ if (!renderVisible) {
283
+ return null;
284
+ }
285
+
286
+ if (error) {
287
+ return (
288
+ <div
289
+ className="graph-stage-loader"
290
+ data-exiting={exiting}
291
+ style={{ background: "linear-gradient(180deg, rgba(1,4,9,0.22), rgba(1,4,9,0.5))" }}
292
+ >
293
+ <style>{LOADING_OVERLAY_CSS}</style>
294
+ <div className="graph-stage-loader-card" data-error="true" role="alert">
295
+ <div style={{ display: "flex", alignItems: "flex-start", gap: 14, marginBottom: 14 }}>
296
+ <div className="graph-stage-loader-error-mark" aria-hidden="true">
297
+ <AlertTriangle size={18} strokeWidth={2.2} />
298
+ </div>
299
+ <div style={{ minWidth: 0 }}>
300
+ <div style={{ color: "#ffffff", fontSize: 20, fontWeight: 700, letterSpacing: "-0.03em", marginBottom: 6 }}>
301
+ Could not load the graph
302
+ </div>
303
+ <div style={{ color: "#c99aa3", fontSize: 13, lineHeight: 1.5 }}>
304
+ The Explorer API did not return graph data. Check that the backend is running and reachable, then try again.
305
+ </div>
306
+ </div>
307
+ </div>
308
+
309
+ <div className="graph-stage-loader-error-detail">{error}</div>
310
+
311
+ {onRetry ? (
312
+ <div style={{ display: "flex", gap: 10, marginTop: 16 }}>
313
+ <button type="button" className="graph-stage-loader-retry" onClick={onRetry}>
314
+ <RefreshCw size={14} strokeWidth={2.2} aria-hidden />
315
+ Retry
316
+ </button>
317
+ </div>
318
+ ) : null}
319
+ </div>
320
+ </div>
321
+ );
322
+ }
323
+
324
+ const activeProgress = progress ?? displayProgress;
325
+ const isLiveStage = activeProgress.phase === "stabilizing_layout" || activeProgress.showGraphBehind || showGraphBehind;
326
+ const overlayBackground = isLiveStage
327
+ ? "linear-gradient(180deg, rgba(1,4,9,0.04), rgba(1,4,9,0.18))"
328
+ : "linear-gradient(180deg, rgba(1,4,9,0.22), rgba(1,4,9,0.5))";
329
+ const determinateRatio = activeProgress.progressKind === "determinate" && activeProgress.total
330
+ ? Math.max(0.05, Math.min(activeProgress.loaded ?? 0, activeProgress.total) / Math.max(activeProgress.total, 1))
331
+ : null;
332
+ const layoutSource = formatLayoutSource(activeProgress.layoutSource);
333
+ const layoutState = formatLayoutState(activeProgress.layoutState);
334
+
335
+ return (
336
+ <div
337
+ className="graph-stage-loader"
338
+ data-exiting={exiting}
339
+ style={{ background: overlayBackground }}
340
+ >
341
+ <style>{LOADING_OVERLAY_CSS}</style>
342
+ <div className="graph-stage-loader-card" data-live={isLiveStage}>
343
+ <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 14, marginBottom: 14 }}>
344
+ <div style={{ minWidth: 0 }}>
345
+ <div style={{ color: "#ffffff", fontSize: 20, fontWeight: 700, letterSpacing: "-0.03em", marginBottom: 6 }}>
346
+ {activeProgress.title}
347
+ </div>
348
+ <div style={{ color: "#c99aa3", fontSize: 13, lineHeight: 1.5 }}>
349
+ {activeProgress.message}
350
+ </div>
351
+ </div>
352
+ <div style={{ display: "inline-flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
353
+ <div className="graph-stage-loader-beacon" aria-hidden="true" />
354
+ <div style={{ color: "#d7e9fb", fontSize: 11, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase" }}>
355
+ Stage {activeProgress.stageIndex ?? 1}/{activeProgress.stageCount ?? GRAPH_LOAD_STAGE_SEQUENCE.length}
356
+ </div>
357
+ </div>
358
+ </div>
359
+
360
+ <div className="graph-stage-loader-track" style={{ marginBottom: 14 }}>
361
+ {GRAPH_LOAD_STAGE_SEQUENCE.map((phase, index) => {
362
+ const current = activeProgress.stageIndex ?? 1;
363
+ const state = index + 1 < current ? "done" : index + 1 === current ? "active" : "upcoming";
364
+ return (
365
+ <div key={phase} className="graph-stage-loader-step" data-state={state}>
366
+ {getGraphLoadStageLabel(phase)}
367
+ </div>
368
+ );
369
+ })}
370
+ </div>
371
+
372
+ <div style={{ display: "flex", justifyContent: "space-between", gap: 12, alignItems: "baseline", marginBottom: 8 }}>
373
+ <div style={{ color: "#dce9f6", fontSize: 12, fontWeight: 600 }}>
374
+ {activeProgress.progressKind === "determinate" && activeProgress.total
375
+ ? `${(activeProgress.loaded ?? 0).toLocaleString()} / ${activeProgress.total.toLocaleString()} in current stage`
376
+ : "Working through this stage"}
377
+ </div>
378
+ <div style={{ color: "#90a8c5", fontSize: 11, fontWeight: 700, letterSpacing: "0.06em", textTransform: "uppercase" }}>
379
+ {activeProgress.progressKind === "determinate" && determinateRatio !== null
380
+ ? `${Math.round(determinateRatio * 100)}%`
381
+ : "Live"}
382
+ </div>
383
+ </div>
384
+
385
+ <div className={`graph-stage-loader-bar ${activeProgress.progressKind === "indeterminate" ? "graph-stage-loader-bar-indeterminate" : ""}`}>
386
+ {activeProgress.progressKind === "determinate" && determinateRatio !== null ? (
387
+ <span className="graph-stage-loader-bar-fill" style={{ width: `${Math.round(determinateRatio * 100)}%` }} />
388
+ ) : null}
389
+ </div>
390
+
391
+ <div style={{ display: "flex", gap: 10, flexWrap: "wrap", marginTop: 14 }}>
392
+ <span style={loadingMetricStyle}>
393
+ {activeProgress.nodesLoaded.toLocaleString()}
394
+ {activeProgress.nodesTotal ? ` / ${activeProgress.nodesTotal.toLocaleString()}` : ""} nodes
395
+ </span>
396
+ <span style={loadingMetricStyle}>
397
+ {activeProgress.edgesLoaded.toLocaleString()}
398
+ {activeProgress.edgesTotal ? ` / ${activeProgress.edgesTotal.toLocaleString()}` : ""} relationships
399
+ </span>
400
+ {layoutSource ? (
401
+ <span style={{ ...loadingMetricStyle, color: "#a9ddff", borderColor: withAlpha(GRAPH_THEME.palette.accent.hovered, 0.22) }}>
402
+ {layoutSource}
403
+ {layoutState ? ` · ${layoutState}` : ""}
404
+ </span>
405
+ ) : null}
406
+ </div>
407
+ </div>
408
+ </div>
409
+ );
410
+ }