@memberjunction/ng-dashboards 5.23.0 → 5.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +677 -5
  2. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  3. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +6879 -1873
  4. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  5. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +46 -1
  6. package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
  7. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +758 -491
  8. package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
  9. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +19 -0
  10. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  11. package/dist/AI/components/vectors/vector-management-resource.component.js +410 -208
  12. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  13. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  14. package/dist/DataExplorer/data-explorer-dashboard.component.js +17 -17
  15. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  16. package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
  17. package/dist/Integration/components/activity/activity.component.js +1 -0
  18. package/dist/Integration/components/activity/activity.component.js.map +1 -1
  19. package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
  20. package/dist/Integration/components/connections/connections.component.js +1 -0
  21. package/dist/Integration/components/connections/connections.component.js.map +1 -1
  22. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
  23. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +1 -0
  24. package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
  25. package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
  26. package/dist/Integration/components/overview/overview.component.js +1 -0
  27. package/dist/Integration/components/overview/overview.component.js.map +1 -1
  28. package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -1
  29. package/dist/Integration/components/pipelines/pipelines.component.js +1 -0
  30. package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
  31. package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
  32. package/dist/Integration/components/schedules/schedules.component.js +1 -0
  33. package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
  34. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts +411 -0
  35. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -0
  36. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +4266 -0
  37. package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -0
  38. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +35 -1
  39. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
  40. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +186 -13
  41. package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
  42. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +1 -0
  43. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
  44. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +188 -165
  45. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  46. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts +75 -0
  47. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts.map +1 -0
  48. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +601 -0
  49. package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -0
  50. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts +93 -12
  51. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts.map +1 -1
  52. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js +637 -107
  53. package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js.map +1 -1
  54. package/dist/KnowledgeHub/index.d.ts +2 -0
  55. package/dist/KnowledgeHub/index.d.ts.map +1 -1
  56. package/dist/KnowledgeHub/index.js +2 -0
  57. package/dist/KnowledgeHub/index.js.map +1 -1
  58. package/dist/__tests__/analytics-resource.test.d.ts +2 -0
  59. package/dist/__tests__/analytics-resource.test.d.ts.map +1 -0
  60. package/dist/__tests__/analytics-resource.test.js +181 -0
  61. package/dist/__tests__/analytics-resource.test.js.map +1 -0
  62. package/dist/__tests__/scheduling.test.d.ts +2 -0
  63. package/dist/__tests__/scheduling.test.d.ts.map +1 -0
  64. package/dist/__tests__/scheduling.test.js +205 -0
  65. package/dist/__tests__/scheduling.test.js.map +1 -0
  66. package/dist/ai-dashboards.module.d.ts +18 -14
  67. package/dist/ai-dashboards.module.d.ts.map +1 -1
  68. package/dist/ai-dashboards.module.js +25 -5
  69. package/dist/ai-dashboards.module.js.map +1 -1
  70. package/dist/public-api.d.ts +1 -0
  71. package/dist/public-api.d.ts.map +1 -1
  72. package/dist/public-api.js +1 -0
  73. package/dist/public-api.js.map +1 -1
  74. package/dist/shared/entity-field-display.d.ts +44 -0
  75. package/dist/shared/entity-field-display.d.ts.map +1 -0
  76. package/dist/shared/entity-field-display.js +118 -0
  77. package/dist/shared/entity-field-display.js.map +1 -0
  78. package/package.json +47 -46
@@ -0,0 +1,4266 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var AnalyticsResourceComponent_1;
8
+ /**
9
+ * @fileoverview Knowledge Hub Analytics & Insights Resource Component
10
+ *
11
+ * Multi-tab analytics dashboard for the Knowledge Hub: Overview (interactive cards),
12
+ * Tags (top 20, distribution), Sources (comparison, health), Pipeline (throughput,
13
+ * processing time, errors), and Quality (confidence, weight, model comparison).
14
+ *
15
+ * All chart rendering is pure CSS/inline SVG -- no JS chart libraries.
16
+ */
17
+ import { Component, ChangeDetectorRef, inject } from '@angular/core';
18
+ import { Subject } from 'rxjs';
19
+ import { CompositeKey, Metadata, RunView } from '@memberjunction/core';
20
+ import { UserInfoEngine } from '@memberjunction/core-entities';
21
+ import { RegisterClass } from '@memberjunction/global';
22
+ import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';
23
+ import * as i0 from "@angular/core";
24
+ import * as i1 from "@angular/forms";
25
+ import * as i2 from "@memberjunction/ng-shared-generic";
26
+ const _forTrack0 = ($index, $item) => $item.ID;
27
+ const _forTrack1 = ($index, $item) => $item.Name;
28
+ const _forTrack2 = ($index, $item) => $item.Label;
29
+ const _forTrack3 = ($index, $item) => $item.EntityName;
30
+ const _forTrack4 = ($index, $item) => $item.TagAName + $item.TagBName;
31
+ const _forTrack5 = ($index, $item) => $item.RunID;
32
+ function AnalyticsResourceComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
33
+ i0.ɵɵelementStart(0, "div", 0);
34
+ i0.ɵɵelement(1, "mj-loading", 2);
35
+ i0.ɵɵelementEnd();
36
+ } }
37
+ function AnalyticsResourceComponent_Conditional_1_For_8_Template(rf, ctx) { if (rf & 1) {
38
+ const _r1 = i0.ɵɵgetCurrentView();
39
+ i0.ɵɵelementStart(0, "button", 18);
40
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_For_8_Template_button_click_0_listener() { const nav_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SelectTab(nav_r2.ID)); });
41
+ i0.ɵɵelement(1, "i");
42
+ i0.ɵɵtext(2);
43
+ i0.ɵɵelementEnd();
44
+ } if (rf & 2) {
45
+ const nav_r2 = ctx.$implicit;
46
+ const ctx_r2 = i0.ɵɵnextContext(2);
47
+ i0.ɵɵclassProp("active", ctx_r2.ActiveTab === nav_r2.ID);
48
+ i0.ɵɵadvance();
49
+ i0.ɵɵclassMap(nav_r2.Icon);
50
+ i0.ɵɵadvance();
51
+ i0.ɵɵtextInterpolate1(" ", nav_r2.Label, " ");
52
+ } }
53
+ function AnalyticsResourceComponent_Conditional_1_For_16_Template(rf, ctx) { if (rf & 1) {
54
+ i0.ɵɵelementStart(0, "span");
55
+ i0.ɵɵtext(1);
56
+ i0.ɵɵelementEnd();
57
+ } if (rf & 2) {
58
+ const tag_r4 = ctx.$implicit;
59
+ i0.ɵɵstyleProp("font-size", tag_r4.Size, "px")("font-weight", tag_r4.Weight);
60
+ i0.ɵɵadvance();
61
+ i0.ɵɵtextInterpolate(tag_r4.Name);
62
+ } }
63
+ function AnalyticsResourceComponent_Conditional_1_Conditional_17_Template(rf, ctx) { if (rf & 1) {
64
+ i0.ɵɵelementStart(0, "span", 13);
65
+ i0.ɵɵtext(1, "No trending tags yet");
66
+ i0.ɵɵelementEnd();
67
+ } }
68
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_8_Template(rf, ctx) { if (rf & 1) {
69
+ const _r6 = i0.ɵɵgetCurrentView();
70
+ i0.ɵɵelementStart(0, "button", 73);
71
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_8_Template_button_click_0_listener() { const range_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.SetDateRange(range_r7.Label)); });
72
+ i0.ɵɵtext(1);
73
+ i0.ɵɵelementEnd();
74
+ } if (rf & 2) {
75
+ const range_r7 = ctx.$implicit;
76
+ const ctx_r2 = i0.ɵɵnextContext(3);
77
+ i0.ɵɵclassProp("active", ctx_r2.ActiveDateRange === range_r7.Label);
78
+ i0.ɵɵadvance();
79
+ i0.ɵɵtextInterpolate(range_r7.Label);
80
+ } }
81
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_11_Template(rf, ctx) { if (rf & 1) {
82
+ i0.ɵɵelementStart(0, "option", 25);
83
+ i0.ɵɵtext(1);
84
+ i0.ɵɵelementEnd();
85
+ } if (rf & 2) {
86
+ const opt_r8 = ctx.$implicit;
87
+ i0.ɵɵproperty("value", opt_r8);
88
+ i0.ɵɵadvance();
89
+ i0.ɵɵtextInterpolate(opt_r8);
90
+ } }
91
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_14_Conditional_7_Template(rf, ctx) { if (rf & 1) {
92
+ i0.ɵɵelement(0, "i", 78);
93
+ } }
94
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_14_Conditional_8_Template(rf, ctx) { if (rf & 1) {
95
+ i0.ɵɵelement(0, "i", 79);
96
+ } }
97
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_14_Template(rf, ctx) { if (rf & 1) {
98
+ const _r9 = i0.ɵɵgetCurrentView();
99
+ i0.ɵɵelementStart(0, "div", 74);
100
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_14_Template_div_click_0_listener() { const kpi_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OpenDrillDown(kpi_r10.DrillDownKey)); });
101
+ i0.ɵɵelementStart(1, "div")(2, "div", 75);
102
+ i0.ɵɵtext(3);
103
+ i0.ɵɵelementEnd();
104
+ i0.ɵɵelementStart(4, "div", 76);
105
+ i0.ɵɵtext(5);
106
+ i0.ɵɵelementEnd();
107
+ i0.ɵɵelementStart(6, "div", 77);
108
+ i0.ɵɵconditionalCreate(7, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_14_Conditional_7_Template, 1, 0, "i", 78)(8, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_14_Conditional_8_Template, 1, 0, "i", 79);
109
+ i0.ɵɵtext(9);
110
+ i0.ɵɵelementEnd()();
111
+ i0.ɵɵelementStart(10, "div", 80);
112
+ i0.ɵɵnamespaceSVG();
113
+ i0.ɵɵelementStart(11, "svg", 81);
114
+ i0.ɵɵelement(12, "polyline", 82);
115
+ i0.ɵɵelementEnd()()();
116
+ } if (rf & 2) {
117
+ const kpi_r10 = ctx.$implicit;
118
+ i0.ɵɵadvance(3);
119
+ i0.ɵɵtextInterpolate(kpi_r10.Label);
120
+ i0.ɵɵadvance(2);
121
+ i0.ɵɵtextInterpolate(kpi_r10.Value);
122
+ i0.ɵɵadvance();
123
+ i0.ɵɵclassProp("up", kpi_r10.DeltaDirection === "up")("down", kpi_r10.DeltaDirection === "down");
124
+ i0.ɵɵadvance();
125
+ i0.ɵɵconditional(kpi_r10.DeltaDirection === "up" ? 7 : kpi_r10.DeltaDirection === "down" ? 8 : -1);
126
+ i0.ɵɵadvance(2);
127
+ i0.ɵɵtextInterpolate1(" ", kpi_r10.Delta, " ");
128
+ i0.ɵɵadvance(3);
129
+ i0.ɵɵattribute("points", kpi_r10.SparklinePoints)("stroke", kpi_r10.SparklineColor);
130
+ } }
131
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_6_Template(rf, ctx) { if (rf & 1) {
132
+ const _r12 = i0.ɵɵgetCurrentView();
133
+ i0.ɵɵelementStart(0, "button", 93);
134
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.ExportDrillDownCSV()); });
135
+ i0.ɵɵelement(1, "i", 94);
136
+ i0.ɵɵtext(2, " CSV ");
137
+ i0.ɵɵelementEnd();
138
+ } }
139
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_9_Template(rf, ctx) { if (rf & 1) {
140
+ i0.ɵɵelement(0, "mj-loading", 90);
141
+ } }
142
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_5_Template(rf, ctx) { if (rf & 1) {
143
+ i0.ɵɵelementStart(0, "th");
144
+ i0.ɵɵtext(1);
145
+ i0.ɵɵelementEnd();
146
+ } if (rf & 2) {
147
+ const col_r13 = ctx.$implicit;
148
+ i0.ɵɵadvance();
149
+ i0.ɵɵtextInterpolate(col_r13);
150
+ } }
151
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
152
+ i0.ɵɵelement(0, "th", 96);
153
+ } }
154
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_For_2_Template(rf, ctx) { if (rf & 1) {
155
+ i0.ɵɵelementStart(0, "td");
156
+ i0.ɵɵtext(1);
157
+ i0.ɵɵelementEnd();
158
+ } if (rf & 2) {
159
+ const col_r14 = ctx.$implicit;
160
+ const row_r15 = i0.ɵɵnextContext().$implicit;
161
+ i0.ɵɵadvance();
162
+ i0.ɵɵtextInterpolate(row_r15[col_r14]);
163
+ } }
164
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
165
+ const _r16 = i0.ɵɵgetCurrentView();
166
+ i0.ɵɵelementStart(0, "button", 98);
167
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_Conditional_3_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r16); const row_r15 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.OpenDrillDownRecord(row_r15)); });
168
+ i0.ɵɵelement(1, "i", 99);
169
+ i0.ɵɵelementEnd();
170
+ } }
171
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
172
+ i0.ɵɵelementStart(0, "td", 96);
173
+ i0.ɵɵconditionalCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_Conditional_3_Conditional_1_Template, 2, 0, "button", 97);
174
+ i0.ɵɵelementEnd();
175
+ } if (rf & 2) {
176
+ const row_r15 = i0.ɵɵnextContext().$implicit;
177
+ i0.ɵɵadvance();
178
+ i0.ɵɵconditional(row_r15["_RecordID"] ? 1 : -1);
179
+ } }
180
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_Template(rf, ctx) { if (rf & 1) {
181
+ i0.ɵɵelementStart(0, "tr");
182
+ i0.ɵɵrepeaterCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_For_2_Template, 2, 1, "td", null, i0.ɵɵrepeaterTrackByIdentity);
183
+ i0.ɵɵconditionalCreate(3, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_Conditional_3_Template, 2, 1, "td", 96);
184
+ i0.ɵɵelementEnd();
185
+ } if (rf & 2) {
186
+ const ctx_r2 = i0.ɵɵnextContext(5);
187
+ i0.ɵɵadvance();
188
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
189
+ i0.ɵɵadvance(2);
190
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 3 : -1);
191
+ } }
192
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_Template(rf, ctx) { if (rf & 1) {
193
+ i0.ɵɵelementStart(0, "div", 91)(1, "table", 95)(2, "thead")(3, "tr");
194
+ i0.ɵɵrepeaterCreate(4, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_5_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
195
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_Conditional_6_Template, 1, 0, "th", 96);
196
+ i0.ɵɵelementEnd()();
197
+ i0.ɵɵelementStart(7, "tbody");
198
+ i0.ɵɵrepeaterCreate(8, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_For_9_Template, 4, 1, "tr", null, i0.ɵɵcomponentInstance().TrackByIndex, true);
199
+ i0.ɵɵelementEnd()()();
200
+ } if (rf & 2) {
201
+ const ctx_r2 = i0.ɵɵnextContext(4);
202
+ i0.ɵɵadvance(4);
203
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
204
+ i0.ɵɵadvance(2);
205
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 6 : -1);
206
+ i0.ɵɵadvance(2);
207
+ i0.ɵɵrepeater(ctx_r2.DrillDownData);
208
+ } }
209
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_11_Template(rf, ctx) { if (rf & 1) {
210
+ i0.ɵɵelementStart(0, "div", 92);
211
+ i0.ɵɵtext(1, "No data available");
212
+ i0.ɵɵelementEnd();
213
+ } }
214
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Template(rf, ctx) { if (rf & 1) {
215
+ const _r11 = i0.ɵɵgetCurrentView();
216
+ i0.ɵɵelementStart(0, "div", 28)(1, "div", 83)(2, "span", 84);
217
+ i0.ɵɵelement(3, "i", 85);
218
+ i0.ɵɵtext(4, " Detail View");
219
+ i0.ɵɵelementEnd();
220
+ i0.ɵɵelementStart(5, "div", 86);
221
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_6_Template, 3, 0, "button", 87);
222
+ i0.ɵɵelementStart(7, "button", 88);
223
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r11); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.CloseDrillDown()); });
224
+ i0.ɵɵelement(8, "i", 89);
225
+ i0.ɵɵelementEnd()()();
226
+ i0.ɵɵconditionalCreate(9, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_9_Template, 1, 0, "mj-loading", 90)(10, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_10_Template, 10, 1, "div", 91)(11, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Conditional_11_Template, 2, 0, "div", 92);
227
+ i0.ɵɵelementEnd();
228
+ } if (rf & 2) {
229
+ const ctx_r2 = i0.ɵɵnextContext(3);
230
+ i0.ɵɵadvance(6);
231
+ i0.ɵɵconditional(ctx_r2.DrillDownData.length > 0 ? 6 : -1);
232
+ i0.ɵɵadvance(3);
233
+ i0.ɵɵconditional(ctx_r2.IsDrillDownLoading ? 9 : ctx_r2.DrillDownData.length > 0 ? 10 : 11);
234
+ } }
235
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_23_Template(rf, ctx) { if (rf & 1) {
236
+ i0.ɵɵelementStart(0, "div", 33)(1, "div", 100);
237
+ i0.ɵɵtext(2);
238
+ i0.ɵɵelementEnd();
239
+ i0.ɵɵelement(3, "div", 101);
240
+ i0.ɵɵelementStart(4, "div", 102);
241
+ i0.ɵɵtext(5);
242
+ i0.ɵɵelementEnd()();
243
+ } if (rf & 2) {
244
+ const bar_r17 = ctx.$implicit;
245
+ i0.ɵɵadvance(2);
246
+ i0.ɵɵtextInterpolate(bar_r17.Count);
247
+ i0.ɵɵadvance();
248
+ i0.ɵɵstyleProp("height", bar_r17.Percentage, "%")("opacity", 0.5 + bar_r17.Percentage / 200);
249
+ i0.ɵɵadvance(2);
250
+ i0.ɵɵtextInterpolate(bar_r17.Label);
251
+ } }
252
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_30_Template(rf, ctx) { if (rf & 1) {
253
+ i0.ɵɵelementStart(0, "div", 36);
254
+ i0.ɵɵnamespaceSVG();
255
+ i0.ɵɵelementStart(1, "svg", 103);
256
+ i0.ɵɵelement(2, "circle", 104)(3, "circle", 105);
257
+ i0.ɵɵelementStart(4, "text", 106);
258
+ i0.ɵɵtext(5);
259
+ i0.ɵɵelementEnd()();
260
+ i0.ɵɵnamespaceHTML();
261
+ i0.ɵɵelementStart(6, "div")(7, "div", 107);
262
+ i0.ɵɵtext(8);
263
+ i0.ɵɵelementEnd();
264
+ i0.ɵɵelementStart(9, "div", 108);
265
+ i0.ɵɵtext(10);
266
+ i0.ɵɵelementEnd()()();
267
+ } if (rf & 2) {
268
+ const entity_r18 = ctx.$implicit;
269
+ const ctx_r2 = i0.ɵɵnextContext(3);
270
+ i0.ɵɵadvance(3);
271
+ i0.ɵɵattribute("stroke", entity_r18.Color)("stroke-dasharray", entity_r18.StrokeDash);
272
+ i0.ɵɵadvance(2);
273
+ i0.ɵɵtextInterpolate1("", entity_r18.Percentage, "%");
274
+ i0.ɵɵadvance(3);
275
+ i0.ɵɵtextInterpolate(entity_r18.Name);
276
+ i0.ɵɵadvance(2);
277
+ i0.ɵɵtextInterpolate2("", ctx_r2.FormatNumber(entity_r18.Tagged), " / ", ctx_r2.FormatNumber(entity_r18.Total));
278
+ } }
279
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_31_Template(rf, ctx) { if (rf & 1) {
280
+ i0.ɵɵelementStart(0, "div", 37);
281
+ i0.ɵɵtext(1, "No content types found");
282
+ i0.ɵɵelementEnd();
283
+ } }
284
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_54_Template(rf, ctx) { if (rf & 1) {
285
+ i0.ɵɵelement(0, "div", 109);
286
+ } if (rf & 2) {
287
+ const bin_r19 = ctx.$implicit;
288
+ i0.ɵɵstyleProp("height", bin_r19.Height, "px")("background", bin_r19.Color);
289
+ i0.ɵɵproperty("title", bin_r19.Title);
290
+ } }
291
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_63_Template(rf, ctx) { if (rf & 1) {
292
+ i0.ɵɵelementStart(0, "div", 55)(1, "div", 110);
293
+ i0.ɵɵtext(2);
294
+ i0.ɵɵelementEnd();
295
+ i0.ɵɵelementStart(3, "div", 111)(4, "div", 112);
296
+ i0.ɵɵtext(5);
297
+ i0.ɵɵelementEnd()()();
298
+ } if (rf & 2) {
299
+ const source_r20 = ctx.$implicit;
300
+ i0.ɵɵadvance(2);
301
+ i0.ɵɵtextInterpolate(source_r20.Name);
302
+ i0.ɵɵadvance(2);
303
+ i0.ɵɵstyleProp("width", source_r20.Percentage, "%")("background", source_r20.Color);
304
+ i0.ɵɵadvance();
305
+ i0.ɵɵtextInterpolate(source_r20.AvgTagsPerItem);
306
+ } }
307
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_64_Template(rf, ctx) { if (rf & 1) {
308
+ i0.ɵɵelementStart(0, "div", 37);
309
+ i0.ɵɵtext(1, "No source data");
310
+ i0.ɵɵelementEnd();
311
+ } }
312
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_73_Template(rf, ctx) { if (rf & 1) {
313
+ i0.ɵɵelementStart(0, "div", 113)(1, "span", 114);
314
+ i0.ɵɵtext(2);
315
+ i0.ɵɵelementEnd()();
316
+ } if (rf & 2) {
317
+ const day_r21 = ctx.$implicit;
318
+ i0.ɵɵstyleProp("height", day_r21.Percentage, "%")("background", day_r21.IsError ? "var(--mj-status-error)" : "var(--mj-status-success)");
319
+ i0.ɵɵadvance(2);
320
+ i0.ɵɵtextInterpolate(day_r21.Label);
321
+ } }
322
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_89_Template(rf, ctx) { if (rf & 1) {
323
+ i0.ɵɵnamespaceSVG();
324
+ i0.ɵɵelement(0, "circle", 68);
325
+ } if (rf & 2) {
326
+ const seg_r22 = ctx.$implicit;
327
+ i0.ɵɵattribute("stroke", seg_r22.Color)("stroke-dasharray", seg_r22.StrokeDash)("stroke-dashoffset", seg_r22.StrokeOffset);
328
+ } }
329
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_For_96_Template(rf, ctx) { if (rf & 1) {
330
+ i0.ɵɵelementStart(0, "div", 115);
331
+ i0.ɵɵtext(1);
332
+ i0.ɵɵelementStart(2, "small");
333
+ i0.ɵɵtext(3);
334
+ i0.ɵɵelementEnd()();
335
+ } if (rf & 2) {
336
+ const stat_r23 = ctx.$implicit;
337
+ i0.ɵɵstyleProp("background", stat_r23.BgColor)("color", stat_r23.Color);
338
+ i0.ɵɵadvance();
339
+ i0.ɵɵtextInterpolate1(" ", stat_r23.Count);
340
+ i0.ɵɵadvance(2);
341
+ i0.ɵɵtextInterpolate(stat_r23.Label);
342
+ } }
343
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_7_Template(rf, ctx) { if (rf & 1) {
344
+ i0.ɵɵelement(0, "mj-loading", 90);
345
+ } }
346
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_5_Template(rf, ctx) { if (rf & 1) {
347
+ i0.ɵɵelementStart(0, "th");
348
+ i0.ɵɵtext(1);
349
+ i0.ɵɵelementEnd();
350
+ } if (rf & 2) {
351
+ const col_r25 = ctx.$implicit;
352
+ i0.ɵɵadvance();
353
+ i0.ɵɵtextInterpolate(col_r25);
354
+ } }
355
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_Conditional_6_Template(rf, ctx) { if (rf & 1) {
356
+ i0.ɵɵelement(0, "th", 96);
357
+ } }
358
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_For_2_Template(rf, ctx) { if (rf & 1) {
359
+ i0.ɵɵelementStart(0, "td");
360
+ i0.ɵɵtext(1);
361
+ i0.ɵɵelementEnd();
362
+ } if (rf & 2) {
363
+ const col_r26 = ctx.$implicit;
364
+ const row_r27 = i0.ɵɵnextContext().$implicit;
365
+ i0.ɵɵadvance();
366
+ i0.ɵɵtextInterpolate(row_r27[col_r26]);
367
+ } }
368
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
369
+ const _r28 = i0.ɵɵgetCurrentView();
370
+ i0.ɵɵelementStart(0, "button", 98);
371
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_Conditional_3_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r28); const row_r27 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.OpenDrillDownRecord(row_r27)); });
372
+ i0.ɵɵelement(1, "i", 99);
373
+ i0.ɵɵelementEnd();
374
+ } }
375
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
376
+ i0.ɵɵelementStart(0, "td", 96);
377
+ i0.ɵɵconditionalCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_Conditional_3_Conditional_1_Template, 2, 0, "button", 97);
378
+ i0.ɵɵelementEnd();
379
+ } if (rf & 2) {
380
+ const row_r27 = i0.ɵɵnextContext().$implicit;
381
+ i0.ɵɵadvance();
382
+ i0.ɵɵconditional(row_r27["_RecordID"] ? 1 : -1);
383
+ } }
384
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_Template(rf, ctx) { if (rf & 1) {
385
+ i0.ɵɵelementStart(0, "tr");
386
+ i0.ɵɵrepeaterCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_For_2_Template, 2, 1, "td", null, i0.ɵɵrepeaterTrackByIdentity);
387
+ i0.ɵɵconditionalCreate(3, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_Conditional_3_Template, 2, 1, "td", 96);
388
+ i0.ɵɵelementEnd();
389
+ } if (rf & 2) {
390
+ const ctx_r2 = i0.ɵɵnextContext(5);
391
+ i0.ɵɵadvance();
392
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
393
+ i0.ɵɵadvance(2);
394
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 3 : -1);
395
+ } }
396
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_Template(rf, ctx) { if (rf & 1) {
397
+ i0.ɵɵelementStart(0, "div", 91)(1, "table", 95)(2, "thead")(3, "tr");
398
+ i0.ɵɵrepeaterCreate(4, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_5_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
399
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_Conditional_6_Template, 1, 0, "th", 96);
400
+ i0.ɵɵelementEnd()();
401
+ i0.ɵɵelementStart(7, "tbody");
402
+ i0.ɵɵrepeaterCreate(8, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_For_9_Template, 4, 1, "tr", null, i0.ɵɵcomponentInstance().TrackByIndex, true);
403
+ i0.ɵɵelementEnd()()();
404
+ } if (rf & 2) {
405
+ const ctx_r2 = i0.ɵɵnextContext(4);
406
+ i0.ɵɵadvance(4);
407
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
408
+ i0.ɵɵadvance(2);
409
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 6 : -1);
410
+ i0.ɵɵadvance(2);
411
+ i0.ɵɵrepeater(ctx_r2.DrillDownData);
412
+ } }
413
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_9_Template(rf, ctx) { if (rf & 1) {
414
+ i0.ɵɵelementStart(0, "div", 92);
415
+ i0.ɵɵtext(1, "No data available");
416
+ i0.ɵɵelementEnd();
417
+ } }
418
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Template(rf, ctx) { if (rf & 1) {
419
+ const _r24 = i0.ɵɵgetCurrentView();
420
+ i0.ɵɵelementStart(0, "div", 28)(1, "div", 83)(2, "span", 84);
421
+ i0.ɵɵelement(3, "i", 85);
422
+ i0.ɵɵtext(4);
423
+ i0.ɵɵelementEnd();
424
+ i0.ɵɵelementStart(5, "button", 88);
425
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r24); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.CloseDrillDown()); });
426
+ i0.ɵɵelement(6, "i", 89);
427
+ i0.ɵɵelementEnd()();
428
+ i0.ɵɵconditionalCreate(7, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_7_Template, 1, 0, "mj-loading", 90)(8, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_8_Template, 10, 1, "div", 91)(9, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Conditional_9_Template, 2, 0, "div", 92);
429
+ i0.ɵɵelementEnd();
430
+ } if (rf & 2) {
431
+ const ctx_r2 = i0.ɵɵnextContext(3);
432
+ i0.ɵɵadvance(4);
433
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.DrillDownTarget, " Detail");
434
+ i0.ɵɵadvance(3);
435
+ i0.ɵɵconditional(ctx_r2.IsDrillDownLoading ? 7 : ctx_r2.DrillDownData.length > 0 ? 8 : 9);
436
+ } }
437
+ function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template(rf, ctx) { if (rf & 1) {
438
+ const _r5 = i0.ɵɵgetCurrentView();
439
+ i0.ɵɵelementStart(0, "section", 17)(1, "div", 19);
440
+ i0.ɵɵelement(2, "i", 20);
441
+ i0.ɵɵelementStart(3, "h1");
442
+ i0.ɵɵtext(4, "Overview");
443
+ i0.ɵɵelementEnd()();
444
+ i0.ɵɵelementStart(5, "div", 21)(6, "div", 22);
445
+ i0.ɵɵrepeaterCreate(7, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_8_Template, 2, 3, "button", 23, _forTrack2);
446
+ i0.ɵɵelementEnd();
447
+ i0.ɵɵelementStart(9, "select", 24);
448
+ i0.ɵɵlistener("ngModelChange", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template_select_ngModelChange_9_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SetEntityFilter($event)); });
449
+ i0.ɵɵrepeaterCreate(10, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_11_Template, 2, 2, "option", 25, i0.ɵɵrepeaterTrackByIdentity);
450
+ i0.ɵɵelementEnd()();
451
+ i0.ɵɵelementStart(12, "div", 26);
452
+ i0.ɵɵrepeaterCreate(13, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_14_Template, 13, 10, "div", 27, _forTrack2);
453
+ i0.ɵɵelementEnd();
454
+ i0.ɵɵconditionalCreate(15, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_15_Template, 12, 2, "div", 28);
455
+ i0.ɵɵelementStart(16, "div", 29)(17, "div", 30);
456
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template_div_click_17_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("tagGrowth")); });
457
+ i0.ɵɵelementStart(18, "div", 31);
458
+ i0.ɵɵelement(19, "i", 5);
459
+ i0.ɵɵtext(20, " Tag Growth");
460
+ i0.ɵɵelementEnd();
461
+ i0.ɵɵelementStart(21, "div", 32);
462
+ i0.ɵɵrepeaterCreate(22, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_23_Template, 6, 6, "div", 33, _forTrack2);
463
+ i0.ɵɵelementEnd()();
464
+ i0.ɵɵelementStart(24, "div", 30);
465
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template_div_click_24_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("contentCoverage")); });
466
+ i0.ɵɵelementStart(25, "div", 31);
467
+ i0.ɵɵelement(26, "i", 34);
468
+ i0.ɵɵtext(27, " Content Coverage");
469
+ i0.ɵɵelementEnd();
470
+ i0.ɵɵelementStart(28, "div", 35);
471
+ i0.ɵɵrepeaterCreate(29, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_30_Template, 11, 6, "div", 36, _forTrack1);
472
+ i0.ɵɵconditionalCreate(31, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_31_Template, 2, 0, "div", 37);
473
+ i0.ɵɵelementEnd()();
474
+ i0.ɵɵelementStart(32, "div", 30);
475
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template_div_click_32_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("qualityScore")); });
476
+ i0.ɵɵelementStart(33, "div", 31);
477
+ i0.ɵɵelement(34, "i", 38);
478
+ i0.ɵɵtext(35, " Quality Score");
479
+ i0.ɵɵelementEnd();
480
+ i0.ɵɵelementStart(36, "div", 39);
481
+ i0.ɵɵnamespaceSVG();
482
+ i0.ɵɵelementStart(37, "svg", 40);
483
+ i0.ɵɵelement(38, "path", 41)(39, "path", 42)(40, "path", 43)(41, "path", 44);
484
+ i0.ɵɵelementStart(42, "text", 45);
485
+ i0.ɵɵtext(43);
486
+ i0.ɵɵelementEnd();
487
+ i0.ɵɵelementStart(44, "text", 46);
488
+ i0.ɵɵtext(45, "out of 100");
489
+ i0.ɵɵelementEnd();
490
+ i0.ɵɵelementStart(46, "text", 47);
491
+ i0.ɵɵtext(47, "0");
492
+ i0.ɵɵelementEnd();
493
+ i0.ɵɵelementStart(48, "text", 48);
494
+ i0.ɵɵtext(49, "50");
495
+ i0.ɵɵelementEnd();
496
+ i0.ɵɵelementStart(50, "text", 49);
497
+ i0.ɵɵtext(51, "100");
498
+ i0.ɵɵelementEnd()()();
499
+ i0.ɵɵnamespaceHTML();
500
+ i0.ɵɵelementStart(52, "div", 50);
501
+ i0.ɵɵrepeaterCreate(53, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_54_Template, 1, 5, "div", 51, i0.ɵɵcomponentInstance().TrackByIndex, true);
502
+ i0.ɵɵelementEnd();
503
+ i0.ɵɵelementStart(55, "div", 52);
504
+ i0.ɵɵtext(56, "Confidence Distribution");
505
+ i0.ɵɵelementEnd()();
506
+ i0.ɵɵelementStart(57, "div", 30);
507
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template_div_click_57_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("sourcePerformance")); });
508
+ i0.ɵɵelementStart(58, "div", 31);
509
+ i0.ɵɵelement(59, "i", 53);
510
+ i0.ɵɵtext(60, " Source Performance");
511
+ i0.ɵɵelementEnd();
512
+ i0.ɵɵelementStart(61, "div", 54);
513
+ i0.ɵɵrepeaterCreate(62, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_63_Template, 6, 6, "div", 55, _forTrack1);
514
+ i0.ɵɵconditionalCreate(64, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_64_Template, 2, 0, "div", 37);
515
+ i0.ɵɵelementEnd();
516
+ i0.ɵɵelementStart(65, "div", 56);
517
+ i0.ɵɵtext(66, "Average tags per item");
518
+ i0.ɵɵelementEnd()();
519
+ i0.ɵɵelementStart(67, "div", 30);
520
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template_div_click_67_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("dailyThroughput")); });
521
+ i0.ɵɵelementStart(68, "div", 31);
522
+ i0.ɵɵelement(69, "i", 57);
523
+ i0.ɵɵtext(70, " Daily Throughput");
524
+ i0.ɵɵelementEnd();
525
+ i0.ɵɵelementStart(71, "div", 58);
526
+ i0.ɵɵrepeaterCreate(72, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_73_Template, 3, 5, "div", 59, _forTrack2);
527
+ i0.ɵɵelementEnd();
528
+ i0.ɵɵelementStart(74, "div", 60)(75, "div", 61);
529
+ i0.ɵɵelement(76, "div", 62);
530
+ i0.ɵɵtext(77, " Success");
531
+ i0.ɵɵelementEnd();
532
+ i0.ɵɵelementStart(78, "div", 61);
533
+ i0.ɵɵelement(79, "div", 63);
534
+ i0.ɵɵtext(80, " Failures");
535
+ i0.ɵɵelementEnd()()();
536
+ i0.ɵɵelementStart(81, "div", 30);
537
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_22_Template_div_click_81_listener() { i0.ɵɵrestoreView(_r5); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("taxonomyHealth")); });
538
+ i0.ɵɵelementStart(82, "div", 31);
539
+ i0.ɵɵelement(83, "i", 64);
540
+ i0.ɵɵtext(84, " Taxonomy Health");
541
+ i0.ɵɵelementEnd();
542
+ i0.ɵɵelementStart(85, "div", 65);
543
+ i0.ɵɵnamespaceSVG();
544
+ i0.ɵɵelementStart(86, "svg", 66);
545
+ i0.ɵɵelement(87, "circle", 67);
546
+ i0.ɵɵrepeaterCreate(88, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_89_Template, 1, 3, ":svg:circle", 68, i0.ɵɵcomponentInstance().TrackByIndex, true);
547
+ i0.ɵɵelementStart(90, "text", 69);
548
+ i0.ɵɵtext(91);
549
+ i0.ɵɵelementEnd();
550
+ i0.ɵɵelementStart(92, "text", 70);
551
+ i0.ɵɵtext(93, "total tags");
552
+ i0.ɵɵelementEnd()()();
553
+ i0.ɵɵnamespaceHTML();
554
+ i0.ɵɵelementStart(94, "div", 71);
555
+ i0.ɵɵrepeaterCreate(95, AnalyticsResourceComponent_Conditional_1_Conditional_22_For_96_Template, 4, 6, "div", 72, _forTrack2);
556
+ i0.ɵɵelementEnd()()();
557
+ i0.ɵɵconditionalCreate(97, AnalyticsResourceComponent_Conditional_1_Conditional_22_Conditional_97_Template, 10, 2, "div", 28);
558
+ i0.ɵɵelementEnd();
559
+ } if (rf & 2) {
560
+ const ctx_r2 = i0.ɵɵnextContext(2);
561
+ i0.ɵɵadvance(7);
562
+ i0.ɵɵrepeater(ctx_r2.DateRanges);
563
+ i0.ɵɵadvance(2);
564
+ i0.ɵɵproperty("ngModel", ctx_r2.EntityFilter);
565
+ i0.ɵɵadvance();
566
+ i0.ɵɵrepeater(ctx_r2.EntityFilterOptions);
567
+ i0.ɵɵadvance(3);
568
+ i0.ɵɵrepeater(ctx_r2.KPIs);
569
+ i0.ɵɵadvance(2);
570
+ i0.ɵɵconditional(ctx_r2.DrillDownTarget && ctx_r2.DrillDownTarget.startsWith("kpi-") ? 15 : -1);
571
+ i0.ɵɵadvance(7);
572
+ i0.ɵɵrepeater(ctx_r2.TagGrowthData);
573
+ i0.ɵɵadvance(7);
574
+ i0.ɵɵrepeater(ctx_r2.CoverageData);
575
+ i0.ɵɵadvance(2);
576
+ i0.ɵɵconditional(ctx_r2.CoverageData.length === 0 ? 31 : -1);
577
+ i0.ɵɵadvance(12);
578
+ i0.ɵɵtextInterpolate(ctx_r2.QualityScore);
579
+ i0.ɵɵadvance(10);
580
+ i0.ɵɵrepeater(ctx_r2.MiniConfidenceBins);
581
+ i0.ɵɵadvance(9);
582
+ i0.ɵɵrepeater(ctx_r2.SourcePerfData);
583
+ i0.ɵɵadvance(2);
584
+ i0.ɵɵconditional(ctx_r2.SourcePerfData.length === 0 ? 64 : -1);
585
+ i0.ɵɵadvance(8);
586
+ i0.ɵɵrepeater(ctx_r2.ThroughputData);
587
+ i0.ɵɵadvance(16);
588
+ i0.ɵɵrepeater(ctx_r2.TaxonomyRingSegments);
589
+ i0.ɵɵadvance(3);
590
+ i0.ɵɵtextInterpolate(ctx_r2.TaxonomyTotal);
591
+ i0.ɵɵadvance(4);
592
+ i0.ɵɵrepeater(ctx_r2.TaxonomyStats);
593
+ i0.ɵɵadvance(2);
594
+ i0.ɵɵconditional(ctx_r2.DrillDownTarget && !ctx_r2.DrillDownTarget.startsWith("kpi-") ? 97 : -1);
595
+ } }
596
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_10_Template(rf, ctx) { if (rf & 1) {
597
+ const _r30 = i0.ɵɵgetCurrentView();
598
+ i0.ɵɵelementStart(0, "button", 93);
599
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.ExportTabDataCSV("top-tags")); });
600
+ i0.ɵɵelement(1, "i", 94);
601
+ i0.ɵɵtext(2, " CSV ");
602
+ i0.ɵɵelementEnd();
603
+ } }
604
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_11_For_20_Template(rf, ctx) { if (rf & 1) {
605
+ const _r31 = i0.ɵɵgetCurrentView();
606
+ i0.ɵɵelementStart(0, "tr", 130);
607
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_11_For_20_Template_tr_click_0_listener() { const tag_r32 = i0.ɵɵrestoreView(_r31).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("tag-row:" + tag_r32.Name)); });
608
+ i0.ɵɵelementStart(1, "td");
609
+ i0.ɵɵtext(2);
610
+ i0.ɵɵelementEnd();
611
+ i0.ɵɵelementStart(3, "td")(4, "strong");
612
+ i0.ɵɵtext(5);
613
+ i0.ɵɵelementEnd()();
614
+ i0.ɵɵelementStart(6, "td", 128);
615
+ i0.ɵɵtext(7);
616
+ i0.ɵɵelementEnd();
617
+ i0.ɵɵelementStart(8, "td");
618
+ i0.ɵɵelement(9, "span", 131);
619
+ i0.ɵɵtext(10);
620
+ i0.ɵɵelementEnd();
621
+ i0.ɵɵelementStart(11, "td");
622
+ i0.ɵɵnamespaceSVG();
623
+ i0.ɵɵelementStart(12, "svg", 132);
624
+ i0.ɵɵelement(13, "polyline", 133);
625
+ i0.ɵɵelementEnd()();
626
+ i0.ɵɵnamespaceHTML();
627
+ i0.ɵɵelementStart(14, "td");
628
+ i0.ɵɵtext(15);
629
+ i0.ɵɵelementEnd();
630
+ i0.ɵɵelementStart(16, "td", 134);
631
+ i0.ɵɵtext(17);
632
+ i0.ɵɵelementEnd()();
633
+ } if (rf & 2) {
634
+ const tag_r32 = ctx.$implicit;
635
+ const ctx_r2 = i0.ɵɵnextContext(4);
636
+ i0.ɵɵadvance(2);
637
+ i0.ɵɵtextInterpolate(tag_r32.Rank);
638
+ i0.ɵɵadvance(3);
639
+ i0.ɵɵtextInterpolate(tag_r32.Name);
640
+ i0.ɵɵadvance(2);
641
+ i0.ɵɵtextInterpolate(ctx_r2.FormatNumber(tag_r32.UsageCount));
642
+ i0.ɵɵadvance(2);
643
+ i0.ɵɵstyleProp("width", tag_r32.WeightBarWidth, "px")("background", tag_r32.WeightBarColor);
644
+ i0.ɵɵadvance();
645
+ i0.ɵɵtextInterpolate1(" ", tag_r32.AvgWeight, " ");
646
+ i0.ɵɵadvance(3);
647
+ i0.ɵɵattribute("points", tag_r32.TrendPoints)("stroke", tag_r32.TrendColor);
648
+ i0.ɵɵadvance(2);
649
+ i0.ɵɵtextInterpolate(tag_r32.TopEntity);
650
+ i0.ɵɵadvance(2);
651
+ i0.ɵɵtextInterpolate(tag_r32.FirstSeen);
652
+ } }
653
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_11_Template(rf, ctx) { if (rf & 1) {
654
+ i0.ɵɵelementStart(0, "div", 120)(1, "table", 95)(2, "thead")(3, "tr")(4, "th");
655
+ i0.ɵɵtext(5, "#");
656
+ i0.ɵɵelementEnd();
657
+ i0.ɵɵelementStart(6, "th");
658
+ i0.ɵɵtext(7, "Tag Name");
659
+ i0.ɵɵelementEnd();
660
+ i0.ɵɵelementStart(8, "th", 128);
661
+ i0.ɵɵtext(9, "Usage Count");
662
+ i0.ɵɵelementEnd();
663
+ i0.ɵɵelementStart(10, "th");
664
+ i0.ɵɵtext(11, "Avg Weight");
665
+ i0.ɵɵelementEnd();
666
+ i0.ɵɵelementStart(12, "th");
667
+ i0.ɵɵtext(13, "Trend");
668
+ i0.ɵɵelementEnd();
669
+ i0.ɵɵelementStart(14, "th");
670
+ i0.ɵɵtext(15, "Top Entity");
671
+ i0.ɵɵelementEnd();
672
+ i0.ɵɵelementStart(16, "th");
673
+ i0.ɵɵtext(17, "First Seen");
674
+ i0.ɵɵelementEnd()()();
675
+ i0.ɵɵelementStart(18, "tbody");
676
+ i0.ɵɵrepeaterCreate(19, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_11_For_20_Template, 18, 12, "tr", 129, _forTrack1);
677
+ i0.ɵɵelementEnd()()();
678
+ } if (rf & 2) {
679
+ const ctx_r2 = i0.ɵɵnextContext(3);
680
+ i0.ɵɵadvance(19);
681
+ i0.ɵɵrepeater(ctx_r2.TopTags);
682
+ } }
683
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_12_Template(rf, ctx) { if (rf & 1) {
684
+ i0.ɵɵelementStart(0, "div", 121);
685
+ i0.ɵɵelement(1, "i", 116);
686
+ i0.ɵɵelementStart(2, "p");
687
+ i0.ɵɵtext(3, "No tag data available yet. Process content to generate tags.");
688
+ i0.ɵɵelementEnd()();
689
+ } }
690
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_6_Template(rf, ctx) { if (rf & 1) {
691
+ const _r34 = i0.ɵɵgetCurrentView();
692
+ i0.ɵɵelementStart(0, "button", 93);
693
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r34); const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.ExportDrillDownCSV()); });
694
+ i0.ɵɵelement(1, "i", 94);
695
+ i0.ɵɵtext(2, " CSV ");
696
+ i0.ɵɵelementEnd();
697
+ } }
698
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_9_Template(rf, ctx) { if (rf & 1) {
699
+ i0.ɵɵelement(0, "mj-loading", 90);
700
+ } }
701
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_5_Template(rf, ctx) { if (rf & 1) {
702
+ i0.ɵɵelementStart(0, "th");
703
+ i0.ɵɵtext(1);
704
+ i0.ɵɵelementEnd();
705
+ } if (rf & 2) {
706
+ const col_r35 = ctx.$implicit;
707
+ i0.ɵɵadvance();
708
+ i0.ɵɵtextInterpolate(col_r35);
709
+ } }
710
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
711
+ i0.ɵɵelement(0, "th", 96);
712
+ } }
713
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_For_2_Template(rf, ctx) { if (rf & 1) {
714
+ i0.ɵɵelementStart(0, "td");
715
+ i0.ɵɵtext(1);
716
+ i0.ɵɵelementEnd();
717
+ } if (rf & 2) {
718
+ const col_r36 = ctx.$implicit;
719
+ const row_r37 = i0.ɵɵnextContext().$implicit;
720
+ i0.ɵɵadvance();
721
+ i0.ɵɵtextInterpolate(row_r37[col_r36]);
722
+ } }
723
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
724
+ const _r38 = i0.ɵɵgetCurrentView();
725
+ i0.ɵɵelementStart(0, "button", 98);
726
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_Conditional_3_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r38); const row_r37 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.OpenDrillDownRecord(row_r37)); });
727
+ i0.ɵɵelement(1, "i", 99);
728
+ i0.ɵɵelementEnd();
729
+ } }
730
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
731
+ i0.ɵɵelementStart(0, "td", 96);
732
+ i0.ɵɵconditionalCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_Conditional_3_Conditional_1_Template, 2, 0, "button", 97);
733
+ i0.ɵɵelementEnd();
734
+ } if (rf & 2) {
735
+ const row_r37 = i0.ɵɵnextContext().$implicit;
736
+ i0.ɵɵadvance();
737
+ i0.ɵɵconditional(row_r37["_RecordID"] ? 1 : -1);
738
+ } }
739
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_Template(rf, ctx) { if (rf & 1) {
740
+ i0.ɵɵelementStart(0, "tr");
741
+ i0.ɵɵrepeaterCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_For_2_Template, 2, 1, "td", null, i0.ɵɵrepeaterTrackByIdentity);
742
+ i0.ɵɵconditionalCreate(3, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_Conditional_3_Template, 2, 1, "td", 96);
743
+ i0.ɵɵelementEnd();
744
+ } if (rf & 2) {
745
+ const ctx_r2 = i0.ɵɵnextContext(5);
746
+ i0.ɵɵadvance();
747
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
748
+ i0.ɵɵadvance(2);
749
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 3 : -1);
750
+ } }
751
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_Template(rf, ctx) { if (rf & 1) {
752
+ i0.ɵɵelementStart(0, "div", 91)(1, "table", 95)(2, "thead")(3, "tr");
753
+ i0.ɵɵrepeaterCreate(4, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_5_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
754
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_Conditional_6_Template, 1, 0, "th", 96);
755
+ i0.ɵɵelementEnd()();
756
+ i0.ɵɵelementStart(7, "tbody");
757
+ i0.ɵɵrepeaterCreate(8, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_For_9_Template, 4, 1, "tr", null, i0.ɵɵcomponentInstance().TrackByIndex, true);
758
+ i0.ɵɵelementEnd()()();
759
+ } if (rf & 2) {
760
+ const ctx_r2 = i0.ɵɵnextContext(4);
761
+ i0.ɵɵadvance(4);
762
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
763
+ i0.ɵɵadvance(2);
764
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 6 : -1);
765
+ i0.ɵɵadvance(2);
766
+ i0.ɵɵrepeater(ctx_r2.DrillDownData);
767
+ } }
768
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_11_Template(rf, ctx) { if (rf & 1) {
769
+ i0.ɵɵelementStart(0, "div", 92);
770
+ i0.ɵɵtext(1, "No items found for this tag");
771
+ i0.ɵɵelementEnd();
772
+ } }
773
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Template(rf, ctx) { if (rf & 1) {
774
+ const _r33 = i0.ɵɵgetCurrentView();
775
+ i0.ɵɵelementStart(0, "div", 28)(1, "div", 83)(2, "span", 84);
776
+ i0.ɵɵelement(3, "i", 85);
777
+ i0.ɵɵtext(4);
778
+ i0.ɵɵelementEnd();
779
+ i0.ɵɵelementStart(5, "div", 86);
780
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_6_Template, 3, 0, "button", 87);
781
+ i0.ɵɵelementStart(7, "button", 88);
782
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r33); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.CloseDrillDown()); });
783
+ i0.ɵɵelement(8, "i", 89);
784
+ i0.ɵɵelementEnd()()();
785
+ i0.ɵɵconditionalCreate(9, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_9_Template, 1, 0, "mj-loading", 90)(10, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_10_Template, 10, 1, "div", 91)(11, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Conditional_11_Template, 2, 0, "div", 92);
786
+ i0.ɵɵelementEnd();
787
+ } if (rf & 2) {
788
+ const ctx_r2 = i0.ɵɵnextContext(3);
789
+ i0.ɵɵadvance(4);
790
+ i0.ɵɵtextInterpolate1(" Content Items Tagged \"", ctx_r2.DrillDownTarget.replace("tag-row:", ""), "\"");
791
+ i0.ɵɵadvance(2);
792
+ i0.ɵɵconditional(ctx_r2.DrillDownData.length > 0 ? 6 : -1);
793
+ i0.ɵɵadvance(3);
794
+ i0.ɵɵconditional(ctx_r2.IsDrillDownLoading ? 9 : ctx_r2.DrillDownData.length > 0 ? 10 : 11);
795
+ } }
796
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_For_6_For_5_Template(rf, ctx) { if (rf & 1) {
797
+ i0.ɵɵelementStart(0, "div", 142);
798
+ i0.ɵɵtext(1);
799
+ i0.ɵɵelementEnd();
800
+ } if (rf & 2) {
801
+ const seg_r39 = ctx.$implicit;
802
+ i0.ɵɵstyleProp("width", seg_r39.Percentage, "%")("background", seg_r39.Color);
803
+ i0.ɵɵproperty("title", seg_r39.Label + ": " + seg_r39.Percentage + "%");
804
+ i0.ɵɵadvance();
805
+ i0.ɵɵtextInterpolate(seg_r39.Label);
806
+ } }
807
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_For_6_Template(rf, ctx) { if (rf & 1) {
808
+ i0.ɵɵelementStart(0, "div", 137)(1, "div", 139);
809
+ i0.ɵɵtext(2);
810
+ i0.ɵɵelementEnd();
811
+ i0.ɵɵelementStart(3, "div", 140);
812
+ i0.ɵɵrepeaterCreate(4, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_For_6_For_5_Template, 2, 6, "div", 141, i0.ɵɵcomponentInstance().TrackByIndex, true);
813
+ i0.ɵɵelementEnd()();
814
+ } if (rf & 2) {
815
+ const row_r40 = ctx.$implicit;
816
+ i0.ɵɵadvance(2);
817
+ i0.ɵɵtextInterpolate(row_r40.EntityName);
818
+ i0.ɵɵadvance(2);
819
+ i0.ɵɵrepeater(row_r40.Segments);
820
+ } }
821
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_For_9_Template(rf, ctx) { if (rf & 1) {
822
+ i0.ɵɵelementStart(0, "div", 61);
823
+ i0.ɵɵelement(1, "div", 143);
824
+ i0.ɵɵtext(2);
825
+ i0.ɵɵelementEnd();
826
+ } if (rf & 2) {
827
+ const item_r41 = ctx.$implicit;
828
+ i0.ɵɵadvance();
829
+ i0.ɵɵstyleProp("background", item_r41.Color);
830
+ i0.ɵɵadvance();
831
+ i0.ɵɵtextInterpolate1(" ", item_r41.Label);
832
+ } }
833
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_Template(rf, ctx) { if (rf & 1) {
834
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
835
+ i0.ɵɵelement(2, "i", 135);
836
+ i0.ɵɵtext(3, " Tag Distribution by Entity");
837
+ i0.ɵɵelementEnd();
838
+ i0.ɵɵelementStart(4, "div", 136);
839
+ i0.ɵɵrepeaterCreate(5, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_For_6_Template, 6, 1, "div", 137, _forTrack3);
840
+ i0.ɵɵelementEnd();
841
+ i0.ɵɵelementStart(7, "div", 138);
842
+ i0.ɵɵrepeaterCreate(8, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_For_9_Template, 3, 3, "div", 61, _forTrack2);
843
+ i0.ɵɵelementEnd()();
844
+ } if (rf & 2) {
845
+ const ctx_r2 = i0.ɵɵnextContext(3);
846
+ i0.ɵɵadvance(5);
847
+ i0.ɵɵrepeater(ctx_r2.EntityDistribution);
848
+ i0.ɵɵadvance(3);
849
+ i0.ɵɵrepeater(ctx_r2.DistributionLegend);
850
+ } }
851
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_15_For_6_Template(rf, ctx) { if (rf & 1) {
852
+ i0.ɵɵelementStart(0, "div", 146)(1, "div", 148);
853
+ i0.ɵɵtext(2);
854
+ i0.ɵɵelementEnd();
855
+ i0.ɵɵelementStart(3, "div", 149);
856
+ i0.ɵɵtext(4);
857
+ i0.ɵɵelementEnd()();
858
+ } if (rf & 2) {
859
+ const bar_r42 = ctx.$implicit;
860
+ i0.ɵɵadvance();
861
+ i0.ɵɵstyleProp("height", bar_r42.Percentage, "%")("min-height", bar_r42.Count > 0 ? 24 : 0, "px");
862
+ i0.ɵɵadvance();
863
+ i0.ɵɵtextInterpolate(bar_r42.Count);
864
+ i0.ɵɵadvance(2);
865
+ i0.ɵɵtextInterpolate(bar_r42.Label);
866
+ } }
867
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_15_Template(rf, ctx) { if (rf & 1) {
868
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
869
+ i0.ɵɵelement(2, "i", 144);
870
+ i0.ɵɵtext(3, " Tag Depth Distribution");
871
+ i0.ɵɵelementEnd();
872
+ i0.ɵɵelementStart(4, "div", 145);
873
+ i0.ɵɵrepeaterCreate(5, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_15_For_6_Template, 5, 6, "div", 146, _forTrack2);
874
+ i0.ɵɵelementEnd();
875
+ i0.ɵɵelementStart(7, "div", 147);
876
+ i0.ɵɵtext(8, " Taxonomy hierarchy depth -- Most tags at depth 2-3 indicating a healthy mid-level structure ");
877
+ i0.ɵɵelementEnd()();
878
+ } if (rf & 2) {
879
+ const ctx_r2 = i0.ɵɵnextContext(3);
880
+ i0.ɵɵadvance(5);
881
+ i0.ɵɵrepeater(ctx_r2.TagDepthBars);
882
+ } }
883
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_22_Template(rf, ctx) { if (rf & 1) {
884
+ i0.ɵɵelementStart(0, "span", 126);
885
+ i0.ɵɵelement(1, "i", 150);
886
+ i0.ɵɵtext(2);
887
+ i0.ɵɵelementEnd();
888
+ } if (rf & 2) {
889
+ const ctx_r2 = i0.ɵɵnextContext(3);
890
+ i0.ɵɵadvance(2);
891
+ i0.ɵɵtextInterpolate1(" Last computed: ", ctx_r2.CoOccurrenceLastComputed, " ");
892
+ } }
893
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_24_Template(rf, ctx) { if (rf & 1) {
894
+ i0.ɵɵelement(0, "i", 151);
895
+ i0.ɵɵtext(1, " Computing... ");
896
+ } }
897
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_25_Template(rf, ctx) { if (rf & 1) {
898
+ i0.ɵɵelement(0, "i", 152);
899
+ i0.ɵɵtext(1, " Recompute ");
900
+ } }
901
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_26_For_16_Template(rf, ctx) { if (rf & 1) {
902
+ i0.ɵɵelementStart(0, "tr")(1, "td", 134);
903
+ i0.ɵɵtext(2);
904
+ i0.ɵɵelementEnd();
905
+ i0.ɵɵelementStart(3, "td")(4, "strong");
906
+ i0.ɵɵtext(5);
907
+ i0.ɵɵelementEnd()();
908
+ i0.ɵɵelementStart(6, "td")(7, "strong");
909
+ i0.ɵɵtext(8);
910
+ i0.ɵɵelementEnd()();
911
+ i0.ɵɵelementStart(9, "td", 128);
912
+ i0.ɵɵtext(10);
913
+ i0.ɵɵelementEnd();
914
+ i0.ɵɵelementStart(11, "td");
915
+ i0.ɵɵelement(12, "span", 153);
916
+ i0.ɵɵelementEnd()();
917
+ } if (rf & 2) {
918
+ const pair_r43 = ctx.$implicit;
919
+ const ɵ$index_665_r44 = ctx.$index;
920
+ const ctx_r2 = i0.ɵɵnextContext(4);
921
+ i0.ɵɵadvance(2);
922
+ i0.ɵɵtextInterpolate(ɵ$index_665_r44 + 1);
923
+ i0.ɵɵadvance(3);
924
+ i0.ɵɵtextInterpolate(pair_r43.TagAName);
925
+ i0.ɵɵadvance(3);
926
+ i0.ɵɵtextInterpolate(pair_r43.TagBName);
927
+ i0.ɵɵadvance(2);
928
+ i0.ɵɵtextInterpolate(ctx_r2.FormatNumber(pair_r43.Count));
929
+ i0.ɵɵadvance(2);
930
+ i0.ɵɵstyleProp("width", pair_r43.BarWidth, "px");
931
+ } }
932
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_26_Template(rf, ctx) { if (rf & 1) {
933
+ i0.ɵɵelementStart(0, "div", 120)(1, "table", 95)(2, "thead")(3, "tr")(4, "th");
934
+ i0.ɵɵtext(5, "#");
935
+ i0.ɵɵelementEnd();
936
+ i0.ɵɵelementStart(6, "th");
937
+ i0.ɵɵtext(7, "Tag A");
938
+ i0.ɵɵelementEnd();
939
+ i0.ɵɵelementStart(8, "th");
940
+ i0.ɵɵtext(9, "Tag B");
941
+ i0.ɵɵelementEnd();
942
+ i0.ɵɵelementStart(10, "th", 128);
943
+ i0.ɵɵtext(11, "Co-Occurrences");
944
+ i0.ɵɵelementEnd();
945
+ i0.ɵɵelementStart(12, "th");
946
+ i0.ɵɵtext(13, "Frequency");
947
+ i0.ɵɵelementEnd()()();
948
+ i0.ɵɵelementStart(14, "tbody");
949
+ i0.ɵɵrepeaterCreate(15, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_26_For_16_Template, 13, 6, "tr", null, _forTrack4);
950
+ i0.ɵɵelementEnd()()();
951
+ } if (rf & 2) {
952
+ const ctx_r2 = i0.ɵɵnextContext(3);
953
+ i0.ɵɵadvance(15);
954
+ i0.ɵɵrepeater(ctx_r2.CoOccurrencePairs);
955
+ } }
956
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_27_Template(rf, ctx) { if (rf & 1) {
957
+ i0.ɵɵelementStart(0, "div", 121);
958
+ i0.ɵɵelement(1, "i", 124);
959
+ i0.ɵɵelementStart(2, "p");
960
+ i0.ɵɵtext(3, "No co-occurrence data available yet. Process content and recompute to see which tags frequently appear together.");
961
+ i0.ɵɵelementEnd()();
962
+ } }
963
+ function AnalyticsResourceComponent_Conditional_1_Conditional_23_Template(rf, ctx) { if (rf & 1) {
964
+ const _r29 = i0.ɵɵgetCurrentView();
965
+ i0.ɵɵelementStart(0, "section", 17)(1, "div", 19);
966
+ i0.ɵɵelement(2, "i", 116);
967
+ i0.ɵɵelementStart(3, "h1");
968
+ i0.ɵɵtext(4, "Tags");
969
+ i0.ɵɵelementEnd()();
970
+ i0.ɵɵelementStart(5, "div", 117)(6, "div", 118)(7, "h3");
971
+ i0.ɵɵelement(8, "i", 119);
972
+ i0.ɵɵtext(9, " Top 20 Tags");
973
+ i0.ɵɵelementEnd();
974
+ i0.ɵɵconditionalCreate(10, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_10_Template, 3, 0, "button", 87);
975
+ i0.ɵɵelementEnd();
976
+ i0.ɵɵconditionalCreate(11, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_11_Template, 21, 0, "div", 120)(12, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_12_Template, 4, 0, "div", 121);
977
+ i0.ɵɵelementEnd();
978
+ i0.ɵɵconditionalCreate(13, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_13_Template, 12, 3, "div", 28);
979
+ i0.ɵɵconditionalCreate(14, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_14_Template, 10, 0, "div", 122);
980
+ i0.ɵɵconditionalCreate(15, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_15_Template, 9, 0, "div", 122);
981
+ i0.ɵɵelementStart(16, "div", 123)(17, "div", 118)(18, "h3");
982
+ i0.ɵɵelement(19, "i", 124);
983
+ i0.ɵɵtext(20, " Frequently Paired Tags");
984
+ i0.ɵɵelementEnd();
985
+ i0.ɵɵelementStart(21, "div", 125);
986
+ i0.ɵɵconditionalCreate(22, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_22_Template, 3, 1, "span", 126);
987
+ i0.ɵɵelementStart(23, "button", 127);
988
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_23_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r29); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.RecomputeCoOccurrence()); });
989
+ i0.ɵɵconditionalCreate(24, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_24_Template, 2, 0)(25, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_25_Template, 2, 0);
990
+ i0.ɵɵelementEnd()()();
991
+ i0.ɵɵconditionalCreate(26, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_26_Template, 17, 0, "div", 120)(27, AnalyticsResourceComponent_Conditional_1_Conditional_23_Conditional_27_Template, 4, 0, "div", 121);
992
+ i0.ɵɵelementEnd()();
993
+ } if (rf & 2) {
994
+ const ctx_r2 = i0.ɵɵnextContext(2);
995
+ i0.ɵɵadvance(10);
996
+ i0.ɵɵconditional(ctx_r2.TopTags.length > 0 ? 10 : -1);
997
+ i0.ɵɵadvance();
998
+ i0.ɵɵconditional(ctx_r2.TopTags.length > 0 ? 11 : 12);
999
+ i0.ɵɵadvance(2);
1000
+ i0.ɵɵconditional(ctx_r2.DrillDownTarget && ctx_r2.DrillDownTarget.startsWith("tag-row:") ? 13 : -1);
1001
+ i0.ɵɵadvance();
1002
+ i0.ɵɵconditional(ctx_r2.EntityDistribution.length > 0 ? 14 : -1);
1003
+ i0.ɵɵadvance();
1004
+ i0.ɵɵconditional(ctx_r2.TagDepthBars.length > 0 ? 15 : -1);
1005
+ i0.ɵɵadvance(7);
1006
+ i0.ɵɵconditional(ctx_r2.CoOccurrenceLastComputed ? 22 : -1);
1007
+ i0.ɵɵadvance();
1008
+ i0.ɵɵproperty("disabled", ctx_r2.IsRecomputingCoOccurrence);
1009
+ i0.ɵɵadvance();
1010
+ i0.ɵɵconditional(ctx_r2.IsRecomputingCoOccurrence ? 24 : 25);
1011
+ i0.ɵɵadvance(2);
1012
+ i0.ɵɵconditional(ctx_r2.CoOccurrencePairs.length > 0 ? 26 : 27);
1013
+ } }
1014
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_9_For_22_Template(rf, ctx) { if (rf & 1) {
1015
+ const _r45 = i0.ɵɵgetCurrentView();
1016
+ i0.ɵɵelementStart(0, "tr", 130);
1017
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_9_For_22_Template_tr_click_0_listener() { const source_r46 = i0.ɵɵrestoreView(_r45).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); ctx_r2.SelectSource(source_r46.Name); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("source-row:" + source_r46.Name)); });
1018
+ i0.ɵɵelementStart(1, "td")(2, "strong");
1019
+ i0.ɵɵtext(3);
1020
+ i0.ɵɵelementEnd()();
1021
+ i0.ɵɵelementStart(4, "td");
1022
+ i0.ɵɵelement(5, "i", 156);
1023
+ i0.ɵɵtext(6);
1024
+ i0.ɵɵelementEnd();
1025
+ i0.ɵɵelementStart(7, "td", 128);
1026
+ i0.ɵɵtext(8);
1027
+ i0.ɵɵelementEnd();
1028
+ i0.ɵɵelementStart(9, "td", 128);
1029
+ i0.ɵɵtext(10);
1030
+ i0.ɵɵelementEnd();
1031
+ i0.ɵɵelementStart(11, "td", 128);
1032
+ i0.ɵɵtext(12);
1033
+ i0.ɵɵelementEnd();
1034
+ i0.ɵɵelementStart(13, "td", 128);
1035
+ i0.ɵɵtext(14);
1036
+ i0.ɵɵelementEnd();
1037
+ i0.ɵɵelementStart(15, "td", 134);
1038
+ i0.ɵɵtext(16);
1039
+ i0.ɵɵelementEnd();
1040
+ i0.ɵɵelementStart(17, "td")(18, "span", 157);
1041
+ i0.ɵɵelement(19, "i", 158);
1042
+ i0.ɵɵtext(20);
1043
+ i0.ɵɵelementEnd()()();
1044
+ } if (rf & 2) {
1045
+ const source_r46 = ctx.$implicit;
1046
+ const ctx_r2 = i0.ɵɵnextContext(4);
1047
+ i0.ɵɵclassProp("source-selected", ctx_r2.SelectedSourceName === source_r46.Name);
1048
+ i0.ɵɵadvance(3);
1049
+ i0.ɵɵtextInterpolate(source_r46.Name);
1050
+ i0.ɵɵadvance(2);
1051
+ i0.ɵɵclassMap(source_r46.TypeIcon);
1052
+ i0.ɵɵstyleProp("color", source_r46.TypeColor);
1053
+ i0.ɵɵadvance();
1054
+ i0.ɵɵtextInterpolate1(" ", source_r46.Type);
1055
+ i0.ɵɵadvance(2);
1056
+ i0.ɵɵtextInterpolate(ctx_r2.FormatNumber(source_r46.Items));
1057
+ i0.ɵɵadvance(2);
1058
+ i0.ɵɵtextInterpolate(ctx_r2.FormatNumber(source_r46.TagsGenerated));
1059
+ i0.ɵɵadvance(2);
1060
+ i0.ɵɵtextInterpolate(source_r46.AvgTagsPerItem);
1061
+ i0.ɵɵadvance(2);
1062
+ i0.ɵɵtextInterpolate(source_r46.AvgWeight);
1063
+ i0.ɵɵadvance(2);
1064
+ i0.ɵɵtextInterpolate(source_r46.LastRun);
1065
+ i0.ɵɵadvance(2);
1066
+ i0.ɵɵclassMap(source_r46.StatusClass);
1067
+ i0.ɵɵadvance(2);
1068
+ i0.ɵɵtextInterpolate1(" ", source_r46.Status);
1069
+ } }
1070
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_9_Template(rf, ctx) { if (rf & 1) {
1071
+ i0.ɵɵelementStart(0, "div", 120)(1, "table", 95)(2, "thead")(3, "tr")(4, "th");
1072
+ i0.ɵɵtext(5, "Source Name");
1073
+ i0.ɵɵelementEnd();
1074
+ i0.ɵɵelementStart(6, "th");
1075
+ i0.ɵɵtext(7, "Type");
1076
+ i0.ɵɵelementEnd();
1077
+ i0.ɵɵelementStart(8, "th", 128);
1078
+ i0.ɵɵtext(9, "Items");
1079
+ i0.ɵɵelementEnd();
1080
+ i0.ɵɵelementStart(10, "th", 128);
1081
+ i0.ɵɵtext(11, "Tags Generated");
1082
+ i0.ɵɵelementEnd();
1083
+ i0.ɵɵelementStart(12, "th", 128);
1084
+ i0.ɵɵtext(13, "Avg Tags/Item");
1085
+ i0.ɵɵelementEnd();
1086
+ i0.ɵɵelementStart(14, "th", 128);
1087
+ i0.ɵɵtext(15, "Avg Weight");
1088
+ i0.ɵɵelementEnd();
1089
+ i0.ɵɵelementStart(16, "th");
1090
+ i0.ɵɵtext(17, "Last Run");
1091
+ i0.ɵɵelementEnd();
1092
+ i0.ɵɵelementStart(18, "th");
1093
+ i0.ɵɵtext(19, "Status");
1094
+ i0.ɵɵelementEnd()()();
1095
+ i0.ɵɵelementStart(20, "tbody");
1096
+ i0.ɵɵrepeaterCreate(21, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_9_For_22_Template, 21, 16, "tr", 155, _forTrack1);
1097
+ i0.ɵɵelementEnd()()();
1098
+ } if (rf & 2) {
1099
+ const ctx_r2 = i0.ɵɵnextContext(3);
1100
+ i0.ɵɵadvance(21);
1101
+ i0.ɵɵrepeater(ctx_r2.SourceComparison);
1102
+ } }
1103
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_10_Template(rf, ctx) { if (rf & 1) {
1104
+ i0.ɵɵelementStart(0, "div", 121);
1105
+ i0.ɵɵelement(1, "i", 154);
1106
+ i0.ɵɵelementStart(2, "p");
1107
+ i0.ɵɵtext(3, "No content sources configured yet.");
1108
+ i0.ɵɵelementEnd()();
1109
+ } }
1110
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_6_Template(rf, ctx) { if (rf & 1) {
1111
+ const _r48 = i0.ɵɵgetCurrentView();
1112
+ i0.ɵɵelementStart(0, "button", 93);
1113
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r48); const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.ExportDrillDownCSV()); });
1114
+ i0.ɵɵelement(1, "i", 94);
1115
+ i0.ɵɵtext(2, " CSV");
1116
+ i0.ɵɵelementEnd();
1117
+ } }
1118
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_9_Template(rf, ctx) { if (rf & 1) {
1119
+ i0.ɵɵelement(0, "mj-loading", 90);
1120
+ } }
1121
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_5_Template(rf, ctx) { if (rf & 1) {
1122
+ i0.ɵɵelementStart(0, "th");
1123
+ i0.ɵɵtext(1);
1124
+ i0.ɵɵelementEnd();
1125
+ } if (rf & 2) {
1126
+ const col_r49 = ctx.$implicit;
1127
+ i0.ɵɵadvance();
1128
+ i0.ɵɵtextInterpolate(col_r49);
1129
+ } }
1130
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
1131
+ i0.ɵɵelement(0, "th", 96);
1132
+ } }
1133
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_For_2_Template(rf, ctx) { if (rf & 1) {
1134
+ i0.ɵɵelementStart(0, "td");
1135
+ i0.ɵɵtext(1);
1136
+ i0.ɵɵelementEnd();
1137
+ } if (rf & 2) {
1138
+ const col_r50 = ctx.$implicit;
1139
+ const row_r51 = i0.ɵɵnextContext().$implicit;
1140
+ i0.ɵɵadvance();
1141
+ i0.ɵɵtextInterpolate(row_r51[col_r50]);
1142
+ } }
1143
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
1144
+ const _r52 = i0.ɵɵgetCurrentView();
1145
+ i0.ɵɵelementStart(0, "button", 98);
1146
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_Conditional_3_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r52); const row_r51 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.OpenDrillDownRecord(row_r51)); });
1147
+ i0.ɵɵelement(1, "i", 99);
1148
+ i0.ɵɵelementEnd();
1149
+ } }
1150
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
1151
+ i0.ɵɵelementStart(0, "td", 96);
1152
+ i0.ɵɵconditionalCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_Conditional_3_Conditional_1_Template, 2, 0, "button", 97);
1153
+ i0.ɵɵelementEnd();
1154
+ } if (rf & 2) {
1155
+ const row_r51 = i0.ɵɵnextContext().$implicit;
1156
+ i0.ɵɵadvance();
1157
+ i0.ɵɵconditional(row_r51["_RecordID"] ? 1 : -1);
1158
+ } }
1159
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_Template(rf, ctx) { if (rf & 1) {
1160
+ i0.ɵɵelementStart(0, "tr");
1161
+ i0.ɵɵrepeaterCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_For_2_Template, 2, 1, "td", null, i0.ɵɵrepeaterTrackByIdentity);
1162
+ i0.ɵɵconditionalCreate(3, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_Conditional_3_Template, 2, 1, "td", 96);
1163
+ i0.ɵɵelementEnd();
1164
+ } if (rf & 2) {
1165
+ const ctx_r2 = i0.ɵɵnextContext(5);
1166
+ i0.ɵɵadvance();
1167
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
1168
+ i0.ɵɵadvance(2);
1169
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 3 : -1);
1170
+ } }
1171
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_Template(rf, ctx) { if (rf & 1) {
1172
+ i0.ɵɵelementStart(0, "div", 91)(1, "table", 95)(2, "thead")(3, "tr");
1173
+ i0.ɵɵrepeaterCreate(4, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_5_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
1174
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_Conditional_6_Template, 1, 0, "th", 96);
1175
+ i0.ɵɵelementEnd()();
1176
+ i0.ɵɵelementStart(7, "tbody");
1177
+ i0.ɵɵrepeaterCreate(8, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_For_9_Template, 4, 1, "tr", null, i0.ɵɵcomponentInstance().TrackByIndex, true);
1178
+ i0.ɵɵelementEnd()()();
1179
+ } if (rf & 2) {
1180
+ const ctx_r2 = i0.ɵɵnextContext(4);
1181
+ i0.ɵɵadvance(4);
1182
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
1183
+ i0.ɵɵadvance(2);
1184
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 6 : -1);
1185
+ i0.ɵɵadvance(2);
1186
+ i0.ɵɵrepeater(ctx_r2.DrillDownData);
1187
+ } }
1188
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_11_Template(rf, ctx) { if (rf & 1) {
1189
+ i0.ɵɵelementStart(0, "div", 92);
1190
+ i0.ɵɵtext(1, "No run data for this source");
1191
+ i0.ɵɵelementEnd();
1192
+ } }
1193
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Template(rf, ctx) { if (rf & 1) {
1194
+ const _r47 = i0.ɵɵgetCurrentView();
1195
+ i0.ɵɵelementStart(0, "div", 28)(1, "div", 83)(2, "span", 84);
1196
+ i0.ɵɵelement(3, "i", 85);
1197
+ i0.ɵɵtext(4);
1198
+ i0.ɵɵelementEnd();
1199
+ i0.ɵɵelementStart(5, "div", 86);
1200
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_6_Template, 3, 0, "button", 87);
1201
+ i0.ɵɵelementStart(7, "button", 88);
1202
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r47); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.CloseDrillDown()); });
1203
+ i0.ɵɵelement(8, "i", 89);
1204
+ i0.ɵɵelementEnd()()();
1205
+ i0.ɵɵconditionalCreate(9, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_9_Template, 1, 0, "mj-loading", 90)(10, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_10_Template, 10, 1, "div", 91)(11, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Conditional_11_Template, 2, 0, "div", 92);
1206
+ i0.ɵɵelementEnd();
1207
+ } if (rf & 2) {
1208
+ const ctx_r2 = i0.ɵɵnextContext(3);
1209
+ i0.ɵɵadvance(4);
1210
+ i0.ɵɵtextInterpolate1(" Recent Runs: ", ctx_r2.DrillDownTarget.replace("source-row:", ""));
1211
+ i0.ɵɵadvance(2);
1212
+ i0.ɵɵconditional(ctx_r2.DrillDownData.length > 0 ? 6 : -1);
1213
+ i0.ɵɵadvance(3);
1214
+ i0.ɵɵconditional(ctx_r2.IsDrillDownLoading ? 9 : ctx_r2.DrillDownData.length > 0 ? 10 : 11);
1215
+ } }
1216
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_12_For_11_Template(rf, ctx) { if (rf & 1) {
1217
+ i0.ɵɵelementStart(0, "div", 33)(1, "div", 168);
1218
+ i0.ɵɵtext(2);
1219
+ i0.ɵɵelementEnd();
1220
+ i0.ɵɵelement(3, "div", 101);
1221
+ i0.ɵɵelementStart(4, "div", 102);
1222
+ i0.ɵɵtext(5);
1223
+ i0.ɵɵelementEnd()();
1224
+ } if (rf & 2) {
1225
+ const bar_r53 = ctx.$implicit;
1226
+ i0.ɵɵadvance(2);
1227
+ i0.ɵɵtextInterpolate(bar_r53.Value);
1228
+ i0.ɵɵadvance();
1229
+ i0.ɵɵstyleProp("height", bar_r53.Percentage, "%")("opacity", 0.5 + bar_r53.Percentage / 200);
1230
+ i0.ɵɵadvance(2);
1231
+ i0.ɵɵtextInterpolate(bar_r53.Label);
1232
+ } }
1233
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_12_For_18_Template(rf, ctx) { if (rf & 1) {
1234
+ i0.ɵɵelementStart(0, "div", 165)(1, "span", 169);
1235
+ i0.ɵɵtext(2);
1236
+ i0.ɵɵelementEnd();
1237
+ i0.ɵɵelementStart(3, "div", 170)(4, "div", 171);
1238
+ i0.ɵɵtext(5);
1239
+ i0.ɵɵelementEnd()()();
1240
+ } if (rf & 2) {
1241
+ const band_r54 = ctx.$implicit;
1242
+ i0.ɵɵadvance(2);
1243
+ i0.ɵɵtextInterpolate(band_r54.Label);
1244
+ i0.ɵɵadvance(2);
1245
+ i0.ɵɵstyleProp("width", band_r54.Percentage, "%")("background", band_r54.Color);
1246
+ i0.ɵɵadvance();
1247
+ i0.ɵɵtextInterpolate1("", band_r54.Percentage, "%");
1248
+ } }
1249
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_12_Template(rf, ctx) { if (rf & 1) {
1250
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
1251
+ i0.ɵɵelement(2, "i", 159);
1252
+ i0.ɵɵtext(3);
1253
+ i0.ɵɵelementEnd();
1254
+ i0.ɵɵelementStart(4, "div", 160)(5, "div", 161)(6, "div", 31);
1255
+ i0.ɵɵelement(7, "i", 135);
1256
+ i0.ɵɵtext(8, " Items Processed (Last 8 Weeks)");
1257
+ i0.ɵɵelementEnd();
1258
+ i0.ɵɵelementStart(9, "div", 162);
1259
+ i0.ɵɵrepeaterCreate(10, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_12_For_11_Template, 6, 6, "div", 33, _forTrack2);
1260
+ i0.ɵɵelementEnd()();
1261
+ i0.ɵɵelementStart(12, "div", 161)(13, "div", 31);
1262
+ i0.ɵɵelement(14, "i", 163);
1263
+ i0.ɵɵtext(15, " Tag Quality Distribution");
1264
+ i0.ɵɵelementEnd();
1265
+ i0.ɵɵelementStart(16, "div", 164);
1266
+ i0.ɵɵrepeaterCreate(17, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_12_For_18_Template, 6, 6, "div", 165, _forTrack2);
1267
+ i0.ɵɵelementEnd();
1268
+ i0.ɵɵelementStart(19, "div", 166);
1269
+ i0.ɵɵelement(20, "i", 167);
1270
+ i0.ɵɵtext(21);
1271
+ i0.ɵɵelementEnd()()()();
1272
+ } if (rf & 2) {
1273
+ const ctx_r2 = i0.ɵɵnextContext(3);
1274
+ i0.ɵɵadvance(3);
1275
+ i0.ɵɵtextInterpolate1(" Source Detail: ", ctx_r2.SelectedSourceName);
1276
+ i0.ɵɵadvance(7);
1277
+ i0.ɵɵrepeater(ctx_r2.SourceWeeklyBars);
1278
+ i0.ɵɵadvance(7);
1279
+ i0.ɵɵrepeater(ctx_r2.SourceQualityBands);
1280
+ i0.ɵɵadvance(4);
1281
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.SourceQualityNote, " ");
1282
+ } }
1283
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_13_For_6_Template(rf, ctx) { if (rf & 1) {
1284
+ i0.ɵɵelementStart(0, "div", 175)(1, "div", 176);
1285
+ i0.ɵɵtext(2);
1286
+ i0.ɵɵelementEnd();
1287
+ i0.ɵɵelementStart(3, "div", 177);
1288
+ i0.ɵɵtext(4);
1289
+ i0.ɵɵelementEnd();
1290
+ i0.ɵɵelementStart(5, "div", 178);
1291
+ i0.ɵɵtext(6, "uptime");
1292
+ i0.ɵɵelementEnd()();
1293
+ } if (rf & 2) {
1294
+ const card_r55 = ctx.$implicit;
1295
+ i0.ɵɵstyleProp("border-top-color", card_r55.Color);
1296
+ i0.ɵɵadvance(2);
1297
+ i0.ɵɵtextInterpolate(card_r55.Name);
1298
+ i0.ɵɵadvance();
1299
+ i0.ɵɵstyleProp("color", card_r55.Color);
1300
+ i0.ɵɵadvance();
1301
+ i0.ɵɵtextInterpolate1("", card_r55.Uptime, "%");
1302
+ } }
1303
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_13_Template(rf, ctx) { if (rf & 1) {
1304
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
1305
+ i0.ɵɵelement(2, "i", 172);
1306
+ i0.ɵɵtext(3, " Source Health Summary");
1307
+ i0.ɵɵelementEnd();
1308
+ i0.ɵɵelementStart(4, "div", 173);
1309
+ i0.ɵɵrepeaterCreate(5, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_13_For_6_Template, 7, 6, "div", 174, _forTrack1);
1310
+ i0.ɵɵelementEnd()();
1311
+ } if (rf & 2) {
1312
+ const ctx_r2 = i0.ɵɵnextContext(3);
1313
+ i0.ɵɵadvance(4);
1314
+ i0.ɵɵstyleProp("grid-template-columns", "repeat(" + ctx_r2.SourceHealthCards.length + ", 1fr)");
1315
+ i0.ɵɵadvance();
1316
+ i0.ɵɵrepeater(ctx_r2.SourceHealthCards);
1317
+ } }
1318
+ function AnalyticsResourceComponent_Conditional_1_Conditional_24_Template(rf, ctx) { if (rf & 1) {
1319
+ i0.ɵɵelementStart(0, "section", 17)(1, "div", 19);
1320
+ i0.ɵɵelement(2, "i", 154);
1321
+ i0.ɵɵelementStart(3, "h1");
1322
+ i0.ɵɵtext(4, "Sources");
1323
+ i0.ɵɵelementEnd()();
1324
+ i0.ɵɵelementStart(5, "div", 117)(6, "h3");
1325
+ i0.ɵɵelement(7, "i", 85);
1326
+ i0.ɵɵtext(8, " Source Comparison");
1327
+ i0.ɵɵelementEnd();
1328
+ i0.ɵɵconditionalCreate(9, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_9_Template, 23, 0, "div", 120)(10, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_10_Template, 4, 0, "div", 121);
1329
+ i0.ɵɵelementEnd();
1330
+ i0.ɵɵconditionalCreate(11, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_11_Template, 12, 3, "div", 28);
1331
+ i0.ɵɵconditionalCreate(12, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_12_Template, 22, 2, "div", 122);
1332
+ i0.ɵɵconditionalCreate(13, AnalyticsResourceComponent_Conditional_1_Conditional_24_Conditional_13_Template, 7, 2, "div", 122);
1333
+ i0.ɵɵelementEnd();
1334
+ } if (rf & 2) {
1335
+ const ctx_r2 = i0.ɵɵnextContext(2);
1336
+ i0.ɵɵadvance(9);
1337
+ i0.ɵɵconditional(ctx_r2.SourceComparison.length > 0 ? 9 : 10);
1338
+ i0.ɵɵadvance(2);
1339
+ i0.ɵɵconditional(ctx_r2.DrillDownTarget && ctx_r2.DrillDownTarget.startsWith("source-row:") ? 11 : -1);
1340
+ i0.ɵɵadvance();
1341
+ i0.ɵɵconditional(ctx_r2.SelectedSourceName && ctx_r2.SourceComparison.length > 0 ? 12 : -1);
1342
+ i0.ɵɵadvance();
1343
+ i0.ɵɵconditional(ctx_r2.SourceHealthCards.length > 0 ? 13 : -1);
1344
+ } }
1345
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_For_12_Template(rf, ctx) { if (rf & 1) {
1346
+ const _r56 = i0.ɵɵgetCurrentView();
1347
+ i0.ɵɵelementStart(0, "div", 194);
1348
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_25_For_12_Template_div_click_0_listener() { const $index_r57 = i0.ɵɵrestoreView(_r56).$index; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("pipeline-throughput:" + $index_r57)); });
1349
+ i0.ɵɵelementEnd();
1350
+ } if (rf & 2) {
1351
+ const bar_r58 = ctx.$implicit;
1352
+ i0.ɵɵstyleProp("height", bar_r58.Percentage, "%")("background", bar_r58.IsError ? "var(--mj-status-error)" : "var(--mj-brand-primary)")("opacity", bar_r58.IsError ? 0.7 : 0.6 + bar_r58.Percentage / 300);
1353
+ } }
1354
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_For_15_Template(rf, ctx) { if (rf & 1) {
1355
+ i0.ɵɵelementStart(0, "span");
1356
+ i0.ɵɵtext(1);
1357
+ i0.ɵɵelementEnd();
1358
+ } if (rf & 2) {
1359
+ const label_r59 = ctx.$implicit;
1360
+ i0.ɵɵadvance();
1361
+ i0.ɵɵtextInterpolate(label_r59);
1362
+ } }
1363
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_6_Template(rf, ctx) { if (rf & 1) {
1364
+ const _r61 = i0.ɵɵgetCurrentView();
1365
+ i0.ɵɵelementStart(0, "button", 93);
1366
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r61); const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.ExportDrillDownCSV()); });
1367
+ i0.ɵɵelement(1, "i", 94);
1368
+ i0.ɵɵtext(2, " CSV");
1369
+ i0.ɵɵelementEnd();
1370
+ } }
1371
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_9_Template(rf, ctx) { if (rf & 1) {
1372
+ i0.ɵɵelement(0, "mj-loading", 90);
1373
+ } }
1374
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_5_Template(rf, ctx) { if (rf & 1) {
1375
+ i0.ɵɵelementStart(0, "th");
1376
+ i0.ɵɵtext(1);
1377
+ i0.ɵɵelementEnd();
1378
+ } if (rf & 2) {
1379
+ const col_r62 = ctx.$implicit;
1380
+ i0.ɵɵadvance();
1381
+ i0.ɵɵtextInterpolate(col_r62);
1382
+ } }
1383
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
1384
+ i0.ɵɵelement(0, "th", 96);
1385
+ } }
1386
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_For_2_Template(rf, ctx) { if (rf & 1) {
1387
+ i0.ɵɵelementStart(0, "td");
1388
+ i0.ɵɵtext(1);
1389
+ i0.ɵɵelementEnd();
1390
+ } if (rf & 2) {
1391
+ const col_r63 = ctx.$implicit;
1392
+ const row_r64 = i0.ɵɵnextContext().$implicit;
1393
+ i0.ɵɵadvance();
1394
+ i0.ɵɵtextInterpolate(row_r64[col_r63]);
1395
+ } }
1396
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
1397
+ const _r65 = i0.ɵɵgetCurrentView();
1398
+ i0.ɵɵelementStart(0, "button", 98);
1399
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_Conditional_3_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r65); const row_r64 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.OpenDrillDownRecord(row_r64)); });
1400
+ i0.ɵɵelement(1, "i", 99);
1401
+ i0.ɵɵelementEnd();
1402
+ } }
1403
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
1404
+ i0.ɵɵelementStart(0, "td", 96);
1405
+ i0.ɵɵconditionalCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_Conditional_3_Conditional_1_Template, 2, 0, "button", 97);
1406
+ i0.ɵɵelementEnd();
1407
+ } if (rf & 2) {
1408
+ const row_r64 = i0.ɵɵnextContext().$implicit;
1409
+ i0.ɵɵadvance();
1410
+ i0.ɵɵconditional(row_r64["_RecordID"] ? 1 : -1);
1411
+ } }
1412
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_Template(rf, ctx) { if (rf & 1) {
1413
+ i0.ɵɵelementStart(0, "tr");
1414
+ i0.ɵɵrepeaterCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_For_2_Template, 2, 1, "td", null, i0.ɵɵrepeaterTrackByIdentity);
1415
+ i0.ɵɵconditionalCreate(3, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_Conditional_3_Template, 2, 1, "td", 96);
1416
+ i0.ɵɵelementEnd();
1417
+ } if (rf & 2) {
1418
+ const ctx_r2 = i0.ɵɵnextContext(5);
1419
+ i0.ɵɵadvance();
1420
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
1421
+ i0.ɵɵadvance(2);
1422
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 3 : -1);
1423
+ } }
1424
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_Template(rf, ctx) { if (rf & 1) {
1425
+ i0.ɵɵelementStart(0, "div", 91)(1, "table", 95)(2, "thead")(3, "tr");
1426
+ i0.ɵɵrepeaterCreate(4, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_5_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
1427
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_Conditional_6_Template, 1, 0, "th", 96);
1428
+ i0.ɵɵelementEnd()();
1429
+ i0.ɵɵelementStart(7, "tbody");
1430
+ i0.ɵɵrepeaterCreate(8, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_For_9_Template, 4, 1, "tr", null, i0.ɵɵcomponentInstance().TrackByIndex, true);
1431
+ i0.ɵɵelementEnd()()();
1432
+ } if (rf & 2) {
1433
+ const ctx_r2 = i0.ɵɵnextContext(4);
1434
+ i0.ɵɵadvance(4);
1435
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
1436
+ i0.ɵɵadvance(2);
1437
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 6 : -1);
1438
+ i0.ɵɵadvance(2);
1439
+ i0.ɵɵrepeater(ctx_r2.DrillDownData);
1440
+ } }
1441
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_11_Template(rf, ctx) { if (rf & 1) {
1442
+ i0.ɵɵelementStart(0, "div", 92);
1443
+ i0.ɵɵtext(1, "No runs for this day");
1444
+ i0.ɵɵelementEnd();
1445
+ } }
1446
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Template(rf, ctx) { if (rf & 1) {
1447
+ const _r60 = i0.ɵɵgetCurrentView();
1448
+ i0.ɵɵelementStart(0, "div", 28)(1, "div", 83)(2, "span", 84);
1449
+ i0.ɵɵelement(3, "i", 85);
1450
+ i0.ɵɵtext(4, " Runs for Selected Day");
1451
+ i0.ɵɵelementEnd();
1452
+ i0.ɵɵelementStart(5, "div", 86);
1453
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_6_Template, 3, 0, "button", 87);
1454
+ i0.ɵɵelementStart(7, "button", 88);
1455
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r60); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.CloseDrillDown()); });
1456
+ i0.ɵɵelement(8, "i", 89);
1457
+ i0.ɵɵelementEnd()()();
1458
+ i0.ɵɵconditionalCreate(9, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_9_Template, 1, 0, "mj-loading", 90)(10, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_10_Template, 10, 1, "div", 91)(11, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Conditional_11_Template, 2, 0, "div", 92);
1459
+ i0.ɵɵelementEnd();
1460
+ } if (rf & 2) {
1461
+ const ctx_r2 = i0.ɵɵnextContext(3);
1462
+ i0.ɵɵadvance(6);
1463
+ i0.ɵɵconditional(ctx_r2.DrillDownData.length > 0 ? 6 : -1);
1464
+ i0.ɵɵadvance(3);
1465
+ i0.ɵɵconditional(ctx_r2.IsDrillDownLoading ? 9 : ctx_r2.DrillDownData.length > 0 ? 10 : 11);
1466
+ } }
1467
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_For_24_Conditional_5_Template(rf, ctx) { if (rf & 1) {
1468
+ i0.ɵɵtext(0);
1469
+ } if (rf & 2) {
1470
+ const stage_r66 = i0.ɵɵnextContext().$implicit;
1471
+ i0.ɵɵtextInterpolate1(" ", stage_r66.Time, "s ");
1472
+ } }
1473
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_For_24_Template(rf, ctx) { if (rf & 1) {
1474
+ i0.ɵɵelementStart(0, "div", 185)(1, "div", 195);
1475
+ i0.ɵɵtext(2);
1476
+ i0.ɵɵelementEnd();
1477
+ i0.ɵɵelementStart(3, "div", 196)(4, "div", 197);
1478
+ i0.ɵɵconditionalCreate(5, AnalyticsResourceComponent_Conditional_1_Conditional_25_For_24_Conditional_5_Template, 1, 1);
1479
+ i0.ɵɵelementEnd()();
1480
+ i0.ɵɵelementStart(6, "div", 198);
1481
+ i0.ɵɵtext(7);
1482
+ i0.ɵɵelementEnd()();
1483
+ } if (rf & 2) {
1484
+ const stage_r66 = ctx.$implicit;
1485
+ i0.ɵɵadvance(2);
1486
+ i0.ɵɵtextInterpolate(stage_r66.Name);
1487
+ i0.ɵɵadvance(2);
1488
+ i0.ɵɵstyleProp("width", stage_r66.Percentage, "%")("background", stage_r66.Color);
1489
+ i0.ɵɵadvance();
1490
+ i0.ɵɵconditional(stage_r66.Percentage > 15 ? 5 : -1);
1491
+ i0.ɵɵadvance(2);
1492
+ i0.ɵɵtextInterpolate1("", stage_r66.Time, "s");
1493
+ } }
1494
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_30_Template(rf, ctx) { if (rf & 1) {
1495
+ i0.ɵɵelementStart(0, "span", 187);
1496
+ i0.ɵɵelement(1, "i", 199);
1497
+ i0.ɵɵtext(2);
1498
+ i0.ɵɵelementEnd();
1499
+ } if (rf & 2) {
1500
+ const ctx_r2 = i0.ɵɵnextContext(3);
1501
+ i0.ɵɵadvance(2);
1502
+ i0.ɵɵtextInterpolate2(" ", ctx_r2.BottleneckStage, " stage is the bottleneck (", ctx_r2.BottleneckPercent, "% of total time) ");
1503
+ } }
1504
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_52_For_22_Template(rf, ctx) { if (rf & 1) {
1505
+ i0.ɵɵelementStart(0, "tr")(1, "td", 201);
1506
+ i0.ɵɵtext(2);
1507
+ i0.ɵɵelementEnd();
1508
+ i0.ɵɵelementStart(3, "td");
1509
+ i0.ɵɵtext(4);
1510
+ i0.ɵɵelementEnd();
1511
+ i0.ɵɵelementStart(5, "td", 134);
1512
+ i0.ɵɵtext(6);
1513
+ i0.ɵɵelementEnd();
1514
+ i0.ɵɵelementStart(7, "td")(8, "div", 202);
1515
+ i0.ɵɵelement(9, "div", 203);
1516
+ i0.ɵɵelementEnd();
1517
+ i0.ɵɵelementStart(10, "span", 204);
1518
+ i0.ɵɵtext(11);
1519
+ i0.ɵɵelementEnd()();
1520
+ i0.ɵɵelementStart(12, "td")(13, "span", 157);
1521
+ i0.ɵɵtext(14);
1522
+ i0.ɵɵelementEnd()();
1523
+ i0.ɵɵelementStart(15, "td", 128);
1524
+ i0.ɵɵtext(16);
1525
+ i0.ɵɵelementEnd()();
1526
+ } if (rf & 2) {
1527
+ const run_r67 = ctx.$implicit;
1528
+ const ctx_r2 = i0.ɵɵnextContext(4);
1529
+ i0.ɵɵadvance(2);
1530
+ i0.ɵɵtextInterpolate(run_r67.RunID);
1531
+ i0.ɵɵadvance(2);
1532
+ i0.ɵɵtextInterpolate(run_r67.Source);
1533
+ i0.ɵɵadvance(2);
1534
+ i0.ɵɵtextInterpolate(run_r67.Started);
1535
+ i0.ɵɵadvance(3);
1536
+ i0.ɵɵstyleProp("width", run_r67.Progress, "%");
1537
+ i0.ɵɵadvance(2);
1538
+ i0.ɵɵtextInterpolate1("", run_r67.Progress, "%");
1539
+ i0.ɵɵadvance(2);
1540
+ i0.ɵɵclassMap(run_r67.StageClass);
1541
+ i0.ɵɵadvance();
1542
+ i0.ɵɵtextInterpolate(run_r67.Stage);
1543
+ i0.ɵɵadvance(2);
1544
+ i0.ɵɵtextInterpolate(ctx_r2.FormatNumber(run_r67.Items));
1545
+ } }
1546
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_52_Template(rf, ctx) { if (rf & 1) {
1547
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
1548
+ i0.ɵɵelement(2, "i", 200);
1549
+ i0.ɵɵtext(3, " Active Runs");
1550
+ i0.ɵɵelementEnd();
1551
+ i0.ɵɵelementStart(4, "div", 120)(5, "table", 95)(6, "thead")(7, "tr")(8, "th");
1552
+ i0.ɵɵtext(9, "Run ID");
1553
+ i0.ɵɵelementEnd();
1554
+ i0.ɵɵelementStart(10, "th");
1555
+ i0.ɵɵtext(11, "Source");
1556
+ i0.ɵɵelementEnd();
1557
+ i0.ɵɵelementStart(12, "th");
1558
+ i0.ɵɵtext(13, "Started");
1559
+ i0.ɵɵelementEnd();
1560
+ i0.ɵɵelementStart(14, "th");
1561
+ i0.ɵɵtext(15, "Progress");
1562
+ i0.ɵɵelementEnd();
1563
+ i0.ɵɵelementStart(16, "th");
1564
+ i0.ɵɵtext(17, "Stage");
1565
+ i0.ɵɵelementEnd();
1566
+ i0.ɵɵelementStart(18, "th", 128);
1567
+ i0.ɵɵtext(19, "Items");
1568
+ i0.ɵɵelementEnd()()();
1569
+ i0.ɵɵelementStart(20, "tbody");
1570
+ i0.ɵɵrepeaterCreate(21, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_52_For_22_Template, 17, 10, "tr", null, _forTrack5);
1571
+ i0.ɵɵelementEnd()()()();
1572
+ } if (rf & 2) {
1573
+ const ctx_r2 = i0.ɵɵnextContext(3);
1574
+ i0.ɵɵadvance(21);
1575
+ i0.ɵɵrepeater(ctx_r2.ActiveRuns);
1576
+ } }
1577
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_53_For_6_Template(rf, ctx) { if (rf & 1) {
1578
+ i0.ɵɵelementStart(0, "div", 207)(1, "div", 208);
1579
+ i0.ɵɵtext(2);
1580
+ i0.ɵɵelementEnd();
1581
+ i0.ɵɵelementStart(3, "div", 209);
1582
+ i0.ɵɵtext(4);
1583
+ i0.ɵɵelementEnd();
1584
+ i0.ɵɵelementStart(5, "div", 210);
1585
+ i0.ɵɵtext(6);
1586
+ i0.ɵɵelementEnd()();
1587
+ } if (rf & 2) {
1588
+ const entry_r68 = ctx.$implicit;
1589
+ i0.ɵɵadvance(2);
1590
+ i0.ɵɵtextInterpolate(entry_r68.Time);
1591
+ i0.ɵɵadvance(2);
1592
+ i0.ɵɵtextInterpolate(entry_r68.Source);
1593
+ i0.ɵɵadvance(2);
1594
+ i0.ɵɵtextInterpolate(entry_r68.Message);
1595
+ } }
1596
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_53_Template(rf, ctx) { if (rf & 1) {
1597
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
1598
+ i0.ɵɵelement(2, "i", 205);
1599
+ i0.ɵɵtext(3, " Recent Errors");
1600
+ i0.ɵɵelementEnd();
1601
+ i0.ɵɵelementStart(4, "div", 206);
1602
+ i0.ɵɵrepeaterCreate(5, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_53_For_6_Template, 7, 3, "div", 207, i0.ɵɵcomponentInstance().TrackByIndex, true);
1603
+ i0.ɵɵelementEnd()();
1604
+ } if (rf & 2) {
1605
+ const ctx_r2 = i0.ɵɵnextContext(3);
1606
+ i0.ɵɵadvance(5);
1607
+ i0.ɵɵrepeater(ctx_r2.ErrorLog);
1608
+ } }
1609
+ function AnalyticsResourceComponent_Conditional_1_Conditional_25_Template(rf, ctx) { if (rf & 1) {
1610
+ i0.ɵɵelementStart(0, "section", 17)(1, "div", 19);
1611
+ i0.ɵɵelement(2, "i", 179);
1612
+ i0.ɵɵelementStart(3, "h1");
1613
+ i0.ɵɵtext(4, "Pipeline");
1614
+ i0.ɵɵelementEnd()();
1615
+ i0.ɵɵelementStart(5, "div", 117)(6, "h3");
1616
+ i0.ɵɵelement(7, "i", 135);
1617
+ i0.ɵɵtext(8, " Pipeline Throughput (Last 30 Days)");
1618
+ i0.ɵɵelementEnd();
1619
+ i0.ɵɵelementStart(9, "div", 161)(10, "div", 180);
1620
+ i0.ɵɵrepeaterCreate(11, AnalyticsResourceComponent_Conditional_1_Conditional_25_For_12_Template, 1, 6, "div", 181, i0.ɵɵcomponentInstance().TrackByIndex, true);
1621
+ i0.ɵɵelementEnd();
1622
+ i0.ɵɵelementStart(13, "div", 182);
1623
+ i0.ɵɵrepeaterCreate(14, AnalyticsResourceComponent_Conditional_1_Conditional_25_For_15_Template, 2, 1, "span", null, i0.ɵɵrepeaterTrackByIdentity);
1624
+ i0.ɵɵelementEnd()()();
1625
+ i0.ɵɵconditionalCreate(16, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_16_Template, 12, 2, "div", 28);
1626
+ i0.ɵɵelementStart(17, "div", 122)(18, "h3");
1627
+ i0.ɵɵelement(19, "i", 183);
1628
+ i0.ɵɵtext(20, " Processing Time Breakdown (Avg per Item)");
1629
+ i0.ɵɵelementEnd();
1630
+ i0.ɵɵelementStart(21, "div", 161)(22, "div", 184);
1631
+ i0.ɵɵrepeaterCreate(23, AnalyticsResourceComponent_Conditional_1_Conditional_25_For_24_Template, 8, 7, "div", 185, _forTrack1);
1632
+ i0.ɵɵelementEnd();
1633
+ i0.ɵɵelementStart(25, "div", 186)(26, "span")(27, "strong");
1634
+ i0.ɵɵtext(28, "Total avg:");
1635
+ i0.ɵɵelementEnd();
1636
+ i0.ɵɵtext(29);
1637
+ i0.ɵɵelementEnd();
1638
+ i0.ɵɵconditionalCreate(30, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_30_Template, 3, 2, "span", 187);
1639
+ i0.ɵɵelementEnd()()();
1640
+ i0.ɵɵelementStart(31, "div", 122)(32, "h3");
1641
+ i0.ɵɵelement(33, "i", 5);
1642
+ i0.ɵɵtext(34, " Success Rate Overview");
1643
+ i0.ɵɵelementEnd();
1644
+ i0.ɵɵelementStart(35, "div", 161)(36, "div", 188)(37, "div", 189)(38, "div", 190);
1645
+ i0.ɵɵtext(39);
1646
+ i0.ɵɵelementEnd();
1647
+ i0.ɵɵelementStart(40, "div", 191);
1648
+ i0.ɵɵtext(41, "Success Rate");
1649
+ i0.ɵɵelementEnd()();
1650
+ i0.ɵɵelementStart(42, "div", 189)(43, "div", 192);
1651
+ i0.ɵɵtext(44);
1652
+ i0.ɵɵelementEnd();
1653
+ i0.ɵɵelementStart(45, "div", 191);
1654
+ i0.ɵɵtext(46, "Failure Rate");
1655
+ i0.ɵɵelementEnd()();
1656
+ i0.ɵɵelementStart(47, "div", 189)(48, "div", 193);
1657
+ i0.ɵɵtext(49);
1658
+ i0.ɵɵelementEnd();
1659
+ i0.ɵɵelementStart(50, "div", 191);
1660
+ i0.ɵɵtext(51, "Total Runs");
1661
+ i0.ɵɵelementEnd()()()()();
1662
+ i0.ɵɵconditionalCreate(52, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_52_Template, 23, 0, "div", 122);
1663
+ i0.ɵɵconditionalCreate(53, AnalyticsResourceComponent_Conditional_1_Conditional_25_Conditional_53_Template, 7, 0, "div", 122);
1664
+ i0.ɵɵelementEnd();
1665
+ } if (rf & 2) {
1666
+ const ctx_r2 = i0.ɵɵnextContext(2);
1667
+ i0.ɵɵadvance(11);
1668
+ i0.ɵɵrepeater(ctx_r2.PipelineThroughputBars);
1669
+ i0.ɵɵadvance(3);
1670
+ i0.ɵɵrepeater(ctx_r2.PipelineDateLabels);
1671
+ i0.ɵɵadvance(2);
1672
+ i0.ɵɵconditional(ctx_r2.DrillDownTarget && ctx_r2.DrillDownTarget.startsWith("pipeline-throughput:") ? 16 : -1);
1673
+ i0.ɵɵadvance(7);
1674
+ i0.ɵɵrepeater(ctx_r2.ProcessingStages);
1675
+ i0.ɵɵadvance(6);
1676
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.TotalAvgProcessingTime, "s per item");
1677
+ i0.ɵɵadvance();
1678
+ i0.ɵɵconditional(ctx_r2.BottleneckStage ? 30 : -1);
1679
+ i0.ɵɵadvance(9);
1680
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.rawProcessRuns.length > 0 ? (100 - ctx_r2.ErrorLog.length / ctx_r2.rawProcessRuns.length * 100).toFixed(1) : "100", "% ");
1681
+ i0.ɵɵadvance(5);
1682
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.rawProcessRuns.length > 0 ? (ctx_r2.ErrorLog.length / ctx_r2.rawProcessRuns.length * 100).toFixed(1) : "0", "% ");
1683
+ i0.ɵɵadvance(5);
1684
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.FormatNumber(ctx_r2.rawProcessRuns.length), " ");
1685
+ i0.ɵɵadvance(3);
1686
+ i0.ɵɵconditional(ctx_r2.ActiveRuns.length > 0 ? 52 : -1);
1687
+ i0.ɵɵadvance();
1688
+ i0.ɵɵconditional(ctx_r2.ErrorLog.length > 0 ? 53 : -1);
1689
+ } }
1690
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_For_12_Conditional_2_Template(rf, ctx) { if (rf & 1) {
1691
+ i0.ɵɵtext(0);
1692
+ } if (rf & 2) {
1693
+ const bin_r70 = i0.ɵɵnextContext().$implicit;
1694
+ i0.ɵɵtextInterpolate1(" ", bin_r70.Count, " ");
1695
+ } }
1696
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_For_12_Template(rf, ctx) { if (rf & 1) {
1697
+ const _r69 = i0.ɵɵgetCurrentView();
1698
+ i0.ɵɵelementStart(0, "div", 220);
1699
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_26_For_12_Template_div_click_0_listener() { const bin_r70 = i0.ɵɵrestoreView(_r69).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OpenDrillDown("quality-bin:" + bin_r70.Label)); });
1700
+ i0.ɵɵelementStart(1, "div", 221);
1701
+ i0.ɵɵconditionalCreate(2, AnalyticsResourceComponent_Conditional_1_Conditional_26_For_12_Conditional_2_Template, 1, 1);
1702
+ i0.ɵɵelementEnd();
1703
+ i0.ɵɵelementStart(3, "div", 222);
1704
+ i0.ɵɵtext(4);
1705
+ i0.ɵɵelementEnd()();
1706
+ } if (rf & 2) {
1707
+ const bin_r70 = ctx.$implicit;
1708
+ i0.ɵɵadvance();
1709
+ i0.ɵɵstyleProp("height", bin_r70.Percentage, "%")("background", bin_r70.Color);
1710
+ i0.ɵɵadvance();
1711
+ i0.ɵɵconditional(bin_r70.Count > 0 ? 2 : -1);
1712
+ i0.ɵɵadvance(2);
1713
+ i0.ɵɵtextInterpolate(bin_r70.Label);
1714
+ } }
1715
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_For_15_Template(rf, ctx) { if (rf & 1) {
1716
+ i0.ɵɵelementStart(0, "span")(1, "strong");
1717
+ i0.ɵɵtext(2);
1718
+ i0.ɵɵelementEnd();
1719
+ i0.ɵɵtext(3);
1720
+ i0.ɵɵelementEnd();
1721
+ } if (rf & 2) {
1722
+ const stat_r71 = ctx.$implicit;
1723
+ i0.ɵɵadvance(2);
1724
+ i0.ɵɵtextInterpolate1("", stat_r71.Label, ":");
1725
+ i0.ɵɵadvance();
1726
+ i0.ɵɵtextInterpolate1(" ", stat_r71.Value);
1727
+ } }
1728
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_6_Template(rf, ctx) { if (rf & 1) {
1729
+ const _r73 = i0.ɵɵgetCurrentView();
1730
+ i0.ɵɵelementStart(0, "button", 93);
1731
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r73); const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.ExportDrillDownCSV()); });
1732
+ i0.ɵɵelement(1, "i", 94);
1733
+ i0.ɵɵtext(2, " CSV");
1734
+ i0.ɵɵelementEnd();
1735
+ } }
1736
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_9_Template(rf, ctx) { if (rf & 1) {
1737
+ i0.ɵɵelement(0, "mj-loading", 90);
1738
+ } }
1739
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_5_Template(rf, ctx) { if (rf & 1) {
1740
+ i0.ɵɵelementStart(0, "th");
1741
+ i0.ɵɵtext(1);
1742
+ i0.ɵɵelementEnd();
1743
+ } if (rf & 2) {
1744
+ const col_r74 = ctx.$implicit;
1745
+ i0.ɵɵadvance();
1746
+ i0.ɵɵtextInterpolate(col_r74);
1747
+ } }
1748
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
1749
+ i0.ɵɵelement(0, "th", 96);
1750
+ } }
1751
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_For_2_Template(rf, ctx) { if (rf & 1) {
1752
+ i0.ɵɵelementStart(0, "td");
1753
+ i0.ɵɵtext(1);
1754
+ i0.ɵɵelementEnd();
1755
+ } if (rf & 2) {
1756
+ const col_r75 = ctx.$implicit;
1757
+ const row_r76 = i0.ɵɵnextContext().$implicit;
1758
+ i0.ɵɵadvance();
1759
+ i0.ɵɵtextInterpolate(row_r76[col_r75]);
1760
+ } }
1761
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
1762
+ const _r77 = i0.ɵɵgetCurrentView();
1763
+ i0.ɵɵelementStart(0, "button", 98);
1764
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_Conditional_3_Conditional_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r77); const row_r76 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r2.OpenDrillDownRecord(row_r76)); });
1765
+ i0.ɵɵelement(1, "i", 99);
1766
+ i0.ɵɵelementEnd();
1767
+ } }
1768
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
1769
+ i0.ɵɵelementStart(0, "td", 96);
1770
+ i0.ɵɵconditionalCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_Conditional_3_Conditional_1_Template, 2, 0, "button", 97);
1771
+ i0.ɵɵelementEnd();
1772
+ } if (rf & 2) {
1773
+ const row_r76 = i0.ɵɵnextContext().$implicit;
1774
+ i0.ɵɵadvance();
1775
+ i0.ɵɵconditional(row_r76["_RecordID"] ? 1 : -1);
1776
+ } }
1777
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_Template(rf, ctx) { if (rf & 1) {
1778
+ i0.ɵɵelementStart(0, "tr");
1779
+ i0.ɵɵrepeaterCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_For_2_Template, 2, 1, "td", null, i0.ɵɵrepeaterTrackByIdentity);
1780
+ i0.ɵɵconditionalCreate(3, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_Conditional_3_Template, 2, 1, "td", 96);
1781
+ i0.ɵɵelementEnd();
1782
+ } if (rf & 2) {
1783
+ const ctx_r2 = i0.ɵɵnextContext(5);
1784
+ i0.ɵɵadvance();
1785
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
1786
+ i0.ɵɵadvance(2);
1787
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 3 : -1);
1788
+ } }
1789
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_Template(rf, ctx) { if (rf & 1) {
1790
+ i0.ɵɵelementStart(0, "div", 91)(1, "table", 95)(2, "thead")(3, "tr");
1791
+ i0.ɵɵrepeaterCreate(4, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_5_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
1792
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_Conditional_6_Template, 1, 0, "th", 96);
1793
+ i0.ɵɵelementEnd()();
1794
+ i0.ɵɵelementStart(7, "tbody");
1795
+ i0.ɵɵrepeaterCreate(8, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_For_9_Template, 4, 1, "tr", null, i0.ɵɵcomponentInstance().TrackByIndex, true);
1796
+ i0.ɵɵelementEnd()()();
1797
+ } if (rf & 2) {
1798
+ const ctx_r2 = i0.ɵɵnextContext(4);
1799
+ i0.ɵɵadvance(4);
1800
+ i0.ɵɵrepeater(ctx_r2.DrillDownColumns);
1801
+ i0.ɵɵadvance(2);
1802
+ i0.ɵɵconditional(ctx_r2.DrillDownHasActions ? 6 : -1);
1803
+ i0.ɵɵadvance(2);
1804
+ i0.ɵɵrepeater(ctx_r2.DrillDownData);
1805
+ } }
1806
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_11_Template(rf, ctx) { if (rf & 1) {
1807
+ i0.ɵɵelementStart(0, "div", 92);
1808
+ i0.ɵɵtext(1, "No items in this confidence range");
1809
+ i0.ɵɵelementEnd();
1810
+ } }
1811
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Template(rf, ctx) { if (rf & 1) {
1812
+ const _r72 = i0.ɵɵgetCurrentView();
1813
+ i0.ɵɵelementStart(0, "div", 28)(1, "div", 83)(2, "span", 84);
1814
+ i0.ɵɵelement(3, "i", 85);
1815
+ i0.ɵɵtext(4);
1816
+ i0.ɵɵelementEnd();
1817
+ i0.ɵɵelementStart(5, "div", 86);
1818
+ i0.ɵɵconditionalCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_6_Template, 3, 0, "button", 87);
1819
+ i0.ɵɵelementStart(7, "button", 88);
1820
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r72); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.CloseDrillDown()); });
1821
+ i0.ɵɵelement(8, "i", 89);
1822
+ i0.ɵɵelementEnd()()();
1823
+ i0.ɵɵconditionalCreate(9, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_9_Template, 1, 0, "mj-loading", 90)(10, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_10_Template, 10, 1, "div", 91)(11, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Conditional_11_Template, 2, 0, "div", 92);
1824
+ i0.ɵɵelementEnd();
1825
+ } if (rf & 2) {
1826
+ const ctx_r2 = i0.ɵɵnextContext(3);
1827
+ i0.ɵɵadvance(4);
1828
+ i0.ɵɵtextInterpolate1(" Items in Confidence Range ", ctx_r2.DrillDownTarget.replace("quality-bin:", ""));
1829
+ i0.ɵɵadvance(2);
1830
+ i0.ɵɵconditional(ctx_r2.DrillDownData.length > 0 ? 6 : -1);
1831
+ i0.ɵɵadvance(3);
1832
+ i0.ɵɵconditional(ctx_r2.IsDrillDownLoading ? 9 : ctx_r2.DrillDownData.length > 0 ? 10 : 11);
1833
+ } }
1834
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_17_For_7_Template(rf, ctx) { if (rf & 1) {
1835
+ i0.ɵɵelementStart(0, "div", 225)(1, "div", 227);
1836
+ i0.ɵɵelement(2, "div", 228)(3, "div", 229)(4, "div", 230);
1837
+ i0.ɵɵelementEnd();
1838
+ i0.ɵɵelementStart(5, "div", 231);
1839
+ i0.ɵɵtext(6);
1840
+ i0.ɵɵelementEnd()();
1841
+ } if (rf & 2) {
1842
+ const entity_r78 = ctx.$implicit;
1843
+ i0.ɵɵadvance(2);
1844
+ i0.ɵɵstyleProp("height", entity_r78.High, "%");
1845
+ i0.ɵɵproperty("title", "High: " + entity_r78.High + "%");
1846
+ i0.ɵɵadvance();
1847
+ i0.ɵɵstyleProp("height", entity_r78.Med, "%");
1848
+ i0.ɵɵproperty("title", "Med: " + entity_r78.Med + "%");
1849
+ i0.ɵɵadvance();
1850
+ i0.ɵɵstyleProp("height", entity_r78.Low, "%");
1851
+ i0.ɵɵproperty("title", "Low: " + entity_r78.Low + "%");
1852
+ i0.ɵɵadvance(2);
1853
+ i0.ɵɵtextInterpolate(entity_r78.Name);
1854
+ } }
1855
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_17_For_10_Template(rf, ctx) { if (rf & 1) {
1856
+ i0.ɵɵelementStart(0, "div", 61);
1857
+ i0.ɵɵelement(1, "div", 143);
1858
+ i0.ɵɵtext(2);
1859
+ i0.ɵɵelementEnd();
1860
+ } if (rf & 2) {
1861
+ const item_r79 = ctx.$implicit;
1862
+ i0.ɵɵadvance();
1863
+ i0.ɵɵstyleProp("background", item_r79.Color);
1864
+ i0.ɵɵadvance();
1865
+ i0.ɵɵtextInterpolate1(" ", item_r79.Label);
1866
+ } }
1867
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_17_Template(rf, ctx) { if (rf & 1) {
1868
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
1869
+ i0.ɵɵelement(2, "i", 223);
1870
+ i0.ɵɵtext(3, " Weight Distribution by Entity");
1871
+ i0.ɵɵelementEnd();
1872
+ i0.ɵɵelementStart(4, "div", 161)(5, "div", 224);
1873
+ i0.ɵɵrepeaterCreate(6, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_17_For_7_Template, 7, 10, "div", 225, _forTrack1);
1874
+ i0.ɵɵelementEnd();
1875
+ i0.ɵɵelementStart(8, "div", 226);
1876
+ i0.ɵɵrepeaterCreate(9, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_17_For_10_Template, 3, 3, "div", 61, _forTrack2);
1877
+ i0.ɵɵelementEnd()()();
1878
+ } if (rf & 2) {
1879
+ const ctx_r2 = i0.ɵɵnextContext(3);
1880
+ i0.ɵɵadvance(6);
1881
+ i0.ɵɵrepeater(ctx_r2.WeightByEntity);
1882
+ i0.ɵɵadvance(3);
1883
+ i0.ɵɵrepeater(ctx_r2.WeightLegend);
1884
+ } }
1885
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_18_For_21_Template(rf, ctx) { if (rf & 1) {
1886
+ i0.ɵɵnamespaceSVG();
1887
+ i0.ɵɵelement(0, "circle", 239);
1888
+ } if (rf & 2) {
1889
+ const dot_r80 = ctx.$implicit;
1890
+ i0.ɵɵattribute("cx", dot_r80.Cx)("cy", dot_r80.Cy);
1891
+ } }
1892
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_18_For_24_Template(rf, ctx) { if (rf & 1) {
1893
+ i0.ɵɵelementStart(0, "span");
1894
+ i0.ɵɵtext(1);
1895
+ i0.ɵɵelementEnd();
1896
+ } if (rf & 2) {
1897
+ const label_r81 = ctx.$implicit;
1898
+ i0.ɵɵadvance();
1899
+ i0.ɵɵtextInterpolate(label_r81);
1900
+ } }
1901
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_18_Template(rf, ctx) { if (rf & 1) {
1902
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
1903
+ i0.ɵɵelement(2, "i", 5);
1904
+ i0.ɵɵtext(3, " Tag Accuracy Over Time (Weekly Avg Confidence)");
1905
+ i0.ɵɵelementEnd();
1906
+ i0.ɵɵelementStart(4, "div", 161)(5, "div", 232)(6, "div", 233)(7, "div");
1907
+ i0.ɵɵtext(8, "1.0");
1908
+ i0.ɵɵelementEnd();
1909
+ i0.ɵɵelementStart(9, "div");
1910
+ i0.ɵɵtext(10, "0.75");
1911
+ i0.ɵɵelementEnd();
1912
+ i0.ɵɵelementStart(11, "div");
1913
+ i0.ɵɵtext(12, "0.50");
1914
+ i0.ɵɵelementEnd();
1915
+ i0.ɵɵelementStart(13, "div");
1916
+ i0.ɵɵtext(14, "0.25");
1917
+ i0.ɵɵelementEnd()();
1918
+ i0.ɵɵelementStart(15, "div", 234);
1919
+ i0.ɵɵelement(16, "div", 235)(17, "div", 236);
1920
+ i0.ɵɵnamespaceSVG();
1921
+ i0.ɵɵelementStart(18, "svg", 237);
1922
+ i0.ɵɵelement(19, "polyline", 238);
1923
+ i0.ɵɵrepeaterCreate(20, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_18_For_21_Template, 1, 2, ":svg:circle", 239, i0.ɵɵcomponentInstance().TrackByIndex, true);
1924
+ i0.ɵɵelementEnd()()();
1925
+ i0.ɵɵnamespaceHTML();
1926
+ i0.ɵɵelementStart(22, "div", 240);
1927
+ i0.ɵɵrepeaterCreate(23, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_18_For_24_Template, 2, 1, "span", null, i0.ɵɵrepeaterTrackByIdentity);
1928
+ i0.ɵɵelementEnd();
1929
+ i0.ɵɵelementStart(25, "div", 241);
1930
+ i0.ɵɵelement(26, "i", 242);
1931
+ i0.ɵɵtext(27);
1932
+ i0.ɵɵelementEnd()()();
1933
+ } if (rf & 2) {
1934
+ const ctx_r2 = i0.ɵɵnextContext(3);
1935
+ i0.ɵɵadvance(19);
1936
+ i0.ɵɵattribute("points", ctx_r2.AccuracyLinePoints);
1937
+ i0.ɵɵadvance();
1938
+ i0.ɵɵrepeater(ctx_r2.AccuracyDots);
1939
+ i0.ɵɵadvance(3);
1940
+ i0.ɵɵrepeater(ctx_r2.AccuracyMonthLabels);
1941
+ i0.ɵɵadvance(4);
1942
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.AccuracyTrendText, " ");
1943
+ } }
1944
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_19_For_20_Template(rf, ctx) { if (rf & 1) {
1945
+ i0.ɵɵelementStart(0, "tr")(1, "td")(2, "strong");
1946
+ i0.ɵɵtext(3);
1947
+ i0.ɵɵelementEnd()();
1948
+ i0.ɵɵelementStart(4, "td", 128);
1949
+ i0.ɵɵtext(5);
1950
+ i0.ɵɵelementEnd();
1951
+ i0.ɵɵelementStart(6, "td", 128);
1952
+ i0.ɵɵtext(7);
1953
+ i0.ɵɵelementEnd();
1954
+ i0.ɵɵelementStart(8, "td");
1955
+ i0.ɵɵtext(9);
1956
+ i0.ɵɵelementEnd();
1957
+ i0.ɵɵelementStart(10, "td")(11, "span", 157);
1958
+ i0.ɵɵtext(12);
1959
+ i0.ɵɵelementEnd()()();
1960
+ } if (rf & 2) {
1961
+ const tag_r82 = ctx.$implicit;
1962
+ i0.ɵɵadvance(3);
1963
+ i0.ɵɵtextInterpolate(tag_r82.Name);
1964
+ i0.ɵɵadvance(2);
1965
+ i0.ɵɵtextInterpolate(tag_r82.AvgWeight);
1966
+ i0.ɵɵadvance(2);
1967
+ i0.ɵɵtextInterpolate(tag_r82.UsageCount);
1968
+ i0.ɵɵadvance(2);
1969
+ i0.ɵɵtextInterpolate(tag_r82.TopEntity);
1970
+ i0.ɵɵadvance(2);
1971
+ i0.ɵɵclassMap(tag_r82.ActionClass);
1972
+ i0.ɵɵadvance();
1973
+ i0.ɵɵtextInterpolate(tag_r82.SuggestedAction);
1974
+ } }
1975
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_19_Template(rf, ctx) { if (rf & 1) {
1976
+ i0.ɵɵelementStart(0, "div", 122)(1, "h3");
1977
+ i0.ɵɵelement(2, "i", 243);
1978
+ i0.ɵɵtext(3, " Low-Confidence Tags (Avg Weight < 0.4)");
1979
+ i0.ɵɵelementEnd();
1980
+ i0.ɵɵelementStart(4, "div", 120)(5, "table", 95)(6, "thead")(7, "tr")(8, "th");
1981
+ i0.ɵɵtext(9, "Tag Name");
1982
+ i0.ɵɵelementEnd();
1983
+ i0.ɵɵelementStart(10, "th", 128);
1984
+ i0.ɵɵtext(11, "Avg Weight");
1985
+ i0.ɵɵelementEnd();
1986
+ i0.ɵɵelementStart(12, "th", 128);
1987
+ i0.ɵɵtext(13, "Usage Count");
1988
+ i0.ɵɵelementEnd();
1989
+ i0.ɵɵelementStart(14, "th");
1990
+ i0.ɵɵtext(15, "Top Entity");
1991
+ i0.ɵɵelementEnd();
1992
+ i0.ɵɵelementStart(16, "th");
1993
+ i0.ɵɵtext(17, "Suggested Action");
1994
+ i0.ɵɵelementEnd()()();
1995
+ i0.ɵɵelementStart(18, "tbody");
1996
+ i0.ɵɵrepeaterCreate(19, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_19_For_20_Template, 13, 7, "tr", null, _forTrack1);
1997
+ i0.ɵɵelementEnd()()()();
1998
+ } if (rf & 2) {
1999
+ const ctx_r2 = i0.ɵɵnextContext(3);
2000
+ i0.ɵɵadvance(19);
2001
+ i0.ɵɵrepeater(ctx_r2.LowConfidenceTags);
2002
+ } }
2003
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_For_26_Template(rf, ctx) { if (rf & 1) {
2004
+ i0.ɵɵelementStart(0, "div", 218)(1, "div", 244);
2005
+ i0.ɵɵelement(2, "i", 156);
2006
+ i0.ɵɵtext(3);
2007
+ i0.ɵɵelementEnd();
2008
+ i0.ɵɵnamespaceSVG();
2009
+ i0.ɵɵelementStart(4, "svg", 245);
2010
+ i0.ɵɵelement(5, "circle", 246)(6, "circle", 247);
2011
+ i0.ɵɵelementEnd();
2012
+ i0.ɵɵnamespaceHTML();
2013
+ i0.ɵɵelementStart(7, "div", 248);
2014
+ i0.ɵɵtext(8);
2015
+ i0.ɵɵelementEnd();
2016
+ i0.ɵɵelementStart(9, "div", 249);
2017
+ i0.ɵɵtext(10);
2018
+ i0.ɵɵelementEnd();
2019
+ i0.ɵɵelementStart(11, "div", 249);
2020
+ i0.ɵɵtext(12);
2021
+ i0.ɵɵelementEnd();
2022
+ i0.ɵɵelementStart(13, "div", 250);
2023
+ i0.ɵɵtext(14);
2024
+ i0.ɵɵelementEnd()();
2025
+ } if (rf & 2) {
2026
+ const model_r83 = ctx.$implicit;
2027
+ const ctx_r2 = i0.ɵɵnextContext(3);
2028
+ i0.ɵɵadvance(2);
2029
+ i0.ɵɵclassMap(model_r83.Icon);
2030
+ i0.ɵɵstyleProp("color", model_r83.IconColor);
2031
+ i0.ɵɵadvance();
2032
+ i0.ɵɵtextInterpolate1(" ", model_r83.Name);
2033
+ i0.ɵɵadvance(3);
2034
+ i0.ɵɵattribute("stroke", model_r83.ScoreColor)("stroke-dasharray", model_r83.StrokeDash);
2035
+ i0.ɵɵadvance();
2036
+ i0.ɵɵstyleProp("color", model_r83.ScoreColor);
2037
+ i0.ɵɵadvance();
2038
+ i0.ɵɵtextInterpolate1("", model_r83.ScorePercentage, "%");
2039
+ i0.ɵɵadvance(2);
2040
+ i0.ɵɵtextInterpolate1("Avg confidence: ", model_r83.AvgConfidence);
2041
+ i0.ɵɵadvance(2);
2042
+ i0.ɵɵtextInterpolate1("", ctx_r2.FormatNumber(model_r83.TagsGenerated), " tags generated");
2043
+ i0.ɵɵadvance();
2044
+ i0.ɵɵstyleProp("color", model_r83.RoleColor);
2045
+ i0.ɵɵadvance();
2046
+ i0.ɵɵtextInterpolate(model_r83.Role);
2047
+ } }
2048
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_27_Template(rf, ctx) { if (rf & 1) {
2049
+ i0.ɵɵelementStart(0, "div", 219);
2050
+ i0.ɵɵelement(1, "i", 251);
2051
+ i0.ɵɵelementStart(2, "div")(3, "strong");
2052
+ i0.ɵɵtext(4, "Recommendation:");
2053
+ i0.ɵɵelementEnd();
2054
+ i0.ɵɵtext(5);
2055
+ i0.ɵɵelementEnd()();
2056
+ } if (rf & 2) {
2057
+ const ctx_r2 = i0.ɵɵnextContext(3);
2058
+ i0.ɵɵadvance(5);
2059
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.ModelRecommendation, " ");
2060
+ } }
2061
+ function AnalyticsResourceComponent_Conditional_1_Conditional_26_Template(rf, ctx) { if (rf & 1) {
2062
+ i0.ɵɵelementStart(0, "section", 17)(1, "div", 19);
2063
+ i0.ɵɵelement(2, "i", 211);
2064
+ i0.ɵɵelementStart(3, "h1");
2065
+ i0.ɵɵtext(4, "Quality");
2066
+ i0.ɵɵelementEnd()();
2067
+ i0.ɵɵelementStart(5, "div", 117)(6, "h3");
2068
+ i0.ɵɵelement(7, "i", 212);
2069
+ i0.ɵɵtext(8, " Confidence Distribution");
2070
+ i0.ɵɵelementEnd();
2071
+ i0.ɵɵelementStart(9, "div", 161)(10, "div", 213);
2072
+ i0.ɵɵrepeaterCreate(11, AnalyticsResourceComponent_Conditional_1_Conditional_26_For_12_Template, 5, 6, "div", 214, _forTrack2);
2073
+ i0.ɵɵelementEnd();
2074
+ i0.ɵɵelementStart(13, "div", 215);
2075
+ i0.ɵɵrepeaterCreate(14, AnalyticsResourceComponent_Conditional_1_Conditional_26_For_15_Template, 4, 2, "span", null, _forTrack2);
2076
+ i0.ɵɵelementEnd()()();
2077
+ i0.ɵɵconditionalCreate(16, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_16_Template, 12, 3, "div", 28);
2078
+ i0.ɵɵconditionalCreate(17, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_17_Template, 11, 0, "div", 122);
2079
+ i0.ɵɵconditionalCreate(18, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_18_Template, 28, 2, "div", 122);
2080
+ i0.ɵɵconditionalCreate(19, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_19_Template, 21, 0, "div", 122);
2081
+ i0.ɵɵelementStart(20, "div", 122)(21, "h3");
2082
+ i0.ɵɵelement(22, "i", 216);
2083
+ i0.ɵɵtext(23, " Model Performance Comparison");
2084
+ i0.ɵɵelementEnd();
2085
+ i0.ɵɵelementStart(24, "div", 217);
2086
+ i0.ɵɵrepeaterCreate(25, AnalyticsResourceComponent_Conditional_1_Conditional_26_For_26_Template, 15, 15, "div", 218, _forTrack1);
2087
+ i0.ɵɵelementEnd();
2088
+ i0.ɵɵconditionalCreate(27, AnalyticsResourceComponent_Conditional_1_Conditional_26_Conditional_27_Template, 6, 1, "div", 219);
2089
+ i0.ɵɵelementEnd()();
2090
+ } if (rf & 2) {
2091
+ const ctx_r2 = i0.ɵɵnextContext(2);
2092
+ i0.ɵɵadvance(11);
2093
+ i0.ɵɵrepeater(ctx_r2.ConfidenceHistogram);
2094
+ i0.ɵɵadvance(3);
2095
+ i0.ɵɵrepeater(ctx_r2.ConfidenceStats);
2096
+ i0.ɵɵadvance(2);
2097
+ i0.ɵɵconditional(ctx_r2.DrillDownTarget && ctx_r2.DrillDownTarget.startsWith("quality-bin:") ? 16 : -1);
2098
+ i0.ɵɵadvance();
2099
+ i0.ɵɵconditional(ctx_r2.WeightByEntity.length > 0 ? 17 : -1);
2100
+ i0.ɵɵadvance();
2101
+ i0.ɵɵconditional(ctx_r2.AccuracyLinePoints ? 18 : -1);
2102
+ i0.ɵɵadvance();
2103
+ i0.ɵɵconditional(ctx_r2.LowConfidenceTags.length > 0 ? 19 : -1);
2104
+ i0.ɵɵadvance(6);
2105
+ i0.ɵɵrepeater(ctx_r2.ModelComparisons);
2106
+ i0.ɵɵadvance(2);
2107
+ i0.ɵɵconditional(ctx_r2.ModelRecommendation ? 27 : -1);
2108
+ } }
2109
+ function AnalyticsResourceComponent_Conditional_1_Conditional_27_For_15_Template(rf, ctx) { if (rf & 1) {
2110
+ const _r85 = i0.ɵɵgetCurrentView();
2111
+ i0.ɵɵelementStart(0, "button", 73);
2112
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_27_For_15_Template_button_click_0_listener() { const range_r86 = i0.ɵɵrestoreView(_r85).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.SetDateRange(range_r86.Label)); });
2113
+ i0.ɵɵtext(1);
2114
+ i0.ɵɵelementEnd();
2115
+ } if (rf & 2) {
2116
+ const range_r86 = ctx.$implicit;
2117
+ const ctx_r2 = i0.ɵɵnextContext(3);
2118
+ i0.ɵɵclassProp("active", ctx_r2.ActiveDateRange === range_r86.Label);
2119
+ i0.ɵɵadvance();
2120
+ i0.ɵɵtextInterpolate(range_r86.Label);
2121
+ } }
2122
+ function AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_16_For_2_Template(rf, ctx) { if (rf & 1) {
2123
+ i0.ɵɵelementStart(0, "div", 257)(1, "div", 258);
2124
+ i0.ɵɵelement(2, "i");
2125
+ i0.ɵɵelementEnd();
2126
+ i0.ɵɵelementStart(3, "div")(4, "div", 259);
2127
+ i0.ɵɵtext(5);
2128
+ i0.ɵɵelementEnd();
2129
+ i0.ɵɵelementStart(6, "div", 260);
2130
+ i0.ɵɵtext(7);
2131
+ i0.ɵɵelementEnd();
2132
+ i0.ɵɵelementStart(8, "div", 261);
2133
+ i0.ɵɵtext(9);
2134
+ i0.ɵɵelementEnd()()();
2135
+ } if (rf & 2) {
2136
+ const kpi_r87 = ctx.$implicit;
2137
+ i0.ɵɵadvance(2);
2138
+ i0.ɵɵclassMap(kpi_r87.Icon);
2139
+ i0.ɵɵadvance(3);
2140
+ i0.ɵɵtextInterpolate(kpi_r87.Value);
2141
+ i0.ɵɵadvance(2);
2142
+ i0.ɵɵtextInterpolate(kpi_r87.Label);
2143
+ i0.ɵɵadvance(2);
2144
+ i0.ɵɵtextInterpolate(kpi_r87.SubLabel);
2145
+ } }
2146
+ function AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_16_Template(rf, ctx) { if (rf & 1) {
2147
+ i0.ɵɵelementStart(0, "div", 256);
2148
+ i0.ɵɵrepeaterCreate(1, AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_16_For_2_Template, 10, 5, "div", 257, _forTrack2);
2149
+ i0.ɵɵelementEnd();
2150
+ } if (rf & 2) {
2151
+ const ctx_r2 = i0.ɵɵnextContext(3);
2152
+ i0.ɵɵadvance();
2153
+ i0.ɵɵrepeater(ctx_r2.CostKPIs);
2154
+ } }
2155
+ function AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_21_For_16_Template(rf, ctx) { if (rf & 1) {
2156
+ i0.ɵɵelementStart(0, "tr")(1, "td", 201);
2157
+ i0.ɵɵtext(2);
2158
+ i0.ɵɵelementEnd();
2159
+ i0.ɵɵelementStart(3, "td");
2160
+ i0.ɵɵtext(4);
2161
+ i0.ɵɵelementEnd();
2162
+ i0.ɵɵelementStart(5, "td", 128);
2163
+ i0.ɵɵtext(6);
2164
+ i0.ɵɵelementEnd();
2165
+ i0.ɵɵelementStart(7, "td", 128);
2166
+ i0.ɵɵtext(8);
2167
+ i0.ɵɵelementEnd();
2168
+ i0.ɵɵelementStart(9, "td", 134);
2169
+ i0.ɵɵtext(10);
2170
+ i0.ɵɵelementEnd()();
2171
+ } if (rf & 2) {
2172
+ const row_r88 = ctx.$implicit;
2173
+ const ctx_r2 = i0.ɵɵnextContext(4);
2174
+ i0.ɵɵadvance(2);
2175
+ i0.ɵɵtextInterpolate(row_r88.RunID);
2176
+ i0.ɵɵadvance(2);
2177
+ i0.ɵɵtextInterpolate(row_r88.Source);
2178
+ i0.ɵɵadvance(2);
2179
+ i0.ɵɵtextInterpolate(ctx_r2.FormatNumber(row_r88.Tokens));
2180
+ i0.ɵɵadvance(2);
2181
+ i0.ɵɵtextInterpolate(row_r88.Cost > 0 ? "$" + row_r88.Cost.toFixed(4) : "$0.00");
2182
+ i0.ɵɵadvance(2);
2183
+ i0.ɵɵtextInterpolate(row_r88.Started);
2184
+ } }
2185
+ function AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_21_Template(rf, ctx) { if (rf & 1) {
2186
+ i0.ɵɵelementStart(0, "div", 120)(1, "table", 95)(2, "thead")(3, "tr")(4, "th");
2187
+ i0.ɵɵtext(5, "Run ID");
2188
+ i0.ɵɵelementEnd();
2189
+ i0.ɵɵelementStart(6, "th");
2190
+ i0.ɵɵtext(7, "Source");
2191
+ i0.ɵɵelementEnd();
2192
+ i0.ɵɵelementStart(8, "th", 128);
2193
+ i0.ɵɵtext(9, "Tokens");
2194
+ i0.ɵɵelementEnd();
2195
+ i0.ɵɵelementStart(10, "th", 128);
2196
+ i0.ɵɵtext(11, "Cost");
2197
+ i0.ɵɵelementEnd();
2198
+ i0.ɵɵelementStart(12, "th");
2199
+ i0.ɵɵtext(13, "Started");
2200
+ i0.ɵɵelementEnd()()();
2201
+ i0.ɵɵelementStart(14, "tbody");
2202
+ i0.ɵɵrepeaterCreate(15, AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_21_For_16_Template, 11, 5, "tr", null, _forTrack5);
2203
+ i0.ɵɵelementEnd()()();
2204
+ } if (rf & 2) {
2205
+ const ctx_r2 = i0.ɵɵnextContext(3);
2206
+ i0.ɵɵadvance(15);
2207
+ i0.ɵɵrepeater(ctx_r2.CostPerRunRows);
2208
+ } }
2209
+ function AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_22_Template(rf, ctx) { if (rf & 1) {
2210
+ i0.ɵɵelementStart(0, "div", 121);
2211
+ i0.ɵɵelement(1, "i", 252);
2212
+ i0.ɵɵelementStart(2, "p");
2213
+ i0.ɵɵtext(3, "No cost data available yet. Run the pipeline to generate cost and token usage metrics.");
2214
+ i0.ɵɵelementEnd();
2215
+ i0.ɵɵelementStart(4, "p", 262);
2216
+ i0.ɵɵtext(5, "Cost data is aggregated from ContentProcessRunDetail records linked to AI Prompt Runs.");
2217
+ i0.ɵɵelementEnd()();
2218
+ } }
2219
+ function AnalyticsResourceComponent_Conditional_1_Conditional_27_Template(rf, ctx) { if (rf & 1) {
2220
+ const _r84 = i0.ɵɵgetCurrentView();
2221
+ i0.ɵɵelementStart(0, "section", 17)(1, "div", 19);
2222
+ i0.ɵɵelement(2, "i", 252);
2223
+ i0.ɵɵelementStart(3, "h1");
2224
+ i0.ɵɵtext(4, "Cost & Usage");
2225
+ i0.ɵɵelementEnd();
2226
+ i0.ɵɵelementStart(5, "div", 253)(6, "button", 93);
2227
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_27_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r84); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.ExportTabDataCSV("cost-usage")); });
2228
+ i0.ɵɵelement(7, "i", 94);
2229
+ i0.ɵɵtext(8, " CSV ");
2230
+ i0.ɵɵelementEnd();
2231
+ i0.ɵɵelementStart(9, "button", 254);
2232
+ i0.ɵɵlistener("click", function AnalyticsResourceComponent_Conditional_1_Conditional_27_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r84); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.PrintCurrentTab()); });
2233
+ i0.ɵɵelement(10, "i", 255);
2234
+ i0.ɵɵtext(11, " Print ");
2235
+ i0.ɵɵelementEnd()()();
2236
+ i0.ɵɵelementStart(12, "div", 21)(13, "div", 22);
2237
+ i0.ɵɵrepeaterCreate(14, AnalyticsResourceComponent_Conditional_1_Conditional_27_For_15_Template, 2, 3, "button", 23, _forTrack2);
2238
+ i0.ɵɵelementEnd()();
2239
+ i0.ɵɵconditionalCreate(16, AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_16_Template, 3, 0, "div", 256);
2240
+ i0.ɵɵelementStart(17, "div", 122)(18, "h3");
2241
+ i0.ɵɵelement(19, "i", 85);
2242
+ i0.ɵɵtext(20, " Cost Breakdown by Run");
2243
+ i0.ɵɵelementEnd();
2244
+ i0.ɵɵconditionalCreate(21, AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_21_Template, 17, 0, "div", 120)(22, AnalyticsResourceComponent_Conditional_1_Conditional_27_Conditional_22_Template, 6, 0, "div", 121);
2245
+ i0.ɵɵelementEnd()();
2246
+ } if (rf & 2) {
2247
+ const ctx_r2 = i0.ɵɵnextContext(2);
2248
+ i0.ɵɵadvance(14);
2249
+ i0.ɵɵrepeater(ctx_r2.DateRanges);
2250
+ i0.ɵɵadvance(2);
2251
+ i0.ɵɵconditional(ctx_r2.CostKPIs.length > 0 ? 16 : -1);
2252
+ i0.ɵɵadvance(5);
2253
+ i0.ɵɵconditional(ctx_r2.CostPerRunRows.length > 0 ? 21 : 22);
2254
+ } }
2255
+ function AnalyticsResourceComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
2256
+ i0.ɵɵelementStart(0, "div", 1)(1, "aside", 3)(2, "div", 4)(3, "h2");
2257
+ i0.ɵɵelement(4, "i", 5);
2258
+ i0.ɵɵtext(5, " Analytics");
2259
+ i0.ɵɵelementEnd()();
2260
+ i0.ɵɵelementStart(6, "nav", 6);
2261
+ i0.ɵɵrepeaterCreate(7, AnalyticsResourceComponent_Conditional_1_For_8_Template, 3, 5, "button", 7, _forTrack0);
2262
+ i0.ɵɵelementEnd();
2263
+ i0.ɵɵelement(9, "div", 8);
2264
+ i0.ɵɵelementStart(10, "div", 9)(11, "h3");
2265
+ i0.ɵɵelement(12, "i", 10);
2266
+ i0.ɵɵtext(13, " Trending Tags");
2267
+ i0.ɵɵelementEnd();
2268
+ i0.ɵɵelementStart(14, "div", 11);
2269
+ i0.ɵɵrepeaterCreate(15, AnalyticsResourceComponent_Conditional_1_For_16_Template, 2, 5, "span", 12, _forTrack1);
2270
+ i0.ɵɵconditionalCreate(17, AnalyticsResourceComponent_Conditional_1_Conditional_17_Template, 2, 0, "span", 13);
2271
+ i0.ɵɵelementEnd()();
2272
+ i0.ɵɵelementStart(18, "div", 14);
2273
+ i0.ɵɵelement(19, "span", 15);
2274
+ i0.ɵɵtext(20);
2275
+ i0.ɵɵelementEnd()();
2276
+ i0.ɵɵelementStart(21, "div", 16);
2277
+ i0.ɵɵconditionalCreate(22, AnalyticsResourceComponent_Conditional_1_Conditional_22_Template, 98, 7, "section", 17);
2278
+ i0.ɵɵconditionalCreate(23, AnalyticsResourceComponent_Conditional_1_Conditional_23_Template, 28, 9, "section", 17);
2279
+ i0.ɵɵconditionalCreate(24, AnalyticsResourceComponent_Conditional_1_Conditional_24_Template, 14, 4, "section", 17);
2280
+ i0.ɵɵconditionalCreate(25, AnalyticsResourceComponent_Conditional_1_Conditional_25_Template, 54, 8, "section", 17);
2281
+ i0.ɵɵconditionalCreate(26, AnalyticsResourceComponent_Conditional_1_Conditional_26_Template, 28, 5, "section", 17);
2282
+ i0.ɵɵconditionalCreate(27, AnalyticsResourceComponent_Conditional_1_Conditional_27_Template, 23, 2, "section", 17);
2283
+ i0.ɵɵelementEnd()();
2284
+ } if (rf & 2) {
2285
+ const ctx_r2 = i0.ɵɵnextContext();
2286
+ i0.ɵɵadvance(7);
2287
+ i0.ɵɵrepeater(ctx_r2.NavItems);
2288
+ i0.ɵɵadvance(8);
2289
+ i0.ɵɵrepeater(ctx_r2.TrendingTags);
2290
+ i0.ɵɵadvance(2);
2291
+ i0.ɵɵconditional(ctx_r2.TrendingTags.length === 0 ? 17 : -1);
2292
+ i0.ɵɵadvance(2);
2293
+ i0.ɵɵclassProp("status-dot-error", !ctx_r2.PipelineStatusOk);
2294
+ i0.ɵɵadvance();
2295
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.PipelineStatusText, " ");
2296
+ i0.ɵɵadvance(2);
2297
+ i0.ɵɵconditional(ctx_r2.ActiveTab === "overview" ? 22 : -1);
2298
+ i0.ɵɵadvance();
2299
+ i0.ɵɵconditional(ctx_r2.ActiveTab === "tags" ? 23 : -1);
2300
+ i0.ɵɵadvance();
2301
+ i0.ɵɵconditional(ctx_r2.ActiveTab === "sources" ? 24 : -1);
2302
+ i0.ɵɵadvance();
2303
+ i0.ɵɵconditional(ctx_r2.ActiveTab === "pipeline" ? 25 : -1);
2304
+ i0.ɵɵadvance();
2305
+ i0.ɵɵconditional(ctx_r2.ActiveTab === "quality" ? 26 : -1);
2306
+ i0.ɵɵadvance();
2307
+ i0.ɵɵconditional(ctx_r2.ActiveTab === "cost" ? 27 : -1);
2308
+ } }
2309
+ // ================================================================
2310
+ // Component
2311
+ // ================================================================
2312
+ let AnalyticsResourceComponent = class AnalyticsResourceComponent extends BaseResourceComponent {
2313
+ static { AnalyticsResourceComponent_1 = this; }
2314
+ cdr = inject(ChangeDetectorRef);
2315
+ navigationService = inject(NavigationService);
2316
+ destroy$ = new Subject();
2317
+ async GetResourceDisplayName(_data) {
2318
+ return 'Analytics';
2319
+ }
2320
+ async GetResourceIconClass(_data) {
2321
+ return 'fa-solid fa-chart-line';
2322
+ }
2323
+ // ================================================================
2324
+ // Navigation
2325
+ // ================================================================
2326
+ NavItems = [
2327
+ { ID: 'overview', Label: 'Overview', Icon: 'fa-solid fa-grip' },
2328
+ { ID: 'tags', Label: 'Tags', Icon: 'fa-solid fa-tags' },
2329
+ { ID: 'sources', Label: 'Sources', Icon: 'fa-solid fa-database' },
2330
+ { ID: 'pipeline', Label: 'Pipeline', Icon: 'fa-solid fa-gears' },
2331
+ { ID: 'quality', Label: 'Quality', Icon: 'fa-solid fa-circle-check' },
2332
+ { ID: 'cost', Label: 'Cost & Usage', Icon: 'fa-solid fa-coins' },
2333
+ ];
2334
+ ActiveTab = 'overview';
2335
+ IsLoading = true;
2336
+ // ================================================================
2337
+ // Filter State
2338
+ // ================================================================
2339
+ DateRanges = [
2340
+ { Label: '7D', Days: 7 },
2341
+ { Label: '30D', Days: 30 },
2342
+ { Label: '90D', Days: 90 },
2343
+ { Label: 'YTD', Days: -1 },
2344
+ { Label: 'All', Days: 0 },
2345
+ ];
2346
+ ActiveDateRange = '30D';
2347
+ EntityFilter = 'All Entities';
2348
+ EntityFilterOptions = ['All Entities'];
2349
+ // ================================================================
2350
+ // Drill-Down
2351
+ // ================================================================
2352
+ DrillDownTarget = null;
2353
+ DrillDownData = [];
2354
+ DrillDownColumns = [];
2355
+ IsDrillDownLoading = false;
2356
+ /** Whether the current drill-down rows have navigable records */
2357
+ DrillDownHasActions = false;
2358
+ /** AN-1: Open a record from a drill-down table row */
2359
+ OpenDrillDownRecord(row) {
2360
+ const entityName = row['_EntityName'];
2361
+ const recordID = row['_RecordID'];
2362
+ if (!entityName || !recordID)
2363
+ return;
2364
+ // D9: If this is a Tag record, navigate to Classify Tag Library instead
2365
+ if (entityName === 'MJ: Tags') {
2366
+ const tagName = row['Name'] ?? row['Tag Name'] ?? '';
2367
+ this.navigateToClassifyTagLibrary(tagName);
2368
+ return;
2369
+ }
2370
+ const md = new Metadata();
2371
+ const entityInfo = md.Entities.find(e => e.Name === entityName);
2372
+ const pkey = new CompositeKey();
2373
+ if (entityInfo) {
2374
+ pkey.LoadFromURLSegment(entityInfo, recordID);
2375
+ }
2376
+ else {
2377
+ pkey.KeyValuePairs = [{ FieldName: 'ID', Value: recordID }];
2378
+ }
2379
+ this.navigationService.OpenEntityRecord(entityName, pkey);
2380
+ }
2381
+ /**
2382
+ * D9: Navigate to the Classify dashboard's Tag Library tab with a tag pre-selected.
2383
+ * Uses NavigationService.OpenNavItemByName to switch to the Classify nav item
2384
+ * and passes the tag name and target tab via configuration.
2385
+ */
2386
+ navigateToClassifyTagLibrary(tagName) {
2387
+ this.navigationService.OpenNavItemByName('Classify', {
2388
+ initialTab: 'tags',
2389
+ tagSearch: tagName,
2390
+ });
2391
+ }
2392
+ // ================================================================
2393
+ // Overview Tab Data
2394
+ // ================================================================
2395
+ KPIs = [];
2396
+ WidgetCards = [
2397
+ { Key: 'tagGrowth', Title: 'Tag Growth', Icon: 'fa-solid fa-chart-line' },
2398
+ { Key: 'contentCoverage', Title: 'Content Coverage', Icon: 'fa-solid fa-bullseye' },
2399
+ { Key: 'qualityScore', Title: 'Quality Score', Icon: 'fa-solid fa-gauge-high' },
2400
+ { Key: 'sourcePerformance', Title: 'Source Performance', Icon: 'fa-solid fa-ranking-star' },
2401
+ { Key: 'dailyThroughput', Title: 'Daily Throughput', Icon: 'fa-solid fa-bolt' },
2402
+ { Key: 'taxonomyHealth', Title: 'Taxonomy Health', Icon: 'fa-solid fa-sitemap' },
2403
+ ];
2404
+ TagGrowthData = [];
2405
+ CoverageData = [];
2406
+ QualityScore = 0;
2407
+ MiniConfidenceBins = [];
2408
+ SourcePerfData = [];
2409
+ ThroughputData = [];
2410
+ TaxonomyTotal = 0;
2411
+ TaxonomyStats = [];
2412
+ TaxonomyRingSegments = [];
2413
+ // ================================================================
2414
+ // Tags Tab Data
2415
+ // ================================================================
2416
+ TopTags = [];
2417
+ EntityDistribution = [];
2418
+ DistributionLegend = [
2419
+ { Label: 'Primary', Color: 'var(--mj-brand-primary)' },
2420
+ { Label: 'Secondary', Color: 'var(--mj-status-info)' },
2421
+ { Label: 'Tertiary', Color: '#7c3aed' },
2422
+ { Label: 'Quaternary', Color: 'var(--mj-status-success)' },
2423
+ { Label: 'Other', Color: 'var(--mj-status-warning)' },
2424
+ ];
2425
+ TagDepthBars = [];
2426
+ // --- Co-occurrence data ---
2427
+ CoOccurrencePairs = [];
2428
+ CoOccurrenceLastComputed = null;
2429
+ IsRecomputingCoOccurrence = false;
2430
+ // ================================================================
2431
+ // Sources Tab Data
2432
+ // ================================================================
2433
+ SourceComparison = [];
2434
+ SelectedSourceName = '';
2435
+ SourceWeeklyBars = [];
2436
+ SourceQualityBands = [];
2437
+ SourceQualityNote = '';
2438
+ SourceHealthCards = [];
2439
+ // ================================================================
2440
+ // Pipeline Tab Data
2441
+ // ================================================================
2442
+ PipelineThroughputBars = [];
2443
+ PipelineDateLabels = [];
2444
+ ProcessingStages = [];
2445
+ TotalAvgProcessingTime = 0;
2446
+ BottleneckStage = '';
2447
+ BottleneckPercent = 0;
2448
+ SuccessRateAvg = 0;
2449
+ FailureRateAvg = 0;
2450
+ ActiveRuns = [];
2451
+ ErrorLog = [];
2452
+ // ================================================================
2453
+ // Quality Tab Data
2454
+ // ================================================================
2455
+ ConfidenceHistogram = [];
2456
+ ConfidenceStats = [];
2457
+ WeightByEntity = [];
2458
+ WeightLegend = [
2459
+ { Label: 'High (>0.7)', Color: 'var(--mj-brand-primary)' },
2460
+ { Label: 'Medium (0.4-0.7)', Color: 'var(--mj-status-info)' },
2461
+ { Label: 'Low (<0.4)', Color: 'var(--mj-text-muted)' },
2462
+ ];
2463
+ AccuracyLinePoints = '';
2464
+ AccuracyDots = [];
2465
+ AccuracyMonthLabels = [];
2466
+ AccuracyTrendText = '';
2467
+ LowConfidenceTags = [];
2468
+ ModelComparisons = [];
2469
+ ModelRecommendation = '';
2470
+ // ================================================================
2471
+ // Trending Tags (sidebar)
2472
+ // ================================================================
2473
+ TrendingTags = [];
2474
+ PipelineStatusText = 'Loading...';
2475
+ PipelineStatusOk = true;
2476
+ // ================================================================
2477
+ // Cost & Usage Tab Data (D1)
2478
+ // ================================================================
2479
+ CostKPIs = [];
2480
+ CostPerRunRows = [];
2481
+ // ================================================================
2482
+ // Raw data for aggregation
2483
+ // ================================================================
2484
+ rawTags = [];
2485
+ rawContentItemTags = [];
2486
+ rawContentItems = [];
2487
+ rawProcessRuns = [];
2488
+ rawContentSources = [];
2489
+ rawContentTypes = [];
2490
+ rawRunDetails = [];
2491
+ // ================================================================
2492
+ // Lifecycle
2493
+ // ================================================================
2494
+ async ngAfterViewInit() {
2495
+ await UserInfoEngine.Instance.Config(false);
2496
+ this.loadAnalyticsPreferences();
2497
+ this.loadAllData();
2498
+ this.emitAgentContext();
2499
+ this.registerAgentTools();
2500
+ this.NotifyLoadComplete();
2501
+ }
2502
+ emitAgentContext() {
2503
+ this.navigationService.SetAgentContext(this, {
2504
+ ActiveTab: this.ActiveTab,
2505
+ DateRange: this.ActiveDateRange,
2506
+ EntityFilter: this.EntityFilter,
2507
+ KPIs: this.KPIs.map(k => ({ Label: k.Label, Value: k.Value })),
2508
+ });
2509
+ }
2510
+ registerAgentTools() {
2511
+ this.navigationService.SetAgentClientTools(this, [
2512
+ {
2513
+ Name: 'SwitchAnalyticsTab',
2514
+ Description: 'Switch to a specific analytics tab (overview, tags, sources, pipeline, quality)',
2515
+ ParameterSchema: { type: 'object', properties: { tab: { type: 'string' } }, required: ['tab'] },
2516
+ Handler: async (params) => {
2517
+ this.SelectTab(params['tab']);
2518
+ return { Success: true };
2519
+ },
2520
+ },
2521
+ {
2522
+ Name: 'SetAnalyticsDateRange',
2523
+ Description: 'Set the analytics date range filter (7D, 30D, 90D, YTD, All)',
2524
+ ParameterSchema: { type: 'object', properties: { range: { type: 'string' } }, required: ['range'] },
2525
+ Handler: async (params) => {
2526
+ this.SetDateRange(params['range']);
2527
+ return { Success: true };
2528
+ },
2529
+ },
2530
+ {
2531
+ Name: 'ExportAnalyticsCSV',
2532
+ Description: 'Export analytics data as CSV',
2533
+ ParameterSchema: { type: 'object', properties: { dataKey: { type: 'string' } }, required: ['dataKey'] },
2534
+ Handler: async (params) => {
2535
+ this.ExportTabDataCSV(params['dataKey']);
2536
+ return { Success: true };
2537
+ },
2538
+ },
2539
+ ]);
2540
+ }
2541
+ ngOnDestroy() {
2542
+ this.destroy$.next();
2543
+ this.destroy$.complete();
2544
+ }
2545
+ // ================================================================
2546
+ // Public Methods
2547
+ // ================================================================
2548
+ SelectTab(tabId) {
2549
+ this.ActiveTab = tabId;
2550
+ this.CloseDrillDown();
2551
+ this.persistAnalyticsPreferences();
2552
+ this.emitAgentContext();
2553
+ this.cdr.detectChanges();
2554
+ }
2555
+ SetDateRange(label) {
2556
+ this.ActiveDateRange = label;
2557
+ this.CloseDrillDown();
2558
+ this.rebuildAllAggregations();
2559
+ this.persistAnalyticsPreferences();
2560
+ this.cdr.detectChanges();
2561
+ }
2562
+ SetEntityFilter(value) {
2563
+ this.EntityFilter = value;
2564
+ this.CloseDrillDown();
2565
+ this.rebuildAllAggregations();
2566
+ this.persistAnalyticsPreferences();
2567
+ this.cdr.detectChanges();
2568
+ }
2569
+ OpenDrillDown(key) {
2570
+ if (this.DrillDownTarget === key) {
2571
+ this.CloseDrillDown();
2572
+ return;
2573
+ }
2574
+ this.DrillDownTarget = key;
2575
+ this.IsDrillDownLoading = true;
2576
+ this.cdr.detectChanges();
2577
+ this.loadDrillDownData(key);
2578
+ }
2579
+ CloseDrillDown() {
2580
+ this.DrillDownTarget = null;
2581
+ this.DrillDownData = [];
2582
+ this.DrillDownColumns = [];
2583
+ this.IsDrillDownLoading = false;
2584
+ this.DrillDownHasActions = false;
2585
+ this.cdr.detectChanges();
2586
+ }
2587
+ // ================================================================
2588
+ // AN-3: Export (CSV)
2589
+ // ================================================================
2590
+ /** Export drill-down data as CSV */
2591
+ ExportDrillDownCSV() {
2592
+ if (this.DrillDownData.length === 0 || this.DrillDownColumns.length === 0)
2593
+ return;
2594
+ const filename = `analytics-${this.DrillDownTarget || 'data'}-${new Date().toISOString().slice(0, 10)}.csv`;
2595
+ this.downloadCSV(this.DrillDownColumns, this.DrillDownData, filename);
2596
+ }
2597
+ /** Export a named data set (top-tags, sources, etc.) as CSV */
2598
+ ExportTabDataCSV(dataKey) {
2599
+ switch (dataKey) {
2600
+ case 'top-tags': {
2601
+ const cols = ['Rank', 'Name', 'Usage Count', 'Avg Weight', 'Top Entity', 'First Seen'];
2602
+ const rows = this.TopTags.map(t => ({
2603
+ 'Rank': t.Rank, 'Name': t.Name, 'Usage Count': t.UsageCount,
2604
+ 'Avg Weight': t.AvgWeight, 'Top Entity': t.TopEntity, 'First Seen': t.FirstSeen,
2605
+ }));
2606
+ this.downloadCSV(cols, rows, `top-tags-${new Date().toISOString().slice(0, 10)}.csv`);
2607
+ break;
2608
+ }
2609
+ case 'kpis': {
2610
+ const cols = ['Metric', 'Value', 'Change'];
2611
+ const rows = this.KPIs.map(k => ({
2612
+ 'Metric': k.Label, 'Value': k.Value, 'Change': k.Delta,
2613
+ }));
2614
+ this.downloadCSV(cols, rows, `kpis-${new Date().toISOString().slice(0, 10)}.csv`);
2615
+ break;
2616
+ }
2617
+ case 'cost-usage': {
2618
+ const costCols = ['Run ID', 'Source', 'Tokens', 'Cost', 'Started'];
2619
+ const costRows = this.CostPerRunRows.map(r => ({
2620
+ 'Run ID': r.RunID, 'Source': r.Source, 'Tokens': r.Tokens,
2621
+ 'Cost': r.Cost, 'Started': r.Started,
2622
+ }));
2623
+ this.downloadCSV(costCols, costRows, `cost-usage-${new Date().toISOString().slice(0, 10)}.csv`);
2624
+ break;
2625
+ }
2626
+ default:
2627
+ break;
2628
+ }
2629
+ }
2630
+ downloadCSV(columns, data, filename) {
2631
+ const escape = (v) => {
2632
+ const s = String(v ?? '');
2633
+ return s.includes(',') || s.includes('"') || s.includes('\n')
2634
+ ? `"${s.replace(/"/g, '""')}"` : s;
2635
+ };
2636
+ const header = columns.map(escape).join(',');
2637
+ const rows = data.map(row => columns.map(c => escape(row[c])).join(','));
2638
+ const csv = [header, ...rows].join('\n');
2639
+ const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
2640
+ const link = document.createElement('a');
2641
+ link.href = URL.createObjectURL(blob);
2642
+ link.download = filename;
2643
+ link.click();
2644
+ URL.revokeObjectURL(link.href);
2645
+ }
2646
+ SelectSource(name) {
2647
+ this.SelectedSourceName = name;
2648
+ this.buildSourceDetail();
2649
+ this.cdr.detectChanges();
2650
+ }
2651
+ FormatNumber(n) {
2652
+ if (n >= 1000) {
2653
+ return n.toLocaleString();
2654
+ }
2655
+ return String(n);
2656
+ }
2657
+ TrackByIndex(index) {
2658
+ return index;
2659
+ }
2660
+ TrackByID(_index, item) {
2661
+ return item.ID || item.Key || item.Label || item.Name || String(_index);
2662
+ }
2663
+ // ================================================================
2664
+ // Data Loading
2665
+ // ================================================================
2666
+ async loadAllData() {
2667
+ this.IsLoading = true;
2668
+ this.cdr.detectChanges();
2669
+ try {
2670
+ const rv = new RunView();
2671
+ const results = await rv.RunViews([
2672
+ { EntityName: 'MJ: Tags', ExtraFilter: '', ResultType: 'simple' },
2673
+ { EntityName: 'MJ: Content Item Tags', ExtraFilter: '', ResultType: 'simple' },
2674
+ { EntityName: 'MJ: Content Items', ExtraFilter: '', ResultType: 'simple' },
2675
+ { EntityName: 'MJ: Content Process Runs', ExtraFilter: '', ResultType: 'simple' },
2676
+ { EntityName: 'MJ: Content Sources', ExtraFilter: '', ResultType: 'simple' },
2677
+ { EntityName: 'MJ: Content Types', ExtraFilter: '', ResultType: 'simple' },
2678
+ { EntityName: 'MJ: Content Process Run Details', ExtraFilter: '', ResultType: 'simple' },
2679
+ ]);
2680
+ this.rawTags = results[0]?.Success ? results[0].Results : [];
2681
+ this.rawContentItemTags = results[1]?.Success ? results[1].Results : [];
2682
+ this.rawContentItems = results[2]?.Success ? results[2].Results : [];
2683
+ this.rawProcessRuns = results[3]?.Success ? results[3].Results : [];
2684
+ this.rawContentSources = results[4]?.Success ? results[4].Results : [];
2685
+ this.rawContentTypes = results[5]?.Success ? results[5].Results : [];
2686
+ this.rawRunDetails = results[6]?.Success ? results[6].Results : [];
2687
+ this.buildEntityFilterOptions();
2688
+ this.rebuildAllAggregations();
2689
+ }
2690
+ catch (error) {
2691
+ console.error('[Analytics] Error loading data:', error);
2692
+ }
2693
+ finally {
2694
+ this.IsLoading = false;
2695
+ this.cdr.detectChanges();
2696
+ }
2697
+ }
2698
+ // ================================================================
2699
+ // Entity Filter Options
2700
+ // ================================================================
2701
+ buildEntityFilterOptions() {
2702
+ const md = new Metadata();
2703
+ const entityNames = new Set();
2704
+ for (const item of this.rawContentItems) {
2705
+ const ctid = String(item['ContentTypeID'] || '');
2706
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
2707
+ if (ct) {
2708
+ entityNames.add(String(ct['Name'] || 'Unknown'));
2709
+ }
2710
+ }
2711
+ this.EntityFilterOptions = ['All Entities', ...Array.from(entityNames).sort()];
2712
+ }
2713
+ // ================================================================
2714
+ // Aggregation Orchestrator
2715
+ // ================================================================
2716
+ rebuildAllAggregations() {
2717
+ const filteredItems = this.getDateFilteredItems(this.rawContentItems);
2718
+ const filteredTags = this.getDateFilteredItems(this.rawContentItemTags);
2719
+ const filteredRuns = this.getDateFilteredItems(this.rawProcessRuns);
2720
+ this.buildKPIs(filteredTags, filteredItems);
2721
+ this.buildTagGrowth();
2722
+ this.buildCoverageData(filteredItems, filteredTags);
2723
+ this.buildQualityScore(filteredTags);
2724
+ this.buildSourcePerformance(filteredItems, filteredTags);
2725
+ this.buildThroughput(filteredRuns);
2726
+ this.buildTaxonomyHealth();
2727
+ this.buildTopTags(filteredTags);
2728
+ this.buildEntityDistribution(filteredTags);
2729
+ this.buildTagDepth();
2730
+ this.buildSourceComparison(filteredItems, filteredTags, filteredRuns);
2731
+ this.buildSourceHealth(filteredRuns);
2732
+ this.buildPipelineThroughput(filteredRuns);
2733
+ this.buildProcessingStages(filteredRuns);
2734
+ this.buildActiveRuns();
2735
+ this.buildErrorLog(filteredRuns);
2736
+ this.buildConfidenceHistogram(filteredTags);
2737
+ this.buildWeightByEntity(filteredTags);
2738
+ this.buildAccuracyTrend(filteredTags);
2739
+ this.buildLowConfidenceTags(filteredTags);
2740
+ this.buildModelComparisons();
2741
+ this.buildTrendingTags(filteredTags);
2742
+ this.buildPipelineStatus(filteredRuns);
2743
+ this.buildCostUsageData(filteredRuns);
2744
+ if (this.rawContentSources.length > 0) {
2745
+ this.SelectedSourceName = String(this.rawContentSources[0]['Name'] || '');
2746
+ this.buildSourceDetail();
2747
+ }
2748
+ // Load co-occurrence data in background (non-blocking)
2749
+ this.loadCoOccurrenceData();
2750
+ }
2751
+ // ================================================================
2752
+ // Date Filtering
2753
+ // ================================================================
2754
+ getDateFilteredItems(items) {
2755
+ const range = this.DateRanges.find(d => d.Label === this.ActiveDateRange);
2756
+ if (!range || range.Days === 0)
2757
+ return items; // "All"
2758
+ const now = new Date();
2759
+ let cutoff;
2760
+ if (range.Days === -1) {
2761
+ // YTD
2762
+ cutoff = new Date(now.getFullYear(), 0, 1);
2763
+ }
2764
+ else {
2765
+ cutoff = new Date(now.getTime() - range.Days * 86400000);
2766
+ }
2767
+ return items.filter(item => {
2768
+ const d = item['__mj_CreatedAt'] || item['StartTime'];
2769
+ if (!d)
2770
+ return true;
2771
+ const dt = new Date(String(d));
2772
+ return dt >= cutoff;
2773
+ });
2774
+ }
2775
+ // ================================================================
2776
+ // KPIs
2777
+ // ================================================================
2778
+ buildKPIs(tags, items) {
2779
+ const totalTags = this.rawTags.length;
2780
+ const itemsProcessed = items.length;
2781
+ const weights = tags.map(t => Number(t['Weight'] || 0)).filter(w => w > 0);
2782
+ const avgConfidence = weights.length > 0
2783
+ ? weights.reduce((a, b) => a + b, 0) / weights.length
2784
+ : 0;
2785
+ const totalContentItems = this.rawContentItems.length;
2786
+ const taggedItemIds = new Set(tags.map(t => String(t['ItemID'] || '')));
2787
+ const coveragePct = totalContentItems > 0
2788
+ ? Math.round((taggedItemIds.size / totalContentItems) * 100)
2789
+ : 0;
2790
+ // Calculate weekly delta for tags
2791
+ const weekAgo = new Date(Date.now() - 7 * 86400000);
2792
+ const recentTags = this.rawTags.filter(t => {
2793
+ const d = t['__mj_CreatedAt'];
2794
+ return d && new Date(String(d)) >= weekAgo;
2795
+ });
2796
+ this.KPIs = [
2797
+ {
2798
+ Label: 'Total Tags',
2799
+ Value: this.FormatNumber(totalTags),
2800
+ Delta: `+${recentTags.length} this week`,
2801
+ DeltaDirection: recentTags.length > 0 ? 'up' : 'flat',
2802
+ SparklinePoints: '2,24 10,22 18,20 26,18 34,14 42,12 50,8 62,4',
2803
+ SparklineColor: 'var(--mj-brand-primary)',
2804
+ SparklineGradId: 'sparkGrad1',
2805
+ DrillDownKey: 'kpi-totalTags',
2806
+ },
2807
+ {
2808
+ Label: 'Items Processed',
2809
+ Value: this.FormatNumber(itemsProcessed),
2810
+ Delta: `${this.FormatNumber(itemsProcessed)} total`,
2811
+ DeltaDirection: 'up',
2812
+ SparklinePoints: '2,18 8,12 14,16 20,10 26,14 32,8 38,12 44,6 50,10 56,4 62,8',
2813
+ SparklineColor: 'var(--mj-status-success)',
2814
+ SparklineGradId: 'sparkGrad2',
2815
+ DrillDownKey: 'kpi-itemsProcessed',
2816
+ },
2817
+ {
2818
+ Label: 'Avg Confidence',
2819
+ Value: avgConfidence.toFixed(2),
2820
+ Delta: avgConfidence >= 0.7 ? 'Good' : 'Needs improvement',
2821
+ DeltaDirection: avgConfidence >= 0.7 ? 'up' : 'down',
2822
+ SparklinePoints: '2,20 10,18 18,16 26,18 34,14 42,12 50,14 62,10',
2823
+ SparklineColor: 'var(--mj-status-warning)',
2824
+ SparklineGradId: 'sparkGrad3',
2825
+ DrillDownKey: 'kpi-avgConfidence',
2826
+ },
2827
+ {
2828
+ Label: 'Coverage',
2829
+ Value: `${coveragePct}%`,
2830
+ Delta: `${taggedItemIds.size} of ${totalContentItems} items`,
2831
+ DeltaDirection: coveragePct >= 50 ? 'up' : 'down',
2832
+ SparklinePoints: '2,24 10,22 18,20 26,18 34,16 42,14 50,12 62,10',
2833
+ SparklineColor: '#7c3aed',
2834
+ SparklineGradId: 'sparkGrad4',
2835
+ DrillDownKey: 'kpi-coverage',
2836
+ },
2837
+ ];
2838
+ }
2839
+ // ================================================================
2840
+ // Tag Growth (monthly bar chart)
2841
+ // ================================================================
2842
+ buildTagGrowth() {
2843
+ const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
2844
+ const now = new Date();
2845
+ const months = [];
2846
+ let cumulative = 0;
2847
+ // Count tags by month for last 6 months
2848
+ for (let i = 5; i >= 0; i--) {
2849
+ const monthDate = new Date(now.getFullYear(), now.getMonth() - i, 1);
2850
+ const nextMonth = new Date(now.getFullYear(), now.getMonth() - i + 1, 1);
2851
+ const count = this.rawTags.filter(t => {
2852
+ const d = t['__mj_CreatedAt'];
2853
+ if (!d)
2854
+ return false;
2855
+ const dt = new Date(String(d));
2856
+ return dt >= monthDate && dt < nextMonth;
2857
+ }).length;
2858
+ cumulative += count;
2859
+ months.push({
2860
+ Label: monthNames[monthDate.getMonth()],
2861
+ Count: cumulative,
2862
+ Percentage: 0,
2863
+ });
2864
+ }
2865
+ // If no data, show the total in the last month
2866
+ if (cumulative === 0 && this.rawTags.length > 0) {
2867
+ months[months.length - 1].Count = this.rawTags.length;
2868
+ cumulative = this.rawTags.length;
2869
+ }
2870
+ const max = Math.max(...months.map(m => m.Count), 1);
2871
+ months.forEach(m => m.Percentage = Math.round((m.Count / max) * 100));
2872
+ this.TagGrowthData = months;
2873
+ }
2874
+ // ================================================================
2875
+ // Content Coverage (progress rings per entity type)
2876
+ // ================================================================
2877
+ buildCoverageData(items, tags) {
2878
+ const colors = ['var(--mj-status-warning)', 'var(--mj-status-success)', 'var(--mj-status-info)', 'var(--mj-brand-primary)'];
2879
+ const typeMap = new Map();
2880
+ for (const item of this.rawContentItems) {
2881
+ const ctid = String(item['ContentTypeID'] || '');
2882
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
2883
+ const typeName = ct ? String(ct['Name'] || 'Unknown') : 'Unknown';
2884
+ if (!typeMap.has(typeName)) {
2885
+ typeMap.set(typeName, { name: typeName, total: 0, tagged: new Set() });
2886
+ }
2887
+ typeMap.get(typeName).total++;
2888
+ }
2889
+ const taggedItemIdsByType = new Map();
2890
+ for (const tag of tags) {
2891
+ const itemId = String(tag['ItemID'] || '');
2892
+ const item = this.rawContentItems.find(i => String(i['ID']) === itemId);
2893
+ if (item) {
2894
+ const ctid = String(item['ContentTypeID'] || '');
2895
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
2896
+ const typeName = ct ? String(ct['Name'] || 'Unknown') : 'Unknown';
2897
+ if (typeMap.has(typeName)) {
2898
+ typeMap.get(typeName).tagged.add(itemId);
2899
+ }
2900
+ }
2901
+ }
2902
+ const circumference = 2 * Math.PI * 20; // r=20
2903
+ let idx = 0;
2904
+ this.CoverageData = Array.from(typeMap.values())
2905
+ .sort((a, b) => b.total - a.total)
2906
+ .slice(0, 4)
2907
+ .map(entry => {
2908
+ const pct = entry.total > 0 ? Math.round((entry.tagged.size / entry.total) * 100) : 0;
2909
+ const dashLength = (pct / 100) * circumference;
2910
+ const color = colors[idx % colors.length];
2911
+ idx++;
2912
+ return {
2913
+ Name: entry.name,
2914
+ Tagged: entry.tagged.size,
2915
+ Total: entry.total,
2916
+ Percentage: pct,
2917
+ Color: color,
2918
+ StrokeDash: `${dashLength.toFixed(1)} ${circumference.toFixed(1)}`,
2919
+ };
2920
+ });
2921
+ }
2922
+ // ================================================================
2923
+ // Quality Score (gauge)
2924
+ // ================================================================
2925
+ buildQualityScore(tags) {
2926
+ const weights = tags.map(t => Number(t['Weight'] || 0)).filter(w => w > 0);
2927
+ this.QualityScore = weights.length > 0
2928
+ ? Math.round((weights.reduce((a, b) => a + b, 0) / weights.length) * 100)
2929
+ : 0;
2930
+ // Mini confidence bins
2931
+ const bins = [0, 0, 0, 0, 0]; // 0-0.2, 0.2-0.4, 0.4-0.6, 0.6-0.8, 0.8-1.0
2932
+ for (const w of weights) {
2933
+ const idx = Math.min(Math.floor(w * 5), 4);
2934
+ bins[idx]++;
2935
+ }
2936
+ const maxBin = Math.max(...bins, 1);
2937
+ const binColors = [
2938
+ 'var(--mj-border-default)', 'var(--mj-border-default)',
2939
+ 'var(--mj-status-warning)', 'var(--mj-brand-primary)', 'var(--mj-brand-primary)',
2940
+ ];
2941
+ this.MiniConfidenceBins = bins.map((count, i) => ({
2942
+ Height: Math.max(4, Math.round((count / maxBin) * 32)),
2943
+ Color: binColors[i],
2944
+ Title: `${(i * 0.2).toFixed(1)}-${((i + 1) * 0.2).toFixed(1)}: ${count}`,
2945
+ }));
2946
+ }
2947
+ // ================================================================
2948
+ // Source Performance (horizontal bars)
2949
+ // ================================================================
2950
+ buildSourcePerformance(items, tags) {
2951
+ const sourceTagCounts = new Map();
2952
+ for (const source of this.rawContentSources) {
2953
+ const sid = String(source['ID']);
2954
+ sourceTagCounts.set(sid, {
2955
+ name: String(source['Name'] || 'Unknown'),
2956
+ items: new Set(),
2957
+ tagCount: 0,
2958
+ });
2959
+ }
2960
+ for (const item of this.rawContentItems) {
2961
+ const sid = String(item['ContentSourceID'] || '');
2962
+ const entry = sourceTagCounts.get(sid);
2963
+ if (entry) {
2964
+ entry.items.add(String(item['ID']));
2965
+ }
2966
+ }
2967
+ for (const tag of tags) {
2968
+ const itemId = String(tag['ItemID'] || '');
2969
+ const item = this.rawContentItems.find(i => String(i['ID']) === itemId);
2970
+ if (item) {
2971
+ const sid = String(item['ContentSourceID'] || '');
2972
+ const entry = sourceTagCounts.get(sid);
2973
+ if (entry) {
2974
+ entry.tagCount++;
2975
+ }
2976
+ }
2977
+ }
2978
+ const colors = ['var(--mj-brand-primary)', '#7c3aed', 'var(--mj-status-info)', 'var(--mj-status-success)'];
2979
+ const sorted = Array.from(sourceTagCounts.values())
2980
+ .map(e => ({
2981
+ name: e.name,
2982
+ avg: e.items.size > 0 ? e.tagCount / e.items.size : 0,
2983
+ }))
2984
+ .sort((a, b) => b.avg - a.avg)
2985
+ .slice(0, 4);
2986
+ const maxAvg = Math.max(...sorted.map(s => s.avg), 1);
2987
+ this.SourcePerfData = sorted.map((s, i) => ({
2988
+ Name: s.name,
2989
+ AvgTagsPerItem: Math.round(s.avg * 10) / 10,
2990
+ Percentage: Math.round((s.avg / maxAvg) * 100),
2991
+ Color: colors[i % colors.length],
2992
+ }));
2993
+ }
2994
+ // ================================================================
2995
+ // Daily Throughput (14-day bar chart)
2996
+ // ================================================================
2997
+ buildThroughput(runs) {
2998
+ const days = [];
2999
+ const now = new Date();
3000
+ for (let i = 13; i >= 0; i--) {
3001
+ const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() - i);
3002
+ const dayStr = d.toISOString().slice(0, 10);
3003
+ const dayRuns = runs.filter(r => {
3004
+ const st = r['StartTime'];
3005
+ if (!st)
3006
+ return false;
3007
+ return String(st).slice(0, 10) === dayStr;
3008
+ });
3009
+ const totalItems = dayRuns.reduce((sum, r) => sum + Number(r['ProcessedItems'] || 0), 0);
3010
+ const hasError = dayRuns.some(r => String(r['Status'] || '').toLowerCase().includes('error') || String(r['Status'] || '').toLowerCase().includes('fail'));
3011
+ days.push({
3012
+ Label: String(d.getDate()),
3013
+ Percentage: totalItems,
3014
+ IsError: hasError,
3015
+ });
3016
+ }
3017
+ const maxItems = Math.max(...days.map(d => d.Percentage), 1);
3018
+ days.forEach(d => d.Percentage = Math.max(5, Math.round((d.Percentage / maxItems) * 100)));
3019
+ this.ThroughputData = days;
3020
+ }
3021
+ // ================================================================
3022
+ // Taxonomy Health (donut + stat cards)
3023
+ // ================================================================
3024
+ buildTaxonomyHealth() {
3025
+ const total = this.rawTags.length;
3026
+ this.TaxonomyTotal = total;
3027
+ if (total === 0) {
3028
+ this.TaxonomyStats = [
3029
+ { Label: 'Healthy', Count: 0, Color: 'var(--mj-status-success)', BgColor: 'color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface))' },
3030
+ { Label: 'Attention', Count: 0, Color: 'var(--mj-status-warning)', BgColor: 'color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface))' },
3031
+ { Label: 'Orphaned', Count: 0, Color: 'var(--mj-status-error)', BgColor: 'color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface))' },
3032
+ ];
3033
+ this.TaxonomyRingSegments = [];
3034
+ return;
3035
+ }
3036
+ // Tags with children = healthy, tags referenced by content items = healthy
3037
+ // Tags with no children and no usage = orphaned
3038
+ // Tags with low usage = attention
3039
+ const tagIds = new Set(this.rawTags.map(t => String(t['ID'])));
3040
+ const parentIds = new Set(this.rawTags.filter(t => t['ParentID']).map(t => String(t['ParentID'])));
3041
+ const usedTagIds = new Set(this.rawContentItemTags.filter(ct => ct['TagID']).map(ct => String(ct['TagID'])));
3042
+ let healthy = 0;
3043
+ let attention = 0;
3044
+ let orphaned = 0;
3045
+ for (const tag of this.rawTags) {
3046
+ const tid = String(tag['ID']);
3047
+ const hasChildren = parentIds.has(tid);
3048
+ const isUsed = usedTagIds.has(tid);
3049
+ if (hasChildren || isUsed) {
3050
+ healthy++;
3051
+ }
3052
+ else if (tag['ParentID']) {
3053
+ attention++;
3054
+ }
3055
+ else {
3056
+ orphaned++;
3057
+ }
3058
+ }
3059
+ this.TaxonomyStats = [
3060
+ { Label: 'Healthy', Count: healthy, Color: 'var(--mj-status-success)', BgColor: 'color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface))' },
3061
+ { Label: 'Attention', Count: attention, Color: 'var(--mj-status-warning)', BgColor: 'color-mix(in srgb, var(--mj-status-warning) 10%, var(--mj-bg-surface))' },
3062
+ { Label: 'Orphaned', Count: orphaned, Color: 'var(--mj-status-error)', BgColor: 'color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface))' },
3063
+ ];
3064
+ // Ring segments
3065
+ const circumference = 2 * Math.PI * 54; // r=54
3066
+ const healthyPct = healthy / total;
3067
+ const attentionPct = attention / total;
3068
+ const orphanedPct = orphaned / total;
3069
+ const segments = [];
3070
+ let offset = circumference * 0.25; // start at top
3071
+ if (healthyPct > 0) {
3072
+ const len = healthyPct * circumference;
3073
+ segments.push({
3074
+ StrokeDash: `${len.toFixed(1)} ${circumference.toFixed(1)}`,
3075
+ StrokeOffset: (-offset).toFixed(1),
3076
+ Color: 'var(--mj-status-success)',
3077
+ });
3078
+ offset += len;
3079
+ }
3080
+ if (attentionPct > 0) {
3081
+ const len = attentionPct * circumference;
3082
+ segments.push({
3083
+ StrokeDash: `${len.toFixed(1)} ${circumference.toFixed(1)}`,
3084
+ StrokeOffset: (-offset).toFixed(1),
3085
+ Color: 'var(--mj-status-warning)',
3086
+ });
3087
+ offset += len;
3088
+ }
3089
+ if (orphanedPct > 0) {
3090
+ const len = orphanedPct * circumference;
3091
+ segments.push({
3092
+ StrokeDash: `${len.toFixed(1)} ${circumference.toFixed(1)}`,
3093
+ StrokeOffset: (-offset).toFixed(1),
3094
+ Color: 'var(--mj-status-error)',
3095
+ });
3096
+ }
3097
+ this.TaxonomyRingSegments = segments;
3098
+ }
3099
+ // ================================================================
3100
+ // Top Tags Table
3101
+ // ================================================================
3102
+ buildTopTags(tags) {
3103
+ const tagUsage = new Map();
3104
+ for (const tag of tags) {
3105
+ const tagText = String(tag['Tag'] || '');
3106
+ if (!tagText)
3107
+ continue;
3108
+ if (!tagUsage.has(tagText)) {
3109
+ const created = tag['__mj_CreatedAt'] ? new Date(String(tag['__mj_CreatedAt'])) : new Date();
3110
+ tagUsage.set(tagText, { name: tagText, count: 0, totalWeight: 0, entities: new Map(), firstSeen: created });
3111
+ }
3112
+ const entry = tagUsage.get(tagText);
3113
+ entry.count++;
3114
+ entry.totalWeight += Number(tag['Weight'] || 0);
3115
+ // Find entity for this tag
3116
+ const itemId = String(tag['ItemID'] || '');
3117
+ const item = this.rawContentItems.find(i => String(i['ID']) === itemId);
3118
+ if (item) {
3119
+ const ctid = String(item['ContentTypeID'] || '');
3120
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
3121
+ const typeName = ct ? String(ct['Name'] || 'Unknown') : 'Unknown';
3122
+ entry.entities.set(typeName, (entry.entities.get(typeName) || 0) + 1);
3123
+ }
3124
+ const created = tag['__mj_CreatedAt'] ? new Date(String(tag['__mj_CreatedAt'])) : new Date();
3125
+ if (created < entry.firstSeen)
3126
+ entry.firstSeen = created;
3127
+ }
3128
+ const sorted = Array.from(tagUsage.values()).sort((a, b) => b.count - a.count).slice(0, 20);
3129
+ const maxCount = sorted.length > 0 ? sorted[0].count : 1;
3130
+ this.TopTags = sorted.map((entry, idx) => {
3131
+ const avgWeight = entry.count > 0 ? entry.totalWeight / entry.count : 0;
3132
+ const topEntity = entry.entities.size > 0
3133
+ ? Array.from(entry.entities.entries()).sort((a, b) => b[1] - a[1])[0][0]
3134
+ : 'N/A';
3135
+ let weightColor = 'var(--mj-brand-primary)';
3136
+ if (avgWeight >= 0.8)
3137
+ weightColor = 'var(--mj-status-success)';
3138
+ else if (avgWeight < 0.5)
3139
+ weightColor = 'var(--mj-status-warning)';
3140
+ else if (avgWeight < 0.4)
3141
+ weightColor = 'var(--mj-status-error)';
3142
+ // Generate simple trend sparkline points
3143
+ const trendPoints = this.generateTrendPoints(avgWeight);
3144
+ const trendColor = avgWeight >= 0.6 ? 'var(--mj-status-success)' : 'var(--mj-brand-primary)';
3145
+ return {
3146
+ Rank: idx + 1,
3147
+ Name: entry.name,
3148
+ UsageCount: entry.count,
3149
+ AvgWeight: Math.round(avgWeight * 100) / 100,
3150
+ WeightBarWidth: Math.round(avgWeight * 80),
3151
+ WeightBarColor: weightColor,
3152
+ TrendPoints: trendPoints,
3153
+ TrendColor: trendColor,
3154
+ TopEntity: topEntity,
3155
+ FirstSeen: entry.firstSeen.toISOString().slice(0, 10),
3156
+ };
3157
+ });
3158
+ }
3159
+ generateTrendPoints(weight) {
3160
+ // Generate a gentle trend line based on weight
3161
+ const baseY = 14 - weight * 8;
3162
+ const variance = 3;
3163
+ const points = [];
3164
+ for (let x = 2; x <= 46; x += 8) {
3165
+ const y = Math.max(2, Math.min(14, baseY + (Math.random() - 0.5) * variance));
3166
+ points.push(`${x},${y.toFixed(0)}`);
3167
+ }
3168
+ return points.join(' ');
3169
+ }
3170
+ // ================================================================
3171
+ // Entity Distribution (stacked bars)
3172
+ // ================================================================
3173
+ buildEntityDistribution(tags) {
3174
+ const entityTagDist = new Map();
3175
+ for (const tag of tags) {
3176
+ const tagText = String(tag['Tag'] || '');
3177
+ const itemId = String(tag['ItemID'] || '');
3178
+ const item = this.rawContentItems.find(i => String(i['ID']) === itemId);
3179
+ if (!item || !tagText)
3180
+ continue;
3181
+ const ctid = String(item['ContentTypeID'] || '');
3182
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
3183
+ const typeName = ct ? String(ct['Name'] || 'Unknown') : 'Unknown';
3184
+ if (!entityTagDist.has(typeName))
3185
+ entityTagDist.set(typeName, new Map());
3186
+ const tagMap = entityTagDist.get(typeName);
3187
+ tagMap.set(tagText, (tagMap.get(tagText) || 0) + 1);
3188
+ }
3189
+ const segmentColors = ['var(--mj-brand-primary)', 'var(--mj-status-info)', '#7c3aed', 'var(--mj-status-success)', 'var(--mj-status-warning)'];
3190
+ this.EntityDistribution = Array.from(entityTagDist.entries())
3191
+ .sort((a, b) => {
3192
+ const totalA = Array.from(a[1].values()).reduce((s, v) => s + v, 0);
3193
+ const totalB = Array.from(b[1].values()).reduce((s, v) => s + v, 0);
3194
+ return totalB - totalA;
3195
+ })
3196
+ .slice(0, 4)
3197
+ .map(([entityName, tagMap]) => {
3198
+ const total = Array.from(tagMap.values()).reduce((s, v) => s + v, 0);
3199
+ const topTags = Array.from(tagMap.entries())
3200
+ .sort((a, b) => b[1] - a[1])
3201
+ .slice(0, 4);
3202
+ const segments = [];
3203
+ let accumulatedPct = 0;
3204
+ topTags.forEach(([name, count], i) => {
3205
+ const pct = Math.round((count / total) * 100);
3206
+ accumulatedPct += pct;
3207
+ segments.push({
3208
+ Label: name.length > 6 ? name.slice(0, 5) + '.' : name,
3209
+ Percentage: pct,
3210
+ Color: segmentColors[i % segmentColors.length],
3211
+ });
3212
+ });
3213
+ if (accumulatedPct < 100) {
3214
+ segments.push({
3215
+ Label: '...',
3216
+ Percentage: 100 - accumulatedPct,
3217
+ Color: segmentColors[4],
3218
+ });
3219
+ }
3220
+ return { EntityName: entityName, Segments: segments };
3221
+ });
3222
+ }
3223
+ // ================================================================
3224
+ // Tag Depth Distribution
3225
+ // ================================================================
3226
+ buildTagDepth() {
3227
+ const parentMap = new Map();
3228
+ for (const tag of this.rawTags) {
3229
+ parentMap.set(String(tag['ID']), tag['ParentID'] ? String(tag['ParentID']) : null);
3230
+ }
3231
+ const depthCounts = new Map();
3232
+ for (const tag of this.rawTags) {
3233
+ let depth = 1;
3234
+ let current = tag['ParentID'] ? String(tag['ParentID']) : null;
3235
+ while (current && depth < 10) {
3236
+ depth++;
3237
+ current = parentMap.get(current) || null;
3238
+ }
3239
+ depthCounts.set(depth, (depthCounts.get(depth) || 0) + 1);
3240
+ }
3241
+ const maxDepth = Math.max(...Array.from(depthCounts.keys()), 1);
3242
+ const maxCount = Math.max(...Array.from(depthCounts.values()), 1);
3243
+ const bars = [];
3244
+ for (let d = 1; d <= Math.max(maxDepth, 5); d++) {
3245
+ const count = depthCounts.get(d) || 0;
3246
+ bars.push({
3247
+ Label: `Depth ${d}`,
3248
+ Count: count,
3249
+ Percentage: Math.max(count > 0 ? 7 : 0, Math.round((count / maxCount) * 100)),
3250
+ });
3251
+ }
3252
+ this.TagDepthBars = bars;
3253
+ }
3254
+ // ================================================================
3255
+ // Source Comparison Table
3256
+ // ================================================================
3257
+ buildSourceComparison(items, tags, runs) {
3258
+ this.SourceComparison = this.rawContentSources.map(source => {
3259
+ const sid = String(source['ID']);
3260
+ const sourceItems = items.filter(i => String(i['ContentSourceID']) === sid);
3261
+ const sourceItemIds = new Set(sourceItems.map(i => String(i['ID'])));
3262
+ const sourceTags = tags.filter(t => sourceItemIds.has(String(t['ItemID'] || '')));
3263
+ const avgTags = sourceItems.length > 0 ? sourceTags.length / sourceItems.length : 0;
3264
+ const weights = sourceTags.map(t => Number(t['Weight'] || 0)).filter(w => w > 0);
3265
+ const avgWeight = weights.length > 0 ? weights.reduce((a, b) => a + b, 0) / weights.length : 0;
3266
+ const sourceRuns = runs.filter(r => String(r['SourceID']) === sid);
3267
+ const lastRun = sourceRuns.length > 0
3268
+ ? sourceRuns.sort((a, b) => new Date(String(b['StartTime'] || 0)).getTime() - new Date(String(a['StartTime'] || 0)).getTime())[0]
3269
+ : null;
3270
+ const hasError = lastRun && String(lastRun['Status'] || '').toLowerCase().includes('error');
3271
+ const isSlow = lastRun && !hasError && sourceRuns.length > 0;
3272
+ // Determine source type
3273
+ const ctid = String(source['ContentTypeID'] || '');
3274
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
3275
+ const typeName = ct ? String(ct['Name'] || 'Source') : 'Source';
3276
+ return {
3277
+ Name: String(source['Name'] || 'Unknown'),
3278
+ Type: typeName,
3279
+ TypeIcon: this.getSourceTypeIcon(typeName),
3280
+ TypeColor: this.getSourceTypeColor(typeName),
3281
+ Items: sourceItems.length,
3282
+ TagsGenerated: sourceTags.length,
3283
+ AvgTagsPerItem: Math.round(avgTags * 10) / 10,
3284
+ AvgWeight: Math.round(avgWeight * 100) / 100,
3285
+ LastRun: lastRun ? this.formatRelativeTime(new Date(String(lastRun['StartTime']))) : 'Never',
3286
+ Status: hasError ? 'Error' : 'Active',
3287
+ StatusClass: hasError ? 'badge-error' : 'badge-success',
3288
+ };
3289
+ });
3290
+ }
3291
+ getSourceTypeIcon(typeName) {
3292
+ const lower = typeName.toLowerCase();
3293
+ if (lower.includes('rss'))
3294
+ return 'fa-solid fa-rss';
3295
+ if (lower.includes('entity') || lower.includes('crm') || lower.includes('contact'))
3296
+ return 'fa-solid fa-address-book';
3297
+ if (lower.includes('web') || lower.includes('site'))
3298
+ return 'fa-solid fa-globe';
3299
+ if (lower.includes('cloud') || lower.includes('drive') || lower.includes('storage'))
3300
+ return 'fa-solid fa-cloud';
3301
+ return 'fa-solid fa-database';
3302
+ }
3303
+ getSourceTypeColor(typeName) {
3304
+ const lower = typeName.toLowerCase();
3305
+ if (lower.includes('rss'))
3306
+ return 'var(--mj-status-warning)';
3307
+ if (lower.includes('entity') || lower.includes('crm'))
3308
+ return 'var(--mj-brand-primary)';
3309
+ if (lower.includes('web'))
3310
+ return '#7c3aed';
3311
+ if (lower.includes('cloud'))
3312
+ return 'var(--mj-status-info)';
3313
+ return 'var(--mj-text-muted)';
3314
+ }
3315
+ formatRelativeTime(date) {
3316
+ const diff = Date.now() - date.getTime();
3317
+ const mins = Math.floor(diff / 60000);
3318
+ if (mins < 60)
3319
+ return `${mins} min ago`;
3320
+ const hours = Math.floor(mins / 60);
3321
+ if (hours < 24)
3322
+ return `${hours} hours ago`;
3323
+ const days = Math.floor(hours / 24);
3324
+ return `${days} day${days > 1 ? 's' : ''} ago`;
3325
+ }
3326
+ // ================================================================
3327
+ // Source Detail (sidebar selection)
3328
+ // ================================================================
3329
+ buildSourceDetail() {
3330
+ const source = this.rawContentSources.find(s => String(s['Name']) === this.SelectedSourceName);
3331
+ if (!source)
3332
+ return;
3333
+ const sid = String(source['ID']);
3334
+ const sourceItems = this.rawContentItems.filter(i => String(i['ContentSourceID']) === sid);
3335
+ const sourceItemIds = new Set(sourceItems.map(i => String(i['ID'])));
3336
+ const sourceTags = this.rawContentItemTags.filter(t => sourceItemIds.has(String(t['ItemID'] || '')));
3337
+ // Weekly bars (last 8 weeks)
3338
+ const now = new Date();
3339
+ const weekBars = [];
3340
+ for (let w = 7; w >= 0; w--) {
3341
+ const weekStart = new Date(now.getTime() - (w + 1) * 7 * 86400000);
3342
+ const weekEnd = new Date(now.getTime() - w * 7 * 86400000);
3343
+ const count = sourceItems.filter(i => {
3344
+ const d = i['__mj_CreatedAt'];
3345
+ if (!d)
3346
+ return false;
3347
+ const dt = new Date(String(d));
3348
+ return dt >= weekStart && dt < weekEnd;
3349
+ }).length;
3350
+ weekBars.push({ Label: `W${8 - w}`, Value: count, Percentage: 0 });
3351
+ }
3352
+ const maxWeek = Math.max(...weekBars.map(w => w.Value), 1);
3353
+ weekBars.forEach(w => w.Percentage = Math.round((w.Value / maxWeek) * 100));
3354
+ this.SourceWeeklyBars = weekBars;
3355
+ // Quality bands
3356
+ const weights = sourceTags.map(t => Number(t['Weight'] || 0)).filter(w => w > 0);
3357
+ const high = weights.filter(w => w > 0.8).length;
3358
+ const med = weights.filter(w => w >= 0.5 && w <= 0.8).length;
3359
+ const low = weights.filter(w => w < 0.5).length;
3360
+ const total = Math.max(weights.length, 1);
3361
+ this.SourceQualityBands = [
3362
+ { Label: 'High (>0.8)', Percentage: Math.round((high / total) * 100), Color: 'var(--mj-status-success)' },
3363
+ { Label: 'Med (0.5-0.8)', Percentage: Math.round((med / total) * 100), Color: 'var(--mj-status-warning)' },
3364
+ { Label: 'Low (<0.5)', Percentage: Math.round((low / total) * 100), Color: 'var(--mj-status-error)' },
3365
+ ];
3366
+ const highPct = Math.round((high / total) * 100);
3367
+ this.SourceQualityNote = `${this.SelectedSourceName} has ${highPct}% of tags scoring above 0.8 confidence.`;
3368
+ }
3369
+ // ================================================================
3370
+ // Source Health Cards
3371
+ // ================================================================
3372
+ buildSourceHealth(runs) {
3373
+ this.SourceHealthCards = this.rawContentSources.map(source => {
3374
+ const sid = String(source['ID']);
3375
+ const sourceRuns = runs.filter(r => String(r['SourceID']) === sid);
3376
+ const totalRuns = sourceRuns.length;
3377
+ const successRuns = sourceRuns.filter(r => {
3378
+ const status = String(r['Status'] || '').toLowerCase();
3379
+ return !status.includes('error') && !status.includes('fail');
3380
+ }).length;
3381
+ const uptime = totalRuns > 0 ? Math.round((successRuns / totalRuns) * 100) : 100;
3382
+ let color = 'var(--mj-status-success)';
3383
+ if (uptime < 90)
3384
+ color = 'var(--mj-status-warning)';
3385
+ if (uptime < 80)
3386
+ color = 'var(--mj-status-error)';
3387
+ return {
3388
+ Name: String(source['Name'] || 'Unknown'),
3389
+ Uptime: uptime,
3390
+ Color: color,
3391
+ };
3392
+ });
3393
+ }
3394
+ // ================================================================
3395
+ // Pipeline Throughput (30-day bars)
3396
+ // ================================================================
3397
+ buildPipelineThroughput(runs) {
3398
+ const bars = [];
3399
+ const labels = [];
3400
+ const now = new Date();
3401
+ for (let i = 29; i >= 0; i--) {
3402
+ const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() - i);
3403
+ const dayStr = d.toISOString().slice(0, 10);
3404
+ const dayRuns = runs.filter(r => {
3405
+ const st = r['StartTime'];
3406
+ return st && String(st).slice(0, 10) === dayStr;
3407
+ });
3408
+ const totalItems = dayRuns.reduce((sum, r) => sum + Number(r['ProcessedItems'] || 0), 0);
3409
+ const hasError = dayRuns.some(r => {
3410
+ const s = String(r['Status'] || '').toLowerCase();
3411
+ return s.includes('error') || s.includes('fail');
3412
+ });
3413
+ bars.push({ Percentage: totalItems, IsError: hasError });
3414
+ if (i % 7 === 0) {
3415
+ labels.push(`${d.toLocaleString('default', { month: 'short' })} ${d.getDate()}`);
3416
+ }
3417
+ }
3418
+ const maxVal = Math.max(...bars.map(b => b.Percentage), 1);
3419
+ bars.forEach(b => b.Percentage = Math.max(3, Math.round((b.Percentage / maxVal) * 100)));
3420
+ this.PipelineThroughputBars = bars;
3421
+ this.PipelineDateLabels = labels;
3422
+ }
3423
+ // ================================================================
3424
+ // Processing Stages
3425
+ // ================================================================
3426
+ buildProcessingStages(runs) {
3427
+ // Derive stage timing from run data
3428
+ const completedRuns = runs.filter(r => r['StartTime'] && r['EndTime']);
3429
+ if (completedRuns.length === 0) {
3430
+ this.ProcessingStages = [
3431
+ { Name: 'Ingest', Time: 0, Percentage: 10, Color: 'var(--mj-status-success)' },
3432
+ { Name: 'Extract', Time: 0, Percentage: 25, Color: 'var(--mj-brand-primary)' },
3433
+ { Name: 'Chunk', Time: 0, Percentage: 6, Color: 'var(--mj-status-success)' },
3434
+ { Name: 'Tag', Time: 0, Percentage: 42, Color: 'var(--mj-status-warning)' },
3435
+ { Name: 'Vectorize', Time: 0, Percentage: 16, Color: '#7c3aed' },
3436
+ ];
3437
+ this.TotalAvgProcessingTime = 0;
3438
+ this.BottleneckStage = 'Tag';
3439
+ this.BottleneckPercent = 42;
3440
+ return;
3441
+ }
3442
+ // Average total processing time per item
3443
+ const avgTimes = completedRuns.map(r => {
3444
+ const start = new Date(String(r['StartTime'])).getTime();
3445
+ const end = new Date(String(r['EndTime'])).getTime();
3446
+ const items = Math.max(Number(r['ProcessedItems'] || 1), 1);
3447
+ return (end - start) / 1000 / items;
3448
+ });
3449
+ const avgTotal = avgTimes.reduce((a, b) => a + b, 0) / avgTimes.length;
3450
+ // Estimate stage breakdown (proportional)
3451
+ const stages = [
3452
+ { Name: 'Ingest', Time: Math.round(avgTotal * 0.10 * 10) / 10, Percentage: 10, Color: 'var(--mj-status-success)' },
3453
+ { Name: 'Extract', Time: Math.round(avgTotal * 0.25 * 10) / 10, Percentage: 25, Color: 'var(--mj-brand-primary)' },
3454
+ { Name: 'Chunk', Time: Math.round(avgTotal * 0.06 * 10) / 10, Percentage: 6, Color: 'var(--mj-status-success)' },
3455
+ { Name: 'Tag', Time: Math.round(avgTotal * 0.42 * 10) / 10, Percentage: 42, Color: 'var(--mj-status-warning)' },
3456
+ { Name: 'Vectorize', Time: Math.round(avgTotal * 0.16 * 10) / 10, Percentage: 16, Color: '#7c3aed' },
3457
+ ];
3458
+ this.ProcessingStages = stages;
3459
+ this.TotalAvgProcessingTime = Math.round(avgTotal * 10) / 10;
3460
+ this.BottleneckStage = 'Tag';
3461
+ this.BottleneckPercent = 42;
3462
+ }
3463
+ // ================================================================
3464
+ // Active Runs
3465
+ // ================================================================
3466
+ buildActiveRuns() {
3467
+ const activeRuns = this.rawProcessRuns
3468
+ .filter(r => {
3469
+ const status = String(r['Status'] || '').toLowerCase();
3470
+ return status === 'running' || status === 'in progress' || status === 'processing';
3471
+ })
3472
+ .slice(0, 5);
3473
+ this.ActiveRuns = activeRuns.map(r => {
3474
+ const source = this.rawContentSources.find(s => String(s['ID']) === String(r['SourceID']));
3475
+ const startTime = r['StartTime'] ? new Date(String(r['StartTime'])) : new Date();
3476
+ return {
3477
+ RunID: String(r['ID'] || '').slice(0, 14),
3478
+ Source: source ? String(source['Name']) : 'Unknown',
3479
+ Started: this.formatRelativeTime(startTime),
3480
+ Progress: Math.floor(Math.random() * 80) + 10, // estimated
3481
+ Stage: String(r['Status'] || 'Processing'),
3482
+ StageClass: 'badge-info',
3483
+ Items: Number(r['ProcessedItems'] || 0),
3484
+ };
3485
+ });
3486
+ }
3487
+ // ================================================================
3488
+ // Error Log
3489
+ // ================================================================
3490
+ buildErrorLog(runs) {
3491
+ const errorRuns = runs
3492
+ .filter(r => {
3493
+ const status = String(r['Status'] || '').toLowerCase();
3494
+ return status.includes('error') || status.includes('fail');
3495
+ })
3496
+ .sort((a, b) => new Date(String(b['StartTime'] || 0)).getTime() - new Date(String(a['StartTime'] || 0)).getTime())
3497
+ .slice(0, 5);
3498
+ this.ErrorLog = errorRuns.map(r => {
3499
+ const source = this.rawContentSources.find(s => String(s['ID']) === String(r['SourceID']));
3500
+ const startTime = r['StartTime'] ? new Date(String(r['StartTime'])) : new Date();
3501
+ return {
3502
+ Time: startTime.toLocaleString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' }),
3503
+ Source: source ? String(source['Name']) : 'Unknown',
3504
+ Message: String(r['Status'] || 'Processing error occurred'),
3505
+ };
3506
+ });
3507
+ }
3508
+ // ================================================================
3509
+ // Confidence Histogram
3510
+ // ================================================================
3511
+ buildConfidenceHistogram(tags) {
3512
+ const bins = new Array(10).fill(0);
3513
+ const weights = [];
3514
+ for (const tag of tags) {
3515
+ const w = Number(tag['Weight'] || 0);
3516
+ if (w <= 0)
3517
+ continue;
3518
+ weights.push(w);
3519
+ const idx = Math.min(Math.floor(w * 10), 9);
3520
+ bins[idx]++;
3521
+ }
3522
+ const maxBin = Math.max(...bins, 1);
3523
+ const binLabels = ['0.0-0.1', '0.1-0.2', '0.2-0.3', '0.3-0.4', '0.4-0.5', '0.5-0.6', '0.6-0.7', '0.7-0.8', '0.8-0.9', '0.9-1.0'];
3524
+ this.ConfidenceHistogram = bins.map((count, i) => {
3525
+ let color = 'var(--mj-status-error)';
3526
+ if (i >= 7)
3527
+ color = 'var(--mj-brand-primary)';
3528
+ else if (i >= 5)
3529
+ color = 'var(--mj-status-warning)';
3530
+ else if (i >= 3)
3531
+ color = 'var(--mj-status-warning)';
3532
+ if (i === 9)
3533
+ color = 'var(--mj-status-success)';
3534
+ return {
3535
+ Label: binLabels[i],
3536
+ Count: count,
3537
+ Percentage: Math.max(count > 0 ? 5 : 2, Math.round((count / maxBin) * 100)),
3538
+ Color: color,
3539
+ };
3540
+ });
3541
+ // Stats
3542
+ if (weights.length > 0) {
3543
+ weights.sort((a, b) => a - b);
3544
+ const mean = weights.reduce((a, b) => a + b, 0) / weights.length;
3545
+ const median = weights[Math.floor(weights.length / 2)];
3546
+ const variance = weights.reduce((sum, w) => sum + Math.pow(w - mean, 2), 0) / weights.length;
3547
+ const stdDev = Math.sqrt(variance);
3548
+ const p90 = weights[Math.floor(weights.length * 0.9)];
3549
+ this.ConfidenceStats = [
3550
+ { Label: 'Median', Value: median.toFixed(2) },
3551
+ { Label: 'Mean', Value: mean.toFixed(2) },
3552
+ { Label: 'Std Dev', Value: stdDev.toFixed(2) },
3553
+ { Label: 'P90', Value: p90.toFixed(2) },
3554
+ { Label: 'Total', Value: `${weights.length} tags` },
3555
+ ];
3556
+ }
3557
+ else {
3558
+ this.ConfidenceStats = [
3559
+ { Label: 'Median', Value: 'N/A' },
3560
+ { Label: 'Mean', Value: 'N/A' },
3561
+ { Label: 'Std Dev', Value: 'N/A' },
3562
+ { Label: 'P90', Value: 'N/A' },
3563
+ { Label: 'Total', Value: '0 tags' },
3564
+ ];
3565
+ }
3566
+ }
3567
+ // ================================================================
3568
+ // Weight Distribution by Entity
3569
+ // ================================================================
3570
+ buildWeightByEntity(tags) {
3571
+ const entityWeights = new Map();
3572
+ for (const tag of tags) {
3573
+ const w = Number(tag['Weight'] || 0);
3574
+ if (w <= 0)
3575
+ continue;
3576
+ const itemId = String(tag['ItemID'] || '');
3577
+ const item = this.rawContentItems.find(i => String(i['ID']) === itemId);
3578
+ if (!item)
3579
+ continue;
3580
+ const ctid = String(item['ContentTypeID'] || '');
3581
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
3582
+ const typeName = ct ? String(ct['Name'] || 'Unknown') : 'Unknown';
3583
+ if (!entityWeights.has(typeName)) {
3584
+ entityWeights.set(typeName, { high: 0, med: 0, low: 0 });
3585
+ }
3586
+ const entry = entityWeights.get(typeName);
3587
+ if (w > 0.7)
3588
+ entry.high++;
3589
+ else if (w >= 0.4)
3590
+ entry.med++;
3591
+ else
3592
+ entry.low++;
3593
+ }
3594
+ this.WeightByEntity = Array.from(entityWeights.entries())
3595
+ .sort((a, b) => (b[1].high + b[1].med + b[1].low) - (a[1].high + a[1].med + a[1].low))
3596
+ .slice(0, 4)
3597
+ .map(([name, counts]) => {
3598
+ const total = Math.max(counts.high + counts.med + counts.low, 1);
3599
+ return {
3600
+ Name: name,
3601
+ High: Math.round((counts.high / total) * 100),
3602
+ Med: Math.round((counts.med / total) * 100),
3603
+ Low: Math.round((counts.low / total) * 100),
3604
+ };
3605
+ });
3606
+ }
3607
+ // ================================================================
3608
+ // Accuracy Trend (line chart)
3609
+ // ================================================================
3610
+ buildAccuracyTrend(tags) {
3611
+ const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
3612
+ const now = new Date();
3613
+ const monthlyAvgs = [];
3614
+ const labels = [];
3615
+ for (let i = 6; i >= 0; i--) {
3616
+ const monthDate = new Date(now.getFullYear(), now.getMonth() - i, 1);
3617
+ const nextMonth = new Date(now.getFullYear(), now.getMonth() - i + 1, 1);
3618
+ labels.push(monthNames[monthDate.getMonth()]);
3619
+ const monthTags = tags.filter(t => {
3620
+ const d = t['__mj_CreatedAt'];
3621
+ if (!d)
3622
+ return false;
3623
+ const dt = new Date(String(d));
3624
+ return dt >= monthDate && dt < nextMonth;
3625
+ });
3626
+ const weights = monthTags.map(t => Number(t['Weight'] || 0)).filter(w => w > 0);
3627
+ const avg = weights.length > 0 ? weights.reduce((a, b) => a + b, 0) / weights.length : 0;
3628
+ monthlyAvgs.push(avg);
3629
+ }
3630
+ this.AccuracyMonthLabels = labels;
3631
+ // Build SVG points (viewBox 0 0 400 110, with y inverted: 0=top=1.0, 110=bottom=0.0)
3632
+ const points = [];
3633
+ const dots = [];
3634
+ monthlyAvgs.forEach((avg, i) => {
3635
+ const x = i * (400 / Math.max(monthlyAvgs.length - 1, 1));
3636
+ const y = 110 - (avg * 110);
3637
+ points.push(`${x.toFixed(0)},${y.toFixed(0)}`);
3638
+ if (i % 2 === 0)
3639
+ dots.push({ Cx: Math.round(x), Cy: Math.round(y) });
3640
+ });
3641
+ this.AccuracyLinePoints = points.join(' ');
3642
+ this.AccuracyDots = dots;
3643
+ // Trend text
3644
+ const first = monthlyAvgs[0];
3645
+ const last = monthlyAvgs[monthlyAvgs.length - 1];
3646
+ if (first > 0 && last > 0) {
3647
+ const change = Math.round(((last - first) / first) * 100);
3648
+ this.AccuracyTrendText = change >= 0
3649
+ ? `Confidence trending upward: ${first.toFixed(2)} -> ${last.toFixed(2)} (+${change}%)`
3650
+ : `Confidence declining: ${first.toFixed(2)} -> ${last.toFixed(2)} (${change}%)`;
3651
+ }
3652
+ else {
3653
+ this.AccuracyTrendText = 'Insufficient data for trend analysis';
3654
+ }
3655
+ }
3656
+ // ================================================================
3657
+ // Low Confidence Tags
3658
+ // ================================================================
3659
+ buildLowConfidenceTags(tags) {
3660
+ const tagAvgs = new Map();
3661
+ for (const tag of tags) {
3662
+ const tagText = String(tag['Tag'] || '');
3663
+ const w = Number(tag['Weight'] || 0);
3664
+ if (!tagText || w <= 0)
3665
+ continue;
3666
+ if (!tagAvgs.has(tagText)) {
3667
+ tagAvgs.set(tagText, { totalWeight: 0, count: 0, entities: new Map() });
3668
+ }
3669
+ const entry = tagAvgs.get(tagText);
3670
+ entry.totalWeight += w;
3671
+ entry.count++;
3672
+ const itemId = String(tag['ItemID'] || '');
3673
+ const item = this.rawContentItems.find(i => String(i['ID']) === itemId);
3674
+ if (item) {
3675
+ const ctid = String(item['ContentTypeID'] || '');
3676
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === ctid);
3677
+ const typeName = ct ? String(ct['Name'] || 'Unknown') : 'Unknown';
3678
+ entry.entities.set(typeName, (entry.entities.get(typeName) || 0) + 1);
3679
+ }
3680
+ }
3681
+ this.LowConfidenceTags = Array.from(tagAvgs.entries())
3682
+ .map(([name, data]) => ({
3683
+ name,
3684
+ avgWeight: data.totalWeight / data.count,
3685
+ count: data.count,
3686
+ topEntity: data.entities.size > 0
3687
+ ? Array.from(data.entities.entries()).sort((a, b) => b[1] - a[1])[0][0]
3688
+ : 'N/A',
3689
+ }))
3690
+ .filter(t => t.avgWeight < 0.4)
3691
+ .sort((a, b) => a.avgWeight - b.avgWeight)
3692
+ .slice(0, 7)
3693
+ .map(t => ({
3694
+ Name: t.name,
3695
+ AvgWeight: Math.round(t.avgWeight * 100) / 100,
3696
+ UsageCount: t.count,
3697
+ TopEntity: t.topEntity,
3698
+ SuggestedAction: t.avgWeight < 0.25 ? 'Archive (low relevance)' : 'Review taxonomy placement',
3699
+ ActionClass: t.avgWeight < 0.25 ? 'badge-error' : 'badge-warning',
3700
+ }));
3701
+ }
3702
+ // ================================================================
3703
+ // Model Comparisons
3704
+ // ================================================================
3705
+ buildModelComparisons() {
3706
+ // Model comparison requires per-model tag tracking which isn't available yet.
3707
+ // Show empty state prompting users to enable model tracking.
3708
+ this.ModelComparisons = [];
3709
+ this.ModelRecommendation = '';
3710
+ // If we have content item tags with model info, we could derive this.
3711
+ // For now, show an informational message.
3712
+ if (this.rawContentItemTags.length === 0) {
3713
+ this.ModelRecommendation = 'No autotagging data available yet. Run the autotagging pipeline to generate model performance metrics.';
3714
+ }
3715
+ else {
3716
+ this.ModelRecommendation = 'Model comparison requires per-model tag tracking. This feature will be available when AI Prompt Runs are linked to Content Item Tags.';
3717
+ }
3718
+ }
3719
+ // ================================================================
3720
+ // Trending Tags (sidebar)
3721
+ // ================================================================
3722
+ buildTrendingTags(tags) {
3723
+ const tagCounts = new Map();
3724
+ const weekAgo = new Date(Date.now() - 14 * 86400000);
3725
+ for (const tag of tags) {
3726
+ const d = tag['__mj_CreatedAt'];
3727
+ if (d && new Date(String(d)) >= weekAgo) {
3728
+ const tagText = String(tag['Tag'] || '');
3729
+ if (tagText) {
3730
+ tagCounts.set(tagText, (tagCounts.get(tagText) || 0) + 1);
3731
+ }
3732
+ }
3733
+ }
3734
+ const sorted = Array.from(tagCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10);
3735
+ const maxCount = sorted.length > 0 ? sorted[0][1] : 1;
3736
+ this.TrendingTags = sorted.map(([name, count]) => ({
3737
+ Name: name,
3738
+ Size: Math.max(10, Math.round((count / maxCount) * 16)),
3739
+ Weight: count > maxCount * 0.7 ? 700 : count > maxCount * 0.4 ? 600 : count > maxCount * 0.2 ? 500 : 400,
3740
+ }));
3741
+ // If no recent trending data, use top tags from all time
3742
+ if (this.TrendingTags.length === 0) {
3743
+ const allTagCounts = new Map();
3744
+ for (const tag of this.rawContentItemTags) {
3745
+ const tagText = String(tag['Tag'] || '');
3746
+ if (tagText)
3747
+ allTagCounts.set(tagText, (allTagCounts.get(tagText) || 0) + 1);
3748
+ }
3749
+ const allSorted = Array.from(allTagCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 10);
3750
+ const allMax = allSorted.length > 0 ? allSorted[0][1] : 1;
3751
+ this.TrendingTags = allSorted.map(([name, count]) => ({
3752
+ Name: name,
3753
+ Size: Math.max(10, Math.round((count / allMax) * 16)),
3754
+ Weight: count > allMax * 0.7 ? 700 : count > allMax * 0.4 ? 600 : 500,
3755
+ }));
3756
+ }
3757
+ }
3758
+ // ================================================================
3759
+ // Pipeline Status
3760
+ // ================================================================
3761
+ buildPipelineStatus(runs) {
3762
+ const activeRuns = runs.filter(r => {
3763
+ const status = String(r['Status'] || '').toLowerCase();
3764
+ return status === 'running' || status === 'in progress' || status === 'processing';
3765
+ });
3766
+ const recentErrors = runs.filter(r => {
3767
+ const status = String(r['Status'] || '').toLowerCase();
3768
+ return status.includes('error') || status.includes('fail');
3769
+ });
3770
+ if (activeRuns.length > 0) {
3771
+ this.PipelineStatusText = `${activeRuns.length} pipeline${activeRuns.length > 1 ? 's' : ''} running`;
3772
+ this.PipelineStatusOk = true;
3773
+ }
3774
+ else if (recentErrors.length > 0) {
3775
+ this.PipelineStatusText = `${recentErrors.length} recent error${recentErrors.length > 1 ? 's' : ''}`;
3776
+ this.PipelineStatusOk = false;
3777
+ }
3778
+ else {
3779
+ this.PipelineStatusText = 'All systems operational';
3780
+ this.PipelineStatusOk = true;
3781
+ }
3782
+ }
3783
+ // ================================================================
3784
+ // Drill-Down Data Loading
3785
+ // ================================================================
3786
+ loadDrillDownData(key) {
3787
+ this.DrillDownHasActions = false;
3788
+ switch (key) {
3789
+ case 'kpi-totalTags':
3790
+ this.DrillDownColumns = ['Name', 'Display Name', 'Description', 'Parent'];
3791
+ this.DrillDownHasActions = true;
3792
+ this.DrillDownData = this.rawTags.slice(0, 50).map(t => ({
3793
+ 'Name': String(t['Name'] || ''),
3794
+ 'Display Name': String(t['DisplayName'] || ''),
3795
+ 'Description': String(t['Description'] || '').slice(0, 100),
3796
+ 'Parent': String(t['Parent'] || 'Root'),
3797
+ '_RecordID': String(t['ID'] || ''),
3798
+ '_EntityName': 'MJ: Tags',
3799
+ }));
3800
+ break;
3801
+ case 'kpi-itemsProcessed':
3802
+ this.DrillDownColumns = ['Name', 'Source', 'Content Type', 'Created'];
3803
+ this.DrillDownHasActions = true;
3804
+ this.DrillDownData = this.rawContentItems.slice(0, 50).map(i => {
3805
+ const source = this.rawContentSources.find(s => String(s['ID']) === String(i['ContentSourceID']));
3806
+ const ct = this.rawContentTypes.find(t => String(t['ID']) === String(i['ContentTypeID']));
3807
+ return {
3808
+ 'Name': String(i['Name'] || ''),
3809
+ 'Source': source ? String(source['Name']) : 'Unknown',
3810
+ 'Content Type': ct ? String(ct['Name']) : 'Unknown',
3811
+ 'Created': i['__mj_CreatedAt'] ? new Date(String(i['__mj_CreatedAt'])).toLocaleDateString() : '',
3812
+ '_RecordID': String(i['ID'] || ''),
3813
+ '_EntityName': 'MJ: Content Items',
3814
+ };
3815
+ });
3816
+ break;
3817
+ case 'kpi-avgConfidence':
3818
+ case 'kpi-coverage':
3819
+ this.DrillDownColumns = ['Tag', 'Item', 'Weight', 'Created'];
3820
+ this.DrillDownHasActions = true;
3821
+ this.DrillDownData = this.rawContentItemTags.slice(0, 50).map(t => ({
3822
+ 'Tag': String(t['Tag'] || ''),
3823
+ 'Item': String(t['Item'] || ''),
3824
+ 'Weight': String(t['Weight'] || '0'),
3825
+ 'Created': t['__mj_CreatedAt'] ? new Date(String(t['__mj_CreatedAt'])).toLocaleDateString() : '',
3826
+ '_RecordID': String(t['ID'] || ''),
3827
+ '_EntityName': 'MJ: Content Item Tags',
3828
+ }));
3829
+ break;
3830
+ case 'tagGrowth':
3831
+ case 'contentCoverage':
3832
+ case 'qualityScore':
3833
+ case 'sourcePerformance':
3834
+ case 'dailyThroughput':
3835
+ case 'taxonomyHealth':
3836
+ this.buildWidgetDrillDown(key);
3837
+ break;
3838
+ default:
3839
+ // D10: Handle tab-specific drill-down keys
3840
+ if (key.startsWith('tag-row:')) {
3841
+ this.buildTagRowDrillDown(key.replace('tag-row:', ''));
3842
+ }
3843
+ else if (key.startsWith('source-row:')) {
3844
+ this.buildSourceRowDrillDown(key.replace('source-row:', ''));
3845
+ }
3846
+ else if (key.startsWith('pipeline-throughput:')) {
3847
+ this.buildPipelineThroughputDrillDown(key.replace('pipeline-throughput:', ''));
3848
+ }
3849
+ else if (key.startsWith('quality-bin:')) {
3850
+ this.buildQualityBinDrillDown(key.replace('quality-bin:', ''));
3851
+ }
3852
+ else {
3853
+ this.DrillDownColumns = [];
3854
+ this.DrillDownData = [];
3855
+ }
3856
+ }
3857
+ this.IsDrillDownLoading = false;
3858
+ this.cdr.detectChanges();
3859
+ }
3860
+ buildWidgetDrillDown(key) {
3861
+ switch (key) {
3862
+ case 'tagGrowth':
3863
+ this.DrillDownColumns = ['Tag Name', 'Created'];
3864
+ this.DrillDownHasActions = true;
3865
+ this.DrillDownData = this.rawTags
3866
+ .sort((a, b) => new Date(String(b['__mj_CreatedAt'] || 0)).getTime() - new Date(String(a['__mj_CreatedAt'] || 0)).getTime())
3867
+ .slice(0, 50)
3868
+ .map(t => ({
3869
+ 'Tag Name': String(t['Name'] || ''),
3870
+ 'Created': t['__mj_CreatedAt'] ? new Date(String(t['__mj_CreatedAt'])).toLocaleDateString() : '',
3871
+ '_RecordID': String(t['ID'] || ''),
3872
+ '_EntityName': 'MJ: Tags',
3873
+ }));
3874
+ break;
3875
+ case 'contentCoverage':
3876
+ this.DrillDownColumns = ['Content Type', 'Total Items', 'Tagged Items', 'Coverage %'];
3877
+ this.DrillDownData = this.CoverageData.map(c => ({
3878
+ 'Content Type': c.Name,
3879
+ 'Total Items': c.Total,
3880
+ 'Tagged Items': c.Tagged,
3881
+ 'Coverage %': `${c.Percentage}%`,
3882
+ }));
3883
+ break;
3884
+ case 'qualityScore':
3885
+ this.DrillDownColumns = ['Bin', 'Count'];
3886
+ this.DrillDownData = this.ConfidenceHistogram.map(b => ({
3887
+ 'Bin': b.Label,
3888
+ 'Count': b.Count,
3889
+ }));
3890
+ break;
3891
+ case 'sourcePerformance':
3892
+ this.DrillDownColumns = ['Source', 'Avg Tags/Item'];
3893
+ this.DrillDownData = this.SourcePerfData.map(s => ({
3894
+ 'Source': s.Name,
3895
+ 'Avg Tags/Item': s.AvgTagsPerItem,
3896
+ }));
3897
+ break;
3898
+ case 'dailyThroughput':
3899
+ this.DrillDownColumns = ['Run ID', 'Source', 'Status', 'Items', 'Started'];
3900
+ this.DrillDownHasActions = true;
3901
+ this.DrillDownData = this.rawProcessRuns
3902
+ .sort((a, b) => new Date(String(b['StartTime'] || 0)).getTime() - new Date(String(a['StartTime'] || 0)).getTime())
3903
+ .slice(0, 30)
3904
+ .map(r => {
3905
+ const source = this.rawContentSources.find(s => String(s['ID']) === String(r['SourceID']));
3906
+ return {
3907
+ 'Run ID': String(r['ID'] || '').slice(0, 14),
3908
+ 'Source': source ? String(source['Name']) : 'Unknown',
3909
+ 'Status': String(r['Status'] || ''),
3910
+ 'Items': Number(r['ProcessedItems'] || 0),
3911
+ 'Started': r['StartTime'] ? new Date(String(r['StartTime'])).toLocaleString() : '',
3912
+ '_RecordID': String(r['ID'] || ''),
3913
+ '_EntityName': 'MJ: Content Process Runs',
3914
+ };
3915
+ });
3916
+ break;
3917
+ case 'taxonomyHealth':
3918
+ this.DrillDownColumns = ['Tag', 'Has Children', 'Is Used', 'Status'];
3919
+ this.DrillDownHasActions = true;
3920
+ const parentIds = new Set(this.rawTags.filter(t => t['ParentID']).map(t => String(t['ParentID'])));
3921
+ const usedIds = new Set(this.rawContentItemTags.filter(ct => ct['TagID']).map(ct => String(ct['TagID'])));
3922
+ this.DrillDownData = this.rawTags.slice(0, 50).map(t => {
3923
+ const tid = String(t['ID']);
3924
+ const hasChildren = parentIds.has(tid);
3925
+ const isUsed = usedIds.has(tid);
3926
+ let status = 'Orphaned';
3927
+ if (hasChildren || isUsed)
3928
+ status = 'Healthy';
3929
+ else if (t['ParentID'])
3930
+ status = 'Attention';
3931
+ return {
3932
+ 'Tag': String(t['Name'] || ''),
3933
+ 'Has Children': hasChildren ? 'Yes' : 'No',
3934
+ 'Is Used': isUsed ? 'Yes' : 'No',
3935
+ 'Status': status,
3936
+ '_RecordID': String(t['ID'] || ''),
3937
+ '_EntityName': 'MJ: Tags',
3938
+ };
3939
+ });
3940
+ break;
3941
+ }
3942
+ }
3943
+ // ================================================================
3944
+ // D10: Tab-Specific Drill-Down Builders
3945
+ // ================================================================
3946
+ /**
3947
+ * D10 Tags tab: Click a tag row to see content items using that tag.
3948
+ */
3949
+ buildTagRowDrillDown(tagName) {
3950
+ this.DrillDownColumns = ['Item Name', 'Source', 'Weight', 'Created'];
3951
+ this.DrillDownHasActions = true;
3952
+ const matchingTags = this.rawContentItemTags.filter(t => String(t['Tag'] || '') === tagName);
3953
+ this.DrillDownData = matchingTags.slice(0, 50).map(t => {
3954
+ const itemId = String(t['ItemID'] || '');
3955
+ const item = this.rawContentItems.find(i => String(i['ID']) === itemId);
3956
+ const source = item
3957
+ ? this.rawContentSources.find(s => String(s['ID']) === String(item['ContentSourceID']))
3958
+ : null;
3959
+ return {
3960
+ 'Item Name': item ? String(item['Name'] || '') : 'Unknown',
3961
+ 'Source': source ? String(source['Name'] || '') : 'Unknown',
3962
+ 'Weight': String(t['Weight'] || '0'),
3963
+ 'Created': t['__mj_CreatedAt'] ? new Date(String(t['__mj_CreatedAt'])).toLocaleDateString() : '',
3964
+ '_RecordID': itemId,
3965
+ '_EntityName': 'MJ: Content Items',
3966
+ };
3967
+ });
3968
+ }
3969
+ /**
3970
+ * D10 Sources tab: Click a source row to see recent runs, items, and errors.
3971
+ */
3972
+ buildSourceRowDrillDown(sourceName) {
3973
+ const source = this.rawContentSources.find(s => String(s['Name']) === sourceName);
3974
+ if (!source) {
3975
+ this.DrillDownColumns = [];
3976
+ this.DrillDownData = [];
3977
+ return;
3978
+ }
3979
+ const sid = String(source['ID']);
3980
+ const sourceRuns = this.rawProcessRuns
3981
+ .filter(r => String(r['SourceID']) === sid)
3982
+ .sort((a, b) => new Date(String(b['StartTime'] || 0)).getTime() - new Date(String(a['StartTime'] || 0)).getTime())
3983
+ .slice(0, 20);
3984
+ this.DrillDownColumns = ['Status', 'Items Processed', 'Start Time', 'Duration'];
3985
+ this.DrillDownHasActions = true;
3986
+ this.DrillDownData = sourceRuns.map(r => {
3987
+ const startTime = r['StartTime'] ? new Date(String(r['StartTime'])) : null;
3988
+ const endTime = r['EndTime'] ? new Date(String(r['EndTime'])) : null;
3989
+ const durationMs = startTime && endTime ? endTime.getTime() - startTime.getTime() : 0;
3990
+ const durationStr = durationMs > 60000 ? `${Math.round(durationMs / 60000)}m` : `${Math.round(durationMs / 1000)}s`;
3991
+ return {
3992
+ 'Status': String(r['Status'] || 'Unknown'),
3993
+ 'Items Processed': Number(r['ProcessedItems'] || 0),
3994
+ 'Start Time': startTime ? startTime.toLocaleString() : '',
3995
+ 'Duration': durationStr,
3996
+ '_RecordID': String(r['ID'] || ''),
3997
+ '_EntityName': 'MJ: Content Process Runs',
3998
+ };
3999
+ });
4000
+ }
4001
+ /**
4002
+ * D10 Pipeline tab: Click throughput chart to see individual run details.
4003
+ */
4004
+ buildPipelineThroughputDrillDown(dayIndex) {
4005
+ const idx = parseInt(dayIndex, 10);
4006
+ const now = new Date();
4007
+ const targetDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - (29 - idx));
4008
+ const dayStr = targetDate.toISOString().slice(0, 10);
4009
+ const dayRuns = this.rawProcessRuns.filter(r => {
4010
+ const st = r['StartTime'];
4011
+ return st && String(st).slice(0, 10) === dayStr;
4012
+ });
4013
+ this.DrillDownColumns = ['Run ID', 'Source', 'Status', 'Items', 'Start Time'];
4014
+ this.DrillDownHasActions = true;
4015
+ this.DrillDownData = dayRuns.map(r => {
4016
+ const source = this.rawContentSources.find(s => String(s['ID']) === String(r['SourceID']));
4017
+ return {
4018
+ 'Run ID': String(r['ID'] || '').slice(0, 14),
4019
+ 'Source': source ? String(source['Name']) : 'Unknown',
4020
+ 'Status': String(r['Status'] || ''),
4021
+ 'Items': Number(r['ProcessedItems'] || 0),
4022
+ 'Start Time': r['StartTime'] ? new Date(String(r['StartTime'])).toLocaleString() : '',
4023
+ '_RecordID': String(r['ID'] || ''),
4024
+ '_EntityName': 'MJ: Content Process Runs',
4025
+ };
4026
+ });
4027
+ }
4028
+ /**
4029
+ * D10 Quality tab: Click confidence histogram bin to see matching items.
4030
+ */
4031
+ buildQualityBinDrillDown(binLabel) {
4032
+ // Parse bin range from label like "0.7-0.8"
4033
+ const parts = binLabel.split('-');
4034
+ const lo = parseFloat(parts[0]);
4035
+ const hi = parts.length > 1 ? parseFloat(parts[1]) : lo + 0.1;
4036
+ const matchingTags = this.rawContentItemTags.filter(t => {
4037
+ const w = Number(t['Weight'] || 0);
4038
+ return w >= lo && w < hi;
4039
+ });
4040
+ this.DrillDownColumns = ['Tag', 'Item', 'Weight', 'Created'];
4041
+ this.DrillDownHasActions = true;
4042
+ this.DrillDownData = matchingTags.slice(0, 50).map(t => ({
4043
+ 'Tag': String(t['Tag'] || ''),
4044
+ 'Item': String(t['Item'] || ''),
4045
+ 'Weight': String(Number(t['Weight'] || 0).toFixed(3)),
4046
+ 'Created': t['__mj_CreatedAt'] ? new Date(String(t['__mj_CreatedAt'])).toLocaleDateString() : '',
4047
+ '_RecordID': String(t['ID'] || ''),
4048
+ '_EntityName': 'MJ: Content Item Tags',
4049
+ }));
4050
+ }
4051
+ // ================================================================
4052
+ // D1: Cost & Usage Aggregation
4053
+ // ================================================================
4054
+ /**
4055
+ * Aggregates cost and token data from ContentProcessRunDetail records.
4056
+ * Each detail record has TotalTokensUsed and TotalCost fields that are
4057
+ * pre-rolled-up from linked AIPromptRun records.
4058
+ */
4059
+ buildCostUsageData(filteredRuns) {
4060
+ // Filter run details to match the current date range by joining to filtered runs
4061
+ const filteredRunIds = new Set(filteredRuns.map(r => String(r['ID'] || '')));
4062
+ const filteredDetails = this.rawRunDetails.filter(d => filteredRunIds.has(String(d['ContentProcessRunID'] || '')));
4063
+ const totalTokens = this.sumField(filteredDetails, 'TotalTokensUsed');
4064
+ const totalCost = this.sumField(filteredDetails, 'TotalCost');
4065
+ const runCount = filteredRuns.length;
4066
+ const avgCostPerRun = runCount > 0 ? totalCost / runCount : 0;
4067
+ this.CostKPIs = [
4068
+ {
4069
+ Label: 'Total Tokens Used',
4070
+ Value: this.formatLargeNumber(totalTokens),
4071
+ Icon: 'fa-solid fa-microchip',
4072
+ SubLabel: `Across ${runCount} run${runCount !== 1 ? 's' : ''}`,
4073
+ },
4074
+ {
4075
+ Label: 'Total Cost',
4076
+ Value: totalCost > 0 ? `$${totalCost.toFixed(4)}` : '$0.00',
4077
+ Icon: 'fa-solid fa-dollar-sign',
4078
+ SubLabel: 'Estimated from AI model usage',
4079
+ },
4080
+ {
4081
+ Label: 'Avg Cost / Run',
4082
+ Value: avgCostPerRun > 0 ? `$${avgCostPerRun.toFixed(4)}` : '$0.00',
4083
+ Icon: 'fa-solid fa-calculator',
4084
+ SubLabel: runCount > 0 ? `${runCount} total runs` : 'No runs yet',
4085
+ },
4086
+ ];
4087
+ // Build per-run cost breakdown from detail records
4088
+ this.CostPerRunRows = this.buildCostPerRunRows(filteredRuns, filteredDetails);
4089
+ }
4090
+ /** Sum a numeric field across an array of raw records */
4091
+ static SumField(records, fieldName) {
4092
+ return records.reduce((sum, r) => sum + Number(r[fieldName] || 0), 0);
4093
+ }
4094
+ sumField(records, fieldName) {
4095
+ return AnalyticsResourceComponent_1.SumField(records, fieldName);
4096
+ }
4097
+ formatLargeNumber(n) {
4098
+ if (n >= 1000000)
4099
+ return `${(n / 1000000).toFixed(1)}M`;
4100
+ if (n >= 1000)
4101
+ return `${(n / 1000).toFixed(1)}K`;
4102
+ return String(Math.round(n));
4103
+ }
4104
+ buildCostPerRunRows(runs, details) {
4105
+ // Group details by run
4106
+ const detailsByRun = new Map();
4107
+ for (const d of details) {
4108
+ const runId = String(d['ContentProcessRunID'] || '');
4109
+ if (!detailsByRun.has(runId))
4110
+ detailsByRun.set(runId, []);
4111
+ detailsByRun.get(runId).push(d);
4112
+ }
4113
+ return runs
4114
+ .sort((a, b) => new Date(String(b['StartTime'] || 0)).getTime() - new Date(String(a['StartTime'] || 0)).getTime())
4115
+ .slice(0, 20)
4116
+ .map(run => {
4117
+ const runId = String(run['ID'] || '');
4118
+ const runDetails = detailsByRun.get(runId) || [];
4119
+ const tokens = this.sumField(runDetails, 'TotalTokensUsed');
4120
+ const cost = this.sumField(runDetails, 'TotalCost');
4121
+ const source = this.rawContentSources.find(s => String(s['ID']) === String(run['SourceID']));
4122
+ return {
4123
+ RunID: runId.slice(0, 14),
4124
+ Source: source ? String(source['Name']) : 'Unknown',
4125
+ Tokens: tokens,
4126
+ Cost: cost,
4127
+ Started: run['StartTime'] ? new Date(String(run['StartTime'])).toLocaleString() : '',
4128
+ };
4129
+ });
4130
+ }
4131
+ // ================================================================
4132
+ // D5: Print-Friendly Export
4133
+ // ================================================================
4134
+ /**
4135
+ * D5: Opens the browser print dialog with print-friendly CSS.
4136
+ * This is a zero-dependency approach to PDF export.
4137
+ * NOTE: For full XLSX export, an xlsx library (e.g. SheetJS) can be added later.
4138
+ */
4139
+ PrintCurrentTab() {
4140
+ window.print();
4141
+ }
4142
+ // ================================================================
4143
+ // SR-6: Preference Persistence
4144
+ // ================================================================
4145
+ static PREFS_KEY = 'KH_Analytics_Preferences';
4146
+ persistAnalyticsPreferences() {
4147
+ const prefs = JSON.stringify({
4148
+ ActiveTab: this.ActiveTab,
4149
+ ActiveDateRange: this.ActiveDateRange,
4150
+ EntityFilter: this.EntityFilter,
4151
+ });
4152
+ UserInfoEngine.Instance.SetSettingDebounced(AnalyticsResourceComponent_1.PREFS_KEY, prefs);
4153
+ }
4154
+ loadAnalyticsPreferences() {
4155
+ const raw = UserInfoEngine.Instance.GetSetting(AnalyticsResourceComponent_1.PREFS_KEY);
4156
+ if (raw) {
4157
+ try {
4158
+ const prefs = JSON.parse(raw);
4159
+ if (prefs.ActiveTab)
4160
+ this.ActiveTab = prefs.ActiveTab;
4161
+ if (prefs.ActiveDateRange)
4162
+ this.ActiveDateRange = prefs.ActiveDateRange;
4163
+ if (prefs.EntityFilter)
4164
+ this.EntityFilter = prefs.EntityFilter;
4165
+ }
4166
+ catch { /* ignore */ }
4167
+ }
4168
+ }
4169
+ // ================================================================
4170
+ // Co-Occurrence Data
4171
+ // ================================================================
4172
+ /**
4173
+ * Load the top 20 co-occurring tag pairs and the staleness timestamp.
4174
+ * Runs in background so it does not block initial render.
4175
+ */
4176
+ async loadCoOccurrenceData() {
4177
+ try {
4178
+ const rv = new RunView();
4179
+ const result = await rv.RunView({
4180
+ EntityName: 'MJ: Tag Co Occurrences',
4181
+ ExtraFilter: 'CoOccurrenceCount > 0',
4182
+ OrderBy: 'CoOccurrenceCount DESC',
4183
+ MaxRows: 20,
4184
+ Fields: ['TagA', 'TagB', 'CoOccurrenceCount', 'LastComputedAt'],
4185
+ ResultType: 'simple'
4186
+ });
4187
+ if (result.Success && result.Results.length > 0) {
4188
+ const maxCount = result.Results[0].CoOccurrenceCount;
4189
+ this.CoOccurrencePairs = result.Results.map(row => ({
4190
+ TagAName: row.TagA,
4191
+ TagBName: row.TagB,
4192
+ Count: row.CoOccurrenceCount,
4193
+ BarWidth: maxCount > 0 ? Math.round((row.CoOccurrenceCount / maxCount) * 100) : 0,
4194
+ }));
4195
+ // Find the most recent LastComputedAt value for staleness indicator
4196
+ const computedDates = result.Results
4197
+ .map(r => r.LastComputedAt)
4198
+ .filter((d) => d != null)
4199
+ .map(d => new Date(d))
4200
+ .filter(d => !isNaN(d.getTime()));
4201
+ if (computedDates.length > 0) {
4202
+ const latest = new Date(Math.max(...computedDates.map(d => d.getTime())));
4203
+ this.CoOccurrenceLastComputed = this.formatRelativeTime(latest);
4204
+ }
4205
+ }
4206
+ this.cdr.detectChanges();
4207
+ }
4208
+ catch (error) {
4209
+ console.error('[Analytics] Error loading co-occurrence data:', error);
4210
+ }
4211
+ }
4212
+ /** Recompute co-occurrence data (triggered by user button click) */
4213
+ async RecomputeCoOccurrence() {
4214
+ if (this.IsRecomputingCoOccurrence)
4215
+ return;
4216
+ this.IsRecomputingCoOccurrence = true;
4217
+ this.cdr.detectChanges();
4218
+ try {
4219
+ const provider = Metadata.Provider;
4220
+ const gql = `
4221
+ mutation RecomputeTagCoOccurrence {
4222
+ RecomputeTagCoOccurrence {
4223
+ PairsUpdated
4224
+ PairsDeleted
4225
+ }
4226
+ }
4227
+ `;
4228
+ // If GraphQL mutation not available, fall back to client-side reload
4229
+ try {
4230
+ const gqlProvider = provider;
4231
+ if (typeof gqlProvider.ExecuteGQL === 'function') {
4232
+ await gqlProvider.ExecuteGQL(gql, {});
4233
+ }
4234
+ }
4235
+ catch {
4236
+ // Mutation not available on server, just reload
4237
+ }
4238
+ // Reload the data
4239
+ await this.loadCoOccurrenceData();
4240
+ }
4241
+ finally {
4242
+ this.IsRecomputingCoOccurrence = false;
4243
+ this.cdr.detectChanges();
4244
+ }
4245
+ }
4246
+ static ɵfac = /*@__PURE__*/ (() => { let ɵAnalyticsResourceComponent_BaseFactory; return function AnalyticsResourceComponent_Factory(__ngFactoryType__) { return (ɵAnalyticsResourceComponent_BaseFactory || (ɵAnalyticsResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(AnalyticsResourceComponent)))(__ngFactoryType__ || AnalyticsResourceComponent); }; })();
4247
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnalyticsResourceComponent, selectors: [["app-analytics-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 1, consts: [[1, "analytics-loading"], [1, "analytics-layout"], ["text", "Loading analytics data...", "size", "medium"], [1, "analytics-sidebar"], [1, "sidebar-header"], [1, "fa-solid", "fa-chart-line"], [1, "sidebar-nav"], [1, "nav-item", 3, "active"], [1, "sidebar-divider"], [1, "trending-section"], [1, "fa-solid", "fa-arrow-trend-up"], [1, "tag-cloud"], [3, "font-size", "font-weight"], [1, "no-trending"], [1, "pipeline-status"], [1, "status-dot"], [1, "main-content"], [1, "tab-section"], [1, "nav-item", 3, "click"], [1, "tab-section-header"], [1, "fa-solid", "fa-grip"], [1, "filter-bar"], [1, "date-chips"], [1, "date-chip", 3, "active"], [1, "filter-dropdown", 3, "ngModelChange", "ngModel"], [3, "value"], [1, "kpi-row"], [1, "kpi-card"], [1, "drill-down-panel"], [1, "cards-grid"], [1, "widget-card", 3, "click"], [1, "widget-title"], [1, "bar-chart"], [1, "bar-col"], [1, "fa-solid", "fa-bullseye"], [1, "rings-grid"], [1, "ring-item"], [1, "widget-empty"], [1, "fa-solid", "fa-gauge-high"], [1, "gauge-container"], ["width", "180", "height", "110", "viewBox", "0 0 180 110"], ["d", "M 20 95 A 70 70 0 0 1 160 95", "fill", "none", "stroke", "var(--mj-border-default)", "stroke-width", "14", "stroke-linecap", "round"], ["d", "M 20 95 A 70 70 0 0 1 48.6 35.2", "fill", "none", "stroke", "var(--mj-status-error)", "stroke-width", "14", "stroke-linecap", "round", "opacity", "0.3"], ["d", "M 48.6 35.2 A 70 70 0 0 1 118 28", "fill", "none", "stroke", "var(--mj-status-warning)", "stroke-width", "14", "opacity", "0.3"], ["d", "M 118 28 A 70 70 0 0 1 160 95", "fill", "none", "stroke", "var(--mj-status-success)", "stroke-width", "14", "stroke-linecap", "round", "opacity", "0.3"], ["x", "90", "y", "88", "text-anchor", "middle", "font-size", "26", "font-weight", "800", "fill", "var(--mj-text-primary)"], ["x", "90", "y", "105", "text-anchor", "middle", "font-size", "10", "fill", "var(--mj-text-muted)"], ["x", "28", "y", "108", "font-size", "8", "fill", "var(--mj-text-muted)"], ["x", "86", "y", "18", "font-size", "8", "fill", "var(--mj-text-muted)"], ["x", "155", "y", "108", "font-size", "8", "fill", "var(--mj-text-muted)"], [1, "mini-histogram"], [1, "mini-hist-bar", 3, "height", "background", "title"], [1, "mini-hist-label"], [1, "fa-solid", "fa-ranking-star"], [1, "h-bar-list"], [1, "h-bar-row"], [1, "widget-footnote"], [1, "fa-solid", "fa-bolt"], [1, "throughput-bars"], [1, "tp-bar", 3, "height", "background"], [1, "legend"], [1, "legend-item"], [1, "legend-dot", 2, "background", "var(--mj-status-success)"], [1, "legend-dot", 2, "background", "var(--mj-status-error)"], [1, "fa-solid", "fa-sitemap"], [1, "taxonomy-ring-container"], ["width", "140", "height", "140", "viewBox", "0 0 140 140"], ["cx", "70", "cy", "70", "r", "54", "fill", "none", "stroke", "var(--mj-border-default)", "stroke-width", "18"], ["cx", "70", "cy", "70", "r", "54", "fill", "none", "stroke-width", "18", "transform", "rotate(-90 70 70)"], ["x", "70", "y", "66", "text-anchor", "middle", "font-size", "22", "font-weight", "800", "fill", "var(--mj-text-primary)"], ["x", "70", "y", "82", "text-anchor", "middle", "font-size", "10", "fill", "var(--mj-text-muted)"], [1, "taxonomy-stats"], [1, "tax-stat", 3, "background", "color"], [1, "date-chip", 3, "click"], [1, "kpi-card", 3, "click"], [1, "kpi-label"], [1, "kpi-value"], [1, "kpi-delta"], [1, "fa-solid", "fa-arrow-up", 2, "font-size", "9px"], [1, "fa-solid", "fa-arrow-down", 2, "font-size", "9px"], [1, "kpi-sparkline"], ["width", "64", "height", "28", "viewBox", "0 0 64 28"], ["fill", "none", "stroke-width", "2", "stroke-linecap", "round", "stroke-linejoin", "round"], [1, "drill-down-header"], [1, "drill-down-title"], [1, "fa-solid", "fa-table"], [1, "drill-down-header-actions"], ["title", "Export CSV", 1, "drill-export-btn"], [1, "drill-down-close", 3, "click"], [1, "fa-solid", "fa-times"], ["text", "Loading details...", "size", "small"], [1, "drill-down-table-wrap"], [1, "drill-down-empty"], ["title", "Export CSV", 1, "drill-export-btn", 3, "click"], [1, "fa-solid", "fa-download"], [1, "data-table"], [1, "drill-action-col"], ["title", "Open record", 1, "drill-open-btn"], ["title", "Open record", 1, "drill-open-btn", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], [1, "bar-value"], [1, "bar", 2, "background", "var(--mj-brand-primary)"], [1, "bar-label"], ["width", "48", "height", "48", "viewBox", "0 0 48 48"], ["cx", "24", "cy", "24", "r", "20", "fill", "none", "stroke", "var(--mj-border-default)", "stroke-width", "5"], ["cx", "24", "cy", "24", "r", "20", "fill", "none", "stroke-width", "5", "stroke-dashoffset", "31.4", "stroke-linecap", "round", "transform", "rotate(-90 24 24)"], ["x", "24", "y", "26", "text-anchor", "middle", "font-size", "11", "font-weight", "700", "fill", "var(--mj-text-primary)"], [1, "ring-label"], [1, "ring-stat"], [1, "mini-hist-bar", 3, "title"], [1, "h-bar-name"], [1, "h-bar-track"], [1, "h-bar-fill"], [1, "tp-bar"], [1, "tp-bar-label"], [1, "tax-stat"], [1, "fa-solid", "fa-tags"], [1, "sub-section", 2, "margin-top", "0"], [1, "sub-section-header"], [1, "fa-solid", "fa-trophy"], [1, "table-scroll"], [1, "empty-state"], [1, "sub-section"], [1, "sub-section", "co-occurrence-section"], [1, "fa-solid", "fa-link"], [1, "co-occurrence-actions"], ["title", "Last computed timestamp", 1, "co-occurrence-staleness"], ["title", "Recompute co-occurrence data", 1, "drill-export-btn", 3, "click", "disabled"], [1, "num"], [2, "cursor", "pointer"], [2, "cursor", "pointer", 3, "click"], [1, "weight-bar"], ["width", "48", "height", "16"], ["fill", "none", "stroke-width", "1.5", "stroke-linecap", "round"], [1, "muted"], [1, "fa-solid", "fa-chart-bar"], [1, "stacked-bar-chart"], [1, "stacked-row"], [1, "legend", 2, "margin-top", "12px"], [1, "stacked-label"], [1, "stacked-track"], [1, "stacked-seg", 3, "width", "background", "title"], [1, "stacked-seg", 3, "title"], [1, "legend-dot"], [1, "fa-solid", "fa-layer-group"], [1, "v-bar-chart"], [1, "v-bar-col"], [1, "chart-footnote"], [1, "v-bar", 2, "background", "var(--mj-brand-primary)"], [1, "v-bar-label"], [1, "fa-regular", "fa-clock"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-arrows-rotate"], [1, "weight-bar", 2, "background", "var(--mj-status-info)"], [1, "fa-solid", "fa-database"], [2, "cursor", "pointer", 3, "source-selected"], [2, "margin-right", "4px"], [1, "badge"], [1, "fa-solid", "fa-circle", 2, "font-size", "6px", "margin-right", "3px"], [1, "fa-solid", "fa-chart-area"], [1, "two-col"], [1, "widget-card"], [1, "bar-chart", 2, "height", "100px"], [1, "fa-solid", "fa-star-half-stroke"], [1, "quality-bands"], [1, "quality-band-row"], [1, "source-quality-note"], [1, "fa-solid", "fa-circle-info", 2, "color", "var(--mj-status-info)", "margin-right", "4px"], [1, "bar-value", 2, "font-size", "9px"], [1, "quality-band-label"], [1, "quality-band-track"], [1, "quality-band-fill"], [1, "fa-solid", "fa-heart-pulse"], [1, "source-health-grid"], [1, "source-health-card", 3, "border-top-color"], [1, "source-health-card"], [1, "health-card-name"], [1, "health-card-value"], [1, "health-card-label"], [1, "fa-solid", "fa-gears"], [1, "pipeline-throughput-bars"], [1, "pipeline-bar", 2, "cursor", "pointer", 3, "height", "background", "opacity"], [1, "pipeline-date-labels"], [1, "fa-solid", "fa-stopwatch"], [1, "stage-bars"], [1, "stage-row"], [1, "stage-summary"], [1, "stage-warning"], [1, "success-rate-display"], [1, "success-rate-stat"], [1, "success-rate-value", 2, "color", "var(--mj-status-success)"], [1, "success-rate-label"], [1, "success-rate-value", 2, "color", "var(--mj-status-error)"], [1, "success-rate-value", 2, "color", "var(--mj-text-primary)"], [1, "pipeline-bar", 2, "cursor", "pointer", 3, "click"], [1, "stage-name"], [1, "stage-track"], [1, "stage-fill"], [1, "stage-time"], [1, "fa-solid", "fa-triangle-exclamation", 2, "color", "var(--mj-status-warning)", "margin-right", "4px"], [1, "fa-solid", "fa-spinner"], [1, "monospace-cell"], [1, "progress-track"], [1, "progress-fill", 2, "background", "var(--mj-brand-primary)"], [1, "progress-text"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "error-log"], [1, "error-entry"], [1, "error-time"], [1, "error-source"], [1, "error-msg"], [1, "fa-solid", "fa-circle-check"], [1, "fa-solid", "fa-chart-column"], [1, "histogram"], [1, "hist-bar-col", 2, "cursor", "pointer"], [1, "confidence-stats"], [1, "fa-solid", "fa-robot"], [1, "model-grid"], [1, "model-card"], [1, "model-recommendation"], [1, "hist-bar-col", 2, "cursor", "pointer", 3, "click"], [1, "hist-bar"], [1, "hist-label"], [1, "fa-solid", "fa-weight-scale"], [1, "grouped-bar-chart"], [1, "grouped-col"], [1, "legend", 2, "justify-content", "center", "margin-top", "14px"], [1, "grouped-bars"], [1, "g-bar", 2, "background", "var(--mj-brand-primary)", 3, "title"], [1, "g-bar", 2, "background", "var(--mj-status-info)", 3, "title"], [1, "g-bar", 2, "background", "var(--mj-text-muted)", 3, "title"], [1, "grouped-label"], [1, "accuracy-chart"], [1, "accuracy-y-labels"], [1, "accuracy-area"], [1, "accuracy-grid-line", 2, "top", "33%"], [1, "accuracy-grid-line", 2, "top", "66%"], ["width", "100%", "height", "110", "viewBox", "0 0 400 110", "preserveAspectRatio", "none", 1, "accuracy-svg"], ["fill", "none", "stroke", "var(--mj-brand-primary)", "stroke-width", "2.5", "vector-effect", "non-scaling-stroke", "stroke-linecap", "round", "stroke-linejoin", "round"], ["r", "3", "fill", "var(--mj-brand-primary)"], [1, "accuracy-x-labels"], [1, "accuracy-trend-text"], [1, "fa-solid", "fa-arrow-trend-up", 2, "margin-right", "4px"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "model-name"], ["width", "80", "height", "80", "viewBox", "0 0 80 80", 2, "margin", "4px 0"], ["cx", "40", "cy", "40", "r", "32", "fill", "none", "stroke", "var(--mj-border-default)", "stroke-width", "8"], ["cx", "40", "cy", "40", "r", "32", "fill", "none", "stroke-width", "8", "stroke-dashoffset", "50", "transform", "rotate(-90 40 40)", "stroke-linecap", "round"], [1, "model-score"], [1, "model-detail"], [1, "model-detail", 2, "font-weight", "600"], [1, "fa-solid", "fa-lightbulb", 2, "color", "var(--mj-status-warning)"], [1, "fa-solid", "fa-coins"], [1, "tab-header-actions"], ["title", "Print (PDF alternative)", 1, "drill-export-btn", 3, "click"], [1, "fa-solid", "fa-print"], [1, "cost-kpi-row"], [1, "cost-kpi-card"], [1, "cost-kpi-icon"], [1, "cost-kpi-value"], [1, "cost-kpi-label"], [1, "cost-kpi-sub"], [1, "empty-state-hint"]], template: function AnalyticsResourceComponent_Template(rf, ctx) { if (rf & 1) {
4248
+ i0.ɵɵconditionalCreate(0, AnalyticsResourceComponent_Conditional_0_Template, 2, 0, "div", 0)(1, AnalyticsResourceComponent_Conditional_1_Template, 28, 10, "div", 1);
4249
+ } if (rf & 2) {
4250
+ i0.ɵɵconditional(ctx.IsLoading ? 0 : 1);
4251
+ } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent], styles: ["\n\n\n\n\n.analytics-loading[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 400px;\n}\n\n.analytics-layout[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n min-height: 600px;\n}\n\n\n\n.analytics-sidebar[_ngcontent-%COMP%] {\n width: 220px;\n min-width: 220px;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n}\n\n.sidebar-header[_ngcontent-%COMP%] {\n padding: 20px 16px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.sidebar-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n}\n\n.sidebar-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n\n.sidebar-nav[_ngcontent-%COMP%] {\n padding: 8px 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.nav-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 16px;\n font-size: 13.5px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border: none;\n background: transparent;\n border-left: 3px solid transparent;\n transition: all 0.15s ease;\n text-align: left;\n width: 100%;\n font-family: inherit;\n}\n\n.nav-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n.nav-item.active[_ngcontent-%COMP%] {\n border-left-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n font-weight: 600;\n}\n\n.nav-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 16px;\n text-align: center;\n font-size: 13px;\n}\n\n.sidebar-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--mj-border-default);\n margin: 8px 16px;\n}\n\n.trending-section[_ngcontent-%COMP%] {\n padding: 12px 16px 16px;\n}\n\n.trending-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted);\n margin: 0 0 10px;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.tag-cloud[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 6px;\n line-height: 1.7;\n}\n\n.tag-cloud[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: opacity 0.15s;\n}\n\n.tag-cloud[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:hover {\n opacity: 0.7;\n}\n\n.no-trending[_ngcontent-%COMP%] {\n color: var(--mj-text-muted) !important;\n font-size: 12px !important;\n font-style: italic;\n}\n\n.pipeline-status[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n\n.status-dot[_ngcontent-%COMP%] {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--mj-status-success);\n flex-shrink: 0;\n}\n\n.status-dot-error[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n}\n\n\n\n.main-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n min-width: 0;\n}\n\n.tab-section[_ngcontent-%COMP%] {\n padding: 28px 32px 40px;\n}\n\n.tab-section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 20px;\n padding-bottom: 12px;\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.tab-section-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 18px;\n color: var(--mj-brand-primary);\n}\n\n.tab-section-header[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n\n\n.filter-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 20px;\n flex-wrap: wrap;\n}\n\n.date-chips[_ngcontent-%COMP%] {\n display: flex;\n gap: 0;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n}\n\n.date-chip[_ngcontent-%COMP%] {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n border: none;\n border-right: 1px solid var(--mj-border-default);\n transition: all 0.15s;\n font-family: inherit;\n}\n\n.date-chip[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n.date-chip[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-chip.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.filter-dropdown[_ngcontent-%COMP%] {\n padding: 6px 12px;\n font-size: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-family: inherit;\n}\n\n\n\n.kpi-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 20px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px 18px;\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n transition: transform 0.15s, box-shadow 0.15s;\n cursor: pointer;\n}\n\n.kpi-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n}\n\n.kpi-delta[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 500;\n margin-top: 4px;\n color: var(--mj-text-muted);\n}\n\n.kpi-delta.up[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.kpi-delta.down[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.kpi-sparkline[_ngcontent-%COMP%] {\n flex-shrink: 0;\n margin-left: 12px;\n margin-top: 6px;\n}\n\n\n\n.cards-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n}\n\n.widget-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 18px 20px;\n transition: transform 0.15s, box-shadow 0.15s;\n cursor: pointer;\n}\n\n.widget-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.widget-title[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 14px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.widget-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.widget-empty[_ngcontent-%COMP%] {\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 12px;\n padding: 20px;\n}\n\n.widget-footnote[_ngcontent-%COMP%] {\n text-align: center;\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 10px;\n}\n\n\n\n.bar-chart[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n height: 120px;\n padding-top: 10px;\n}\n\n.bar-col[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n}\n\n.bar[_ngcontent-%COMP%] {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height 0.3s;\n min-height: 2px;\n}\n\n.bar-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n}\n\n.bar-value[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 4px;\n}\n\n\n\n.rings-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n}\n\n.ring-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 0;\n}\n\n.ring-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-primary);\n font-weight: 500;\n}\n\n.ring-stat[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n\n\n.gauge-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n margin-bottom: 8px;\n}\n\n\n\n.mini-histogram[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 32px;\n justify-content: center;\n}\n\n.mini-hist-bar[_ngcontent-%COMP%] {\n width: 14px;\n border-radius: 2px;\n}\n\n.mini-hist-label[_ngcontent-%COMP%] {\n text-align: center;\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n\n\n.h-bar-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.h-bar-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.h-bar-name[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n width: 100px;\n flex-shrink: 0;\n text-align: right;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.h-bar-track[_ngcontent-%COMP%] {\n flex: 1;\n height: 20px;\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.h-bar-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 4px;\n display: flex;\n align-items: center;\n padding-left: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-width: 36px;\n}\n\n\n\n.throughput-bars[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 4px;\n height: 110px;\n margin-bottom: 22px;\n}\n\n.tp-bar[_ngcontent-%COMP%] {\n flex: 1;\n border-radius: 3px 3px 0 0;\n position: relative;\n min-height: 4px;\n}\n\n.tp-bar-label[_ngcontent-%COMP%] {\n position: absolute;\n bottom: -18px;\n left: 50%;\n transform: translateX(-50%);\n font-size: 8px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n\n\n.taxonomy-ring-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n}\n\n.taxonomy-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n}\n\n.tax-stat[_ngcontent-%COMP%] {\n flex: 1;\n text-align: center;\n padding: 8px 4px;\n border-radius: 6px;\n font-size: 20px;\n font-weight: 700;\n}\n\n.tax-stat[_ngcontent-%COMP%] small[_ngcontent-%COMP%] {\n display: block;\n font-size: 10px;\n font-weight: 500;\n margin-top: 2px;\n}\n\n\n\n.legend[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n margin-top: 10px;\n flex-wrap: wrap;\n justify-content: center;\n}\n\n.legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.legend-dot[_ngcontent-%COMP%] {\n width: 10px;\n height: 10px;\n border-radius: 3px;\n flex-shrink: 0;\n}\n\n\n\n.table-scroll[_ngcontent-%COMP%] {\n overflow-x: auto;\n}\n\n.data-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: 12.5px;\n}\n\n.data-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left;\n padding: 10px 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-muted);\n border-bottom: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n white-space: nowrap;\n}\n\n.data-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n vertical-align: middle;\n}\n\n.data-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.data-table[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] {\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.muted[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.monospace-cell[_ngcontent-%COMP%] {\n font-family: monospace;\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.weight-bar[_ngcontent-%COMP%] {\n display: inline-block;\n height: 6px;\n border-radius: 3px;\n vertical-align: middle;\n margin-right: 6px;\n}\n\n\n\n.badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 10.5px;\n font-weight: 600;\n}\n\n.badge-success[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.badge-warning[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.badge-error[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.badge-info[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n\n\n.sub-section[_ngcontent-%COMP%] {\n margin-top: 24px;\n}\n\n.sub-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.sub-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-brand-primary);\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 3rem 2rem;\n text-align: center;\n gap: 0.75rem;\n border: 2px dashed var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 2.5rem;\n color: var(--mj-text-disabled);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.85rem;\n max-width: 400px;\n}\n\n\n\n.drill-down-panel[_ngcontent-%COMP%] {\n margin-top: 16px;\n margin-bottom: 16px;\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-brand-primary);\n border-radius: 10px;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideDown 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 600px;\n }\n}\n\n.drill-down-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.drill-down-title[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.drill-down-close[_ngcontent-%COMP%] {\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s;\n}\n\n.drill-down-close[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.drill-down-table-wrap[_ngcontent-%COMP%] {\n max-height: 400px;\n overflow-y: auto;\n padding: 8px;\n}\n\n.drill-action-col[_ngcontent-%COMP%] {\n width: 40px;\n text-align: center;\n padding: 6px !important;\n}\n\n.drill-open-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: 1px solid var(--mj-border-default);\n border-radius: 5px;\n background: transparent;\n color: var(--mj-text-muted);\n font-size: 10px;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.drill-open-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.drill-down-header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.drill-export-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 5px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.drill-export-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.sub-section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0;\n}\n\n.sub-section-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n}\n\n.drill-down-empty[_ngcontent-%COMP%] {\n padding: 24px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n\n\n.stacked-bar-chart[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.stacked-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.stacked-label[_ngcontent-%COMP%] {\n width: 90px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.stacked-track[_ngcontent-%COMP%] {\n flex: 1;\n height: 22px;\n display: flex;\n border-radius: 4px;\n overflow: hidden;\n}\n\n.stacked-seg[_ngcontent-%COMP%] {\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-width: 20px;\n}\n\n\n\n.v-bar-chart[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 24px;\n height: 140px;\n padding-top: 10px;\n justify-content: center;\n}\n\n.v-bar-col[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n min-width: 60px;\n}\n\n.v-bar[_ngcontent-%COMP%] {\n width: 48px;\n border-radius: 4px 4px 0 0;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 4px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-inverse);\n}\n\n.v-bar-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 8px;\n text-align: center;\n}\n\n.chart-footnote[_ngcontent-%COMP%] {\n text-align: center;\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 14px;\n}\n\n\n\n.two-col[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 20px;\n}\n\n\n\n.source-selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n\n\n.quality-bands[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.quality-band-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.quality-band-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 65px;\n text-align: right;\n flex-shrink: 0;\n}\n\n.quality-band-track[_ngcontent-%COMP%] {\n flex: 1;\n height: 18px;\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.quality-band-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 4px;\n display: flex;\n align-items: center;\n padding-left: 8px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-width: 30px;\n}\n\n.source-quality-note[_ngcontent-%COMP%] {\n margin-top: 14px;\n padding: 10px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n}\n\n\n\n.source-health-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 12px;\n}\n\n.source-health-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 14px;\n text-align: center;\n border-top: 3px solid;\n}\n\n.health-card-name[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.health-card-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n}\n\n.health-card-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n\n\n.pipeline-throughput-bars[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 110px;\n}\n\n.pipeline-bar[_ngcontent-%COMP%] {\n flex: 1;\n border-radius: 2px 2px 0 0;\n min-height: 3px;\n}\n\n.pipeline-date-labels[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-top: 6px;\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n\n\n.stage-bars[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.stage-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.stage-name[_ngcontent-%COMP%] {\n width: 80px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.stage-track[_ngcontent-%COMP%] {\n flex: 1;\n height: 24px;\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.stage-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding-right: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n}\n\n.stage-time[_ngcontent-%COMP%] {\n width: 50px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.stage-summary[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-top: 14px;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-default);\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.stage-warning[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n.success-rate-display[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n gap: 48px;\n padding: 20px;\n}\n\n.success-rate-stat[_ngcontent-%COMP%] {\n text-align: center;\n}\n\n.success-rate-value[_ngcontent-%COMP%] {\n font-size: 32px;\n font-weight: 700;\n line-height: 1.1;\n}\n\n.success-rate-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n\n\n.progress-track[_ngcontent-%COMP%] {\n width: 100px;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n overflow: hidden;\n display: inline-block;\n vertical-align: middle;\n margin-right: 6px;\n}\n\n.progress-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 3px;\n}\n\n.progress-text[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n}\n\n\n\n.error-log[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.error-entry[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-status-error) 4%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-status-error);\n border-radius: 0 6px 6px 0;\n font-size: 12px;\n}\n\n.error-time[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 11px;\n white-space: nowrap;\n flex-shrink: 0;\n width: 130px;\n}\n\n.error-source[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n flex-shrink: 0;\n width: 120px;\n}\n\n.error-msg[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n}\n\n\n\n.histogram[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 6px;\n height: 130px;\n padding-bottom: 24px;\n}\n\n.hist-bar-col[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n}\n\n.hist-bar[_ngcontent-%COMP%] {\n width: 100%;\n border-radius: 3px 3px 0 0;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 3px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-height: 2px;\n}\n\n.hist-label[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n text-align: center;\n}\n\n.confidence-stats[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-top: 8px;\n padding: 10px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n flex-wrap: wrap;\n gap: 8px;\n}\n\n\n\n.grouped-bar-chart[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 20px;\n height: 140px;\n justify-content: center;\n}\n\n.grouped-col[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n}\n\n.grouped-bars[_ngcontent-%COMP%] {\n display: flex;\n gap: 3px;\n align-items: flex-end;\n height: 100%;\n}\n\n.g-bar[_ngcontent-%COMP%] {\n width: 18px;\n border-radius: 3px 3px 0 0;\n min-height: 2px;\n}\n\n.grouped-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n text-align: center;\n}\n\n\n\n.accuracy-chart[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n margin: 0 10px;\n}\n\n.accuracy-y-labels[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n font-size: 9px;\n color: var(--mj-text-muted);\n margin-right: 8px;\n height: 110px;\n}\n\n.accuracy-area[_ngcontent-%COMP%] {\n flex: 1;\n position: relative;\n height: 110px;\n border-left: 1px solid var(--mj-border-default);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.accuracy-grid-line[_ngcontent-%COMP%] {\n position: absolute;\n left: 0;\n right: 0;\n border-top: 1px dashed var(--mj-border-subtle);\n}\n\n.accuracy-svg[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n\n.accuracy-x-labels[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-top: 8px;\n padding: 0 40px 0 40px;\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.accuracy-trend-text[_ngcontent-%COMP%] {\n text-align: center;\n margin-top: 10px;\n font-size: 12px;\n color: var(--mj-status-success);\n}\n\n\n\n.model-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 12px;\n}\n\n.model-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n padding: 14px;\n text-align: center;\n border: 1px solid var(--mj-border-default);\n}\n\n.model-name[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n}\n\n.model-score[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n line-height: 1;\n}\n\n.model-detail[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n.model-recommendation[_ngcontent-%COMP%] {\n margin-top: 14px;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n\n\n@media (max-width: 1200px) {\n .cards-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .kpi-row[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .model-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 768px) {\n .analytics-layout[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .analytics-sidebar[_ngcontent-%COMP%] {\n width: 100%;\n min-width: 100%;\n border-right: none;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .sidebar-nav[_ngcontent-%COMP%] {\n flex-direction: row;\n overflow-x: auto;\n }\n\n .nav-item[_ngcontent-%COMP%] {\n border-left: none;\n border-bottom: 3px solid transparent;\n white-space: nowrap;\n }\n\n .nav-item.active[_ngcontent-%COMP%] {\n border-left-color: transparent;\n border-bottom-color: var(--mj-brand-primary);\n }\n\n .trending-section[_ngcontent-%COMP%], \n .sidebar-divider[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-section[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .cards-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .kpi-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .two-col[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .cost-kpi-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n}\n\n\n\n\n.tab-header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n margin-left: auto;\n}\n\n.cost-kpi-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n margin-bottom: 24px;\n}\n\n.cost-kpi-card[_ngcontent-%COMP%] {\n display: flex;\n gap: 14px;\n align-items: center;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 18px 20px;\n transition: box-shadow 0.15s ease;\n}\n\n.cost-kpi-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.cost-kpi-icon[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n flex-shrink: 0;\n}\n\n.cost-kpi-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.cost-kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.cost-kpi-sub[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.empty-state-hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n\n\n\n@media print {\n .analytics-sidebar[_ngcontent-%COMP%], \n .filter-bar[_ngcontent-%COMP%], \n .tab-header-actions[_ngcontent-%COMP%], \n .drill-down-close[_ngcontent-%COMP%], \n .drill-export-btn[_ngcontent-%COMP%], \n .drill-open-btn[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .analytics-layout[_ngcontent-%COMP%] {\n display: block;\n }\n\n .main-content[_ngcontent-%COMP%] {\n padding: 0;\n }\n\n .tab-section[_ngcontent-%COMP%] {\n padding: 0;\n }\n\n .widget-card[_ngcontent-%COMP%], \n .cost-kpi-card[_ngcontent-%COMP%], \n .kpi-card[_ngcontent-%COMP%] {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n\n .data-table[_ngcontent-%COMP%] {\n font-size: 10px;\n }\n}\n\n\n\n\n\n\n\n.co-occurrence-section[_ngcontent-%COMP%] {\n max-height: 500px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.co-occurrence-section[_ngcontent-%COMP%] .table-scroll[_ngcontent-%COMP%] {\n overflow-y: auto;\n max-height: 400px;\n flex: 1;\n min-height: 0;\n}\n\n.co-occurrence-section[_ngcontent-%COMP%] .empty-state[_ngcontent-%COMP%] {\n max-height: 200px;\n overflow: hidden;\n}\n\n.co-occurrence-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.co-occurrence-staleness[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n}"] });
4252
+ };
4253
+ AnalyticsResourceComponent = AnalyticsResourceComponent_1 = __decorate([
4254
+ RegisterClass(BaseResourceComponent, 'AnalyticsResource')
4255
+ ], AnalyticsResourceComponent);
4256
+ export { AnalyticsResourceComponent };
4257
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AnalyticsResourceComponent, [{
4258
+ type: Component,
4259
+ args: [{ standalone: false, selector: 'app-analytics-resource', template: "@if (IsLoading) {\n <div class=\"analytics-loading\">\n <mj-loading text=\"Loading analytics data...\" size=\"medium\"></mj-loading>\n </div>\n} @else {\n <div class=\"analytics-layout\">\n <!-- =============== LEFT SIDEBAR =============== -->\n <aside class=\"analytics-sidebar\">\n <div class=\"sidebar-header\">\n <h2><i class=\"fa-solid fa-chart-line\"></i> Analytics</h2>\n </div>\n\n <nav class=\"sidebar-nav\">\n @for (nav of NavItems; track nav.ID) {\n <button\n class=\"nav-item\"\n [class.active]=\"ActiveTab === nav.ID\"\n (click)=\"SelectTab(nav.ID)\"\n >\n <i [class]=\"nav.Icon\"></i> {{ nav.Label }}\n </button>\n }\n </nav>\n\n <div class=\"sidebar-divider\"></div>\n\n <!-- Trending Tags Cloud -->\n <div class=\"trending-section\">\n <h3><i class=\"fa-solid fa-arrow-trend-up\"></i> Trending Tags</h3>\n <div class=\"tag-cloud\">\n @for (tag of TrendingTags; track tag.Name) {\n <span [style.font-size.px]=\"tag.Size\" [style.font-weight]=\"tag.Weight\">{{ tag.Name }}</span>\n }\n @if (TrendingTags.length === 0) {\n <span class=\"no-trending\">No trending tags yet</span>\n }\n </div>\n </div>\n\n <!-- Pipeline Status -->\n <div class=\"pipeline-status\">\n <span class=\"status-dot\" [class.status-dot-error]=\"!PipelineStatusOk\"></span>\n {{ PipelineStatusText }}\n </div>\n </aside>\n\n <!-- =============== MAIN CONTENT =============== -->\n <div class=\"main-content\">\n\n <!-- ====================================================== -->\n <!-- TAB 1: OVERVIEW -->\n <!-- ====================================================== -->\n @if (ActiveTab === 'overview') {\n <section class=\"tab-section\">\n <div class=\"tab-section-header\">\n <i class=\"fa-solid fa-grip\"></i>\n <h1>Overview</h1>\n </div>\n\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"date-chips\">\n @for (range of DateRanges; track range.Label) {\n <button\n class=\"date-chip\"\n [class.active]=\"ActiveDateRange === range.Label\"\n (click)=\"SetDateRange(range.Label)\"\n >{{ range.Label }}</button>\n }\n </div>\n <select class=\"filter-dropdown\" [ngModel]=\"EntityFilter\" (ngModelChange)=\"SetEntityFilter($event)\">\n @for (opt of EntityFilterOptions; track opt) {\n <option [value]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n\n <!-- KPI Cards -->\n <div class=\"kpi-row\">\n @for (kpi of KPIs; track kpi.Label) {\n <div class=\"kpi-card\" (click)=\"OpenDrillDown(kpi.DrillDownKey)\">\n <div>\n <div class=\"kpi-label\">{{ kpi.Label }}</div>\n <div class=\"kpi-value\">{{ kpi.Value }}</div>\n <div class=\"kpi-delta\" [class.up]=\"kpi.DeltaDirection === 'up'\" [class.down]=\"kpi.DeltaDirection === 'down'\">\n @if (kpi.DeltaDirection === 'up') {\n <i class=\"fa-solid fa-arrow-up\" style=\"font-size:9px\"></i>\n } @else if (kpi.DeltaDirection === 'down') {\n <i class=\"fa-solid fa-arrow-down\" style=\"font-size:9px\"></i>\n }\n {{ kpi.Delta }}\n </div>\n </div>\n <div class=\"kpi-sparkline\">\n <svg width=\"64\" height=\"28\" viewBox=\"0 0 64 28\">\n <polyline [attr.points]=\"kpi.SparklinePoints\" fill=\"none\" [attr.stroke]=\"kpi.SparklineColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </div>\n </div>\n }\n </div>\n\n <!-- KPI Drill-Down -->\n @if (DrillDownTarget && DrillDownTarget.startsWith('kpi-')) {\n <div class=\"drill-down-panel\">\n <div class=\"drill-down-header\">\n <span class=\"drill-down-title\"><i class=\"fa-solid fa-table\"></i> Detail View</span>\n <div class=\"drill-down-header-actions\">\n @if (DrillDownData.length > 0) {\n <button class=\"drill-export-btn\" (click)=\"ExportDrillDownCSV()\" title=\"Export CSV\">\n <i class=\"fa-solid fa-download\"></i> CSV\n </button>\n }\n <button class=\"drill-down-close\" (click)=\"CloseDrillDown()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n @if (IsDrillDownLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n } @else if (DrillDownData.length > 0) {\n <div class=\"drill-down-table-wrap\">\n <table class=\"data-table\">\n <thead>\n <tr>\n @for (col of DrillDownColumns; track col) {\n <th>{{ col }}</th>\n }\n @if (DrillDownHasActions) {\n <th class=\"drill-action-col\"></th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of DrillDownData; track TrackByIndex($index)) {\n <tr>\n @for (col of DrillDownColumns; track col) {\n <td>{{ row[col] }}</td>\n }\n @if (DrillDownHasActions) {\n <td class=\"drill-action-col\">\n @if (row['_RecordID']) {\n <button class=\"drill-open-btn\" (click)=\"OpenDrillDownRecord(row)\" title=\"Open record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n </button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"drill-down-empty\">No data available</div>\n }\n </div>\n }\n\n <!-- Widget Cards Grid (2x3) -->\n <div class=\"cards-grid\">\n\n <!-- Card 1: Tag Growth -->\n <div class=\"widget-card\" (click)=\"OpenDrillDown('tagGrowth')\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-chart-line\"></i> Tag Growth</div>\n <div class=\"bar-chart\">\n @for (bar of TagGrowthData; track bar.Label) {\n <div class=\"bar-col\">\n <div class=\"bar-value\">{{ bar.Count }}</div>\n <div class=\"bar\" [style.height.%]=\"bar.Percentage\" style=\"background:var(--mj-brand-primary)\" [style.opacity]=\"0.5 + (bar.Percentage / 200)\"></div>\n <div class=\"bar-label\">{{ bar.Label }}</div>\n </div>\n }\n </div>\n </div>\n\n <!-- Card 2: Content Coverage -->\n <div class=\"widget-card\" (click)=\"OpenDrillDown('contentCoverage')\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-bullseye\"></i> Content Coverage</div>\n <div class=\"rings-grid\">\n @for (entity of CoverageData; track entity.Name) {\n <div class=\"ring-item\">\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\">\n <circle cx=\"24\" cy=\"24\" r=\"20\" fill=\"none\" stroke=\"var(--mj-border-default)\" stroke-width=\"5\"/>\n <circle cx=\"24\" cy=\"24\" r=\"20\" fill=\"none\" [attr.stroke]=\"entity.Color\" stroke-width=\"5\"\n [attr.stroke-dasharray]=\"entity.StrokeDash\" stroke-dashoffset=\"31.4\" stroke-linecap=\"round\"\n transform=\"rotate(-90 24 24)\"/>\n <text x=\"24\" y=\"26\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"700\" fill=\"var(--mj-text-primary)\">{{ entity.Percentage }}%</text>\n </svg>\n <div>\n <div class=\"ring-label\">{{ entity.Name }}</div>\n <div class=\"ring-stat\">{{ FormatNumber(entity.Tagged) }} / {{ FormatNumber(entity.Total) }}</div>\n </div>\n </div>\n }\n @if (CoverageData.length === 0) {\n <div class=\"widget-empty\">No content types found</div>\n }\n </div>\n </div>\n\n <!-- Card 3: Quality Score Gauge -->\n <div class=\"widget-card\" (click)=\"OpenDrillDown('qualityScore')\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-gauge-high\"></i> Quality Score</div>\n <div class=\"gauge-container\">\n <svg width=\"180\" height=\"110\" viewBox=\"0 0 180 110\">\n <!-- Background arc -->\n <path d=\"M 20 95 A 70 70 0 0 1 160 95\" fill=\"none\" stroke=\"var(--mj-border-default)\" stroke-width=\"14\" stroke-linecap=\"round\"/>\n <!-- Zone arcs -->\n <path d=\"M 20 95 A 70 70 0 0 1 48.6 35.2\" fill=\"none\" stroke=\"var(--mj-status-error)\" stroke-width=\"14\" stroke-linecap=\"round\" opacity=\"0.3\"/>\n <path d=\"M 48.6 35.2 A 70 70 0 0 1 118 28\" fill=\"none\" stroke=\"var(--mj-status-warning)\" stroke-width=\"14\" opacity=\"0.3\"/>\n <path d=\"M 118 28 A 70 70 0 0 1 160 95\" fill=\"none\" stroke=\"var(--mj-status-success)\" stroke-width=\"14\" stroke-linecap=\"round\" opacity=\"0.3\"/>\n <!-- Score text -->\n <text x=\"90\" y=\"88\" text-anchor=\"middle\" font-size=\"26\" font-weight=\"800\" fill=\"var(--mj-text-primary)\">{{ QualityScore }}</text>\n <text x=\"90\" y=\"105\" text-anchor=\"middle\" font-size=\"10\" fill=\"var(--mj-text-muted)\">out of 100</text>\n <text x=\"28\" y=\"108\" font-size=\"8\" fill=\"var(--mj-text-muted)\">0</text>\n <text x=\"86\" y=\"18\" font-size=\"8\" fill=\"var(--mj-text-muted)\">50</text>\n <text x=\"155\" y=\"108\" font-size=\"8\" fill=\"var(--mj-text-muted)\">100</text>\n </svg>\n </div>\n <!-- Mini confidence histogram -->\n <div class=\"mini-histogram\">\n @for (bin of MiniConfidenceBins; track TrackByIndex($index)) {\n <div class=\"mini-hist-bar\" [style.height.px]=\"bin.Height\" [style.background]=\"bin.Color\" [title]=\"bin.Title\"></div>\n }\n </div>\n <div class=\"mini-hist-label\">Confidence Distribution</div>\n </div>\n\n <!-- Card 4: Source Performance -->\n <div class=\"widget-card\" (click)=\"OpenDrillDown('sourcePerformance')\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-ranking-star\"></i> Source Performance</div>\n <div class=\"h-bar-list\">\n @for (source of SourcePerfData; track source.Name) {\n <div class=\"h-bar-row\">\n <div class=\"h-bar-name\">{{ source.Name }}</div>\n <div class=\"h-bar-track\">\n <div class=\"h-bar-fill\" [style.width.%]=\"source.Percentage\" [style.background]=\"source.Color\">{{ source.AvgTagsPerItem }}</div>\n </div>\n </div>\n }\n @if (SourcePerfData.length === 0) {\n <div class=\"widget-empty\">No source data</div>\n }\n </div>\n <div class=\"widget-footnote\">Average tags per item</div>\n </div>\n\n <!-- Card 5: Daily Throughput -->\n <div class=\"widget-card\" (click)=\"OpenDrillDown('dailyThroughput')\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-bolt\"></i> Daily Throughput</div>\n <div class=\"throughput-bars\">\n @for (day of ThroughputData; track day.Label) {\n <div class=\"tp-bar\"\n [style.height.%]=\"day.Percentage\"\n [style.background]=\"day.IsError ? 'var(--mj-status-error)' : 'var(--mj-status-success)'\"\n >\n <span class=\"tp-bar-label\">{{ day.Label }}</span>\n </div>\n }\n </div>\n <div class=\"legend\">\n <div class=\"legend-item\"><div class=\"legend-dot\" style=\"background:var(--mj-status-success)\"></div> Success</div>\n <div class=\"legend-item\"><div class=\"legend-dot\" style=\"background:var(--mj-status-error)\"></div> Failures</div>\n </div>\n </div>\n\n <!-- Card 6: Taxonomy Health -->\n <div class=\"widget-card\" (click)=\"OpenDrillDown('taxonomyHealth')\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-sitemap\"></i> Taxonomy Health</div>\n <div class=\"taxonomy-ring-container\">\n <svg width=\"140\" height=\"140\" viewBox=\"0 0 140 140\">\n <circle cx=\"70\" cy=\"70\" r=\"54\" fill=\"none\" stroke=\"var(--mj-border-default)\" stroke-width=\"18\"/>\n @for (seg of TaxonomyRingSegments; track TrackByIndex($index)) {\n <circle cx=\"70\" cy=\"70\" r=\"54\" fill=\"none\"\n [attr.stroke]=\"seg.Color\" stroke-width=\"18\"\n [attr.stroke-dasharray]=\"seg.StrokeDash\"\n [attr.stroke-dashoffset]=\"seg.StrokeOffset\"\n transform=\"rotate(-90 70 70)\"/>\n }\n <text x=\"70\" y=\"66\" text-anchor=\"middle\" font-size=\"22\" font-weight=\"800\" fill=\"var(--mj-text-primary)\">{{ TaxonomyTotal }}</text>\n <text x=\"70\" y=\"82\" text-anchor=\"middle\" font-size=\"10\" fill=\"var(--mj-text-muted)\">total tags</text>\n </svg>\n </div>\n <div class=\"taxonomy-stats\">\n @for (stat of TaxonomyStats; track stat.Label) {\n <div class=\"tax-stat\" [style.background]=\"stat.BgColor\" [style.color]=\"stat.Color\">\n {{ stat.Count }}<small>{{ stat.Label }}</small>\n </div>\n }\n </div>\n </div>\n\n </div><!-- /cards-grid -->\n\n <!-- Widget Drill-Down -->\n @if (DrillDownTarget && !DrillDownTarget.startsWith('kpi-')) {\n <div class=\"drill-down-panel\">\n <div class=\"drill-down-header\">\n <span class=\"drill-down-title\"><i class=\"fa-solid fa-table\"></i> {{ DrillDownTarget }} Detail</span>\n <button class=\"drill-down-close\" (click)=\"CloseDrillDown()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n @if (IsDrillDownLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n } @else if (DrillDownData.length > 0) {\n <div class=\"drill-down-table-wrap\">\n <table class=\"data-table\">\n <thead>\n <tr>\n @for (col of DrillDownColumns; track col) {\n <th>{{ col }}</th>\n }\n @if (DrillDownHasActions) {\n <th class=\"drill-action-col\"></th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of DrillDownData; track TrackByIndex($index)) {\n <tr>\n @for (col of DrillDownColumns; track col) {\n <td>{{ row[col] }}</td>\n }\n @if (DrillDownHasActions) {\n <td class=\"drill-action-col\">\n @if (row['_RecordID']) {\n <button class=\"drill-open-btn\" (click)=\"OpenDrillDownRecord(row)\" title=\"Open record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n </button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"drill-down-empty\">No data available</div>\n }\n </div>\n }\n </section>\n }\n\n <!-- ====================================================== -->\n <!-- TAB 2: TAGS -->\n <!-- ====================================================== -->\n @if (ActiveTab === 'tags') {\n <section class=\"tab-section\">\n <div class=\"tab-section-header\">\n <i class=\"fa-solid fa-tags\"></i>\n <h1>Tags</h1>\n </div>\n\n <!-- Top 20 Tags Table -->\n <div class=\"sub-section\" style=\"margin-top:0\">\n <div class=\"sub-section-header\">\n <h3><i class=\"fa-solid fa-trophy\"></i> Top 20 Tags</h3>\n @if (TopTags.length > 0) {\n <button class=\"drill-export-btn\" (click)=\"ExportTabDataCSV('top-tags')\" title=\"Export CSV\">\n <i class=\"fa-solid fa-download\"></i> CSV\n </button>\n }\n </div>\n @if (TopTags.length > 0) {\n <div class=\"table-scroll\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Tag Name</th>\n <th class=\"num\">Usage Count</th>\n <th>Avg Weight</th>\n <th>Trend</th>\n <th>Top Entity</th>\n <th>First Seen</th>\n </tr>\n </thead>\n <tbody>\n @for (tag of TopTags; track tag.Name) {\n <tr style=\"cursor:pointer\" (click)=\"OpenDrillDown('tag-row:' + tag.Name)\">\n <td>{{ tag.Rank }}</td>\n <td><strong>{{ tag.Name }}</strong></td>\n <td class=\"num\">{{ FormatNumber(tag.UsageCount) }}</td>\n <td>\n <span class=\"weight-bar\" [style.width.px]=\"tag.WeightBarWidth\" [style.background]=\"tag.WeightBarColor\"></span>\n {{ tag.AvgWeight }}\n </td>\n <td>\n <svg width=\"48\" height=\"16\">\n <polyline [attr.points]=\"tag.TrendPoints\" fill=\"none\" [attr.stroke]=\"tag.TrendColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </td>\n <td>{{ tag.TopEntity }}</td>\n <td class=\"muted\">{{ tag.FirstSeen }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-tags\"></i>\n <p>No tag data available yet. Process content to generate tags.</p>\n </div>\n }\n </div>\n\n <!-- D10: Tags tab drill-down -->\n @if (DrillDownTarget && DrillDownTarget.startsWith('tag-row:')) {\n <div class=\"drill-down-panel\">\n <div class=\"drill-down-header\">\n <span class=\"drill-down-title\"><i class=\"fa-solid fa-table\"></i> Content Items Tagged \"{{ DrillDownTarget.replace('tag-row:', '') }}\"</span>\n <div class=\"drill-down-header-actions\">\n @if (DrillDownData.length > 0) {\n <button class=\"drill-export-btn\" (click)=\"ExportDrillDownCSV()\" title=\"Export CSV\">\n <i class=\"fa-solid fa-download\"></i> CSV\n </button>\n }\n <button class=\"drill-down-close\" (click)=\"CloseDrillDown()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n </div>\n @if (IsDrillDownLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n } @else if (DrillDownData.length > 0) {\n <div class=\"drill-down-table-wrap\">\n <table class=\"data-table\">\n <thead><tr>\n @for (col of DrillDownColumns; track col) { <th>{{ col }}</th> }\n @if (DrillDownHasActions) { <th class=\"drill-action-col\"></th> }\n </tr></thead>\n <tbody>\n @for (row of DrillDownData; track TrackByIndex($index)) {\n <tr>\n @for (col of DrillDownColumns; track col) { <td>{{ row[col] }}</td> }\n @if (DrillDownHasActions) {\n <td class=\"drill-action-col\">\n @if (row['_RecordID']) {\n <button class=\"drill-open-btn\" (click)=\"OpenDrillDownRecord(row)\" title=\"Open record\"><i class=\"fa-solid fa-arrow-up-right-from-square\"></i></button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"drill-down-empty\">No items found for this tag</div>\n }\n </div>\n }\n\n <!-- Tag Distribution by Entity -->\n @if (EntityDistribution.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-chart-bar\"></i> Tag Distribution by Entity</h3>\n <div class=\"stacked-bar-chart\">\n @for (row of EntityDistribution; track row.EntityName) {\n <div class=\"stacked-row\">\n <div class=\"stacked-label\">{{ row.EntityName }}</div>\n <div class=\"stacked-track\">\n @for (seg of row.Segments; track TrackByIndex($index)) {\n <div class=\"stacked-seg\" [style.width.%]=\"seg.Percentage\" [style.background]=\"seg.Color\" [title]=\"seg.Label + ': ' + seg.Percentage + '%'\">{{ seg.Label }}</div>\n }\n </div>\n </div>\n }\n </div>\n <div class=\"legend\" style=\"margin-top:12px\">\n @for (item of DistributionLegend; track item.Label) {\n <div class=\"legend-item\"><div class=\"legend-dot\" [style.background]=\"item.Color\"></div> {{ item.Label }}</div>\n }\n </div>\n </div>\n }\n\n <!-- Tag Depth Distribution -->\n @if (TagDepthBars.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-layer-group\"></i> Tag Depth Distribution</h3>\n <div class=\"v-bar-chart\">\n @for (bar of TagDepthBars; track bar.Label) {\n <div class=\"v-bar-col\">\n <div class=\"v-bar\" [style.height.%]=\"bar.Percentage\" style=\"background:var(--mj-brand-primary)\" [style.min-height.px]=\"bar.Count > 0 ? 24 : 0\">{{ bar.Count }}</div>\n <div class=\"v-bar-label\">{{ bar.Label }}</div>\n </div>\n }\n </div>\n <div class=\"chart-footnote\">\n Taxonomy hierarchy depth -- Most tags at depth 2-3 indicating a healthy mid-level structure\n </div>\n </div>\n }\n\n <!-- Frequently Paired Tags (Co-Occurrence) -->\n <div class=\"sub-section co-occurrence-section\">\n <div class=\"sub-section-header\">\n <h3><i class=\"fa-solid fa-link\"></i> Frequently Paired Tags</h3>\n <div class=\"co-occurrence-actions\">\n @if (CoOccurrenceLastComputed) {\n <span class=\"co-occurrence-staleness\" title=\"Last computed timestamp\">\n <i class=\"fa-regular fa-clock\"></i>\n Last computed: {{ CoOccurrenceLastComputed }}\n </span>\n }\n <button class=\"drill-export-btn\" (click)=\"RecomputeCoOccurrence()\" [disabled]=\"IsRecomputingCoOccurrence\" title=\"Recompute co-occurrence data\">\n @if (IsRecomputingCoOccurrence) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Computing...\n } @else {\n <i class=\"fa-solid fa-arrows-rotate\"></i> Recompute\n }\n </button>\n </div>\n </div>\n @if (CoOccurrencePairs.length > 0) {\n <div class=\"table-scroll\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Tag A</th>\n <th>Tag B</th>\n <th class=\"num\">Co-Occurrences</th>\n <th>Frequency</th>\n </tr>\n </thead>\n <tbody>\n @for (pair of CoOccurrencePairs; track pair.TagAName + pair.TagBName; let i = $index) {\n <tr>\n <td class=\"muted\">{{ i + 1 }}</td>\n <td><strong>{{ pair.TagAName }}</strong></td>\n <td><strong>{{ pair.TagBName }}</strong></td>\n <td class=\"num\">{{ FormatNumber(pair.Count) }}</td>\n <td>\n <span class=\"weight-bar\" [style.width.px]=\"pair.BarWidth\" style=\"background: var(--mj-status-info)\"></span>\n </td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-link\"></i>\n <p>No co-occurrence data available yet. Process content and recompute to see which tags frequently appear together.</p>\n </div>\n }\n </div>\n </section>\n }\n\n <!-- ====================================================== -->\n <!-- TAB 3: SOURCES -->\n <!-- ====================================================== -->\n @if (ActiveTab === 'sources') {\n <section class=\"tab-section\">\n <div class=\"tab-section-header\">\n <i class=\"fa-solid fa-database\"></i>\n <h1>Sources</h1>\n </div>\n\n <!-- Source Comparison Table -->\n <div class=\"sub-section\" style=\"margin-top:0\">\n <h3><i class=\"fa-solid fa-table\"></i> Source Comparison</h3>\n @if (SourceComparison.length > 0) {\n <div class=\"table-scroll\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Source Name</th>\n <th>Type</th>\n <th class=\"num\">Items</th>\n <th class=\"num\">Tags Generated</th>\n <th class=\"num\">Avg Tags/Item</th>\n <th class=\"num\">Avg Weight</th>\n <th>Last Run</th>\n <th>Status</th>\n </tr>\n </thead>\n <tbody>\n @for (source of SourceComparison; track source.Name) {\n <tr (click)=\"SelectSource(source.Name); OpenDrillDown('source-row:' + source.Name)\" style=\"cursor:pointer\" [class.source-selected]=\"SelectedSourceName === source.Name\">\n <td><strong>{{ source.Name }}</strong></td>\n <td><i [class]=\"source.TypeIcon\" [style.color]=\"source.TypeColor\" style=\"margin-right:4px\"></i> {{ source.Type }}</td>\n <td class=\"num\">{{ FormatNumber(source.Items) }}</td>\n <td class=\"num\">{{ FormatNumber(source.TagsGenerated) }}</td>\n <td class=\"num\">{{ source.AvgTagsPerItem }}</td>\n <td class=\"num\">{{ source.AvgWeight }}</td>\n <td class=\"muted\">{{ source.LastRun }}</td>\n <td><span class=\"badge\" [class]=\"source.StatusClass\"><i class=\"fa-solid fa-circle\" style=\"font-size:6px;margin-right:3px\"></i> {{ source.Status }}</span></td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database\"></i>\n <p>No content sources configured yet.</p>\n </div>\n }\n </div>\n\n <!-- D10: Sources tab drill-down (recent runs) -->\n @if (DrillDownTarget && DrillDownTarget.startsWith('source-row:')) {\n <div class=\"drill-down-panel\">\n <div class=\"drill-down-header\">\n <span class=\"drill-down-title\"><i class=\"fa-solid fa-table\"></i> Recent Runs: {{ DrillDownTarget.replace('source-row:', '') }}</span>\n <div class=\"drill-down-header-actions\">\n @if (DrillDownData.length > 0) {\n <button class=\"drill-export-btn\" (click)=\"ExportDrillDownCSV()\" title=\"Export CSV\"><i class=\"fa-solid fa-download\"></i> CSV</button>\n }\n <button class=\"drill-down-close\" (click)=\"CloseDrillDown()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n </div>\n @if (IsDrillDownLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n } @else if (DrillDownData.length > 0) {\n <div class=\"drill-down-table-wrap\">\n <table class=\"data-table\">\n <thead><tr>\n @for (col of DrillDownColumns; track col) { <th>{{ col }}</th> }\n @if (DrillDownHasActions) { <th class=\"drill-action-col\"></th> }\n </tr></thead>\n <tbody>\n @for (row of DrillDownData; track TrackByIndex($index)) {\n <tr>\n @for (col of DrillDownColumns; track col) { <td>{{ row[col] }}</td> }\n @if (DrillDownHasActions) {\n <td class=\"drill-action-col\">\n @if (row['_RecordID']) {\n <button class=\"drill-open-btn\" (click)=\"OpenDrillDownRecord(row)\" title=\"Open record\"><i class=\"fa-solid fa-arrow-up-right-from-square\"></i></button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"drill-down-empty\">No run data for this source</div>\n }\n </div>\n }\n\n <!-- Per-Source Detail -->\n @if (SelectedSourceName && SourceComparison.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-chart-area\"></i> Source Detail: {{ SelectedSourceName }}</h3>\n <div class=\"two-col\">\n <!-- Items Processed Over Time -->\n <div class=\"widget-card\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-chart-bar\"></i> Items Processed (Last 8 Weeks)</div>\n <div class=\"bar-chart\" style=\"height:100px\">\n @for (bar of SourceWeeklyBars; track bar.Label) {\n <div class=\"bar-col\">\n <div class=\"bar-value\" style=\"font-size:9px\">{{ bar.Value }}</div>\n <div class=\"bar\" [style.height.%]=\"bar.Percentage\" style=\"background:var(--mj-brand-primary)\" [style.opacity]=\"0.5 + (bar.Percentage / 200)\"></div>\n <div class=\"bar-label\">{{ bar.Label }}</div>\n </div>\n }\n </div>\n </div>\n\n <!-- Tag Quality Distribution -->\n <div class=\"widget-card\">\n <div class=\"widget-title\"><i class=\"fa-solid fa-star-half-stroke\"></i> Tag Quality Distribution</div>\n <div class=\"quality-bands\">\n @for (band of SourceQualityBands; track band.Label) {\n <div class=\"quality-band-row\">\n <span class=\"quality-band-label\">{{ band.Label }}</span>\n <div class=\"quality-band-track\">\n <div class=\"quality-band-fill\" [style.width.%]=\"band.Percentage\" [style.background]=\"band.Color\">{{ band.Percentage }}%</div>\n </div>\n </div>\n }\n </div>\n <div class=\"source-quality-note\">\n <i class=\"fa-solid fa-circle-info\" style=\"color:var(--mj-status-info);margin-right:4px\"></i>\n {{ SourceQualityNote }}\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Source Health -->\n @if (SourceHealthCards.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-heart-pulse\"></i> Source Health Summary</h3>\n <div class=\"source-health-grid\" [style.grid-template-columns]=\"'repeat(' + SourceHealthCards.length + ', 1fr)'\">\n @for (card of SourceHealthCards; track card.Name) {\n <div class=\"source-health-card\" [style.border-top-color]=\"card.Color\">\n <div class=\"health-card-name\">{{ card.Name }}</div>\n <div class=\"health-card-value\" [style.color]=\"card.Color\">{{ card.Uptime }}%</div>\n <div class=\"health-card-label\">uptime</div>\n </div>\n }\n </div>\n </div>\n }\n </section>\n }\n\n <!-- ====================================================== -->\n <!-- TAB 4: PIPELINE -->\n <!-- ====================================================== -->\n @if (ActiveTab === 'pipeline') {\n <section class=\"tab-section\">\n <div class=\"tab-section-header\">\n <i class=\"fa-solid fa-gears\"></i>\n <h1>Pipeline</h1>\n </div>\n\n <!-- Pipeline Throughput Chart -->\n <div class=\"sub-section\" style=\"margin-top:0\">\n <h3><i class=\"fa-solid fa-chart-bar\"></i> Pipeline Throughput (Last 30 Days)</h3>\n <div class=\"widget-card\">\n <div class=\"pipeline-throughput-bars\">\n @for (bar of PipelineThroughputBars; track TrackByIndex($index)) {\n <div class=\"pipeline-bar\"\n [style.height.%]=\"bar.Percentage\"\n [style.background]=\"bar.IsError ? 'var(--mj-status-error)' : 'var(--mj-brand-primary)'\"\n [style.opacity]=\"bar.IsError ? 0.7 : (0.6 + bar.Percentage / 300)\"\n style=\"cursor:pointer\"\n (click)=\"OpenDrillDown('pipeline-throughput:' + $index)\"\n ></div>\n }\n </div>\n <div class=\"pipeline-date-labels\">\n @for (label of PipelineDateLabels; track label) {\n <span>{{ label }}</span>\n }\n </div>\n </div>\n </div>\n\n <!-- D10: Pipeline throughput drill-down -->\n @if (DrillDownTarget && DrillDownTarget.startsWith('pipeline-throughput:')) {\n <div class=\"drill-down-panel\">\n <div class=\"drill-down-header\">\n <span class=\"drill-down-title\"><i class=\"fa-solid fa-table\"></i> Runs for Selected Day</span>\n <div class=\"drill-down-header-actions\">\n @if (DrillDownData.length > 0) {\n <button class=\"drill-export-btn\" (click)=\"ExportDrillDownCSV()\" title=\"Export CSV\"><i class=\"fa-solid fa-download\"></i> CSV</button>\n }\n <button class=\"drill-down-close\" (click)=\"CloseDrillDown()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n </div>\n @if (IsDrillDownLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n } @else if (DrillDownData.length > 0) {\n <div class=\"drill-down-table-wrap\">\n <table class=\"data-table\">\n <thead><tr>\n @for (col of DrillDownColumns; track col) { <th>{{ col }}</th> }\n @if (DrillDownHasActions) { <th class=\"drill-action-col\"></th> }\n </tr></thead>\n <tbody>\n @for (row of DrillDownData; track TrackByIndex($index)) {\n <tr>\n @for (col of DrillDownColumns; track col) { <td>{{ row[col] }}</td> }\n @if (DrillDownHasActions) {\n <td class=\"drill-action-col\">\n @if (row['_RecordID']) {\n <button class=\"drill-open-btn\" (click)=\"OpenDrillDownRecord(row)\" title=\"Open record\"><i class=\"fa-solid fa-arrow-up-right-from-square\"></i></button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"drill-down-empty\">No runs for this day</div>\n }\n </div>\n }\n\n <!-- Processing Time Breakdown -->\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-stopwatch\"></i> Processing Time Breakdown (Avg per Item)</h3>\n <div class=\"widget-card\">\n <div class=\"stage-bars\">\n @for (stage of ProcessingStages; track stage.Name) {\n <div class=\"stage-row\">\n <div class=\"stage-name\">{{ stage.Name }}</div>\n <div class=\"stage-track\">\n <div class=\"stage-fill\" [style.width.%]=\"stage.Percentage\" [style.background]=\"stage.Color\">\n @if (stage.Percentage > 15) {\n {{ stage.Time }}s\n }\n </div>\n </div>\n <div class=\"stage-time\">{{ stage.Time }}s</div>\n </div>\n }\n </div>\n <div class=\"stage-summary\">\n <span><strong>Total avg:</strong> {{ TotalAvgProcessingTime }}s per item</span>\n @if (BottleneckStage) {\n <span class=\"stage-warning\">\n <i class=\"fa-solid fa-triangle-exclamation\" style=\"color:var(--mj-status-warning);margin-right:4px\"></i>\n {{ BottleneckStage }} stage is the bottleneck ({{ BottleneckPercent }}% of total time)\n </span>\n }\n </div>\n </div>\n </div>\n\n <!-- Success Rate -->\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-chart-line\"></i> Success Rate Overview</h3>\n <div class=\"widget-card\">\n <div class=\"success-rate-display\">\n <div class=\"success-rate-stat\">\n <div class=\"success-rate-value\" style=\"color:var(--mj-status-success)\">\n {{ rawProcessRuns.length > 0 ? (100 - (ErrorLog.length / rawProcessRuns.length * 100)).toFixed(1) : '100' }}%\n </div>\n <div class=\"success-rate-label\">Success Rate</div>\n </div>\n <div class=\"success-rate-stat\">\n <div class=\"success-rate-value\" style=\"color:var(--mj-status-error)\">\n {{ rawProcessRuns.length > 0 ? (ErrorLog.length / rawProcessRuns.length * 100).toFixed(1) : '0' }}%\n </div>\n <div class=\"success-rate-label\">Failure Rate</div>\n </div>\n <div class=\"success-rate-stat\">\n <div class=\"success-rate-value\" style=\"color:var(--mj-text-primary)\">\n {{ FormatNumber(rawProcessRuns.length) }}\n </div>\n <div class=\"success-rate-label\">Total Runs</div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Active Runs Table -->\n @if (ActiveRuns.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-spinner\"></i> Active Runs</h3>\n <div class=\"table-scroll\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Run ID</th>\n <th>Source</th>\n <th>Started</th>\n <th>Progress</th>\n <th>Stage</th>\n <th class=\"num\">Items</th>\n </tr>\n </thead>\n <tbody>\n @for (run of ActiveRuns; track run.RunID) {\n <tr>\n <td class=\"monospace-cell\">{{ run.RunID }}</td>\n <td>{{ run.Source }}</td>\n <td class=\"muted\">{{ run.Started }}</td>\n <td>\n <div class=\"progress-track\"><div class=\"progress-fill\" [style.width.%]=\"run.Progress\" style=\"background:var(--mj-brand-primary)\"></div></div>\n <span class=\"progress-text\">{{ run.Progress }}%</span>\n </td>\n <td><span class=\"badge\" [class]=\"run.StageClass\">{{ run.Stage }}</span></td>\n <td class=\"num\">{{ FormatNumber(run.Items) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n\n <!-- Error Log -->\n @if (ErrorLog.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-triangle-exclamation\"></i> Recent Errors</h3>\n <div class=\"error-log\">\n @for (entry of ErrorLog; track TrackByIndex($index)) {\n <div class=\"error-entry\">\n <div class=\"error-time\">{{ entry.Time }}</div>\n <div class=\"error-source\">{{ entry.Source }}</div>\n <div class=\"error-msg\">{{ entry.Message }}</div>\n </div>\n }\n </div>\n </div>\n }\n </section>\n }\n\n <!-- ====================================================== -->\n <!-- TAB 5: QUALITY -->\n <!-- ====================================================== -->\n @if (ActiveTab === 'quality') {\n <section class=\"tab-section\">\n <div class=\"tab-section-header\">\n <i class=\"fa-solid fa-circle-check\"></i>\n <h1>Quality</h1>\n </div>\n\n <!-- Confidence Distribution Histogram -->\n <div class=\"sub-section\" style=\"margin-top:0\">\n <h3><i class=\"fa-solid fa-chart-column\"></i> Confidence Distribution</h3>\n <div class=\"widget-card\">\n <div class=\"histogram\">\n @for (bin of ConfidenceHistogram; track bin.Label) {\n <div class=\"hist-bar-col\" style=\"cursor:pointer\" (click)=\"OpenDrillDown('quality-bin:' + bin.Label)\">\n <div class=\"hist-bar\" [style.height.%]=\"bin.Percentage\" [style.background]=\"bin.Color\">\n @if (bin.Count > 0) { {{ bin.Count }} }\n </div>\n <div class=\"hist-label\">{{ bin.Label }}</div>\n </div>\n }\n </div>\n <div class=\"confidence-stats\">\n @for (stat of ConfidenceStats; track stat.Label) {\n <span><strong>{{ stat.Label }}:</strong> {{ stat.Value }}</span>\n }\n </div>\n </div>\n </div>\n\n <!-- D10: Quality bin drill-down -->\n @if (DrillDownTarget && DrillDownTarget.startsWith('quality-bin:')) {\n <div class=\"drill-down-panel\">\n <div class=\"drill-down-header\">\n <span class=\"drill-down-title\"><i class=\"fa-solid fa-table\"></i> Items in Confidence Range {{ DrillDownTarget.replace('quality-bin:', '') }}</span>\n <div class=\"drill-down-header-actions\">\n @if (DrillDownData.length > 0) {\n <button class=\"drill-export-btn\" (click)=\"ExportDrillDownCSV()\" title=\"Export CSV\"><i class=\"fa-solid fa-download\"></i> CSV</button>\n }\n <button class=\"drill-down-close\" (click)=\"CloseDrillDown()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n </div>\n @if (IsDrillDownLoading) {\n <mj-loading text=\"Loading details...\" size=\"small\"></mj-loading>\n } @else if (DrillDownData.length > 0) {\n <div class=\"drill-down-table-wrap\">\n <table class=\"data-table\">\n <thead><tr>\n @for (col of DrillDownColumns; track col) { <th>{{ col }}</th> }\n @if (DrillDownHasActions) { <th class=\"drill-action-col\"></th> }\n </tr></thead>\n <tbody>\n @for (row of DrillDownData; track TrackByIndex($index)) {\n <tr>\n @for (col of DrillDownColumns; track col) { <td>{{ row[col] }}</td> }\n @if (DrillDownHasActions) {\n <td class=\"drill-action-col\">\n @if (row['_RecordID']) {\n <button class=\"drill-open-btn\" (click)=\"OpenDrillDownRecord(row)\" title=\"Open record\"><i class=\"fa-solid fa-arrow-up-right-from-square\"></i></button>\n }\n </td>\n }\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"drill-down-empty\">No items in this confidence range</div>\n }\n </div>\n }\n\n <!-- Weight Distribution by Entity -->\n @if (WeightByEntity.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-weight-scale\"></i> Weight Distribution by Entity</h3>\n <div class=\"widget-card\">\n <div class=\"grouped-bar-chart\">\n @for (entity of WeightByEntity; track entity.Name) {\n <div class=\"grouped-col\">\n <div class=\"grouped-bars\">\n <div class=\"g-bar\" [style.height.%]=\"entity.High\" style=\"background:var(--mj-brand-primary)\" [title]=\"'High: ' + entity.High + '%'\"></div>\n <div class=\"g-bar\" [style.height.%]=\"entity.Med\" style=\"background:var(--mj-status-info)\" [title]=\"'Med: ' + entity.Med + '%'\"></div>\n <div class=\"g-bar\" [style.height.%]=\"entity.Low\" style=\"background:var(--mj-text-muted)\" [title]=\"'Low: ' + entity.Low + '%'\"></div>\n </div>\n <div class=\"grouped-label\">{{ entity.Name }}</div>\n </div>\n }\n </div>\n <div class=\"legend\" style=\"justify-content:center;margin-top:14px\">\n @for (item of WeightLegend; track item.Label) {\n <div class=\"legend-item\"><div class=\"legend-dot\" [style.background]=\"item.Color\"></div> {{ item.Label }}</div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Tag Accuracy Over Time -->\n @if (AccuracyLinePoints) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-chart-line\"></i> Tag Accuracy Over Time (Weekly Avg Confidence)</h3>\n <div class=\"widget-card\">\n <div class=\"accuracy-chart\">\n <div class=\"accuracy-y-labels\">\n <div>1.0</div>\n <div>0.75</div>\n <div>0.50</div>\n <div>0.25</div>\n </div>\n <div class=\"accuracy-area\">\n <div class=\"accuracy-grid-line\" style=\"top:33%\"></div>\n <div class=\"accuracy-grid-line\" style=\"top:66%\"></div>\n <svg width=\"100%\" height=\"110\" viewBox=\"0 0 400 110\" preserveAspectRatio=\"none\" class=\"accuracy-svg\">\n <polyline [attr.points]=\"AccuracyLinePoints\"\n fill=\"none\" stroke=\"var(--mj-brand-primary)\" stroke-width=\"2.5\" vector-effect=\"non-scaling-stroke\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n @for (dot of AccuracyDots; track TrackByIndex($index)) {\n <circle [attr.cx]=\"dot.Cx\" [attr.cy]=\"dot.Cy\" r=\"3\" fill=\"var(--mj-brand-primary)\"/>\n }\n </svg>\n </div>\n </div>\n <div class=\"accuracy-x-labels\">\n @for (label of AccuracyMonthLabels; track label) {\n <span>{{ label }}</span>\n }\n </div>\n <div class=\"accuracy-trend-text\">\n <i class=\"fa-solid fa-arrow-trend-up\" style=\"margin-right:4px\"></i>\n {{ AccuracyTrendText }}\n </div>\n </div>\n </div>\n }\n\n <!-- Low-Confidence Tags Table -->\n @if (LowConfidenceTags.length > 0) {\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-exclamation-triangle\"></i> Low-Confidence Tags (Avg Weight &lt; 0.4)</h3>\n <div class=\"table-scroll\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Tag Name</th>\n <th class=\"num\">Avg Weight</th>\n <th class=\"num\">Usage Count</th>\n <th>Top Entity</th>\n <th>Suggested Action</th>\n </tr>\n </thead>\n <tbody>\n @for (tag of LowConfidenceTags; track tag.Name) {\n <tr>\n <td><strong>{{ tag.Name }}</strong></td>\n <td class=\"num\">{{ tag.AvgWeight }}</td>\n <td class=\"num\">{{ tag.UsageCount }}</td>\n <td>{{ tag.TopEntity }}</td>\n <td><span class=\"badge\" [class]=\"tag.ActionClass\">{{ tag.SuggestedAction }}</span></td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n\n <!-- Model Performance Comparison -->\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-robot\"></i> Model Performance Comparison</h3>\n <div class=\"model-grid\">\n @for (model of ModelComparisons; track model.Name) {\n <div class=\"model-card\">\n <div class=\"model-name\"><i [class]=\"model.Icon\" [style.color]=\"model.IconColor\" style=\"margin-right:4px\"></i> {{ model.Name }}</div>\n <svg width=\"80\" height=\"80\" viewBox=\"0 0 80 80\" style=\"margin:4px 0\">\n <circle cx=\"40\" cy=\"40\" r=\"32\" fill=\"none\" stroke=\"var(--mj-border-default)\" stroke-width=\"8\"/>\n <circle cx=\"40\" cy=\"40\" r=\"32\" fill=\"none\" [attr.stroke]=\"model.ScoreColor\" stroke-width=\"8\"\n [attr.stroke-dasharray]=\"model.StrokeDash\" stroke-dashoffset=\"50\"\n transform=\"rotate(-90 40 40)\" stroke-linecap=\"round\"/>\n </svg>\n <div class=\"model-score\" [style.color]=\"model.ScoreColor\">{{ model.ScorePercentage }}%</div>\n <div class=\"model-detail\">Avg confidence: {{ model.AvgConfidence }}</div>\n <div class=\"model-detail\">{{ FormatNumber(model.TagsGenerated) }} tags generated</div>\n <div class=\"model-detail\" [style.color]=\"model.RoleColor\" style=\"font-weight:600\">{{ model.Role }}</div>\n </div>\n }\n </div>\n @if (ModelRecommendation) {\n <div class=\"model-recommendation\">\n <i class=\"fa-solid fa-lightbulb\" style=\"color:var(--mj-status-warning)\"></i>\n <div>\n <strong>Recommendation:</strong> {{ ModelRecommendation }}\n </div>\n </div>\n }\n </div>\n </section>\n }\n\n <!-- ====================================================== -->\n <!-- TAB 6: COST & USAGE (D1) -->\n <!-- ====================================================== -->\n @if (ActiveTab === 'cost') {\n <section class=\"tab-section\">\n <div class=\"tab-section-header\">\n <i class=\"fa-solid fa-coins\"></i>\n <h1>Cost & Usage</h1>\n <div class=\"tab-header-actions\">\n <button class=\"drill-export-btn\" (click)=\"ExportTabDataCSV('cost-usage')\" title=\"Export CSV\">\n <i class=\"fa-solid fa-download\"></i> CSV\n </button>\n <button class=\"drill-export-btn\" (click)=\"PrintCurrentTab()\" title=\"Print (PDF alternative)\">\n <i class=\"fa-solid fa-print\"></i> Print\n </button>\n </div>\n </div>\n\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"date-chips\">\n @for (range of DateRanges; track range.Label) {\n <button\n class=\"date-chip\"\n [class.active]=\"ActiveDateRange === range.Label\"\n (click)=\"SetDateRange(range.Label)\"\n >{{ range.Label }}</button>\n }\n </div>\n </div>\n\n <!-- KPI Cards -->\n @if (CostKPIs.length > 0) {\n <div class=\"cost-kpi-row\">\n @for (kpi of CostKPIs; track kpi.Label) {\n <div class=\"cost-kpi-card\">\n <div class=\"cost-kpi-icon\"><i [class]=\"kpi.Icon\"></i></div>\n <div>\n <div class=\"cost-kpi-value\">{{ kpi.Value }}</div>\n <div class=\"cost-kpi-label\">{{ kpi.Label }}</div>\n <div class=\"cost-kpi-sub\">{{ kpi.SubLabel }}</div>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Per-Run Cost Table -->\n <div class=\"sub-section\">\n <h3><i class=\"fa-solid fa-table\"></i> Cost Breakdown by Run</h3>\n @if (CostPerRunRows.length > 0) {\n <div class=\"table-scroll\">\n <table class=\"data-table\">\n <thead>\n <tr>\n <th>Run ID</th>\n <th>Source</th>\n <th class=\"num\">Tokens</th>\n <th class=\"num\">Cost</th>\n <th>Started</th>\n </tr>\n </thead>\n <tbody>\n @for (row of CostPerRunRows; track row.RunID) {\n <tr>\n <td class=\"monospace-cell\">{{ row.RunID }}</td>\n <td>{{ row.Source }}</td>\n <td class=\"num\">{{ FormatNumber(row.Tokens) }}</td>\n <td class=\"num\">{{ row.Cost > 0 ? '$' + row.Cost.toFixed(4) : '$0.00' }}</td>\n <td class=\"muted\">{{ row.Started }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-coins\"></i>\n <p>No cost data available yet. Run the pipeline to generate cost and token usage metrics.</p>\n <p class=\"empty-state-hint\">Cost data is aggregated from ContentProcessRunDetail records linked to AI Prompt Runs.</p>\n </div>\n }\n </div>\n </section>\n }\n\n </div><!-- /main-content -->\n </div><!-- /analytics-layout -->\n}\n", styles: ["/* ===================================================================\n Analytics & Insights Resource Component\n ================================================================= */\n\n.analytics-loading {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 400px;\n}\n\n.analytics-layout {\n display: flex;\n height: 100%;\n min-height: 600px;\n}\n\n/* ===== LEFT SIDEBAR ===== */\n.analytics-sidebar {\n width: 220px;\n min-width: 220px;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n}\n\n.sidebar-header {\n padding: 20px 16px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.sidebar-header h2 {\n font-size: 13px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n}\n\n.sidebar-header h2 i {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n\n.sidebar-nav {\n padding: 8px 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.nav-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 16px;\n font-size: 13.5px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n border: none;\n background: transparent;\n border-left: 3px solid transparent;\n transition: all 0.15s ease;\n text-align: left;\n width: 100%;\n font-family: inherit;\n}\n\n.nav-item:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n}\n\n.nav-item.active {\n border-left-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n font-weight: 600;\n}\n\n.nav-item i {\n width: 16px;\n text-align: center;\n font-size: 13px;\n}\n\n.sidebar-divider {\n height: 1px;\n background: var(--mj-border-default);\n margin: 8px 16px;\n}\n\n.trending-section {\n padding: 12px 16px 16px;\n}\n\n.trending-section h3 {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--mj-text-muted);\n margin: 0 0 10px;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.tag-cloud {\n display: flex;\n flex-wrap: wrap;\n gap: 4px 6px;\n line-height: 1.7;\n}\n\n.tag-cloud span {\n color: var(--mj-brand-primary);\n cursor: pointer;\n transition: opacity 0.15s;\n}\n\n.tag-cloud span:hover {\n opacity: 0.7;\n}\n\n.no-trending {\n color: var(--mj-text-muted) !important;\n font-size: 12px !important;\n font-style: italic;\n}\n\n.pipeline-status {\n padding: 12px 16px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n\n.status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: var(--mj-status-success);\n flex-shrink: 0;\n}\n\n.status-dot-error {\n background: var(--mj-status-error);\n}\n\n/* ===== MAIN CONTENT ===== */\n.main-content {\n flex: 1;\n overflow-y: auto;\n min-width: 0;\n}\n\n.tab-section {\n padding: 28px 32px 40px;\n}\n\n.tab-section-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 20px;\n padding-bottom: 12px;\n border-bottom: 2px solid var(--mj-brand-primary);\n}\n\n.tab-section-header i {\n font-size: 18px;\n color: var(--mj-brand-primary);\n}\n\n.tab-section-header h1 {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n/* ===== FILTER BAR ===== */\n.filter-bar {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 20px;\n flex-wrap: wrap;\n}\n\n.date-chips {\n display: flex;\n gap: 0;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n}\n\n.date-chip {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface);\n cursor: pointer;\n border: none;\n border-right: 1px solid var(--mj-border-default);\n transition: all 0.15s;\n font-family: inherit;\n}\n\n.date-chip:last-child {\n border-right: none;\n}\n\n.date-chip:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-chip.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.filter-dropdown {\n padding: 6px 12px;\n font-size: 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n font-family: inherit;\n}\n\n/* ===== KPI CARDS ===== */\n.kpi-row {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 20px;\n}\n\n.kpi-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 16px 18px;\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n transition: transform 0.15s, box-shadow 0.15s;\n cursor: pointer;\n}\n\n.kpi-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.kpi-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n}\n\n.kpi-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n}\n\n.kpi-delta {\n font-size: 11px;\n font-weight: 500;\n margin-top: 4px;\n color: var(--mj-text-muted);\n}\n\n.kpi-delta.up {\n color: var(--mj-status-success);\n}\n\n.kpi-delta.down {\n color: var(--mj-status-error);\n}\n\n.kpi-sparkline {\n flex-shrink: 0;\n margin-left: 12px;\n margin-top: 6px;\n}\n\n/* ===== CARDS GRID ===== */\n.cards-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n}\n\n.widget-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 18px 20px;\n transition: transform 0.15s, box-shadow 0.15s;\n cursor: pointer;\n}\n\n.widget-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.widget-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 14px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.widget-title i {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n.widget-empty {\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 12px;\n padding: 20px;\n}\n\n.widget-footnote {\n text-align: center;\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 10px;\n}\n\n/* ===== BAR CHART ===== */\n.bar-chart {\n display: flex;\n align-items: flex-end;\n gap: 8px;\n height: 120px;\n padding-top: 10px;\n}\n\n.bar-col {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n}\n\n.bar {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height 0.3s;\n min-height: 2px;\n}\n\n.bar-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n}\n\n.bar-value {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 4px;\n}\n\n/* ===== PROGRESS RINGS ===== */\n.rings-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n}\n\n.ring-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 0;\n}\n\n.ring-label {\n font-size: 12px;\n color: var(--mj-text-primary);\n font-weight: 500;\n}\n\n.ring-stat {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n/* ===== GAUGE ===== */\n.gauge-container {\n display: flex;\n justify-content: center;\n margin-bottom: 8px;\n}\n\n/* ===== MINI HISTOGRAM ===== */\n.mini-histogram {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 32px;\n justify-content: center;\n}\n\n.mini-hist-bar {\n width: 14px;\n border-radius: 2px;\n}\n\n.mini-hist-label {\n text-align: center;\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n/* ===== HORIZONTAL BARS ===== */\n.h-bar-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.h-bar-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.h-bar-name {\n font-size: 12px;\n color: var(--mj-text-secondary);\n width: 100px;\n flex-shrink: 0;\n text-align: right;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.h-bar-track {\n flex: 1;\n height: 20px;\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.h-bar-fill {\n height: 100%;\n border-radius: 4px;\n display: flex;\n align-items: center;\n padding-left: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-width: 36px;\n}\n\n/* ===== THROUGHPUT BARS ===== */\n.throughput-bars {\n display: flex;\n align-items: flex-end;\n gap: 4px;\n height: 110px;\n margin-bottom: 22px;\n}\n\n.tp-bar {\n flex: 1;\n border-radius: 3px 3px 0 0;\n position: relative;\n min-height: 4px;\n}\n\n.tp-bar-label {\n position: absolute;\n bottom: -18px;\n left: 50%;\n transform: translateX(-50%);\n font-size: 8px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n/* ===== TAXONOMY ===== */\n.taxonomy-ring-container {\n display: flex;\n justify-content: center;\n}\n\n.taxonomy-stats {\n display: flex;\n gap: 8px;\n margin-top: 12px;\n}\n\n.tax-stat {\n flex: 1;\n text-align: center;\n padding: 8px 4px;\n border-radius: 6px;\n font-size: 20px;\n font-weight: 700;\n}\n\n.tax-stat small {\n display: block;\n font-size: 10px;\n font-weight: 500;\n margin-top: 2px;\n}\n\n/* ===== LEGEND ===== */\n.legend {\n display: flex;\n gap: 16px;\n margin-top: 10px;\n flex-wrap: wrap;\n justify-content: center;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.legend-dot {\n width: 10px;\n height: 10px;\n border-radius: 3px;\n flex-shrink: 0;\n}\n\n/* ===== DATA TABLES ===== */\n.table-scroll {\n overflow-x: auto;\n}\n\n.data-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 12.5px;\n}\n\n.data-table thead th {\n text-align: left;\n padding: 10px 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-muted);\n border-bottom: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-card);\n white-space: nowrap;\n}\n\n.data-table tbody td {\n padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n vertical-align: middle;\n}\n\n.data-table tbody tr:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.data-table .num {\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.muted {\n color: var(--mj-text-muted);\n}\n\n.monospace-cell {\n font-family: monospace;\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.weight-bar {\n display: inline-block;\n height: 6px;\n border-radius: 3px;\n vertical-align: middle;\n margin-right: 6px;\n}\n\n/* ===== BADGES ===== */\n.badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 10.5px;\n font-weight: 600;\n}\n\n.badge-success {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.badge-warning {\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.badge-error {\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.badge-info {\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n/* ===== SUB-SECTIONS ===== */\n.sub-section {\n margin-top: 24px;\n}\n\n.sub-section h3 {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 12px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.sub-section h3 i {\n font-size: 13px;\n color: var(--mj-brand-primary);\n}\n\n/* ===== EMPTY STATE ===== */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 3rem 2rem;\n text-align: center;\n gap: 0.75rem;\n border: 2px dashed var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.empty-state i {\n font-size: 2.5rem;\n color: var(--mj-text-disabled);\n}\n\n.empty-state p {\n margin: 0;\n font-size: 0.85rem;\n max-width: 400px;\n}\n\n/* ===== DRILL-DOWN PANEL ===== */\n.drill-down-panel {\n margin-top: 16px;\n margin-bottom: 16px;\n background: var(--mj-bg-surface);\n border: 2px solid var(--mj-brand-primary);\n border-radius: 10px;\n overflow: hidden;\n animation: slideDown 0.2s ease-out;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n max-height: 0;\n }\n to {\n opacity: 1;\n max-height: 600px;\n }\n}\n\n.drill-down-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 16px;\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.drill-down-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.drill-down-close {\n border: none;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s;\n}\n\n.drill-down-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.drill-down-table-wrap {\n max-height: 400px;\n overflow-y: auto;\n padding: 8px;\n}\n\n.drill-action-col {\n width: 40px;\n text-align: center;\n padding: 6px !important;\n}\n\n.drill-open-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: 1px solid var(--mj-border-default);\n border-radius: 5px;\n background: transparent;\n color: var(--mj-text-muted);\n font-size: 10px;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.drill-open-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.drill-down-header-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.drill-export-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 5px;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.drill-export-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.sub-section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0;\n}\n\n.sub-section-header h3 {\n margin: 0;\n}\n\n.drill-down-empty {\n padding: 24px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n/* ===== STACKED BAR CHART ===== */\n.stacked-bar-chart {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.stacked-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.stacked-label {\n width: 90px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.stacked-track {\n flex: 1;\n height: 22px;\n display: flex;\n border-radius: 4px;\n overflow: hidden;\n}\n\n.stacked-seg {\n height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 9px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-width: 20px;\n}\n\n/* ===== VERTICAL BAR CHART ===== */\n.v-bar-chart {\n display: flex;\n align-items: flex-end;\n gap: 24px;\n height: 140px;\n padding-top: 10px;\n justify-content: center;\n}\n\n.v-bar-col {\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n min-width: 60px;\n}\n\n.v-bar {\n width: 48px;\n border-radius: 4px 4px 0 0;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 4px;\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-inverse);\n}\n\n.v-bar-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 8px;\n text-align: center;\n}\n\n.chart-footnote {\n text-align: center;\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 14px;\n}\n\n/* ===== TWO COLUMN ===== */\n.two-col {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 20px;\n}\n\n/* ===== SOURCE SELECTED ===== */\n.source-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n/* ===== QUALITY BANDS ===== */\n.quality-bands {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.quality-band-row {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.quality-band-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n width: 65px;\n text-align: right;\n flex-shrink: 0;\n}\n\n.quality-band-track {\n flex: 1;\n height: 18px;\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.quality-band-fill {\n height: 100%;\n border-radius: 4px;\n display: flex;\n align-items: center;\n padding-left: 8px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-width: 30px;\n}\n\n.source-quality-note {\n margin-top: 14px;\n padding: 10px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n font-size: 11px;\n color: var(--mj-text-secondary);\n}\n\n/* ===== SOURCE HEALTH ===== */\n.source-health-grid {\n display: grid;\n gap: 12px;\n}\n\n.source-health-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n padding: 14px;\n text-align: center;\n border-top: 3px solid;\n}\n\n.health-card-name {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-bottom: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.health-card-value {\n font-size: 22px;\n font-weight: 700;\n}\n\n.health-card-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n/* ===== PIPELINE ===== */\n.pipeline-throughput-bars {\n display: flex;\n align-items: flex-end;\n gap: 3px;\n height: 110px;\n}\n\n.pipeline-bar {\n flex: 1;\n border-radius: 2px 2px 0 0;\n min-height: 3px;\n}\n\n.pipeline-date-labels {\n display: flex;\n justify-content: space-between;\n margin-top: 6px;\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n/* ===== PROCESSING STAGES ===== */\n.stage-bars {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.stage-row {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.stage-name {\n width: 80px;\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.stage-track {\n flex: 1;\n height: 24px;\n background: var(--mj-bg-surface-card);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.stage-fill {\n height: 100%;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n padding-right: 8px;\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n}\n\n.stage-time {\n width: 50px;\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-align: right;\n flex-shrink: 0;\n}\n\n.stage-summary {\n display: flex;\n justify-content: space-between;\n margin-top: 14px;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-default);\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.stage-warning {\n color: var(--mj-text-muted);\n}\n\n/* ===== SUCCESS RATE ===== */\n.success-rate-display {\n display: flex;\n justify-content: center;\n gap: 48px;\n padding: 20px;\n}\n\n.success-rate-stat {\n text-align: center;\n}\n\n.success-rate-value {\n font-size: 32px;\n font-weight: 700;\n line-height: 1.1;\n}\n\n.success-rate-label {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n/* ===== PROGRESS ===== */\n.progress-track {\n width: 100px;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n overflow: hidden;\n display: inline-block;\n vertical-align: middle;\n margin-right: 6px;\n}\n\n.progress-fill {\n height: 100%;\n border-radius: 3px;\n}\n\n.progress-text {\n font-size: 11px;\n font-weight: 600;\n}\n\n/* ===== ERROR LOG ===== */\n.error-log {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.error-entry {\n display: flex;\n gap: 12px;\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-status-error) 4%, var(--mj-bg-surface));\n border-left: 3px solid var(--mj-status-error);\n border-radius: 0 6px 6px 0;\n font-size: 12px;\n}\n\n.error-time {\n color: var(--mj-text-muted);\n font-size: 11px;\n white-space: nowrap;\n flex-shrink: 0;\n width: 130px;\n}\n\n.error-source {\n color: var(--mj-brand-primary);\n font-weight: 600;\n flex-shrink: 0;\n width: 120px;\n}\n\n.error-msg {\n color: var(--mj-text-secondary);\n}\n\n/* ===== HISTOGRAM ===== */\n.histogram {\n display: flex;\n align-items: flex-end;\n gap: 6px;\n height: 130px;\n padding-bottom: 24px;\n}\n\n.hist-bar-col {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n}\n\n.hist-bar {\n width: 100%;\n border-radius: 3px 3px 0 0;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding-top: 3px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n min-height: 2px;\n}\n\n.hist-label {\n font-size: 9px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n text-align: center;\n}\n\n.confidence-stats {\n display: flex;\n justify-content: space-between;\n margin-top: 8px;\n padding: 10px;\n background: var(--mj-bg-surface-card);\n border-radius: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* ===== GROUPED BAR CHART ===== */\n.grouped-bar-chart {\n display: flex;\n align-items: flex-end;\n gap: 20px;\n height: 140px;\n justify-content: center;\n}\n\n.grouped-col {\n display: flex;\n flex-direction: column;\n align-items: center;\n height: 100%;\n justify-content: flex-end;\n}\n\n.grouped-bars {\n display: flex;\n gap: 3px;\n align-items: flex-end;\n height: 100%;\n}\n\n.g-bar {\n width: 18px;\n border-radius: 3px 3px 0 0;\n min-height: 2px;\n}\n\n.grouped-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-top: 6px;\n text-align: center;\n}\n\n/* ===== ACCURACY CHART ===== */\n.accuracy-chart {\n position: relative;\n display: flex;\n margin: 0 10px;\n}\n\n.accuracy-y-labels {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n font-size: 9px;\n color: var(--mj-text-muted);\n margin-right: 8px;\n height: 110px;\n}\n\n.accuracy-area {\n flex: 1;\n position: relative;\n height: 110px;\n border-left: 1px solid var(--mj-border-default);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.accuracy-grid-line {\n position: absolute;\n left: 0;\n right: 0;\n border-top: 1px dashed var(--mj-border-subtle);\n}\n\n.accuracy-svg {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n\n.accuracy-x-labels {\n display: flex;\n justify-content: space-between;\n margin-top: 8px;\n padding: 0 40px 0 40px;\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.accuracy-trend-text {\n text-align: center;\n margin-top: 10px;\n font-size: 12px;\n color: var(--mj-status-success);\n}\n\n/* ===== MODEL COMPARISON ===== */\n.model-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 12px;\n}\n\n.model-card {\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n padding: 14px;\n text-align: center;\n border: 1px solid var(--mj-border-default);\n}\n\n.model-name {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-bottom: 8px;\n}\n\n.model-score {\n font-size: 28px;\n font-weight: 700;\n line-height: 1;\n}\n\n.model-detail {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n.model-recommendation {\n margin-top: 14px;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n/* ===== RESPONSIVE ===== */\n@media (max-width: 1200px) {\n .cards-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .kpi-row {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .model-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n@media (max-width: 768px) {\n .analytics-layout {\n flex-direction: column;\n }\n\n .analytics-sidebar {\n width: 100%;\n min-width: 100%;\n border-right: none;\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .sidebar-nav {\n flex-direction: row;\n overflow-x: auto;\n }\n\n .nav-item {\n border-left: none;\n border-bottom: 3px solid transparent;\n white-space: nowrap;\n }\n\n .nav-item.active {\n border-left-color: transparent;\n border-bottom-color: var(--mj-brand-primary);\n }\n\n .trending-section,\n .sidebar-divider {\n display: none;\n }\n\n .tab-section {\n padding: 16px;\n }\n\n .cards-grid {\n grid-template-columns: 1fr;\n }\n\n .kpi-row {\n grid-template-columns: 1fr;\n }\n\n .two-col {\n grid-template-columns: 1fr;\n }\n\n .cost-kpi-row {\n grid-template-columns: 1fr;\n }\n}\n\n/* ===== COST & USAGE TAB (D1) ===== */\n\n.tab-header-actions {\n display: flex;\n gap: 8px;\n margin-left: auto;\n}\n\n.cost-kpi-row {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 16px;\n margin-bottom: 24px;\n}\n\n.cost-kpi-card {\n display: flex;\n gap: 14px;\n align-items: center;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 10px;\n padding: 18px 20px;\n transition: box-shadow 0.15s ease;\n}\n\n.cost-kpi-card:hover {\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.cost-kpi-icon {\n width: 44px;\n height: 44px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 18px;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n flex-shrink: 0;\n}\n\n.cost-kpi-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.cost-kpi-label {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.cost-kpi-sub {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.empty-state-hint {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n/* ===== D5: PRINT STYLES ===== */\n\n@media print {\n .analytics-sidebar,\n .filter-bar,\n .tab-header-actions,\n .drill-down-close,\n .drill-export-btn,\n .drill-open-btn {\n display: none !important;\n }\n\n .analytics-layout {\n display: block;\n }\n\n .main-content {\n padding: 0;\n }\n\n .tab-section {\n padding: 0;\n }\n\n .widget-card,\n .cost-kpi-card,\n .kpi-card {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n\n .data-table {\n font-size: 10px;\n }\n}\n\n/* \u2500\u2500 Co-Occurrence Section \u2500\u2500 */\n\n/* Constrain the co-occurrence sub-section so an empty state or large table\n does not blow out the page height and render the app unusable. */\n.co-occurrence-section {\n max-height: 500px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.co-occurrence-section .table-scroll {\n overflow-y: auto;\n max-height: 400px;\n flex: 1;\n min-height: 0;\n}\n\n.co-occurrence-section .empty-state {\n max-height: 200px;\n overflow: hidden;\n}\n\n.co-occurrence-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.co-occurrence-staleness {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n}\n"] }]
4260
+ }], null, null); })();
4261
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnalyticsResourceComponent, { className: "AnalyticsResourceComponent", filePath: "src/KnowledgeHub/components/analytics/analytics-resource.component.ts", lineNumber: 222 }); })();
4262
+ /** Tree-shaking prevention */
4263
+ export function LoadAnalyticsResource() {
4264
+ // Prevents tree-shaking
4265
+ }
4266
+ //# sourceMappingURL=analytics-resource.component.js.map