@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,546 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import {
3
+ Layers,
4
+ GitMerge,
5
+ Clock,
6
+ FileText,
7
+ CheckCircle,
8
+ XCircle,
9
+ AlertCircle,
10
+ Send,
11
+ X,
12
+ ArrowRight,
13
+ Scale,
14
+ } from "lucide-react";
15
+
16
+ interface VersionEntry {
17
+ version_id: string;
18
+ ontology_uri: string;
19
+ state: "draft" | "published";
20
+ author: string;
21
+ date: string;
22
+ diff_summary: Record<string, any>;
23
+ }
24
+
25
+ interface Proposal {
26
+ proposal_id: string;
27
+ draft_id: string;
28
+ ontology_uri: string;
29
+ summary: string;
30
+ author: string;
31
+ reviewer: string | null;
32
+ state: "draft" | "proposed" | "approved" | "published" | "rejected";
33
+ impact_analysis: Record<string, any>;
34
+ shacl_validation: Record<string, any>;
35
+ created_at: string;
36
+ updated_at: string;
37
+ comments: Record<string, any>[];
38
+ }
39
+
40
+ export function VersionsTab() {
41
+ const [ontologyUri, setOntologyUri] = useState<string>("");
42
+ const [versions, setVersions] = useState<VersionEntry[]>([]);
43
+ const [proposals, setProposals] = useState<Proposal[]>([]);
44
+ const [selectedProposal, setSelectedProposal] = useState<Proposal | null>(null);
45
+ const [showProposalModal, setShowProposalModal] = useState(false);
46
+ const [showCompareModal, setShowCompareModal] = useState(false);
47
+ const [comparePair, setComparePair] = useState<{ v1: string; v2: string } | null>(null);
48
+ const [compareResult, setCompareResult] = useState<Record<string, any> | null>(null);
49
+ const [isLoading, setIsLoading] = useState(false);
50
+ const [error, setError] = useState("");
51
+
52
+ const loadVersions = useCallback(async () => {
53
+ if (!ontologyUri) return;
54
+ setError("");
55
+ try {
56
+ const response = await fetch(`/api/ontology/versions/${encodeURIComponent(ontologyUri)}`);
57
+ if (response.ok) {
58
+ const data = await response.json();
59
+ setVersions(data);
60
+ if (response.status === 207) setError(data.message || "Warning: Partial success loading versions.");
61
+ } else {
62
+ setError(`Failed to load versions (${response.status})`);
63
+ }
64
+ } catch (err) {
65
+ setError(err instanceof Error ? err.message : "Failed to load versions.");
66
+ }
67
+ }, [ontologyUri]);
68
+
69
+ const loadProposals = useCallback(async () => {
70
+ setError("");
71
+ try {
72
+ const response = await fetch("/api/ontology/proposals");
73
+ if (response.ok) {
74
+ const data = await response.json();
75
+ setProposals(data);
76
+ if (response.status === 207) setError(data.message || "Warning: Partial success loading proposals.");
77
+ } else {
78
+ setError(`Failed to load proposals (${response.status})`);
79
+ }
80
+ } catch (err) {
81
+ setError(err instanceof Error ? err.message : "Failed to load proposals.");
82
+ }
83
+ }, []);
84
+
85
+ useEffect(() => {
86
+ let ignore = false;
87
+ async function fetchInitial() {
88
+ if (!ignore) setError("");
89
+ try {
90
+ const propRes = await fetch("/api/ontology/proposals");
91
+ if (propRes.ok) {
92
+ const propData = await propRes.json();
93
+ if (!ignore) {
94
+ setProposals(propData);
95
+ if (propRes.status === 207) setError(propData.message || "Warning: Partial success loading proposals.");
96
+ }
97
+ } else if (!ignore) {
98
+ setError(`Failed to load proposals (${propRes.status})`);
99
+ }
100
+ } catch (err) {
101
+ if (!ignore) setError(err instanceof Error ? err.message : "Failed to load proposals.");
102
+ }
103
+
104
+ if (!ontologyUri) return;
105
+ try {
106
+ const verRes = await fetch(`/api/ontology/versions/${encodeURIComponent(ontologyUri)}`);
107
+ if (verRes.ok) {
108
+ const verData = await verRes.json();
109
+ if (!ignore) {
110
+ setVersions(verData);
111
+ if (verRes.status === 207) setError(verData.message || "Warning: Partial success loading versions.");
112
+ }
113
+ } else if (!ignore) {
114
+ setError((prev) => prev || `Failed to load versions (${verRes.status})`);
115
+ }
116
+ } catch (err) {
117
+ if (!ignore) setError((prev) => prev || (err instanceof Error ? err.message : "Failed to load versions."));
118
+ }
119
+ }
120
+ void fetchInitial();
121
+ return () => { ignore = true; };
122
+ }, [ontologyUri]);
123
+
124
+ const approveProposal = useCallback(async (proposalId: string) => {
125
+ setError("");
126
+ try {
127
+ const response = await fetch(`/api/ontology/proposals/${proposalId}/approve`, {
128
+ method: "POST",
129
+ });
130
+ if (response.ok) {
131
+ if (response.status === 207) {
132
+ const data = await response.json().catch(() => ({}));
133
+ setError(data.message || "Warning: Partial success approving proposal.");
134
+ } else {
135
+ alert("Proposal approved");
136
+ }
137
+ loadProposals();
138
+ } else {
139
+ setError(`Failed to approve proposal (${response.status})`);
140
+ }
141
+ } catch (err) {
142
+ setError(err instanceof Error ? err.message : "Failed to approve proposal.");
143
+ }
144
+ }, [loadProposals]);
145
+
146
+ const rejectProposal = useCallback(async (proposalId: string) => {
147
+ setError("");
148
+ try {
149
+ const response = await fetch(`/api/ontology/proposals/${proposalId}/reject`, {
150
+ method: "POST",
151
+ });
152
+ if (response.ok) {
153
+ if (response.status === 207) {
154
+ const data = await response.json().catch(() => ({}));
155
+ setError(data.message || "Warning: Partial success rejecting proposal.");
156
+ } else {
157
+ alert("Proposal rejected");
158
+ }
159
+ loadProposals();
160
+ } else {
161
+ setError(`Failed to reject proposal (${response.status})`);
162
+ }
163
+ } catch (err) {
164
+ setError(err instanceof Error ? err.message : "Failed to reject proposal.");
165
+ }
166
+ }, [loadProposals]);
167
+
168
+ const publishProposal = useCallback(async (proposalId: string) => {
169
+ setError("");
170
+ try {
171
+ const response = await fetch(`/api/ontology/proposals/${proposalId}/publish`, {
172
+ method: "POST",
173
+ });
174
+ if (response.ok) {
175
+ if (response.status === 207) {
176
+ const data = await response.json().catch(() => ({}));
177
+ setError(data.message || "Warning: Partial success publishing proposal.");
178
+ } else {
179
+ alert("Proposal published");
180
+ }
181
+ loadProposals();
182
+ loadVersions();
183
+ } else {
184
+ setError(`Failed to publish proposal (${response.status})`);
185
+ }
186
+ } catch (err) {
187
+ setError(err instanceof Error ? err.message : "Failed to publish proposal.");
188
+ }
189
+ }, [loadProposals, loadVersions]);
190
+
191
+ const runVersionComparison = useCallback(async () => {
192
+ if (!comparePair || !ontologyUri) return;
193
+ setIsLoading(true);
194
+ setError("");
195
+ try {
196
+ const response = await fetch(`/api/ontology/versions/${encodeURIComponent(ontologyUri)}/compare`, {
197
+ method: "POST",
198
+ headers: { "Content-Type": "application/json" },
199
+ body: JSON.stringify({
200
+ version1: comparePair.v1,
201
+ version2: comparePair.v2,
202
+ }),
203
+ });
204
+ if (response.ok) {
205
+ const data = await response.json();
206
+ if (response.status === 207) setError(data.message || "Warning: Partial success comparing versions.");
207
+ setCompareResult(data);
208
+ } else {
209
+ setError(`Failed to compare versions (${response.status})`);
210
+ }
211
+ } catch (err) {
212
+ setError(err instanceof Error ? err.message : "Failed to compare versions.");
213
+ } finally {
214
+ setIsLoading(false);
215
+ }
216
+ }, [comparePair, ontologyUri]);
217
+
218
+ const getStateIcon = (state: string) => {
219
+ switch (state) {
220
+ case "published":
221
+ return <CheckCircle size={16} color="#4cc38a" />;
222
+ case "approved":
223
+ return <CheckCircle size={16} color="#ff2d4b" />;
224
+ case "rejected":
225
+ return <XCircle size={16} color="#ff6b6b" />;
226
+ case "proposed":
227
+ return <AlertCircle size={16} color="#ff7a45" />;
228
+ default:
229
+ return <Clock size={16} color="#c99aa3" />;
230
+ }
231
+ };
232
+
233
+ const containerStyle: React.CSSProperties = {
234
+ display: "flex",
235
+ flexDirection: "column",
236
+ height: "100%",
237
+ background: "#0b0508",
238
+ padding: "20px",
239
+ overflow: "auto",
240
+ };
241
+
242
+ const headerStyle: React.CSSProperties = {
243
+ display: "flex",
244
+ justifyContent: "space-between",
245
+ alignItems: "center",
246
+ marginBottom: "20px",
247
+ };
248
+
249
+ const titleStyle: React.CSSProperties = {
250
+ margin: 0,
251
+ color: "#fff0f2",
252
+ fontSize: "20px",
253
+ fontWeight: "700",
254
+ };
255
+
256
+ const sectionStyle: React.CSSProperties = {
257
+ marginBottom: "24px",
258
+ };
259
+
260
+ const sectionTitleStyle: React.CSSProperties = {
261
+ margin: "0 0 12px",
262
+ color: "#fff0f2",
263
+ fontSize: "14px",
264
+ fontWeight: "600",
265
+ display: "flex",
266
+ alignItems: "center",
267
+ gap: "8px",
268
+ };
269
+
270
+ const listStyle: React.CSSProperties = {
271
+ display: "flex",
272
+ flexDirection: "column",
273
+ gap: "8px",
274
+ };
275
+
276
+ const itemStyle: React.CSSProperties = {
277
+ display: "flex",
278
+ alignItems: "center",
279
+ gap: "12px",
280
+ padding: "12px 16px",
281
+ borderRadius: "8px",
282
+ background: "rgba(12, 6, 9, 0.8)",
283
+ border: "1px solid rgba(255, 107, 129, 0.12)",
284
+ transition: "160ms ease",
285
+ };
286
+
287
+ const modalOverlayStyle: React.CSSProperties = {
288
+ position: "fixed",
289
+ inset: 0,
290
+ background: "rgba(0, 0, 0, 0.7)",
291
+ display: "flex",
292
+ alignItems: "center",
293
+ justifyContent: "center",
294
+ zIndex: 1000,
295
+ };
296
+
297
+ const modalStyle: React.CSSProperties = {
298
+ background: "rgba(12, 6, 9, 0.95)",
299
+ border: "1px solid rgba(255, 107, 129, 0.2)",
300
+ borderRadius: "12px",
301
+ padding: "24px",
302
+ minWidth: "480px",
303
+ maxWidth: "640px",
304
+ maxHeight: "80vh",
305
+ overflow: "auto",
306
+ backdropFilter: "blur(18px)",
307
+ };
308
+
309
+ const buttonStyle: React.CSSProperties = {
310
+ display: "inline-flex",
311
+ alignItems: "center",
312
+ gap: "6px",
313
+ padding: "8px 14px",
314
+ borderRadius: "6px",
315
+ border: "1px solid rgba(255, 107, 129, 0.2)",
316
+ background: "rgba(255, 45, 75, 0.1)",
317
+ color: "#fff0f2",
318
+ fontSize: "12px",
319
+ fontWeight: "600",
320
+ cursor: "pointer",
321
+ transition: "160ms ease",
322
+ };
323
+
324
+ const inputStyle: React.CSSProperties = {
325
+ width: "100%",
326
+ padding: "10px 12px",
327
+ borderRadius: "6px",
328
+ border: "1px solid rgba(255, 107, 129, 0.2)",
329
+ background: "rgba(6, 3, 5, 0.8)",
330
+ color: "#fff0f2",
331
+ fontSize: "13px",
332
+ marginBottom: "12px",
333
+ };
334
+
335
+ const errorStyle: React.CSSProperties = { padding: "12px", borderRadius: "14px", color: "#ffb4c2", background: "rgba(255,157,175,0.1)", border: "1px solid rgba(255,157,175,0.18)", marginBottom: "16px" };
336
+
337
+ return (
338
+ <div style={containerStyle}>
339
+ <div style={headerStyle}>
340
+ <h1 style={titleStyle}>Versions & Change Proposals</h1>
341
+ <input
342
+ type="text"
343
+ placeholder="Ontology URI"
344
+ value={ontologyUri}
345
+ onChange={(e) => setOntologyUri(e.target.value)}
346
+ style={{ ...inputStyle, width: "300px", marginBottom: 0 }}
347
+ />
348
+ </div>
349
+
350
+ {error ? <div style={errorStyle}>{error}</div> : null}
351
+
352
+ <div style={sectionStyle}>
353
+ <h2 style={sectionTitleStyle}>
354
+ <Layers size={16} />
355
+ Version History
356
+ </h2>
357
+ <div style={listStyle}>
358
+ {versions.length === 0 ? (
359
+ <div style={{ color: "#c99aa3", fontSize: "13px" }}>No versions found</div>
360
+ ) : (
361
+ versions.map((version) => (
362
+ <div key={version.version_id} style={itemStyle}>
363
+ {getStateIcon(version.state)}
364
+ <div style={{ flex: 1 }}>
365
+ <div style={{ color: "#fff0f2", fontSize: "13px", fontWeight: "600" }}>
366
+ {version.version_id}
367
+ </div>
368
+ <div style={{ color: "#c99aa3", fontSize: "11px" }}>
369
+ {version.author} • {new Date(version.date).toLocaleDateString()}
370
+ </div>
371
+ </div>
372
+ <button
373
+ style={buttonStyle}
374
+ onClick={() => {
375
+ setComparePair({ v1: version.version_id, v2: versions[0]?.version_id || "" });
376
+ setShowCompareModal(true);
377
+ }}
378
+ >
379
+ <ArrowRight size={12} />
380
+ Compare
381
+ </button>
382
+ </div>
383
+ ))
384
+ )}
385
+ </div>
386
+ </div>
387
+
388
+ <div style={sectionStyle}>
389
+ <h2 style={sectionTitleStyle}>
390
+ <GitMerge size={16} />
391
+ Change Proposals
392
+ </h2>
393
+ <div style={listStyle}>
394
+ {proposals.length === 0 ? (
395
+ <div style={{ color: "#c99aa3", fontSize: "13px" }}>No proposals found</div>
396
+ ) : (
397
+ proposals.map((proposal) => (
398
+ <div key={proposal.proposal_id} style={itemStyle}>
399
+ {getStateIcon(proposal.state)}
400
+ <div style={{ flex: 1 }}>
401
+ <div style={{ color: "#fff0f2", fontSize: "13px", fontWeight: "600" }}>
402
+ {proposal.summary}
403
+ </div>
404
+ <div style={{ color: "#c99aa3", fontSize: "11px" }}>
405
+ {proposal.author} • {new Date(proposal.created_at).toLocaleDateString()}
406
+ </div>
407
+ </div>
408
+ {proposal.state === "proposed" && (
409
+ <div style={{ display: "flex", gap: "6px" }}>
410
+ <button style={buttonStyle} onClick={() => approveProposal(proposal.proposal_id)}>
411
+ <CheckCircle size={12} />
412
+ Approve
413
+ </button>
414
+ <button style={buttonStyle} onClick={() => rejectProposal(proposal.proposal_id)}>
415
+ <XCircle size={12} />
416
+ Reject
417
+ </button>
418
+ </div>
419
+ )}
420
+ {proposal.state === "approved" && (
421
+ <button style={buttonStyle} onClick={() => publishProposal(proposal.proposal_id)}>
422
+ <Send size={12} />
423
+ Publish
424
+ </button>
425
+ )}
426
+ <button
427
+ style={buttonStyle}
428
+ onClick={() => {
429
+ setSelectedProposal(proposal);
430
+ setShowProposalModal(true);
431
+ }}
432
+ >
433
+ <FileText size={12} />
434
+ Details
435
+ </button>
436
+ </div>
437
+ ))
438
+ )}
439
+ </div>
440
+ </div>
441
+
442
+ {showProposalModal && selectedProposal && (
443
+ <div style={modalOverlayStyle} onClick={() => setShowProposalModal(false)}>
444
+ <div style={modalStyle} onClick={(e) => e.stopPropagation()}>
445
+ <div style={{ display: "flex", justifyContent: "space-between", marginBottom: "16px" }}>
446
+ <h3 style={{ margin: 0, color: "#fff0f2", fontSize: "16px" }}>Proposal Details</h3>
447
+ <button onClick={() => setShowProposalModal(false)} style={{ background: "none", border: "none", color: "#c99aa3", cursor: "pointer" }}>
448
+ <X size={18} />
449
+ </button>
450
+ </div>
451
+ <div style={{ marginBottom: "12px" }}>
452
+ <label style={{ display: "block", color: "#c99aa3", fontSize: "12px", marginBottom: "4px" }}>
453
+ Summary
454
+ </label>
455
+ <div style={{ color: "#fff0f2", fontSize: "13px" }}>{selectedProposal.summary}</div>
456
+ </div>
457
+ <div style={{ marginBottom: "12px" }}>
458
+ <label style={{ display: "block", color: "#c99aa3", fontSize: "12px", marginBottom: "4px" }}>
459
+ State
460
+ </label>
461
+ <div style={{ display: "flex", alignItems: "center", gap: "6px", color: "#fff0f2", fontSize: "13px" }}>
462
+ {getStateIcon(selectedProposal.state)}
463
+ {selectedProposal.state}
464
+ </div>
465
+ </div>
466
+ <div style={{ marginBottom: "12px" }}>
467
+ <label style={{ display: "block", color: "#c99aa3", fontSize: "12px", marginBottom: "4px" }}>
468
+ Impact Analysis
469
+ </label>
470
+ <pre style={{ background: "rgba(6, 3, 5, 0.8)", padding: "12px", borderRadius: "6px", color: "#fff0f2", fontSize: "12px", overflow: "auto" }}>
471
+ {JSON.stringify(selectedProposal.impact_analysis, null, 2)}
472
+ </pre>
473
+ </div>
474
+ <div style={{ marginBottom: "12px" }}>
475
+ <label style={{ display: "block", color: "#c99aa3", fontSize: "12px", marginBottom: "4px" }}>
476
+ SHACL Validation
477
+ </label>
478
+ <pre style={{ background: "rgba(6, 3, 5, 0.8)", padding: "12px", borderRadius: "6px", color: "#fff0f2", fontSize: "12px", overflow: "auto" }}>
479
+ {JSON.stringify(selectedProposal.shacl_validation, null, 2)}
480
+ </pre>
481
+ </div>
482
+ <div>
483
+ <label style={{ display: "block", color: "#c99aa3", fontSize: "12px", marginBottom: "4px" }}>
484
+ Comments ({selectedProposal.comments.length})
485
+ </label>
486
+ <div style={{ maxHeight: "120px", overflow: "auto" }}>
487
+ {selectedProposal.comments.map((comment) => (
488
+ <div key={comment.id} style={{ padding: "8px", background: "rgba(6, 3, 5, 0.6)", borderRadius: "4px", marginBottom: "6px" }}>
489
+ <div style={{ color: "#fff0f2", fontSize: "12px", fontWeight: "600" }}>{comment.author}</div>
490
+ <div style={{ color: "#c99aa3", fontSize: "11px" }}>{comment.text}</div>
491
+ </div>
492
+ ))}
493
+ </div>
494
+ </div>
495
+ </div>
496
+ </div>
497
+ )}
498
+
499
+ {showCompareModal && comparePair && (
500
+ <div style={modalOverlayStyle} onClick={() => setShowCompareModal(false)}>
501
+ <div style={modalStyle} onClick={(e) => e.stopPropagation()}>
502
+ <div style={{ display: "flex", justifyContent: "space-between", marginBottom: "16px" }}>
503
+ <h3 style={{ margin: 0, color: "#fff0f2", fontSize: "16px" }}>Compare Versions</h3>
504
+ <button onClick={() => setShowCompareModal(false)} style={{ background: "none", border: "none", color: "#c99aa3", cursor: "pointer" }}>
505
+ <X size={18} />
506
+ </button>
507
+ </div>
508
+ <div style={{ display: "flex", gap: "12px", marginBottom: "16px" }}>
509
+ <div style={{ flex: 1 }}>
510
+ <label style={{ display: "block", color: "#c99aa3", fontSize: "12px", marginBottom: "4px" }}>
511
+ Version 1
512
+ </label>
513
+ <input
514
+ type="text"
515
+ value={comparePair.v1}
516
+ onChange={(e) => setComparePair({ ...comparePair, v1: e.target.value })}
517
+ style={inputStyle}
518
+ />
519
+ </div>
520
+ <div style={{ flex: 1 }}>
521
+ <label style={{ display: "block", color: "#c99aa3", fontSize: "12px", marginBottom: "4px" }}>
522
+ Version 2
523
+ </label>
524
+ <input
525
+ type="text"
526
+ value={comparePair.v2}
527
+ onChange={(e) => setComparePair({ ...comparePair, v2: e.target.value })}
528
+ style={inputStyle}
529
+ />
530
+ </div>
531
+ </div>
532
+ <button style={buttonStyle} onClick={runVersionComparison} disabled={isLoading}>
533
+ <Scale size={12} />
534
+ {isLoading ? "Comparing..." : "Compare"}
535
+ </button>
536
+ {compareResult && (
537
+ <pre style={{ marginTop: "16px", background: "rgba(6, 3, 5, 0.8)", padding: "12px", borderRadius: "6px", color: "#fff0f2", fontSize: "12px", overflow: "auto" }}>
538
+ {JSON.stringify(compareResult, null, 2)}
539
+ </pre>
540
+ )}
541
+ </div>
542
+ </div>
543
+ )}
544
+ </div>
545
+ );
546
+ }