@memberjunction/ng-dashboards 6.2.0-edge.7 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +25 -4
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +11 -22
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +2 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +11 -3
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +16 -16
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/visualize/semantic-graph/semantic-graph-explorer.component.d.ts +113 -0
- package/dist/KnowledgeHub/components/visualize/semantic-graph/semantic-graph-explorer.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/visualize/semantic-graph/semantic-graph-explorer.component.js +1184 -0
- package/dist/KnowledgeHub/components/visualize/semantic-graph/semantic-graph-explorer.component.js.map +1 -0
- package/dist/KnowledgeHub/components/visualize/visualize-agent-context.d.ts +1 -1
- package/dist/KnowledgeHub/components/visualize/visualize-agent-context.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/visualize/visualize-agent-context.js +1 -1
- package/dist/KnowledgeHub/components/visualize/visualize-agent-context.js.map +1 -1
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts +1 -1
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js +21 -10
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.js +4 -2
- package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +46 -44
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +10 -0
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +74 -73
package/dist/KnowledgeHub/components/visualize/semantic-graph/semantic-graph-explorer.component.js
ADDED
|
@@ -0,0 +1,1184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Knowledge Hub Semantic Graph & Canon Explorer (Visualize > Graphs & Canon mode)
|
|
3
|
+
*
|
|
4
|
+
* Interactive 2-pane workspace built on `@memberjunction/ng-graph-view` (`<mj-graph-view>`)
|
|
5
|
+
* for exploring `MJ: Graphs` (grouped by `MJ: Graph Types` and `IsCanon`), ranked
|
|
6
|
+
* `MJ: Graph Concept Types` (`Policy #10`, `Metric #20`, `Process #30`, `Role #40`,
|
|
7
|
+
* `Domain #50`, `Term #60`), `MJ: Graph Concepts`, grounded MJ primitives, source
|
|
8
|
+
* provenance chunks (`SourcedFrom`), and cross-source authority conflicts (`Contradicts`).
|
|
9
|
+
*/
|
|
10
|
+
import { Component, Input, Output, EventEmitter, ChangeDetectorRef, inject, } from '@angular/core';
|
|
11
|
+
import { RunView } from '@memberjunction/core';
|
|
12
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
13
|
+
import { NormalizeUUID, UUIDsEqual } from '@memberjunction/global';
|
|
14
|
+
import { DEFAULT_GRAPH_CATEGORIES, } from '@memberjunction/ng-graph-view';
|
|
15
|
+
import * as i0 from "@angular/core";
|
|
16
|
+
import * as i1 from "@angular/forms";
|
|
17
|
+
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
18
|
+
import * as i3 from "@memberjunction/ng-graph-view";
|
|
19
|
+
const _forTrack0 = ($index, $item) => $item.ID;
|
|
20
|
+
const _forTrack1 = ($index, $item) => $item.HigherAuthoritySummary;
|
|
21
|
+
const _forTrack2 = ($index, $item) => $item.TargetRecordID + $item.EdgeLabel;
|
|
22
|
+
const _forTrack3 = ($index, $item) => $item.ChunkID;
|
|
23
|
+
function SemanticGraphExplorerComponent_For_12_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
24
|
+
i0.ɵɵtext(0, " \u2605 ");
|
|
25
|
+
} }
|
|
26
|
+
function SemanticGraphExplorerComponent_For_12_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
27
|
+
i0.ɵɵelementStart(0, "span", 29);
|
|
28
|
+
i0.ɵɵelement(1, "i", 30);
|
|
29
|
+
i0.ɵɵtext(2);
|
|
30
|
+
i0.ɵɵelementEnd();
|
|
31
|
+
} if (rf & 2) {
|
|
32
|
+
const g_r3 = i0.ɵɵnextContext().$implicit;
|
|
33
|
+
i0.ɵɵadvance(2);
|
|
34
|
+
i0.ɵɵtextInterpolate2(" ", g_r3.ConflictCount, " ", g_r3.ConflictCount === 1 ? "conflict" : "conflicts", " ");
|
|
35
|
+
} }
|
|
36
|
+
function SemanticGraphExplorerComponent_For_12_Template(rf, ctx) { if (rf & 1) {
|
|
37
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
38
|
+
i0.ɵɵelementStart(0, "button", 23);
|
|
39
|
+
i0.ɵɵlistener("click", function SemanticGraphExplorerComponent_For_12_Template_button_click_0_listener() { const g_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.SelectGraph(g_r3.ID)); });
|
|
40
|
+
i0.ɵɵelementStart(1, "div", 24)(2, "span", 25);
|
|
41
|
+
i0.ɵɵelement(3, "i", 26);
|
|
42
|
+
i0.ɵɵtext(4);
|
|
43
|
+
i0.ɵɵelementEnd();
|
|
44
|
+
i0.ɵɵelementStart(5, "span", 27);
|
|
45
|
+
i0.ɵɵconditionalCreate(6, SemanticGraphExplorerComponent_For_12_Conditional_6_Template, 1, 0);
|
|
46
|
+
i0.ɵɵtext(7);
|
|
47
|
+
i0.ɵɵelementEnd()();
|
|
48
|
+
i0.ɵɵelementStart(8, "div", 28)(9, "span");
|
|
49
|
+
i0.ɵɵtext(10);
|
|
50
|
+
i0.ɵɵelementEnd();
|
|
51
|
+
i0.ɵɵconditionalCreate(11, SemanticGraphExplorerComponent_For_12_Conditional_11_Template, 3, 2, "span", 29);
|
|
52
|
+
i0.ɵɵelementEnd()();
|
|
53
|
+
} if (rf & 2) {
|
|
54
|
+
const g_r3 = ctx.$implicit;
|
|
55
|
+
const ctx_r3 = i0.ɵɵnextContext();
|
|
56
|
+
i0.ɵɵclassProp("selected", (ctx_r3.SelectedGraph == null ? null : ctx_r3.SelectedGraph.ID) === g_r3.ID);
|
|
57
|
+
i0.ɵɵadvance(3);
|
|
58
|
+
i0.ɵɵclassMap(g_r3.IconClass);
|
|
59
|
+
i0.ɵɵadvance();
|
|
60
|
+
i0.ɵɵtextInterpolate1(" ", g_r3.Name, " ");
|
|
61
|
+
i0.ɵɵadvance();
|
|
62
|
+
i0.ɵɵclassProp("is-canon", g_r3.IsCanon);
|
|
63
|
+
i0.ɵɵadvance();
|
|
64
|
+
i0.ɵɵconditional(g_r3.IsCanon ? 6 : -1);
|
|
65
|
+
i0.ɵɵadvance();
|
|
66
|
+
i0.ɵɵtextInterpolate2(" ", g_r3.GraphTypeName, " \u00B7 #", g_r3.GraphTypeRank, " ");
|
|
67
|
+
i0.ɵɵadvance(3);
|
|
68
|
+
i0.ɵɵtextInterpolate1("", g_r3.ConceptCount, " concepts");
|
|
69
|
+
i0.ɵɵadvance();
|
|
70
|
+
i0.ɵɵconditional(g_r3.ConflictCount > 0 ? 11 : -1);
|
|
71
|
+
} }
|
|
72
|
+
function SemanticGraphExplorerComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
73
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
74
|
+
i0.ɵɵelementStart(0, "button", 31);
|
|
75
|
+
i0.ɵɵlistener("click", function SemanticGraphExplorerComponent_Conditional_17_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.ToggleConceptTypeFilter(null)); });
|
|
76
|
+
i0.ɵɵtext(1, " All ");
|
|
77
|
+
i0.ɵɵelementEnd();
|
|
78
|
+
} }
|
|
79
|
+
function SemanticGraphExplorerComponent_For_20_Template(rf, ctx) { if (rf & 1) {
|
|
80
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
81
|
+
i0.ɵɵelementStart(0, "button", 32);
|
|
82
|
+
i0.ɵɵlistener("click", function SemanticGraphExplorerComponent_For_20_Template_button_click_0_listener() { const ct_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.ToggleConceptTypeFilter(ct_r7.Name)); });
|
|
83
|
+
i0.ɵɵelementStart(1, "span", 33);
|
|
84
|
+
i0.ɵɵelement(2, "span", 34)(3, "i", 35);
|
|
85
|
+
i0.ɵɵelementStart(4, "span", 36);
|
|
86
|
+
i0.ɵɵtext(5);
|
|
87
|
+
i0.ɵɵelementEnd()();
|
|
88
|
+
i0.ɵɵelementStart(6, "span", 37);
|
|
89
|
+
i0.ɵɵtext(7);
|
|
90
|
+
i0.ɵɵelementStart(8, "strong");
|
|
91
|
+
i0.ɵɵtext(9);
|
|
92
|
+
i0.ɵɵelementEnd()()();
|
|
93
|
+
} if (rf & 2) {
|
|
94
|
+
const ct_r7 = ctx.$implicit;
|
|
95
|
+
const ctx_r3 = i0.ɵɵnextContext();
|
|
96
|
+
i0.ɵɵclassProp("active", (ctx_r3.ActiveConceptTypeFilter == null ? null : ctx_r3.ActiveConceptTypeFilter.toLowerCase()) === ct_r7.Name.toLowerCase())("dimmed", ctx_r3.ActiveConceptTypeFilter && ctx_r3.ActiveConceptTypeFilter.toLowerCase() !== ct_r7.Name.toLowerCase());
|
|
97
|
+
i0.ɵɵadvance(2);
|
|
98
|
+
i0.ɵɵstyleProp("background", ct_r7.Color);
|
|
99
|
+
i0.ɵɵadvance();
|
|
100
|
+
i0.ɵɵclassMap(ct_r7.IconClass);
|
|
101
|
+
i0.ɵɵadvance(2);
|
|
102
|
+
i0.ɵɵtextInterpolate(ct_r7.Name);
|
|
103
|
+
i0.ɵɵadvance(2);
|
|
104
|
+
i0.ɵɵtextInterpolate1(" Rank #", ct_r7.Rank, " \u00B7 ");
|
|
105
|
+
i0.ɵɵadvance(2);
|
|
106
|
+
i0.ɵɵtextInterpolate(ct_r7.Count);
|
|
107
|
+
} }
|
|
108
|
+
function SemanticGraphExplorerComponent_Conditional_37_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
109
|
+
i0.ɵɵelementStart(0, "div", 39);
|
|
110
|
+
i0.ɵɵelement(1, "i", 40);
|
|
111
|
+
i0.ɵɵelementStart(2, "span");
|
|
112
|
+
i0.ɵɵtext(3);
|
|
113
|
+
i0.ɵɵelementEnd()();
|
|
114
|
+
} if (rf & 2) {
|
|
115
|
+
const srcName_r8 = ctx.$implicit;
|
|
116
|
+
i0.ɵɵadvance(3);
|
|
117
|
+
i0.ɵɵtextInterpolate(srcName_r8);
|
|
118
|
+
} }
|
|
119
|
+
function SemanticGraphExplorerComponent_Conditional_37_Template(rf, ctx) { if (rf & 1) {
|
|
120
|
+
i0.ɵɵelementStart(0, "section", 4)(1, "span", 6);
|
|
121
|
+
i0.ɵɵtext(2, "Connected Content Sources");
|
|
122
|
+
i0.ɵɵelementEnd();
|
|
123
|
+
i0.ɵɵelementStart(3, "div", 38);
|
|
124
|
+
i0.ɵɵrepeaterCreate(4, SemanticGraphExplorerComponent_Conditional_37_For_5_Template, 4, 1, "div", 39, i0.ɵɵrepeaterTrackByIdentity);
|
|
125
|
+
i0.ɵɵelementEnd()();
|
|
126
|
+
} if (rf & 2) {
|
|
127
|
+
const ctx_r3 = i0.ɵɵnextContext();
|
|
128
|
+
i0.ɵɵadvance(4);
|
|
129
|
+
i0.ɵɵrepeater(ctx_r3.SelectedGraph.SourceNames);
|
|
130
|
+
} }
|
|
131
|
+
function SemanticGraphExplorerComponent_Conditional_39_Template(rf, ctx) { if (rf & 1) {
|
|
132
|
+
i0.ɵɵelementStart(0, "div", 19);
|
|
133
|
+
i0.ɵɵelement(1, "i", 30);
|
|
134
|
+
i0.ɵɵelementStart(2, "span");
|
|
135
|
+
i0.ɵɵtext(3);
|
|
136
|
+
i0.ɵɵelementEnd()();
|
|
137
|
+
} if (rf & 2) {
|
|
138
|
+
const ctx_r3 = i0.ɵɵnextContext();
|
|
139
|
+
i0.ɵɵadvance(3);
|
|
140
|
+
i0.ɵɵtextInterpolate(ctx_r3.LoadError || ctx_r3.ActionError);
|
|
141
|
+
} }
|
|
142
|
+
function SemanticGraphExplorerComponent_Conditional_40_Template(rf, ctx) { if (rf & 1) {
|
|
143
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
144
|
+
i0.ɵɵelementStart(0, "div", 20)(1, "span");
|
|
145
|
+
i0.ɵɵtext(2, "No concepts or edges in this graph yet.");
|
|
146
|
+
i0.ɵɵelementEnd();
|
|
147
|
+
i0.ɵɵelementStart(3, "button", 41);
|
|
148
|
+
i0.ɵɵlistener("click", function SemanticGraphExplorerComponent_Conditional_40_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r9); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.LoadSampleGraphPreview()); });
|
|
149
|
+
i0.ɵɵtext(4, " Load Example Canon Graph ");
|
|
150
|
+
i0.ɵɵelementEnd()();
|
|
151
|
+
} }
|
|
152
|
+
function SemanticGraphExplorerComponent_Conditional_41_Template(rf, ctx) { if (rf & 1) {
|
|
153
|
+
i0.ɵɵelementStart(0, "div", 21);
|
|
154
|
+
i0.ɵɵelement(1, "mj-loading", 42);
|
|
155
|
+
i0.ɵɵelementEnd();
|
|
156
|
+
} }
|
|
157
|
+
function SemanticGraphExplorerComponent_Conditional_42_Template(rf, ctx) { if (rf & 1) {
|
|
158
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
159
|
+
i0.ɵɵelementStart(0, "mj-graph-view", 43);
|
|
160
|
+
i0.ɵɵlistener("NodeSelected", function SemanticGraphExplorerComponent_Conditional_42_Template_mj_graph_view_NodeSelected_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnNodeSelected($event)); })("NodeNavigated", function SemanticGraphExplorerComponent_Conditional_42_Template_mj_graph_view_NodeNavigated_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnNodeNavigated($event)); })("NodeAction", function SemanticGraphExplorerComponent_Conditional_42_Template_mj_graph_view_NodeAction_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnNodeAction($event)); })("CategoryFilterChanged", function SemanticGraphExplorerComponent_Conditional_42_Template_mj_graph_view_CategoryFilterChanged_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnCategoryFilterChangedFromCanvas($event)); });
|
|
161
|
+
i0.ɵɵelementEnd();
|
|
162
|
+
} if (rf & 2) {
|
|
163
|
+
const ctx_r3 = i0.ɵɵnextContext();
|
|
164
|
+
const canonInspectorTemplate_r11 = i0.ɵɵreference(44);
|
|
165
|
+
i0.ɵɵproperty("Title", (ctx_r3.SelectedGraph == null ? null : ctx_r3.SelectedGraph.Name) || "Semantic Graph")("Nodes", ctx_r3.Nodes)("Edges", ctx_r3.Edges)("Categories", ctx_r3.Categories)("LayoutMode", ctx_r3.LayoutMode)("SelectedNodeId", ctx_r3.SelectedNodeId)("ActiveCategoryFilter", ctx_r3.ActiveConceptTypeFilter)("AutoOpenInspector", true)("ShowToolbar", true)("ShowLegend", true)("ShowInspector", true)("InspectorCustomTemplate", canonInspectorTemplate_r11)("Searchable", true);
|
|
166
|
+
} }
|
|
167
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
168
|
+
i0.ɵɵelementStart(0, "div", 44)(1, "span", 46);
|
|
169
|
+
i0.ɵɵtext(2, "Specification");
|
|
170
|
+
i0.ɵɵelementEnd();
|
|
171
|
+
i0.ɵɵelementStart(3, "pre", 47);
|
|
172
|
+
i0.ɵɵtext(4);
|
|
173
|
+
i0.ɵɵelementEnd()();
|
|
174
|
+
} if (rf & 2) {
|
|
175
|
+
const node_r12 = i0.ɵɵnextContext().$implicit;
|
|
176
|
+
i0.ɵɵadvance(4);
|
|
177
|
+
i0.ɵɵtextInterpolate(node_r12.Specification);
|
|
178
|
+
} }
|
|
179
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_1_For_5_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
180
|
+
i0.ɵɵelementStart(0, "div", 50);
|
|
181
|
+
i0.ɵɵtext(1);
|
|
182
|
+
i0.ɵɵelementEnd();
|
|
183
|
+
} if (rf & 2) {
|
|
184
|
+
const conflict_r13 = i0.ɵɵnextContext().$implicit;
|
|
185
|
+
i0.ɵɵadvance();
|
|
186
|
+
i0.ɵɵtextInterpolate(conflict_r13.ResolutionNote);
|
|
187
|
+
} }
|
|
188
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_1_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
189
|
+
i0.ɵɵelementStart(0, "div", 49)(1, "div")(2, "strong");
|
|
190
|
+
i0.ɵɵtext(3, "Higher Tier:");
|
|
191
|
+
i0.ɵɵelementEnd();
|
|
192
|
+
i0.ɵɵtext(4);
|
|
193
|
+
i0.ɵɵelementEnd();
|
|
194
|
+
i0.ɵɵelementStart(5, "div")(6, "strong");
|
|
195
|
+
i0.ɵɵtext(7, "Conflicting:");
|
|
196
|
+
i0.ɵɵelementEnd();
|
|
197
|
+
i0.ɵɵtext(8);
|
|
198
|
+
i0.ɵɵelementEnd();
|
|
199
|
+
i0.ɵɵconditionalCreate(9, SemanticGraphExplorerComponent_ng_template_43_Conditional_1_For_5_Conditional_9_Template, 2, 1, "div", 50);
|
|
200
|
+
i0.ɵɵelementEnd();
|
|
201
|
+
} if (rf & 2) {
|
|
202
|
+
const conflict_r13 = ctx.$implicit;
|
|
203
|
+
i0.ɵɵadvance(4);
|
|
204
|
+
i0.ɵɵtextInterpolate1(" ", conflict_r13.HigherAuthoritySummary);
|
|
205
|
+
i0.ɵɵadvance(4);
|
|
206
|
+
i0.ɵɵtextInterpolate1(" ", conflict_r13.ConflictingSummary);
|
|
207
|
+
i0.ɵɵadvance();
|
|
208
|
+
i0.ɵɵconditional(conflict_r13.ResolutionNote ? 9 : -1);
|
|
209
|
+
} }
|
|
210
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
211
|
+
i0.ɵɵelementStart(0, "div", 45)(1, "div", 48);
|
|
212
|
+
i0.ɵɵelement(2, "i", 30);
|
|
213
|
+
i0.ɵɵtext(3, " Authority Conflict (Contradicts Edge) ");
|
|
214
|
+
i0.ɵɵelementEnd();
|
|
215
|
+
i0.ɵɵrepeaterCreate(4, SemanticGraphExplorerComponent_ng_template_43_Conditional_1_For_5_Template, 10, 3, "div", 49, _forTrack1);
|
|
216
|
+
i0.ɵɵelementEnd();
|
|
217
|
+
} if (rf & 2) {
|
|
218
|
+
const node_r12 = i0.ɵɵnextContext().$implicit;
|
|
219
|
+
i0.ɵɵadvance(4);
|
|
220
|
+
i0.ɵɵrepeater(node_r12.Conflicts);
|
|
221
|
+
} }
|
|
222
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_2_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
223
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
224
|
+
i0.ɵɵelementStart(0, "button", 53);
|
|
225
|
+
i0.ɵɵlistener("click", function SemanticGraphExplorerComponent_ng_template_43_Conditional_2_For_5_Template_button_click_0_listener() { const g_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r3 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r3.OpenGroundingRecord(g_r15)); });
|
|
226
|
+
i0.ɵɵelementStart(1, "span", 54);
|
|
227
|
+
i0.ɵɵtext(2);
|
|
228
|
+
i0.ɵɵelementEnd();
|
|
229
|
+
i0.ɵɵelementStart(3, "span", 55);
|
|
230
|
+
i0.ɵɵtext(4);
|
|
231
|
+
i0.ɵɵelementEnd();
|
|
232
|
+
i0.ɵɵelement(5, "i", 56);
|
|
233
|
+
i0.ɵɵelementEnd();
|
|
234
|
+
} if (rf & 2) {
|
|
235
|
+
const g_r15 = ctx.$implicit;
|
|
236
|
+
i0.ɵɵadvance(2);
|
|
237
|
+
i0.ɵɵtextInterpolate(g_r15.EdgeLabel);
|
|
238
|
+
i0.ɵɵadvance(2);
|
|
239
|
+
i0.ɵɵtextInterpolate(g_r15.TargetDisplayName);
|
|
240
|
+
} }
|
|
241
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
242
|
+
i0.ɵɵelementStart(0, "div", 44)(1, "span", 46);
|
|
243
|
+
i0.ɵɵtext(2);
|
|
244
|
+
i0.ɵɵelementEnd();
|
|
245
|
+
i0.ɵɵelementStart(3, "div", 51);
|
|
246
|
+
i0.ɵɵrepeaterCreate(4, SemanticGraphExplorerComponent_ng_template_43_Conditional_2_For_5_Template, 6, 2, "button", 52, _forTrack2);
|
|
247
|
+
i0.ɵɵelementEnd()();
|
|
248
|
+
} if (rf & 2) {
|
|
249
|
+
const node_r12 = i0.ɵɵnextContext().$implicit;
|
|
250
|
+
i0.ɵɵadvance(2);
|
|
251
|
+
i0.ɵɵtextInterpolate1("Grounded MJ Primitives (", node_r12.Groundings.length, ")");
|
|
252
|
+
i0.ɵɵadvance(2);
|
|
253
|
+
i0.ɵɵrepeater(node_r12.Groundings);
|
|
254
|
+
} }
|
|
255
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_3_For_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
256
|
+
i0.ɵɵelementStart(0, "span", 60);
|
|
257
|
+
i0.ɵɵtext(1);
|
|
258
|
+
i0.ɵɵelementEnd();
|
|
259
|
+
} if (rf & 2) {
|
|
260
|
+
const chunk_r16 = i0.ɵɵnextContext().$implicit;
|
|
261
|
+
i0.ɵɵadvance();
|
|
262
|
+
i0.ɵɵtextInterpolate(chunk_r16.AuthorityTier);
|
|
263
|
+
} }
|
|
264
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_3_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
265
|
+
i0.ɵɵelementStart(0, "div", 58)(1, "div", 59)(2, "span");
|
|
266
|
+
i0.ɵɵtext(3);
|
|
267
|
+
i0.ɵɵelementEnd();
|
|
268
|
+
i0.ɵɵconditionalCreate(4, SemanticGraphExplorerComponent_ng_template_43_Conditional_3_For_5_Conditional_4_Template, 2, 1, "span", 60);
|
|
269
|
+
i0.ɵɵelementEnd();
|
|
270
|
+
i0.ɵɵelementStart(5, "div", 61);
|
|
271
|
+
i0.ɵɵtext(6);
|
|
272
|
+
i0.ɵɵelementEnd()();
|
|
273
|
+
} if (rf & 2) {
|
|
274
|
+
const chunk_r16 = ctx.$implicit;
|
|
275
|
+
i0.ɵɵadvance(3);
|
|
276
|
+
i0.ɵɵtextInterpolate2("", chunk_r16.SourceName, "", chunk_r16.Locator ? " \u00B7 " + chunk_r16.Locator : "");
|
|
277
|
+
i0.ɵɵadvance();
|
|
278
|
+
i0.ɵɵconditional(chunk_r16.AuthorityTier ? 4 : -1);
|
|
279
|
+
i0.ɵɵadvance(2);
|
|
280
|
+
i0.ɵɵtextInterpolate(chunk_r16.Snippet);
|
|
281
|
+
} }
|
|
282
|
+
function SemanticGraphExplorerComponent_ng_template_43_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
283
|
+
i0.ɵɵelementStart(0, "div", 44)(1, "span", 46);
|
|
284
|
+
i0.ɵɵtext(2);
|
|
285
|
+
i0.ɵɵelementEnd();
|
|
286
|
+
i0.ɵɵelementStart(3, "div", 57);
|
|
287
|
+
i0.ɵɵrepeaterCreate(4, SemanticGraphExplorerComponent_ng_template_43_Conditional_3_For_5_Template, 7, 4, "div", 58, _forTrack3);
|
|
288
|
+
i0.ɵɵelementEnd()();
|
|
289
|
+
} if (rf & 2) {
|
|
290
|
+
const node_r12 = i0.ɵɵnextContext().$implicit;
|
|
291
|
+
i0.ɵɵadvance(2);
|
|
292
|
+
i0.ɵɵtextInterpolate1("SourcedFrom Chunks (", node_r12.ProvenanceChunks.length, ")");
|
|
293
|
+
i0.ɵɵadvance(2);
|
|
294
|
+
i0.ɵɵrepeater(node_r12.ProvenanceChunks);
|
|
295
|
+
} }
|
|
296
|
+
function SemanticGraphExplorerComponent_ng_template_43_Template(rf, ctx) { if (rf & 1) {
|
|
297
|
+
i0.ɵɵconditionalCreate(0, SemanticGraphExplorerComponent_ng_template_43_Conditional_0_Template, 5, 1, "div", 44);
|
|
298
|
+
i0.ɵɵconditionalCreate(1, SemanticGraphExplorerComponent_ng_template_43_Conditional_1_Template, 6, 0, "div", 45);
|
|
299
|
+
i0.ɵɵconditionalCreate(2, SemanticGraphExplorerComponent_ng_template_43_Conditional_2_Template, 6, 1, "div", 44);
|
|
300
|
+
i0.ɵɵconditionalCreate(3, SemanticGraphExplorerComponent_ng_template_43_Conditional_3_Template, 6, 1, "div", 44);
|
|
301
|
+
} if (rf & 2) {
|
|
302
|
+
const node_r12 = ctx.$implicit;
|
|
303
|
+
i0.ɵɵconditional(node_r12.Specification ? 0 : -1);
|
|
304
|
+
i0.ɵɵadvance();
|
|
305
|
+
i0.ɵɵconditional(node_r12.Conflicts && node_r12.Conflicts.length > 0 ? 1 : -1);
|
|
306
|
+
i0.ɵɵadvance();
|
|
307
|
+
i0.ɵɵconditional(node_r12.Groundings && node_r12.Groundings.length > 0 ? 2 : -1);
|
|
308
|
+
i0.ɵɵadvance();
|
|
309
|
+
i0.ɵɵconditional(node_r12.ProvenanceChunks && node_r12.ProvenanceChunks.length > 0 ? 3 : -1);
|
|
310
|
+
} }
|
|
311
|
+
/** Default ranked Canon & Semantic Graph categories used by the Knowledge Hub explorer. */
|
|
312
|
+
export const DEFAULT_SEMANTIC_GRAPH_CATEGORIES = [
|
|
313
|
+
{ Category: 'Policy', Label: 'Policy', Color: '#f43f5e', IconClass: 'fa-solid fa-gavel', Rank: 10 },
|
|
314
|
+
{ Category: 'Metric', Label: 'Metric', Color: '#10b981', IconClass: 'fa-solid fa-chart-line', Rank: 20 },
|
|
315
|
+
{ Category: 'Process', Label: 'Process', Color: '#8b5cf6', IconClass: 'fa-solid fa-gears', Rank: 30 },
|
|
316
|
+
{ Category: 'Role', Label: 'Role', Color: '#f59e0b', IconClass: 'fa-solid fa-user-shield', Rank: 40 },
|
|
317
|
+
{ Category: 'Domain', Label: 'Domain', Color: '#3b82f6', IconClass: 'fa-solid fa-layer-group', Rank: 50 },
|
|
318
|
+
{ Category: 'Term', Label: 'Term', Color: '#06b6d4', IconClass: 'fa-solid fa-book-bookmark', Rank: 60 },
|
|
319
|
+
{ Category: 'grounding', Label: 'Grounded Primitive', Color: '#14b8a6', IconClass: 'fa-solid fa-bolt', Rank: 90 },
|
|
320
|
+
{ Category: 'chunk', Label: 'Source Chunk', Color: '#64748b', IconClass: 'fa-solid fa-file-lines', Rank: 95 },
|
|
321
|
+
...DEFAULT_GRAPH_CATEGORIES,
|
|
322
|
+
];
|
|
323
|
+
const SAMPLE_GRAPH_ID = 'D1000000-0000-4000-8000-000000000004';
|
|
324
|
+
const CONCEPT_TYPE_COLORS = {
|
|
325
|
+
policy: '#f43f5e',
|
|
326
|
+
metric: '#10b981',
|
|
327
|
+
process: '#8b5cf6',
|
|
328
|
+
role: '#f59e0b',
|
|
329
|
+
domain: '#3b82f6',
|
|
330
|
+
term: '#06b6d4',
|
|
331
|
+
};
|
|
332
|
+
export class SemanticGraphExplorerComponent extends BaseAngularComponent {
|
|
333
|
+
cdr = inject(ChangeDetectorRef);
|
|
334
|
+
Provider = null;
|
|
335
|
+
/** Emitted when the user requests to open an entity record from the graph or inspector. */
|
|
336
|
+
OpenRecordRequested = new EventEmitter();
|
|
337
|
+
/** Emitted when a graph node is selected on canvas. */
|
|
338
|
+
ConceptSelected = new EventEmitter();
|
|
339
|
+
// ================================================================
|
|
340
|
+
// State
|
|
341
|
+
// ================================================================
|
|
342
|
+
IsLoading = true;
|
|
343
|
+
LoadError = null;
|
|
344
|
+
ActionError = null;
|
|
345
|
+
GraphOptions = [];
|
|
346
|
+
ConceptTypeOptions = [];
|
|
347
|
+
SelectedGraphID = '';
|
|
348
|
+
OnlyCanonGraphs = false;
|
|
349
|
+
ActiveConceptTypeFilter = null;
|
|
350
|
+
LayoutMode = 'force';
|
|
351
|
+
authorityTiersById = new Map();
|
|
352
|
+
/** Edge / Node Overlay Toggles */
|
|
353
|
+
ShowGroundedPrimitives = true;
|
|
354
|
+
ShowSourceChunks = true;
|
|
355
|
+
HighlightConflicts = true;
|
|
356
|
+
/** Raw & Filtered Graph Data passed to <mj-graph-view> */
|
|
357
|
+
rawNodes = [];
|
|
358
|
+
rawEdges = [];
|
|
359
|
+
Nodes = [];
|
|
360
|
+
Edges = [];
|
|
361
|
+
Categories = [...DEFAULT_SEMANTIC_GRAPH_CATEGORIES];
|
|
362
|
+
SelectedNodeId;
|
|
363
|
+
// ================================================================
|
|
364
|
+
// Lifecycle
|
|
365
|
+
// ================================================================
|
|
366
|
+
async ngOnInit() {
|
|
367
|
+
await this.LoadGraphCatalog();
|
|
368
|
+
}
|
|
369
|
+
// ================================================================
|
|
370
|
+
// Public Getters & Actions
|
|
371
|
+
// ================================================================
|
|
372
|
+
get VisibleGraphOptions() {
|
|
373
|
+
if (!this.OnlyCanonGraphs) {
|
|
374
|
+
return this.GraphOptions;
|
|
375
|
+
}
|
|
376
|
+
return this.GraphOptions.filter(g => g.IsCanon);
|
|
377
|
+
}
|
|
378
|
+
get SelectedGraph() {
|
|
379
|
+
return this.GraphOptions.find(g => UUIDsEqual(g.ID, this.SelectedGraphID));
|
|
380
|
+
}
|
|
381
|
+
async SelectGraph(graphId) {
|
|
382
|
+
if (UUIDsEqual(this.SelectedGraphID, graphId)) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
this.SelectedGraphID = graphId;
|
|
386
|
+
this.ActiveConceptTypeFilter = null;
|
|
387
|
+
await this.LoadSelectedGraphData();
|
|
388
|
+
}
|
|
389
|
+
ToggleCanonFilter() {
|
|
390
|
+
this.OnlyCanonGraphs = !this.OnlyCanonGraphs;
|
|
391
|
+
const visible = this.VisibleGraphOptions;
|
|
392
|
+
if (visible.length > 0 && !visible.some(g => UUIDsEqual(g.ID, this.SelectedGraphID))) {
|
|
393
|
+
void this.SelectGraph(visible[0].ID);
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
this.cdr.detectChanges();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
ToggleConceptTypeFilter(typeName) {
|
|
400
|
+
if (!typeName || (this.ActiveConceptTypeFilter && this.ActiveConceptTypeFilter.toLowerCase() === typeName.toLowerCase())) {
|
|
401
|
+
this.ActiveConceptTypeFilter = null;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
this.ActiveConceptTypeFilter = typeName;
|
|
405
|
+
}
|
|
406
|
+
this.rebuildConceptTypeCounts();
|
|
407
|
+
this.cdr.detectChanges();
|
|
408
|
+
}
|
|
409
|
+
OnCategoryFilterChangedFromCanvas(category) {
|
|
410
|
+
this.ActiveConceptTypeFilter = category;
|
|
411
|
+
this.cdr.detectChanges();
|
|
412
|
+
}
|
|
413
|
+
OnOverlayToggleChanged() {
|
|
414
|
+
this.applyOverlayFilters();
|
|
415
|
+
this.cdr.detectChanges();
|
|
416
|
+
}
|
|
417
|
+
CreateNewGraphRecord() {
|
|
418
|
+
if (this.SelectedGraph && !this.SelectedGraph.IsSample) {
|
|
419
|
+
this.OpenRecordRequested.emit({
|
|
420
|
+
EntityName: 'MJ: Graphs',
|
|
421
|
+
RecordID: this.SelectedGraph.ID,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
OnNodeSelected(event) {
|
|
426
|
+
const node = event.Node;
|
|
427
|
+
this.SelectedNodeId = node.ID;
|
|
428
|
+
this.ConceptSelected.emit({
|
|
429
|
+
NodeID: node.ID,
|
|
430
|
+
Label: node.Label,
|
|
431
|
+
ConceptType: String(node.Category),
|
|
432
|
+
Status: String(node.Status ?? 'Approved'),
|
|
433
|
+
AuthorityTier: String(node.AuthorityTier ?? 'Reference'),
|
|
434
|
+
ConnectedChunkCount: node.ProvenanceChunks?.length ?? 0,
|
|
435
|
+
ConflictCount: node.Conflicts?.length ?? 0,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
OnNodeNavigated(event) {
|
|
439
|
+
const entityName = event.EntityName || String(event.Node.Data?.['EntityName'] ?? 'MJ: Graph Concepts');
|
|
440
|
+
const recordId = event.RecordID || String(event.Node.Data?.['RecordID'] ?? event.Node.ID);
|
|
441
|
+
if (entityName && recordId && !recordId.startsWith('sample-')) {
|
|
442
|
+
this.OpenRecordRequested.emit({ EntityName: entityName, RecordID: recordId });
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async OnNodeAction(event) {
|
|
446
|
+
if (event.Action === 'approve') {
|
|
447
|
+
const node = event.Node;
|
|
448
|
+
this.ActionError = null;
|
|
449
|
+
if (node.ID.startsWith('sample-') || this.SelectedGraph?.IsSample) {
|
|
450
|
+
node.Status = 'Approved';
|
|
451
|
+
this.Nodes = [...this.Nodes];
|
|
452
|
+
this.cdr.detectChanges();
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const provider = this.ProviderToUse;
|
|
457
|
+
const conceptEntity = await provider.GetEntityObject('MJ: Graph Concepts', provider.CurrentUser);
|
|
458
|
+
if (await conceptEntity.Load(node.ID)) {
|
|
459
|
+
conceptEntity.Status = 'Approved';
|
|
460
|
+
const saved = await conceptEntity.Save();
|
|
461
|
+
if (saved) {
|
|
462
|
+
node.Status = 'Approved';
|
|
463
|
+
this.Nodes = [...this.Nodes];
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
this.ActionError =
|
|
467
|
+
conceptEntity.LatestResult?.CompleteMessage || 'Failed to save concept approval.';
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
this.ActionError = `Could not load Graph Concept ${node.ID}.`;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
catch (err) {
|
|
475
|
+
this.ActionError = err instanceof Error ? err.message : String(err);
|
|
476
|
+
}
|
|
477
|
+
this.cdr.detectChanges();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
LoadSampleGraphPreview() {
|
|
481
|
+
this.LoadError = null;
|
|
482
|
+
this.ActionError = null;
|
|
483
|
+
const sampleOpt = this.buildSampleGraphOption();
|
|
484
|
+
if (!this.GraphOptions.some(o => UUIDsEqual(o.ID, sampleOpt.ID))) {
|
|
485
|
+
this.GraphOptions = [...this.GraphOptions, sampleOpt];
|
|
486
|
+
}
|
|
487
|
+
this.SelectedGraphID = sampleOpt.ID;
|
|
488
|
+
this.loadSampleCanonGraphNodesAndEdges();
|
|
489
|
+
this.applyOverlayFilters();
|
|
490
|
+
this.rebuildConceptTypeCounts();
|
|
491
|
+
this.cdr.detectChanges();
|
|
492
|
+
}
|
|
493
|
+
// ================================================================
|
|
494
|
+
// Data Loading (MJ: Graph Types, MJ: Graph Concept Types, MJ: Graphs)
|
|
495
|
+
// ================================================================
|
|
496
|
+
async LoadGraphCatalog() {
|
|
497
|
+
this.IsLoading = true;
|
|
498
|
+
this.LoadError = null;
|
|
499
|
+
this.ActionError = null;
|
|
500
|
+
this.cdr.detectChanges();
|
|
501
|
+
try {
|
|
502
|
+
const provider = this.ProviderToUse;
|
|
503
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
504
|
+
const user = provider.CurrentUser;
|
|
505
|
+
const [graphTypesRes, conceptTypesRes, authorityTiersRes, graphsRes, sourcesRes] = await rv.RunViews([
|
|
506
|
+
{
|
|
507
|
+
EntityName: 'MJ: Graph Types',
|
|
508
|
+
ExtraFilter: `Status = 'Active'`,
|
|
509
|
+
OrderBy: 'Rank ASC, Name ASC',
|
|
510
|
+
ResultType: 'simple',
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
EntityName: 'MJ: Graph Concept Types',
|
|
514
|
+
ExtraFilter: `Status = 'Active'`,
|
|
515
|
+
OrderBy: 'Rank ASC, Name ASC',
|
|
516
|
+
ResultType: 'simple',
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
EntityName: 'MJ: Graph Authority Tiers',
|
|
520
|
+
ExtraFilter: `Status = 'Active'`,
|
|
521
|
+
OrderBy: 'Rank DESC, Name ASC',
|
|
522
|
+
ResultType: 'simple',
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
EntityName: 'MJ: Graphs',
|
|
526
|
+
ExtraFilter: `Status = 'Active'`,
|
|
527
|
+
OrderBy: 'Name ASC',
|
|
528
|
+
ResultType: 'simple',
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
EntityName: 'MJ: Content Sources',
|
|
532
|
+
Fields: ['ID', 'Name', 'GraphID'],
|
|
533
|
+
ResultType: 'simple',
|
|
534
|
+
},
|
|
535
|
+
], user);
|
|
536
|
+
const graphTypesById = new Map();
|
|
537
|
+
for (const gt of (graphTypesRes?.Results ?? [])) {
|
|
538
|
+
graphTypesById.set(NormalizeUUID(gt.ID), gt);
|
|
539
|
+
}
|
|
540
|
+
this.authorityTiersById.clear();
|
|
541
|
+
for (const at of (authorityTiersRes?.Results ?? [])) {
|
|
542
|
+
this.authorityTiersById.set(NormalizeUUID(at.ID), at);
|
|
543
|
+
}
|
|
544
|
+
const conceptTypes = (conceptTypesRes?.Results ?? []);
|
|
545
|
+
this.ConceptTypeOptions = conceptTypes.length > 0
|
|
546
|
+
? conceptTypes.map(ct => ({
|
|
547
|
+
ID: ct.ID,
|
|
548
|
+
Name: ct.Name,
|
|
549
|
+
Rank: ct.Rank ?? 100,
|
|
550
|
+
IconClass: ct.IconClass || 'fa-solid fa-circle-dot',
|
|
551
|
+
Color: this.resolveConceptTypeColor(ct.Name),
|
|
552
|
+
Count: 0,
|
|
553
|
+
}))
|
|
554
|
+
: this.buildDefaultConceptTypeOptions();
|
|
555
|
+
this.Categories = [
|
|
556
|
+
...this.ConceptTypeOptions.map(ct => ({
|
|
557
|
+
Category: ct.Name,
|
|
558
|
+
Label: ct.Name,
|
|
559
|
+
Color: ct.Color,
|
|
560
|
+
IconClass: ct.IconClass,
|
|
561
|
+
Rank: ct.Rank,
|
|
562
|
+
})),
|
|
563
|
+
{ Category: 'grounding', Label: 'Grounded Primitive', Color: '#14b8a6', IconClass: 'fa-solid fa-bolt', Rank: 90 },
|
|
564
|
+
{ Category: 'chunk', Label: 'Source Chunk', Color: '#64748b', IconClass: 'fa-solid fa-file-lines', Rank: 95 },
|
|
565
|
+
];
|
|
566
|
+
const sourcesByGraphId = new Map();
|
|
567
|
+
for (const src of (sourcesRes?.Results ?? [])) {
|
|
568
|
+
if (src.GraphID) {
|
|
569
|
+
const key = NormalizeUUID(src.GraphID);
|
|
570
|
+
const list = sourcesByGraphId.get(key) ?? [];
|
|
571
|
+
list.push(src.Name || 'Untitled Source');
|
|
572
|
+
sourcesByGraphId.set(key, list);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
const dbGraphs = (graphsRes?.Results ?? []);
|
|
576
|
+
const options = dbGraphs.map(g => {
|
|
577
|
+
const gt = graphTypesById.get(NormalizeUUID(g.GraphTypeID));
|
|
578
|
+
return {
|
|
579
|
+
ID: g.ID,
|
|
580
|
+
Name: g.Name,
|
|
581
|
+
Description: g.Description ?? '',
|
|
582
|
+
GraphTypeID: g.GraphTypeID,
|
|
583
|
+
GraphTypeName: gt?.Name ?? g.GraphType ?? 'Custom',
|
|
584
|
+
IsCanon: Boolean(gt?.IsCanon ?? (g.GraphType === 'Canon')),
|
|
585
|
+
GraphTypeRank: gt?.Rank ?? 100,
|
|
586
|
+
IconClass: gt?.IconClass || 'fa-solid fa-diagram-project',
|
|
587
|
+
ConceptCount: 0,
|
|
588
|
+
ConflictCount: 0,
|
|
589
|
+
SourceNames: sourcesByGraphId.get(NormalizeUUID(g.ID)) ?? [],
|
|
590
|
+
};
|
|
591
|
+
}).sort((a, b) => a.GraphTypeRank - b.GraphTypeRank || a.Name.localeCompare(b.Name));
|
|
592
|
+
this.GraphOptions = options;
|
|
593
|
+
if (this.GraphOptions.length > 0) {
|
|
594
|
+
if (!this.SelectedGraphID || !this.GraphOptions.some(o => UUIDsEqual(o.ID, this.SelectedGraphID))) {
|
|
595
|
+
this.SelectedGraphID = this.GraphOptions[0].ID;
|
|
596
|
+
}
|
|
597
|
+
await this.LoadSelectedGraphData();
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
this.rawNodes = [];
|
|
601
|
+
this.rawEdges = [];
|
|
602
|
+
this.Nodes = [];
|
|
603
|
+
this.Edges = [];
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
catch (err) {
|
|
607
|
+
this.LoadError = err instanceof Error ? err.message : String(err);
|
|
608
|
+
this.ConceptTypeOptions = this.buildDefaultConceptTypeOptions();
|
|
609
|
+
this.rawNodes = [];
|
|
610
|
+
this.rawEdges = [];
|
|
611
|
+
this.Nodes = [];
|
|
612
|
+
this.Edges = [];
|
|
613
|
+
}
|
|
614
|
+
finally {
|
|
615
|
+
this.IsLoading = false;
|
|
616
|
+
this.cdr.detectChanges();
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
async LoadSelectedGraphData() {
|
|
620
|
+
const selected = this.SelectedGraph;
|
|
621
|
+
if (!selected) {
|
|
622
|
+
this.rawNodes = [];
|
|
623
|
+
this.rawEdges = [];
|
|
624
|
+
this.applyOverlayFilters();
|
|
625
|
+
this.rebuildConceptTypeCounts();
|
|
626
|
+
this.cdr.detectChanges();
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (selected.IsSample) {
|
|
630
|
+
this.loadSampleCanonGraphNodesAndEdges();
|
|
631
|
+
this.applyOverlayFilters();
|
|
632
|
+
this.rebuildConceptTypeCounts();
|
|
633
|
+
this.cdr.detectChanges();
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
if (!this.isValidUUID(selected.ID)) {
|
|
637
|
+
this.LoadError = `Invalid Graph ID: ${selected.ID}`;
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
this.IsLoading = true;
|
|
641
|
+
this.LoadError = null;
|
|
642
|
+
this.cdr.detectChanges();
|
|
643
|
+
try {
|
|
644
|
+
const provider = this.ProviderToUse;
|
|
645
|
+
const rv = RunView.FromMetadataProvider(provider);
|
|
646
|
+
const user = provider.CurrentUser;
|
|
647
|
+
const normalizedGraphId = NormalizeUUID(selected.ID);
|
|
648
|
+
const [conceptsRes, edgesRes] = await rv.RunViews([
|
|
649
|
+
{
|
|
650
|
+
EntityName: 'MJ: Graph Concepts',
|
|
651
|
+
ExtraFilter: `GraphID = '${normalizedGraphId}'`,
|
|
652
|
+
OrderBy: 'Name ASC',
|
|
653
|
+
MaxRows: 500,
|
|
654
|
+
ResultType: 'simple',
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
EntityName: 'MJ: Graph Edges',
|
|
658
|
+
ExtraFilter: `GraphID = '${normalizedGraphId}'`,
|
|
659
|
+
MaxRows: 1000,
|
|
660
|
+
ResultType: 'simple',
|
|
661
|
+
},
|
|
662
|
+
], user);
|
|
663
|
+
const concepts = (conceptsRes?.Results ?? []);
|
|
664
|
+
const edges = (edgesRes?.Results ?? []);
|
|
665
|
+
if (concepts.length === 0 && edges.length === 0) {
|
|
666
|
+
this.rawNodes = [];
|
|
667
|
+
this.rawEdges = [];
|
|
668
|
+
selected.ConceptCount = 0;
|
|
669
|
+
selected.ConflictCount = 0;
|
|
670
|
+
this.applyOverlayFilters();
|
|
671
|
+
this.rebuildConceptTypeCounts();
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
const rankByTypeName = new Map();
|
|
675
|
+
for (const ct of this.ConceptTypeOptions) {
|
|
676
|
+
rankByTypeName.set(ct.Name.toLowerCase(), ct.Rank);
|
|
677
|
+
}
|
|
678
|
+
const nodes = concepts.map(c => {
|
|
679
|
+
const typeName = c.ConceptType || 'Term';
|
|
680
|
+
const rank = rankByTypeName.get(typeName.toLowerCase()) ?? 60;
|
|
681
|
+
const tierEntity = c.AuthorityTierID ? this.authorityTiersById.get(NormalizeUUID(c.AuthorityTierID)) : undefined;
|
|
682
|
+
const tierLabel = tierEntity ? `${tierEntity.Name} (${tierEntity.Rank})` : (c.AuthorityTier || 'Reference');
|
|
683
|
+
return {
|
|
684
|
+
ID: c.ID,
|
|
685
|
+
Label: c.Name,
|
|
686
|
+
Sublabel: `${typeName} · ${tierEntity?.Name ?? c.AuthorityTier ?? 'Reference'}`,
|
|
687
|
+
Category: typeName,
|
|
688
|
+
Rank: rank,
|
|
689
|
+
Badge: `#${rank}`,
|
|
690
|
+
Status: c.Status,
|
|
691
|
+
AuthorityTier: tierLabel,
|
|
692
|
+
ParentID: c.ParentID ?? undefined,
|
|
693
|
+
Description: c.Description,
|
|
694
|
+
Specification: c.Specification ?? undefined,
|
|
695
|
+
Conflicts: [],
|
|
696
|
+
Groundings: [],
|
|
697
|
+
ProvenanceChunks: [],
|
|
698
|
+
Data: {
|
|
699
|
+
EntityName: 'MJ: Graph Concepts',
|
|
700
|
+
RecordID: c.ID,
|
|
701
|
+
},
|
|
702
|
+
};
|
|
703
|
+
});
|
|
704
|
+
const nodeById = new Map();
|
|
705
|
+
for (const n of nodes) {
|
|
706
|
+
nodeById.set(NormalizeUUID(n.ID), n);
|
|
707
|
+
}
|
|
708
|
+
const graphEdges = [];
|
|
709
|
+
let conflictCount = 0;
|
|
710
|
+
for (const e of edges) {
|
|
711
|
+
const edgeLabel = e.EdgeType || 'Related To';
|
|
712
|
+
const isConflict = edgeLabel.toLowerCase().includes('contradict');
|
|
713
|
+
if (isConflict) {
|
|
714
|
+
conflictCount++;
|
|
715
|
+
}
|
|
716
|
+
// Ensure synthetic endpoint nodes exist for non-concept endpoints (chunks or grounded MJ entities)
|
|
717
|
+
const srcKey = NormalizeUUID(e.SourceRecordID);
|
|
718
|
+
const tgtKey = NormalizeUUID(e.TargetRecordID);
|
|
719
|
+
if (!nodeById.has(srcKey)) {
|
|
720
|
+
const synth = this.createSyntheticEndpointNode(e.SourceEntity || 'Record', e.SourceRecordID, edgeLabel);
|
|
721
|
+
nodes.push(synth);
|
|
722
|
+
nodeById.set(srcKey, synth);
|
|
723
|
+
}
|
|
724
|
+
if (!nodeById.has(tgtKey)) {
|
|
725
|
+
const synth = this.createSyntheticEndpointNode(e.TargetEntity || 'Record', e.TargetRecordID, edgeLabel);
|
|
726
|
+
nodes.push(synth);
|
|
727
|
+
nodeById.set(tgtKey, synth);
|
|
728
|
+
}
|
|
729
|
+
const srcNode = nodeById.get(srcKey);
|
|
730
|
+
const tgtNode = nodeById.get(tgtKey);
|
|
731
|
+
if (edgeLabel === 'Defines' || edgeLabel === 'Describes' || edgeLabel === 'Measures' || edgeLabel === 'Implements') {
|
|
732
|
+
srcNode.Groundings = srcNode.Groundings ?? [];
|
|
733
|
+
srcNode.Groundings.push({
|
|
734
|
+
EdgeLabel: edgeLabel,
|
|
735
|
+
TargetEntityName: e.TargetEntity || 'MJ: Entities',
|
|
736
|
+
TargetRecordID: e.TargetRecordID,
|
|
737
|
+
TargetDisplayName: `${e.TargetEntity || 'Entity'}: ${tgtNode.Label}`,
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
else if (edgeLabel === 'SourcedFrom') {
|
|
741
|
+
srcNode.ProvenanceChunks = srcNode.ProvenanceChunks ?? [];
|
|
742
|
+
srcNode.ProvenanceChunks.push({
|
|
743
|
+
ChunkID: e.TargetRecordID,
|
|
744
|
+
SourceName: e.TargetEntity || 'MJ: Content Item Chunks',
|
|
745
|
+
Snippet: `Chunk ${e.TargetRecordID.slice(0, 8)} (Confidence: ${Math.round((e.Confidence ?? 1) * 100)}%)`,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
else if (isConflict) {
|
|
749
|
+
const conflictItem = {
|
|
750
|
+
HigherAuthoritySummary: srcNode.Label,
|
|
751
|
+
ConflictingSummary: tgtNode.Label,
|
|
752
|
+
ResolutionNote: 'Flagged by Contradicts edge for steward review.',
|
|
753
|
+
EdgeID: e.ID,
|
|
754
|
+
};
|
|
755
|
+
srcNode.Conflicts = [...(srcNode.Conflicts ?? []), conflictItem];
|
|
756
|
+
tgtNode.Conflicts = [...(tgtNode.Conflicts ?? []), conflictItem];
|
|
757
|
+
}
|
|
758
|
+
graphEdges.push({
|
|
759
|
+
ID: e.ID,
|
|
760
|
+
SourceID: e.SourceRecordID,
|
|
761
|
+
TargetID: e.TargetRecordID,
|
|
762
|
+
Label: edgeLabel,
|
|
763
|
+
Direction: 'directed',
|
|
764
|
+
Weight: e.Weight ?? 1,
|
|
765
|
+
Style: isConflict ? 'dashed' : (edgeLabel === 'SourcedFrom' ? 'dotted' : 'solid'),
|
|
766
|
+
Color: isConflict ? '#f43f5e' : undefined,
|
|
767
|
+
Animated: isConflict,
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
selected.ConceptCount = concepts.length;
|
|
771
|
+
selected.ConflictCount = conflictCount;
|
|
772
|
+
this.rawNodes = nodes;
|
|
773
|
+
this.rawEdges = graphEdges;
|
|
774
|
+
this.applyOverlayFilters();
|
|
775
|
+
this.rebuildConceptTypeCounts();
|
|
776
|
+
}
|
|
777
|
+
catch (err) {
|
|
778
|
+
console.error('[SemanticGraphExplorer] Error loading graph data:', err);
|
|
779
|
+
}
|
|
780
|
+
finally {
|
|
781
|
+
this.IsLoading = false;
|
|
782
|
+
this.cdr.detectChanges();
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
// ================================================================
|
|
786
|
+
// Private Helpers & Sample Canon Graph
|
|
787
|
+
// ================================================================
|
|
788
|
+
applyOverlayFilters() {
|
|
789
|
+
const filteredNodes = this.rawNodes.filter(n => {
|
|
790
|
+
if (!this.ShowGroundedPrimitives && n.Category === 'grounding') {
|
|
791
|
+
return false;
|
|
792
|
+
}
|
|
793
|
+
if (!this.ShowSourceChunks && n.Category === 'chunk') {
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
return true;
|
|
797
|
+
});
|
|
798
|
+
const visibleNodeIds = new Set(filteredNodes.map(n => NormalizeUUID(n.ID)));
|
|
799
|
+
const filteredEdges = this.rawEdges.filter(e => {
|
|
800
|
+
if (!visibleNodeIds.has(NormalizeUUID(e.SourceID)) || !visibleNodeIds.has(NormalizeUUID(e.TargetID))) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
if (!this.HighlightConflicts && e.Label.toLowerCase().includes('contradict')) {
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
return true;
|
|
807
|
+
});
|
|
808
|
+
this.Nodes = filteredNodes;
|
|
809
|
+
this.Edges = filteredEdges;
|
|
810
|
+
}
|
|
811
|
+
rebuildConceptTypeCounts() {
|
|
812
|
+
const counts = new Map();
|
|
813
|
+
for (const n of this.rawNodes) {
|
|
814
|
+
const key = String(n.Category || '').toLowerCase();
|
|
815
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
816
|
+
}
|
|
817
|
+
this.ConceptTypeOptions = this.ConceptTypeOptions.map(opt => ({
|
|
818
|
+
...opt,
|
|
819
|
+
Count: counts.get(opt.Name.toLowerCase()) ?? 0,
|
|
820
|
+
}));
|
|
821
|
+
}
|
|
822
|
+
createSyntheticEndpointNode(entityName, recordId, edgeLabel) {
|
|
823
|
+
const isChunk = entityName.toLowerCase().includes('chunk') || edgeLabel === 'SourcedFrom';
|
|
824
|
+
return {
|
|
825
|
+
ID: recordId,
|
|
826
|
+
Label: isChunk ? `Chunk ${recordId.slice(0, 6)}` : `${entityName.replace(/^MJ:\s*/, '')}`,
|
|
827
|
+
Sublabel: entityName,
|
|
828
|
+
Category: isChunk ? 'chunk' : 'grounding',
|
|
829
|
+
Badge: isChunk ? '§' : '⚡',
|
|
830
|
+
Radius: 20,
|
|
831
|
+
Status: 'Approved',
|
|
832
|
+
Data: {
|
|
833
|
+
EntityName: entityName,
|
|
834
|
+
RecordID: recordId,
|
|
835
|
+
},
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
OpenGroundingRecord(grounding) {
|
|
839
|
+
if (grounding.TargetEntityName && grounding.TargetRecordID && !grounding.TargetRecordID.startsWith('sample-')) {
|
|
840
|
+
this.OpenRecordRequested.emit({
|
|
841
|
+
EntityName: grounding.TargetEntityName,
|
|
842
|
+
RecordID: grounding.TargetRecordID,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
isValidUUID(id) {
|
|
847
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id.trim());
|
|
848
|
+
}
|
|
849
|
+
resolveConceptTypeColor(name) {
|
|
850
|
+
return CONCEPT_TYPE_COLORS[name.trim().toLowerCase()] ?? '#38bdf8';
|
|
851
|
+
}
|
|
852
|
+
buildDefaultConceptTypeOptions() {
|
|
853
|
+
return [
|
|
854
|
+
{ ID: 'ct-policy', Name: 'Policy', Rank: 10, IconClass: 'fa-solid fa-gavel', Color: '#f43f5e', Count: 0 },
|
|
855
|
+
{ ID: 'ct-metric', Name: 'Metric', Rank: 20, IconClass: 'fa-solid fa-chart-line', Color: '#10b981', Count: 0 },
|
|
856
|
+
{ ID: 'ct-process', Name: 'Process', Rank: 30, IconClass: 'fa-solid fa-gears', Color: '#8b5cf6', Count: 0 },
|
|
857
|
+
{ ID: 'ct-role', Name: 'Role', Rank: 40, IconClass: 'fa-solid fa-user-shield', Color: '#f59e0b', Count: 0 },
|
|
858
|
+
{ ID: 'ct-domain', Name: 'Domain', Rank: 50, IconClass: 'fa-solid fa-layer-group', Color: '#3b82f6', Count: 0 },
|
|
859
|
+
{ ID: 'ct-term', Name: 'Term', Rank: 60, IconClass: 'fa-solid fa-book-bookmark', Color: '#06b6d4', Count: 0 },
|
|
860
|
+
];
|
|
861
|
+
}
|
|
862
|
+
buildSampleGraphOption() {
|
|
863
|
+
return {
|
|
864
|
+
ID: SAMPLE_GRAPH_ID,
|
|
865
|
+
Name: 'Association Governance Canon',
|
|
866
|
+
Description: 'Multi-source Canon graph illustrating ranked Concept Types, AuthorityTier precedence, grounded ABVs/Queries, and Contradicts conflict detection.',
|
|
867
|
+
GraphTypeID: 'A4B9E210-1001-4C81-9A01-000000000001',
|
|
868
|
+
GraphTypeName: 'Canon',
|
|
869
|
+
IsCanon: true,
|
|
870
|
+
GraphTypeRank: 10,
|
|
871
|
+
IconClass: 'fa-solid fa-scale-balanced',
|
|
872
|
+
ConceptCount: 5,
|
|
873
|
+
ConflictCount: 1,
|
|
874
|
+
SourceNames: ['Association Bylaws (PDF)', 'Finance & Dues SOPs', 'Staff Desk Manual'],
|
|
875
|
+
IsSample: true,
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
loadSampleCanonGraphNodesAndEdges() {
|
|
879
|
+
const ID_DOMAIN_GOV = 'C3000000-0000-4000-8000-000000000001';
|
|
880
|
+
const ID_POLICY_GRACE = 'C3000000-0000-4000-8000-000000000002';
|
|
881
|
+
const ID_METRIC_NRR = 'C3000000-0000-4000-8000-000000000003';
|
|
882
|
+
const ID_PROCESS_RENEWAL = 'C3000000-0000-4000-8000-000000000004';
|
|
883
|
+
const ID_ROLE_STEWARD = 'C3000000-0000-4000-8000-000000000005';
|
|
884
|
+
const ID_CHUNK_BYLAWS = 'C3000000-0000-4000-8000-000000000006';
|
|
885
|
+
const ID_CHUNK_MANUAL = 'C3000000-0000-4000-8000-000000000007';
|
|
886
|
+
const ID_ABV_GRACE = 'B4000000-0000-4000-8000-000000000001';
|
|
887
|
+
const ID_ABV_ACTIVE = 'B4000000-0000-4000-8000-000000000002';
|
|
888
|
+
const ID_QUERY_RETENTION = 'B4000000-0000-4000-8000-000000000003';
|
|
889
|
+
const conflictDetail = {
|
|
890
|
+
HigherAuthoritySummary: 'Association Bylaws (Article IV §4.2) — "60 days"',
|
|
891
|
+
ConflictingSummary: 'Staff Desk Manual (Ch. 3 p. 42) — "90 days"',
|
|
892
|
+
ResolutionNote: 'Resolved in favor of Bylaws (Rank 100 > DeptPractice 40); Contradicts edge flagged for steward review.',
|
|
893
|
+
};
|
|
894
|
+
const sampleChunks = [
|
|
895
|
+
{
|
|
896
|
+
ChunkID: ID_CHUNK_BYLAWS,
|
|
897
|
+
SourceName: 'Association Bylaws PDF',
|
|
898
|
+
Locator: 'Article IV > §4.2',
|
|
899
|
+
AuthorityTier: 'Bylaws (100)',
|
|
900
|
+
Snippet: 'A member whose dues remain unpaid 60 days after the renewal date shall be suspended.',
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
ChunkID: ID_CHUNK_MANUAL,
|
|
904
|
+
SourceName: 'Staff Desk Manual',
|
|
905
|
+
Locator: 'Chapter 3 > Grace Handling',
|
|
906
|
+
AuthorityTier: 'DeptPractice (40)',
|
|
907
|
+
Snippet: 'Customer service reps wait 90 days before deactivating member portal access.',
|
|
908
|
+
},
|
|
909
|
+
];
|
|
910
|
+
const sampleGroundingsGrace = [
|
|
911
|
+
{
|
|
912
|
+
EdgeLabel: 'Defines',
|
|
913
|
+
TargetEntityName: 'MJ: Entity Alternate Base Views',
|
|
914
|
+
TargetRecordID: ID_ABV_GRACE,
|
|
915
|
+
TargetDisplayName: 'MembersInGracePeriod (vwUsers)',
|
|
916
|
+
},
|
|
917
|
+
];
|
|
918
|
+
const sampleGroundingsMetric = [
|
|
919
|
+
{
|
|
920
|
+
EdgeLabel: 'Measures',
|
|
921
|
+
TargetEntityName: 'MJ: Queries',
|
|
922
|
+
TargetRecordID: ID_QUERY_RETENTION,
|
|
923
|
+
TargetDisplayName: 'Golden Query: Annual Cohort Retention',
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
EdgeLabel: 'Defines',
|
|
927
|
+
TargetEntityName: 'MJ: Entity Alternate Base Views',
|
|
928
|
+
TargetRecordID: ID_ABV_ACTIVE,
|
|
929
|
+
TargetDisplayName: 'Active Subscribers (vwUsers)',
|
|
930
|
+
},
|
|
931
|
+
];
|
|
932
|
+
this.rawNodes = [
|
|
933
|
+
{
|
|
934
|
+
ID: ID_DOMAIN_GOV,
|
|
935
|
+
Label: 'Membership Governance',
|
|
936
|
+
Sublabel: 'Domain · Bylaws',
|
|
937
|
+
Category: 'Domain',
|
|
938
|
+
Rank: 50,
|
|
939
|
+
Badge: '#50',
|
|
940
|
+
Status: 'Approved',
|
|
941
|
+
AuthorityTier: 'Bylaws (100)',
|
|
942
|
+
Description: 'Umbrella governance domain for member standing, eligibility, dues billing, and suspension rules.',
|
|
943
|
+
Specification: '### Scope\nCovers all active membership classes, renewal cycles, and standing transitions across national and chapter tiers.',
|
|
944
|
+
Data: { EntityName: 'MJ: Graph Concepts', RecordID: ID_DOMAIN_GOV },
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
ID: ID_POLICY_GRACE,
|
|
948
|
+
Label: 'Renewal Grace Period',
|
|
949
|
+
Sublabel: 'Policy · Bylaws',
|
|
950
|
+
Category: 'Policy',
|
|
951
|
+
Rank: 10,
|
|
952
|
+
Badge: '#10',
|
|
953
|
+
ParentID: ID_DOMAIN_GOV,
|
|
954
|
+
Status: 'Proposed',
|
|
955
|
+
AuthorityTier: 'Bylaws (100)',
|
|
956
|
+
Description: 'Members have 60 calendar days after invoice due date before benefits are suspended.',
|
|
957
|
+
Specification: '### Canonical Rule (Bylaws Precedence)\n- Grace Window: Strictly 60 calendar days past invoice due date.\n- Late Notice: Triggered at day 30 and day 45.\n- Overrides the 90-day informal practice in the Staff Desk Manual.',
|
|
958
|
+
Conflicts: [conflictDetail],
|
|
959
|
+
Groundings: sampleGroundingsGrace,
|
|
960
|
+
ProvenanceChunks: sampleChunks,
|
|
961
|
+
Data: { EntityName: 'MJ: Graph Concepts', RecordID: ID_POLICY_GRACE },
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
ID: ID_METRIC_NRR,
|
|
965
|
+
Label: 'Net Member Retention Rate',
|
|
966
|
+
Sublabel: 'Metric · ExecutiveSOP',
|
|
967
|
+
Category: 'Metric',
|
|
968
|
+
Rank: 20,
|
|
969
|
+
Badge: '#20',
|
|
970
|
+
ParentID: ID_DOMAIN_GOV,
|
|
971
|
+
Status: 'Approved',
|
|
972
|
+
AuthorityTier: 'ExecutiveSOP (60)',
|
|
973
|
+
Description: 'Percentage of active cohort members renewing within the 60-day grace window.',
|
|
974
|
+
Specification: '### Formula\nRenewedActiveMembers / PriorPeriodActiveSubscribers * 100',
|
|
975
|
+
Groundings: sampleGroundingsMetric,
|
|
976
|
+
Data: { EntityName: 'MJ: Graph Concepts', RecordID: ID_METRIC_NRR },
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
ID: ID_PROCESS_RENEWAL,
|
|
980
|
+
Label: 'Dues Renewal & Escalation',
|
|
981
|
+
Sublabel: 'Process · ExecutiveSOP',
|
|
982
|
+
Category: 'Process',
|
|
983
|
+
Rank: 30,
|
|
984
|
+
Badge: '#30',
|
|
985
|
+
ParentID: ID_DOMAIN_GOV,
|
|
986
|
+
Status: 'Proposed',
|
|
987
|
+
AuthorityTier: 'ExecutiveSOP (60)',
|
|
988
|
+
Description: 'End-to-end invoice dispatch, D&B credit check, 60-day grace monitoring, and suspension workflow.',
|
|
989
|
+
Specification: '### Steps\n1. Dispatch invoice 30 days prior to expiration.\n2. Run credit risk check for enterprise tiers.\n3. Enforce 60-day Renewal Grace Period.',
|
|
990
|
+
Groundings: [
|
|
991
|
+
{
|
|
992
|
+
EdgeLabel: 'Defines',
|
|
993
|
+
TargetEntityName: 'MJ: Entity Alternate Base Views',
|
|
994
|
+
TargetRecordID: ID_ABV_GRACE,
|
|
995
|
+
TargetDisplayName: 'MembersInGracePeriod (vwUsers)',
|
|
996
|
+
},
|
|
997
|
+
],
|
|
998
|
+
Data: { EntityName: 'MJ: Graph Concepts', RecordID: ID_PROCESS_RENEWAL },
|
|
999
|
+
},
|
|
1000
|
+
{
|
|
1001
|
+
ID: ID_ROLE_STEWARD,
|
|
1002
|
+
Label: 'Finance Policy Steward',
|
|
1003
|
+
Sublabel: 'Role · Bylaws',
|
|
1004
|
+
Category: 'Role',
|
|
1005
|
+
Rank: 40,
|
|
1006
|
+
Badge: '#40',
|
|
1007
|
+
ParentID: ID_DOMAIN_GOV,
|
|
1008
|
+
Status: 'Approved',
|
|
1009
|
+
AuthorityTier: 'Bylaws (100)',
|
|
1010
|
+
Description: 'Designated officer authorized to approve grace waivers and canon policy updates.',
|
|
1011
|
+
Specification: '### Authority\nApproves Proposed GraphConcepts in the Association Core Canon and resolves Contradicts edges.',
|
|
1012
|
+
Data: { EntityName: 'MJ: Graph Concepts', RecordID: ID_ROLE_STEWARD },
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
ID: ID_ABV_ACTIVE,
|
|
1016
|
+
Label: 'ABV: Active Subscribers',
|
|
1017
|
+
Sublabel: 'MJ: Entity Alternate Base Views',
|
|
1018
|
+
Category: 'grounding',
|
|
1019
|
+
Badge: '⚡',
|
|
1020
|
+
Radius: 21,
|
|
1021
|
+
Status: 'Approved',
|
|
1022
|
+
AuthorityTier: 'Schema Grounded',
|
|
1023
|
+
Description: 'Governed SQL cohort view filtering active paid members.',
|
|
1024
|
+
Specification: "WHERE Status = 'Active' AND PaidThroughDate >= GETUTCDATE()",
|
|
1025
|
+
Data: { EntityName: 'MJ: Entity Alternate Base Views', RecordID: ID_ABV_ACTIVE },
|
|
1026
|
+
},
|
|
1027
|
+
{
|
|
1028
|
+
ID: ID_QUERY_RETENTION,
|
|
1029
|
+
Label: 'Query: Cohort Retention',
|
|
1030
|
+
Sublabel: 'MJ: Queries',
|
|
1031
|
+
Category: 'grounding',
|
|
1032
|
+
Badge: '⚡',
|
|
1033
|
+
Radius: 21,
|
|
1034
|
+
Status: 'Approved',
|
|
1035
|
+
AuthorityTier: 'Schema Grounded',
|
|
1036
|
+
Description: 'Verified Golden Query computing trailing 12-month cohort retention.',
|
|
1037
|
+
Data: { EntityName: 'MJ: Queries', RecordID: ID_QUERY_RETENTION },
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
ID: ID_CHUNK_BYLAWS,
|
|
1041
|
+
Label: 'Bylaws §4.2 ("60 days")',
|
|
1042
|
+
Sublabel: 'Association Bylaws PDF',
|
|
1043
|
+
Category: 'chunk',
|
|
1044
|
+
Badge: '§',
|
|
1045
|
+
Radius: 20,
|
|
1046
|
+
Status: 'Approved',
|
|
1047
|
+
AuthorityTier: 'Bylaws (100)',
|
|
1048
|
+
Description: 'Authoritative chunk from Association Bylaws Article IV §4.2.',
|
|
1049
|
+
Specification: '"A member whose dues remain unpaid 60 days after the renewal date shall be suspended from good standing."',
|
|
1050
|
+
Data: { EntityName: 'MJ: Graph Concepts', RecordID: ID_CHUNK_BYLAWS },
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
ID: ID_CHUNK_MANUAL,
|
|
1054
|
+
Label: 'Desk Manual p.42 ("90 days")',
|
|
1055
|
+
Sublabel: 'Staff Desk Manual',
|
|
1056
|
+
Category: 'chunk',
|
|
1057
|
+
Badge: '§',
|
|
1058
|
+
Radius: 20,
|
|
1059
|
+
Status: 'Proposed',
|
|
1060
|
+
AuthorityTier: 'DeptPractice (40)',
|
|
1061
|
+
Description: 'Conflicting lower-authority chunk from Staff Desk Manual Ch. 3.',
|
|
1062
|
+
Specification: '"Customer service reps wait 90 days before deactivating member portal access."',
|
|
1063
|
+
Conflicts: [conflictDetail],
|
|
1064
|
+
Data: { EntityName: 'MJ: Graph Concepts', RecordID: ID_CHUNK_MANUAL },
|
|
1065
|
+
},
|
|
1066
|
+
];
|
|
1067
|
+
this.rawEdges = [
|
|
1068
|
+
{ ID: 'e-1', SourceID: ID_DOMAIN_GOV, TargetID: ID_POLICY_GRACE, Label: 'Broader Than', Direction: 'directed' },
|
|
1069
|
+
{ ID: 'e-2', SourceID: ID_DOMAIN_GOV, TargetID: ID_METRIC_NRR, Label: 'Broader Than', Direction: 'directed' },
|
|
1070
|
+
{ ID: 'e-3', SourceID: ID_DOMAIN_GOV, TargetID: ID_PROCESS_RENEWAL, Label: 'Broader Than', Direction: 'directed' },
|
|
1071
|
+
{ ID: 'e-4', SourceID: ID_ROLE_STEWARD, TargetID: ID_POLICY_GRACE, Label: 'Governs', Direction: 'directed' },
|
|
1072
|
+
{ ID: 'e-5', SourceID: ID_METRIC_NRR, TargetID: ID_ABV_ACTIVE, Label: 'Defines', Direction: 'directed' },
|
|
1073
|
+
{ ID: 'e-6', SourceID: ID_METRIC_NRR, TargetID: ID_QUERY_RETENTION, Label: 'Measures', Direction: 'directed' },
|
|
1074
|
+
{ ID: 'e-7', SourceID: ID_POLICY_GRACE, TargetID: ID_CHUNK_BYLAWS, Label: 'SourcedFrom', Direction: 'directed', Style: 'dotted' },
|
|
1075
|
+
{ ID: 'e-8', SourceID: ID_POLICY_GRACE, TargetID: ID_CHUNK_MANUAL, Label: 'SourcedFrom', Direction: 'directed', Style: 'dotted' },
|
|
1076
|
+
{
|
|
1077
|
+
ID: 'e-conflict-1',
|
|
1078
|
+
SourceID: ID_CHUNK_BYLAWS,
|
|
1079
|
+
TargetID: ID_CHUNK_MANUAL,
|
|
1080
|
+
Label: 'Contradicts (60d vs 90d)',
|
|
1081
|
+
Direction: 'directed',
|
|
1082
|
+
Style: 'dashed',
|
|
1083
|
+
Color: '#f43f5e',
|
|
1084
|
+
Animated: true,
|
|
1085
|
+
Weight: 2.5,
|
|
1086
|
+
},
|
|
1087
|
+
];
|
|
1088
|
+
this.SelectedNodeId = ID_POLICY_GRACE;
|
|
1089
|
+
}
|
|
1090
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵSemanticGraphExplorerComponent_BaseFactory; return function SemanticGraphExplorerComponent_Factory(__ngFactoryType__) { return (ɵSemanticGraphExplorerComponent_BaseFactory || (ɵSemanticGraphExplorerComponent_BaseFactory = i0.ɵɵgetInheritedFactory(SemanticGraphExplorerComponent)))(__ngFactoryType__ || SemanticGraphExplorerComponent); }; })();
|
|
1091
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SemanticGraphExplorerComponent, selectors: [["app-kh-semantic-graph"]], inputs: { Provider: "Provider" }, outputs: { OpenRecordRequested: "OpenRecordRequested", ConceptSelected: "ConceptSelected" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 45, vars: 10, consts: [["canonInspectorTemplate", ""], [1, "semantic-graph-studio"], [1, "semantic-graph-rail"], [1, "rail-scroll"], [1, "rail-section"], [1, "rail-section-header"], [1, "rail-section-title"], ["type", "button", "title", "Filter to Graph Types with IsCanon = true", 1, "canon-filter-toggle", 3, "click"], [1, "fa-solid", "fa-star"], [1, "graph-list"], ["type", "button", 1, "graph-card", 3, "selected"], ["type", "button", 1, "rail-reset-btn"], [1, "concept-type-list"], ["type", "button", 1, "concept-type-pill", 3, "active", "dimmed"], [1, "overlay-toggle-list"], [1, "overlay-toggle-row"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], [1, "overlay-toggle-row", "conflict-toggle"], [1, "semantic-graph-canvas"], ["role", "alert", 1, "semantic-graph-alert"], [1, "semantic-graph-empty-banner"], [1, "semantic-graph-loading"], [3, "Title", "Nodes", "Edges", "Categories", "LayoutMode", "SelectedNodeId", "ActiveCategoryFilter", "AutoOpenInspector", "ShowToolbar", "ShowLegend", "ShowInspector", "InspectorCustomTemplate", "Searchable"], ["type", "button", 1, "graph-card", 3, "click"], [1, "graph-card-top"], [1, "graph-card-name"], [1, "graph-card-icon"], [1, "graph-type-badge"], [1, "graph-card-meta"], [1, "conflict-pill"], [1, "fa-solid", "fa-triangle-exclamation"], ["type", "button", 1, "rail-reset-btn", 3, "click"], ["type", "button", 1, "concept-type-pill", 3, "click"], [1, "concept-type-left"], [1, "concept-type-dot"], [1, "concept-type-icon"], [1, "concept-type-name"], [1, "concept-type-right"], [1, "connected-source-list"], [1, "connected-source-row"], [1, "fa-solid", "fa-database"], ["type", "button", 1, "sample-preview-btn", 3, "click"], ["text", "Loading Semantic Graph & Canon concepts..."], [3, "NodeSelected", "NodeNavigated", "NodeAction", "CategoryFilterChanged", "Title", "Nodes", "Edges", "Categories", "LayoutMode", "SelectedNodeId", "ActiveCategoryFilter", "AutoOpenInspector", "ShowToolbar", "ShowLegend", "ShowInspector", "InspectorCustomTemplate", "Searchable"], [1, "canon-inspector-section"], [1, "canon-conflict-box"], [1, "canon-inspector-section-label"], [1, "canon-inspector-spec"], [1, "canon-conflict-title"], [1, "canon-conflict-details"], [1, "canon-conflict-note"], [1, "canon-grounding-list"], ["type", "button", 1, "canon-grounding-item"], ["type", "button", 1, "canon-grounding-item", 3, "click"], [1, "canon-grounding-edge"], [1, "canon-grounding-target"], [1, "fa-solid", "fa-arrow-up-right-from-square", "canon-grounding-icon"], [1, "canon-chunk-list"], [1, "canon-chunk-card"], [1, "canon-chunk-header"], [1, "canon-chunk-tier"], [1, "canon-chunk-snippet"]], template: function SemanticGraphExplorerComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1092
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
1093
|
+
i0.ɵɵelementStart(0, "div", 1)(1, "aside", 2)(2, "div", 3)(3, "section", 4)(4, "div", 5)(5, "span", 6);
|
|
1094
|
+
i0.ɵɵtext(6, "MJ: Graphs");
|
|
1095
|
+
i0.ɵɵelementEnd();
|
|
1096
|
+
i0.ɵɵelementStart(7, "button", 7);
|
|
1097
|
+
i0.ɵɵlistener("click", function SemanticGraphExplorerComponent_Template_button_click_7_listener() { return ctx.ToggleCanonFilter(); });
|
|
1098
|
+
i0.ɵɵelement(8, "i", 8);
|
|
1099
|
+
i0.ɵɵtext(9, " Canon Only ");
|
|
1100
|
+
i0.ɵɵelementEnd()();
|
|
1101
|
+
i0.ɵɵelementStart(10, "div", 9);
|
|
1102
|
+
i0.ɵɵrepeaterCreate(11, SemanticGraphExplorerComponent_For_12_Template, 12, 12, "button", 10, _forTrack0);
|
|
1103
|
+
i0.ɵɵelementEnd()();
|
|
1104
|
+
i0.ɵɵelementStart(13, "section", 4)(14, "div", 5)(15, "span", 6);
|
|
1105
|
+
i0.ɵɵtext(16, "Concept Types (By Rank)");
|
|
1106
|
+
i0.ɵɵelementEnd();
|
|
1107
|
+
i0.ɵɵconditionalCreate(17, SemanticGraphExplorerComponent_Conditional_17_Template, 2, 0, "button", 11);
|
|
1108
|
+
i0.ɵɵelementEnd();
|
|
1109
|
+
i0.ɵɵelementStart(18, "div", 12);
|
|
1110
|
+
i0.ɵɵrepeaterCreate(19, SemanticGraphExplorerComponent_For_20_Template, 10, 11, "button", 13, _forTrack0);
|
|
1111
|
+
i0.ɵɵelementEnd()();
|
|
1112
|
+
i0.ɵɵelementStart(21, "section", 4)(22, "span", 6);
|
|
1113
|
+
i0.ɵɵtext(23, "Graph Overlays");
|
|
1114
|
+
i0.ɵɵelementEnd();
|
|
1115
|
+
i0.ɵɵelementStart(24, "div", 14)(25, "label", 15)(26, "span");
|
|
1116
|
+
i0.ɵɵtext(27, "Grounded MJ Primitives");
|
|
1117
|
+
i0.ɵɵelementEnd();
|
|
1118
|
+
i0.ɵɵelementStart(28, "input", 16);
|
|
1119
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SemanticGraphExplorerComponent_Template_input_ngModelChange_28_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.ShowGroundedPrimitives, $event) || (ctx.ShowGroundedPrimitives = $event); return i0.ɵɵresetView($event); });
|
|
1120
|
+
i0.ɵɵlistener("ngModelChange", function SemanticGraphExplorerComponent_Template_input_ngModelChange_28_listener() { return ctx.OnOverlayToggleChanged(); });
|
|
1121
|
+
i0.ɵɵelementEnd()();
|
|
1122
|
+
i0.ɵɵelementStart(29, "label", 15)(30, "span");
|
|
1123
|
+
i0.ɵɵtext(31, "Source Chunks (SourcedFrom)");
|
|
1124
|
+
i0.ɵɵelementEnd();
|
|
1125
|
+
i0.ɵɵelementStart(32, "input", 16);
|
|
1126
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SemanticGraphExplorerComponent_Template_input_ngModelChange_32_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.ShowSourceChunks, $event) || (ctx.ShowSourceChunks = $event); return i0.ɵɵresetView($event); });
|
|
1127
|
+
i0.ɵɵlistener("ngModelChange", function SemanticGraphExplorerComponent_Template_input_ngModelChange_32_listener() { return ctx.OnOverlayToggleChanged(); });
|
|
1128
|
+
i0.ɵɵelementEnd()();
|
|
1129
|
+
i0.ɵɵelementStart(33, "label", 17)(34, "span");
|
|
1130
|
+
i0.ɵɵtext(35, "Highlight Contradicts Edges");
|
|
1131
|
+
i0.ɵɵelementEnd();
|
|
1132
|
+
i0.ɵɵelementStart(36, "input", 16);
|
|
1133
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SemanticGraphExplorerComponent_Template_input_ngModelChange_36_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.HighlightConflicts, $event) || (ctx.HighlightConflicts = $event); return i0.ɵɵresetView($event); });
|
|
1134
|
+
i0.ɵɵlistener("ngModelChange", function SemanticGraphExplorerComponent_Template_input_ngModelChange_36_listener() { return ctx.OnOverlayToggleChanged(); });
|
|
1135
|
+
i0.ɵɵelementEnd()()()();
|
|
1136
|
+
i0.ɵɵconditionalCreate(37, SemanticGraphExplorerComponent_Conditional_37_Template, 6, 0, "section", 4);
|
|
1137
|
+
i0.ɵɵelementEnd()();
|
|
1138
|
+
i0.ɵɵelementStart(38, "main", 18);
|
|
1139
|
+
i0.ɵɵconditionalCreate(39, SemanticGraphExplorerComponent_Conditional_39_Template, 4, 1, "div", 19);
|
|
1140
|
+
i0.ɵɵconditionalCreate(40, SemanticGraphExplorerComponent_Conditional_40_Template, 5, 0, "div", 20);
|
|
1141
|
+
i0.ɵɵconditionalCreate(41, SemanticGraphExplorerComponent_Conditional_41_Template, 2, 0, "div", 21)(42, SemanticGraphExplorerComponent_Conditional_42_Template, 1, 13, "mj-graph-view", 22);
|
|
1142
|
+
i0.ɵɵtemplate(43, SemanticGraphExplorerComponent_ng_template_43_Template, 4, 4, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
|
|
1143
|
+
i0.ɵɵelementEnd()();
|
|
1144
|
+
} if (rf & 2) {
|
|
1145
|
+
i0.ɵɵadvance(7);
|
|
1146
|
+
i0.ɵɵclassProp("active", ctx.OnlyCanonGraphs);
|
|
1147
|
+
i0.ɵɵadvance(4);
|
|
1148
|
+
i0.ɵɵrepeater(ctx.VisibleGraphOptions);
|
|
1149
|
+
i0.ɵɵadvance(6);
|
|
1150
|
+
i0.ɵɵconditional(ctx.ActiveConceptTypeFilter ? 17 : -1);
|
|
1151
|
+
i0.ɵɵadvance(2);
|
|
1152
|
+
i0.ɵɵrepeater(ctx.ConceptTypeOptions);
|
|
1153
|
+
i0.ɵɵadvance(9);
|
|
1154
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.ShowGroundedPrimitives);
|
|
1155
|
+
i0.ɵɵadvance(4);
|
|
1156
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.ShowSourceChunks);
|
|
1157
|
+
i0.ɵɵadvance(4);
|
|
1158
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx.HighlightConflicts);
|
|
1159
|
+
i0.ɵɵadvance();
|
|
1160
|
+
i0.ɵɵconditional(ctx.SelectedGraph && ctx.SelectedGraph.SourceNames.length > 0 ? 37 : -1);
|
|
1161
|
+
i0.ɵɵadvance(2);
|
|
1162
|
+
i0.ɵɵconditional(ctx.LoadError || ctx.ActionError ? 39 : -1);
|
|
1163
|
+
i0.ɵɵadvance();
|
|
1164
|
+
i0.ɵɵconditional(!ctx.IsLoading && ctx.Nodes.length === 0 ? 40 : -1);
|
|
1165
|
+
i0.ɵɵadvance();
|
|
1166
|
+
i0.ɵɵconditional(ctx.IsLoading ? 41 : 42);
|
|
1167
|
+
} }, dependencies: [i1.CheckboxControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent, i3.GraphViewComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex: 1;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n}\n\n.semantic-graph-studio[_ngcontent-%COMP%] {\n display: flex;\n flex: 1;\n width: 100%;\n height: 100%;\n min-height: 0;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken, #0b1220);\n}\n\n.semantic-graph-rail[_ngcontent-%COMP%] {\n width: 290px;\n flex-shrink: 0;\n background: var(--mj-bg-surface, #111a2e);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: var(--mj-radius-lg, 12px);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.rail-scroll[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 14px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.rail-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rail-section[_ngcontent-%COMP%] + .rail-section[_ngcontent-%COMP%] {\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-default, #223254);\n}\n\n.rail-section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.rail-section-title[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted, #64748b);\n}\n\n.canon-filter-toggle[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 9999px;\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n background: color-mix(in srgb, var(--mj-status-warning) 12%, transparent);\n color: var(--mj-status-warning);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n transition: all 0.15s ease;\n}\n\n.canon-filter-toggle.active[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n color: var(--mj-text-inverse);\n border-color: var(--mj-status-warning);\n}\n\n.rail-reset-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.graph-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.graph-card[_ngcontent-%COMP%] {\n width: 100%;\n text-align: left;\n padding: 9px 10px;\n border-radius: 8px;\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n color: var(--mj-text-primary, #f8fafc);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.graph-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary, #38bdf8);\n}\n\n.graph-card.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary, #38bdf8);\n background: var(--mj-bg-surface-elevated, #1a2744);\n}\n\n.graph-card-top[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n}\n\n.graph-card-name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.graph-card-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 11px;\n}\n\n.graph-type-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.graph-type-badge.is-canon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 18%, transparent);\n color: var(--mj-status-warning);\n}\n\n.graph-card-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.conflict-pill[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.concept-type-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n\n.concept-type-pill[_ngcontent-%COMP%] {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 9px;\n border-radius: 7px;\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n color: var(--mj-text-primary, #f8fafc);\n font-size: 11.5px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.concept-type-pill[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary, #38bdf8);\n}\n\n.concept-type-pill.active[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary, #38bdf8);\n background: var(--mj-bg-surface-elevated, #1a2744);\n}\n\n.concept-type-pill.dimmed[_ngcontent-%COMP%] {\n opacity: 0.45;\n}\n\n.concept-type-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: 600;\n}\n\n.concept-type-dot[_ngcontent-%COMP%] {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n\n.concept-type-icon[_ngcontent-%COMP%] {\n font-size: 11px;\n opacity: 0.85;\n}\n\n.concept-type-right[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.overlay-toggle-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.overlay-toggle-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 11.5px;\n color: var(--mj-text-secondary, #94a3b8);\n cursor: pointer;\n}\n\n.overlay-toggle-row.conflict-toggle[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n font-weight: 600;\n}\n\n.semantic-graph-alert[_ngcontent-%COMP%] {\n position: absolute;\n top: 64px;\n left: 14px;\n z-index: 30;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n color: var(--mj-status-error);\n font-size: 12px;\n font-weight: 600;\n}\n\n.semantic-graph-empty-banner[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 64px;\n left: 14px;\n z-index: 25;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-secondary);\n font-size: 11.5px;\n}\n\n.sample-preview-btn[_ngcontent-%COMP%] {\n padding: 4px 10px;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.connected-source-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n\n.connected-source-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 8px;\n border-radius: 6px;\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n font-size: 11px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.semantic-graph-canvas[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n position: relative;\n}\n\n.semantic-graph-loading[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface, #111a2e);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: var(--mj-radius-lg, 12px);\n}\n\n.canon-inspector-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 10px 12px;\n font-size: 11.5px;\n color: var(--mj-text-primary);\n}\n\n.canon-inspector-section-label[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted);\n margin-bottom: 6px;\n display: block;\n}\n\n.canon-inspector-spec[_ngcontent-%COMP%] {\n margin: 0;\n white-space: pre-wrap;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.45;\n color: var(--mj-text-primary);\n}\n\n.canon-conflict-box[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n border-radius: 8px;\n padding: 10px 12px;\n font-size: 11.5px;\n color: var(--mj-text-primary);\n}\n\n.canon-conflict-title[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-status-error);\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.canon-conflict-details[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 11px;\n}\n\n.canon-conflict-note[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n margin-top: 2px;\n}\n\n.canon-grounding-list[_ngcontent-%COMP%], \n.canon-chunk-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.canon-grounding-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: border-color 0.15s ease;\n width: 100%;\n text-align: left;\n color: var(--mj-text-primary);\n font-size: 11px;\n}\n\n.canon-grounding-item[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-status-success);\n}\n\n.canon-grounding-edge[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n font-weight: 700;\n}\n\n.canon-grounding-target[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n}\n\n.canon-grounding-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.canon-chunk-card[_ngcontent-%COMP%] {\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n font-size: 11px;\n}\n\n.canon-chunk-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-weight: 600;\n margin-bottom: 3px;\n}\n\n.canon-chunk-tier[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 10px;\n}\n\n.canon-chunk-snippet[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n line-height: 1.4;\n}"] });
|
|
1168
|
+
}
|
|
1169
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SemanticGraphExplorerComponent, [{
|
|
1170
|
+
type: Component,
|
|
1171
|
+
args: [{ standalone: false, selector: 'app-kh-semantic-graph', template: "<div class=\"semantic-graph-studio\">\n <!-- Left Rail: MJ: Graphs Selector, Ranked MJ: Graph Concept Types, Overlays & Connected Sources -->\n <aside class=\"semantic-graph-rail\">\n <div class=\"rail-scroll\">\n <!-- 1. MJ: Graphs Partition Selector -->\n <section class=\"rail-section\">\n <div class=\"rail-section-header\">\n <span class=\"rail-section-title\">MJ: Graphs</span>\n <button\n type=\"button\"\n class=\"canon-filter-toggle\"\n [class.active]=\"OnlyCanonGraphs\"\n (click)=\"ToggleCanonFilter()\"\n title=\"Filter to Graph Types with IsCanon = true\">\n <i class=\"fa-solid fa-star\"></i>\n Canon Only\n </button>\n </div>\n\n <div class=\"graph-list\">\n @for (g of VisibleGraphOptions; track g.ID) {\n <button\n type=\"button\"\n class=\"graph-card\"\n [class.selected]=\"SelectedGraph?.ID === g.ID\"\n (click)=\"SelectGraph(g.ID)\">\n <div class=\"graph-card-top\">\n <span class=\"graph-card-name\">\n <i [class]=\"g.IconClass\" class=\"graph-card-icon\"></i>\n {{ g.Name }}\n </span>\n <span class=\"graph-type-badge\" [class.is-canon]=\"g.IsCanon\">\n @if (g.IsCanon) { \u2605 } {{ g.GraphTypeName }} \u00B7 #{{ g.GraphTypeRank }}\n </span>\n </div>\n <div class=\"graph-card-meta\">\n <span>{{ g.ConceptCount }} concepts</span>\n @if (g.ConflictCount > 0) {\n <span class=\"conflict-pill\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n {{ g.ConflictCount }} {{ g.ConflictCount === 1 ? 'conflict' : 'conflicts' }}\n </span>\n }\n </div>\n </button>\n }\n </div>\n </section>\n\n <!-- 2. Ranked MJ: Graph Concept Types Filter -->\n <section class=\"rail-section\">\n <div class=\"rail-section-header\">\n <span class=\"rail-section-title\">Concept Types (By Rank)</span>\n @if (ActiveConceptTypeFilter) {\n <button type=\"button\" class=\"rail-reset-btn\" (click)=\"ToggleConceptTypeFilter(null)\">\n All\n </button>\n }\n </div>\n\n <div class=\"concept-type-list\">\n @for (ct of ConceptTypeOptions; track ct.ID) {\n <button\n type=\"button\"\n class=\"concept-type-pill\"\n [class.active]=\"ActiveConceptTypeFilter?.toLowerCase() === ct.Name.toLowerCase()\"\n [class.dimmed]=\"ActiveConceptTypeFilter && ActiveConceptTypeFilter.toLowerCase() !== ct.Name.toLowerCase()\"\n (click)=\"ToggleConceptTypeFilter(ct.Name)\">\n <span class=\"concept-type-left\">\n <span class=\"concept-type-dot\" [style.background]=\"ct.Color\"></span>\n <i [class]=\"ct.IconClass\" class=\"concept-type-icon\"></i>\n <span class=\"concept-type-name\">{{ ct.Name }}</span>\n </span>\n <span class=\"concept-type-right\">\n Rank #{{ ct.Rank }} \u00B7 <strong>{{ ct.Count }}</strong>\n </span>\n </button>\n }\n </div>\n </section>\n\n <!-- 3. Edge & Node Overlay Toggles -->\n <section class=\"rail-section\">\n <span class=\"rail-section-title\">Graph Overlays</span>\n <div class=\"overlay-toggle-list\">\n <label class=\"overlay-toggle-row\">\n <span>Grounded MJ Primitives</span>\n <input\n type=\"checkbox\"\n [(ngModel)]=\"ShowGroundedPrimitives\"\n (ngModelChange)=\"OnOverlayToggleChanged()\" />\n </label>\n <label class=\"overlay-toggle-row\">\n <span>Source Chunks (SourcedFrom)</span>\n <input\n type=\"checkbox\"\n [(ngModel)]=\"ShowSourceChunks\"\n (ngModelChange)=\"OnOverlayToggleChanged()\" />\n </label>\n <label class=\"overlay-toggle-row conflict-toggle\">\n <span>Highlight Contradicts Edges</span>\n <input\n type=\"checkbox\"\n [(ngModel)]=\"HighlightConflicts\"\n (ngModelChange)=\"OnOverlayToggleChanged()\" />\n </label>\n </div>\n </section>\n\n <!-- 4. Connected Content Sources -->\n @if (SelectedGraph && SelectedGraph.SourceNames.length > 0) {\n <section class=\"rail-section\">\n <span class=\"rail-section-title\">Connected Content Sources</span>\n <div class=\"connected-source-list\">\n @for (srcName of SelectedGraph.SourceNames; track srcName) {\n <div class=\"connected-source-row\">\n <i class=\"fa-solid fa-database\"></i>\n <span>{{ srcName }}</span>\n </div>\n }\n </div>\n </section>\n }\n </div>\n </aside>\n\n <!-- Main Canvas: <mj-graph-view> with Force/Hierarchy/Circular Layouts & Projected Canon Inspector -->\n <main class=\"semantic-graph-canvas\">\n @if (LoadError || ActionError) {\n <div class=\"semantic-graph-alert\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ LoadError || ActionError }}</span>\n </div>\n }\n\n @if (!IsLoading && Nodes.length === 0) {\n <div class=\"semantic-graph-empty-banner\">\n <span>No concepts or edges in this graph yet.</span>\n <button type=\"button\" class=\"sample-preview-btn\" (click)=\"LoadSampleGraphPreview()\">\n Load Example Canon Graph\n </button>\n </div>\n }\n\n @if (IsLoading) {\n <div class=\"semantic-graph-loading\">\n <mj-loading text=\"Loading Semantic Graph & Canon concepts...\"></mj-loading>\n </div>\n } @else {\n <mj-graph-view\n [Title]=\"SelectedGraph?.Name || 'Semantic Graph'\"\n [Nodes]=\"Nodes\"\n [Edges]=\"Edges\"\n [Categories]=\"Categories\"\n [LayoutMode]=\"LayoutMode\"\n [SelectedNodeId]=\"SelectedNodeId\"\n [ActiveCategoryFilter]=\"ActiveConceptTypeFilter\"\n [AutoOpenInspector]=\"true\"\n [ShowToolbar]=\"true\"\n [ShowLegend]=\"true\"\n [ShowInspector]=\"true\"\n [InspectorCustomTemplate]=\"canonInspectorTemplate\"\n [Searchable]=\"true\"\n (NodeSelected)=\"OnNodeSelected($event)\"\n (NodeNavigated)=\"OnNodeNavigated($event)\"\n (NodeAction)=\"OnNodeAction($event)\"\n (CategoryFilterChanged)=\"OnCategoryFilterChangedFromCanvas($event)\">\n </mj-graph-view>\n }\n\n <ng-template #canonInspectorTemplate let-node>\n @if (node.Specification) {\n <div class=\"canon-inspector-section\">\n <span class=\"canon-inspector-section-label\">Specification</span>\n <pre class=\"canon-inspector-spec\">{{ node.Specification }}</pre>\n </div>\n }\n\n @if (node.Conflicts && node.Conflicts.length > 0) {\n <div class=\"canon-conflict-box\">\n <div class=\"canon-conflict-title\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n Authority Conflict (Contradicts Edge)\n </div>\n @for (conflict of node.Conflicts; track conflict.HigherAuthoritySummary) {\n <div class=\"canon-conflict-details\">\n <div><strong>Higher Tier:</strong> {{ conflict.HigherAuthoritySummary }}</div>\n <div><strong>Conflicting:</strong> {{ conflict.ConflictingSummary }}</div>\n @if (conflict.ResolutionNote) {\n <div class=\"canon-conflict-note\">{{ conflict.ResolutionNote }}</div>\n }\n </div>\n }\n </div>\n }\n\n @if (node.Groundings && node.Groundings.length > 0) {\n <div class=\"canon-inspector-section\">\n <span class=\"canon-inspector-section-label\">Grounded MJ Primitives ({{ node.Groundings.length }})</span>\n <div class=\"canon-grounding-list\">\n @for (g of node.Groundings; track g.TargetRecordID + g.EdgeLabel) {\n <button\n type=\"button\"\n class=\"canon-grounding-item\"\n (click)=\"OpenGroundingRecord(g)\">\n <span class=\"canon-grounding-edge\">{{ g.EdgeLabel }}</span>\n <span class=\"canon-grounding-target\">{{ g.TargetDisplayName }}</span>\n <i class=\"fa-solid fa-arrow-up-right-from-square canon-grounding-icon\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n @if (node.ProvenanceChunks && node.ProvenanceChunks.length > 0) {\n <div class=\"canon-inspector-section\">\n <span class=\"canon-inspector-section-label\">SourcedFrom Chunks ({{ node.ProvenanceChunks.length }})</span>\n <div class=\"canon-chunk-list\">\n @for (chunk of node.ProvenanceChunks; track chunk.ChunkID) {\n <div class=\"canon-chunk-card\">\n <div class=\"canon-chunk-header\">\n <span>{{ chunk.SourceName }}{{ chunk.Locator ? ' \u00B7 ' + chunk.Locator : '' }}</span>\n @if (chunk.AuthorityTier) {\n <span class=\"canon-chunk-tier\">{{ chunk.AuthorityTier }}</span>\n }\n </div>\n <div class=\"canon-chunk-snippet\">{{ chunk.Snippet }}</div>\n </div>\n }\n </div>\n </div>\n }\n </ng-template>\n </main>\n</div>\n", styles: [":host {\n display: flex;\n flex: 1;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n}\n\n.semantic-graph-studio {\n display: flex;\n flex: 1;\n width: 100%;\n height: 100%;\n min-height: 0;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken, #0b1220);\n}\n\n.semantic-graph-rail {\n width: 290px;\n flex-shrink: 0;\n background: var(--mj-bg-surface, #111a2e);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: var(--mj-radius-lg, 12px);\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.rail-scroll {\n flex: 1;\n overflow-y: auto;\n padding: 14px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.rail-section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.rail-section + .rail-section {\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-default, #223254);\n}\n\n.rail-section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n\n.rail-section-title {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted, #64748b);\n}\n\n.canon-filter-toggle {\n font-size: 11px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 9999px;\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 35%, transparent);\n background: color-mix(in srgb, var(--mj-status-warning) 12%, transparent);\n color: var(--mj-status-warning);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n transition: all 0.15s ease;\n}\n\n.canon-filter-toggle.active {\n background: var(--mj-status-warning);\n color: var(--mj-text-inverse);\n border-color: var(--mj-status-warning);\n}\n\n.rail-reset-btn {\n background: none;\n border: none;\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.graph-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.graph-card {\n width: 100%;\n text-align: left;\n padding: 9px 10px;\n border-radius: 8px;\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n color: var(--mj-text-primary, #f8fafc);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.graph-card:hover {\n border-color: var(--mj-brand-primary, #38bdf8);\n}\n\n.graph-card.selected {\n border-color: var(--mj-brand-primary, #38bdf8);\n background: var(--mj-bg-surface-elevated, #1a2744);\n}\n\n.graph-card-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n}\n\n.graph-card-name {\n font-size: 12px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.graph-card-icon {\n color: var(--mj-brand-primary, #38bdf8);\n font-size: 11px;\n}\n\n.graph-type-badge {\n font-size: 10px;\n font-weight: 600;\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.graph-type-badge.is-canon {\n background: color-mix(in srgb, var(--mj-status-warning) 18%, transparent);\n color: var(--mj-status-warning);\n}\n\n.graph-card-meta {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 4px;\n font-size: 11px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.conflict-pill {\n color: var(--mj-status-error);\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.concept-type-list {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n\n.concept-type-pill {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 9px;\n border-radius: 7px;\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n color: var(--mj-text-primary, #f8fafc);\n font-size: 11.5px;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.concept-type-pill:hover {\n border-color: var(--mj-brand-primary, #38bdf8);\n}\n\n.concept-type-pill.active {\n border-color: var(--mj-brand-primary, #38bdf8);\n background: var(--mj-bg-surface-elevated, #1a2744);\n}\n\n.concept-type-pill.dimmed {\n opacity: 0.45;\n}\n\n.concept-type-left {\n display: flex;\n align-items: center;\n gap: 7px;\n font-weight: 600;\n}\n\n.concept-type-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n}\n\n.concept-type-icon {\n font-size: 11px;\n opacity: 0.85;\n}\n\n.concept-type-right {\n font-size: 11px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.overlay-toggle-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.overlay-toggle-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 11.5px;\n color: var(--mj-text-secondary, #94a3b8);\n cursor: pointer;\n}\n\n.overlay-toggle-row.conflict-toggle {\n color: var(--mj-status-error);\n font-weight: 600;\n}\n\n.semantic-graph-alert {\n position: absolute;\n top: 64px;\n left: 14px;\n z-index: 30;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md, 8px);\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n color: var(--mj-status-error);\n font-size: 12px;\n font-weight: 600;\n}\n\n.semantic-graph-empty-banner {\n position: absolute;\n bottom: 64px;\n left: 14px;\n z-index: 25;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md, 8px);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-secondary);\n font-size: 11.5px;\n}\n\n.sample-preview-btn {\n padding: 4px 10px;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.connected-source-list {\n display: flex;\n flex-direction: column;\n gap: 5px;\n}\n\n.connected-source-row {\n display: flex;\n align-items: center;\n gap: 7px;\n padding: 5px 8px;\n border-radius: 6px;\n background: var(--mj-bg-surface-sunken, #090e1a);\n border: 1px solid var(--mj-border-default, #223254);\n font-size: 11px;\n color: var(--mj-text-secondary, #94a3b8);\n}\n\n.semantic-graph-canvas {\n flex: 1;\n min-width: 0;\n min-height: 0;\n display: flex;\n position: relative;\n}\n\n.semantic-graph-loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-surface, #111a2e);\n border: 1px solid var(--mj-border-default, #223254);\n border-radius: var(--mj-radius-lg, 12px);\n}\n\n.canon-inspector-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 10px 12px;\n font-size: 11.5px;\n color: var(--mj-text-primary);\n}\n\n.canon-inspector-section-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted);\n margin-bottom: 6px;\n display: block;\n}\n\n.canon-inspector-spec {\n margin: 0;\n white-space: pre-wrap;\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n line-height: 1.45;\n color: var(--mj-text-primary);\n}\n\n.canon-conflict-box {\n background: color-mix(in srgb, var(--mj-status-error) 12%, transparent);\n border: 1px solid color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n border-radius: 8px;\n padding: 10px 12px;\n font-size: 11.5px;\n color: var(--mj-text-primary);\n}\n\n.canon-conflict-title {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-status-error);\n margin-bottom: 6px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.canon-conflict-details {\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 11px;\n}\n\n.canon-conflict-note {\n color: var(--mj-text-secondary);\n margin-top: 2px;\n}\n\n.canon-grounding-list,\n.canon-chunk-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.canon-grounding-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: border-color 0.15s ease;\n width: 100%;\n text-align: left;\n color: var(--mj-text-primary);\n font-size: 11px;\n}\n\n.canon-grounding-item:hover {\n border-color: var(--mj-status-success);\n}\n\n.canon-grounding-edge {\n color: var(--mj-status-success);\n font-weight: 700;\n}\n\n.canon-grounding-target {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n}\n\n.canon-grounding-icon {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.canon-chunk-card {\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n font-size: 11px;\n}\n\n.canon-chunk-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-weight: 600;\n margin-bottom: 3px;\n}\n\n.canon-chunk-tier {\n color: var(--mj-status-warning);\n font-size: 10px;\n}\n\n.canon-chunk-snippet {\n color: var(--mj-text-secondary);\n line-height: 1.4;\n}\n"] }]
|
|
1172
|
+
}], null, { Provider: [{
|
|
1173
|
+
type: Input
|
|
1174
|
+
}], OpenRecordRequested: [{
|
|
1175
|
+
type: Output
|
|
1176
|
+
}], ConceptSelected: [{
|
|
1177
|
+
type: Output
|
|
1178
|
+
}] }); })();
|
|
1179
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SemanticGraphExplorerComponent, { className: "SemanticGraphExplorerComponent", filePath: "src/KnowledgeHub/components/visualize/semantic-graph/semantic-graph-explorer.component.ts", lineNumber: 118 }); })();
|
|
1180
|
+
/** Tree-shaking prevention */
|
|
1181
|
+
export function LoadSemanticGraphExplorerComponent() {
|
|
1182
|
+
// Prevents tree-shaking of the component
|
|
1183
|
+
}
|
|
1184
|
+
//# sourceMappingURL=semantic-graph-explorer.component.js.map
|