@memberjunction/ng-dashboards 5.39.0 → 5.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +128 -4
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +548 -145
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts +56 -0
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js +423 -0
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts +70 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.js +308 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts +29 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +186 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts +69 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js +278 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts +73 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js +393 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js.map +1 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts +122 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js +908 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js.map +1 -0
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +100 -2
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +603 -213
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.format.d.ts +15 -0
- package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.format.js +51 -0
- package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.types.d.ts +43 -0
- package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +38 -1
- package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/history-tab.component.js +185 -68
- package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +10 -1
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +249 -188
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +12 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js +377 -296
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +8 -0
- package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/tags-tab.component.js +112 -68
- package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +9 -0
- package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/types-tab.component.js +87 -36
- package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +3 -0
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +15 -3
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +1 -1
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +1 -0
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +28 -6
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +3 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +330 -302
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +2 -2
- package/dist/APIKeys/api-key-create-dialog.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +31 -340
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +468 -1958
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-resource.component.js +10 -0
- package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +12 -9
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +27 -2
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +244 -120
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts +65 -0
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js +176 -0
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js.map +1 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts +81 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js +308 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js.map +1 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts +85 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js +362 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/index.d.ts +3 -0
- package/dist/KnowledgeHub/index.d.ts.map +1 -1
- package/dist/KnowledgeHub/index.js +3 -0
- package/dist/KnowledgeHub/index.js.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
- package/dist/QueryBrowser/query-browser-resource.component.js +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +48 -38
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +41 -1
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/data-explorer-dashboards.module.d.ts +12 -14
- package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
- package/dist/data-explorer-dashboards.module.js +5 -14
- package/dist/data-explorer-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +57 -55
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts +0 -79
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts.map +0 -1
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +0 -195
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js.map +0 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +0 -226
- package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +0 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.js +0 -861
- package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Classify · Overview Analytics (Phase 4 audit/analytics).
|
|
3
|
+
*
|
|
4
|
+
* KPI cards + three hand-rolled inline-SVG charts (tag distribution bar,
|
|
5
|
+
* items-over-time line, weight histogram) for the classify dataset. All numbers
|
|
6
|
+
* come from `ClassifyAnalyticsEngine` so agents and UI share one source of truth.
|
|
7
|
+
*
|
|
8
|
+
* The engine is framework-agnostic (server + client safe); this component simply
|
|
9
|
+
* calls it with the current scope and the active metadata provider. Charts are
|
|
10
|
+
* SVG built from typed view models — NO charting library.
|
|
11
|
+
*/
|
|
12
|
+
import { AfterViewInit } from '@angular/core';
|
|
13
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
14
|
+
import { ClassifyAnalyticsScope, ClassifyKPIs } from '@memberjunction/tag-engine-base';
|
|
15
|
+
import { formatNumber } from '../shared/classify.format';
|
|
16
|
+
import * as i0 from "@angular/core";
|
|
17
|
+
/** A bar in the tag-distribution chart, pre-scaled to the chart width. */
|
|
18
|
+
interface DistributionBar {
|
|
19
|
+
Tag: string;
|
|
20
|
+
Count: number;
|
|
21
|
+
WidthPct: number;
|
|
22
|
+
}
|
|
23
|
+
/** A point in the items-over-time line chart, in SVG coordinate space. */
|
|
24
|
+
interface LinePoint {
|
|
25
|
+
X: number;
|
|
26
|
+
Y: number;
|
|
27
|
+
Label: string;
|
|
28
|
+
Count: number;
|
|
29
|
+
}
|
|
30
|
+
/** A bar in the weight histogram, pre-scaled to the chart height. */
|
|
31
|
+
interface HistogramBar {
|
|
32
|
+
Label: string;
|
|
33
|
+
Count: number;
|
|
34
|
+
HeightPct: number;
|
|
35
|
+
}
|
|
36
|
+
export declare class ClassifyOverviewAnalyticsComponent extends BaseAngularComponent implements AfterViewInit {
|
|
37
|
+
private cdr;
|
|
38
|
+
ngAfterViewInit(): Promise<void>;
|
|
39
|
+
/** Number of distinct tags shown in the distribution chart. */
|
|
40
|
+
private static readonly TAG_DISTRIBUTION_LIMIT;
|
|
41
|
+
/** Line-chart viewBox geometry. */
|
|
42
|
+
private static readonly LINE_WIDTH;
|
|
43
|
+
private static readonly LINE_HEIGHT;
|
|
44
|
+
private static readonly LINE_PAD;
|
|
45
|
+
/** Optional analytics scope (source / content-type / date range). Re-loads on change. */
|
|
46
|
+
private _scope;
|
|
47
|
+
set Scope(value: ClassifyAnalyticsScope | null);
|
|
48
|
+
get Scope(): ClassifyAnalyticsScope | null;
|
|
49
|
+
IsLoading: boolean;
|
|
50
|
+
HasData: boolean;
|
|
51
|
+
KPIs: ClassifyKPIs;
|
|
52
|
+
DistributionBars: DistributionBar[];
|
|
53
|
+
LinePoints: LinePoint[];
|
|
54
|
+
LinePath: string;
|
|
55
|
+
HistogramBars: HistogramBar[];
|
|
56
|
+
readonly FormatNumber: typeof formatNumber;
|
|
57
|
+
readonly LineWidth = 600;
|
|
58
|
+
readonly LineHeight = 160;
|
|
59
|
+
private _loadedOnce;
|
|
60
|
+
/** Load (or reload) all analytics for the current scope. Public entry point for the parent. */
|
|
61
|
+
Reload(): Promise<void>;
|
|
62
|
+
private buildDistribution;
|
|
63
|
+
private buildOverTime;
|
|
64
|
+
private buildHistogram;
|
|
65
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ClassifyOverviewAnalyticsComponent, never>;
|
|
66
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ClassifyOverviewAnalyticsComponent, "classify-overview-analytics", never, { "Scope": { "alias": "Scope"; "required": false; }; }, {}, never, never, false, never>;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=classify-overview-analytics.component.d.ts.map
|
package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify-overview-analytics.component.d.ts","sourceRoot":"","sources":["../../../../../src/AI/components/autotagging/components/classify-overview-analytics.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAGH,aAAa,EAGhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAEH,sBAAsB,EACtB,YAAY,EAIf,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,YAAY,EAAmB,MAAM,2BAA2B,CAAC;;AAE1E,0EAA0E;AAC1E,UAAU,eAAe;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,0EAA0E;AAC1E,UAAU,SAAS;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,qEAAqE;AACrE,UAAU,YAAY;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAMa,kCAAmC,SAAQ,oBAAqB,YAAW,aAAa;IACjG,OAAO,CAAC,GAAG,CAA6B;IAElC,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC,+DAA+D;IAC/D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAM;IACpD,mCAAmC;IACnC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAO;IACzC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAO;IAC1C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAK;IAErC,yFAAyF;IACzF,OAAO,CAAC,MAAM,CAAuC;IACrD,IACI,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,IAAI,EAG7C;IACD,IAAI,KAAK,IAAI,sBAAsB,GAAG,IAAI,CAEzC;IAEM,SAAS,UAAS;IAClB,OAAO,UAAS;IAEhB,IAAI,EAAE,YAAY,CAAuE;IAEzF,gBAAgB,EAAE,eAAe,EAAE,CAAM;IACzC,UAAU,EAAE,SAAS,EAAE,CAAM;IAC7B,QAAQ,SAAM;IACd,aAAa,EAAE,YAAY,EAAE,CAAM;IAG1C,SAAgB,YAAY,sBAAgB;IAC5C,SAAgB,SAAS,OAAiD;IAC1E,SAAgB,UAAU,OAAkD;IAE5E,OAAO,CAAC,WAAW,CAAS;IAE5B,+FAA+F;IAClF,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IA2BpC,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,cAAc;yCAzGb,kCAAkC;2CAAlC,kCAAkC;CAiH9C"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Classify · Overview Analytics (Phase 4 audit/analytics).
|
|
3
|
+
*
|
|
4
|
+
* KPI cards + three hand-rolled inline-SVG charts (tag distribution bar,
|
|
5
|
+
* items-over-time line, weight histogram) for the classify dataset. All numbers
|
|
6
|
+
* come from `ClassifyAnalyticsEngine` so agents and UI share one source of truth.
|
|
7
|
+
*
|
|
8
|
+
* The engine is framework-agnostic (server + client safe); this component simply
|
|
9
|
+
* calls it with the current scope and the active metadata provider. Charts are
|
|
10
|
+
* SVG built from typed view models — NO charting library.
|
|
11
|
+
*/
|
|
12
|
+
import { Component, Input, ChangeDetectorRef, inject, } from '@angular/core';
|
|
13
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
14
|
+
import { ClassifyAnalyticsEngine, } from '@memberjunction/tag-engine-base';
|
|
15
|
+
import { formatNumber, formatShortDate } from '../shared/classify.format';
|
|
16
|
+
import * as i0 from "@angular/core";
|
|
17
|
+
import * as i1 from "@memberjunction/ng-shared-generic";
|
|
18
|
+
const _forTrack0 = ($index, $item) => $item.Tag;
|
|
19
|
+
const _forTrack1 = ($index, $item) => $item.Label;
|
|
20
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
21
|
+
i0.ɵɵelement(0, "mj-loading", 1);
|
|
22
|
+
} }
|
|
23
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
24
|
+
i0.ɵɵelementStart(0, "div", 2);
|
|
25
|
+
i0.ɵɵelement(1, "i", 4);
|
|
26
|
+
i0.ɵɵelementStart(2, "p");
|
|
27
|
+
i0.ɵɵtext(3, "No classification data yet. Run the pipeline to populate analytics.");
|
|
28
|
+
i0.ɵɵelementEnd()();
|
|
29
|
+
} }
|
|
30
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
+
i0.ɵɵelementStart(0, "p", 8);
|
|
32
|
+
i0.ɵɵtext(1, "No tags in scope.");
|
|
33
|
+
i0.ɵɵelementEnd();
|
|
34
|
+
} }
|
|
35
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_6_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
36
|
+
i0.ɵɵelementStart(0, "div", 12)(1, "span", 13);
|
|
37
|
+
i0.ɵɵtext(2);
|
|
38
|
+
i0.ɵɵelementEnd();
|
|
39
|
+
i0.ɵɵelementStart(3, "div", 14);
|
|
40
|
+
i0.ɵɵelement(4, "div", 15);
|
|
41
|
+
i0.ɵɵelementEnd();
|
|
42
|
+
i0.ɵɵelementStart(5, "span", 16);
|
|
43
|
+
i0.ɵɵtext(6);
|
|
44
|
+
i0.ɵɵelementEnd()();
|
|
45
|
+
} if (rf & 2) {
|
|
46
|
+
const bar_r1 = ctx.$implicit;
|
|
47
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
48
|
+
i0.ɵɵadvance();
|
|
49
|
+
i0.ɵɵproperty("title", bar_r1.Tag);
|
|
50
|
+
i0.ɵɵadvance();
|
|
51
|
+
i0.ɵɵtextInterpolate(bar_r1.Tag);
|
|
52
|
+
i0.ɵɵadvance(2);
|
|
53
|
+
i0.ɵɵstyleProp("width", bar_r1.WidthPct, "%");
|
|
54
|
+
i0.ɵɵadvance(2);
|
|
55
|
+
i0.ɵɵtextInterpolate(ctx_r1.FormatNumber(bar_r1.Count));
|
|
56
|
+
} }
|
|
57
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
58
|
+
i0.ɵɵelementStart(0, "div", 9);
|
|
59
|
+
i0.ɵɵrepeaterCreate(1, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_6_For_2_Template, 7, 5, "div", 12, _forTrack0);
|
|
60
|
+
i0.ɵɵelementEnd();
|
|
61
|
+
} if (rf & 2) {
|
|
62
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
63
|
+
i0.ɵɵadvance();
|
|
64
|
+
i0.ɵɵrepeater(ctx_r1.DistributionBars);
|
|
65
|
+
} }
|
|
66
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
67
|
+
i0.ɵɵelementStart(0, "p", 8);
|
|
68
|
+
i0.ɵɵtext(1, "No time-series data in scope.");
|
|
69
|
+
i0.ɵɵelementEnd();
|
|
70
|
+
} }
|
|
71
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_12_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
72
|
+
i0.ɵɵnamespaceSVG();
|
|
73
|
+
i0.ɵɵelementStart(0, "circle", 19)(1, "title");
|
|
74
|
+
i0.ɵɵtext(2);
|
|
75
|
+
i0.ɵɵelementEnd()();
|
|
76
|
+
} if (rf & 2) {
|
|
77
|
+
const pt_r3 = ctx.$implicit;
|
|
78
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
79
|
+
i0.ɵɵattribute("cx", pt_r3.X)("cy", pt_r3.Y);
|
|
80
|
+
i0.ɵɵadvance(2);
|
|
81
|
+
i0.ɵɵtextInterpolate2("", pt_r3.Label, ": ", ctx_r1.FormatNumber(pt_r3.Count));
|
|
82
|
+
} }
|
|
83
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
+
i0.ɵɵnamespaceSVG();
|
|
85
|
+
i0.ɵɵelementStart(0, "svg", 17);
|
|
86
|
+
i0.ɵɵelement(1, "path", 18);
|
|
87
|
+
i0.ɵɵrepeaterCreate(2, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_12_For_3_Template, 3, 4, ":svg:circle", 19, _forTrack1);
|
|
88
|
+
i0.ɵɵelementEnd();
|
|
89
|
+
i0.ɵɵnamespaceHTML();
|
|
90
|
+
i0.ɵɵelementStart(4, "div", 20)(5, "span");
|
|
91
|
+
i0.ɵɵtext(6);
|
|
92
|
+
i0.ɵɵelementEnd();
|
|
93
|
+
i0.ɵɵelementStart(7, "span");
|
|
94
|
+
i0.ɵɵtext(8);
|
|
95
|
+
i0.ɵɵelementEnd()();
|
|
96
|
+
} if (rf & 2) {
|
|
97
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
98
|
+
i0.ɵɵattribute("viewBox", "0 0 " + ctx_r1.LineWidth + " " + ctx_r1.LineHeight);
|
|
99
|
+
i0.ɵɵadvance();
|
|
100
|
+
i0.ɵɵattribute("d", ctx_r1.LinePath);
|
|
101
|
+
i0.ɵɵadvance();
|
|
102
|
+
i0.ɵɵrepeater(ctx_r1.LinePoints);
|
|
103
|
+
i0.ɵɵadvance(4);
|
|
104
|
+
i0.ɵɵtextInterpolate(ctx_r1.LinePoints[0].Label);
|
|
105
|
+
i0.ɵɵadvance(2);
|
|
106
|
+
i0.ɵɵtextInterpolate(ctx_r1.LinePoints[ctx_r1.LinePoints.length - 1].Label);
|
|
107
|
+
} }
|
|
108
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
109
|
+
i0.ɵɵelementStart(0, "p", 8);
|
|
110
|
+
i0.ɵɵtext(1, "No weighted tags in scope.");
|
|
111
|
+
i0.ɵɵelementEnd();
|
|
112
|
+
} }
|
|
113
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_18_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
114
|
+
i0.ɵɵelementStart(0, "div", 22);
|
|
115
|
+
i0.ɵɵelement(1, "div", 24);
|
|
116
|
+
i0.ɵɵelementStart(2, "span", 25);
|
|
117
|
+
i0.ɵɵtext(3);
|
|
118
|
+
i0.ɵɵelementEnd()();
|
|
119
|
+
} if (rf & 2) {
|
|
120
|
+
const hbar_r4 = ctx.$implicit;
|
|
121
|
+
i0.ɵɵproperty("title", hbar_r4.Label + "% confidence: " + hbar_r4.Count);
|
|
122
|
+
i0.ɵɵadvance();
|
|
123
|
+
i0.ɵɵstyleProp("height", hbar_r4.HeightPct, "%");
|
|
124
|
+
i0.ɵɵadvance(2);
|
|
125
|
+
i0.ɵɵtextInterpolate(hbar_r4.Label);
|
|
126
|
+
} }
|
|
127
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
128
|
+
i0.ɵɵelementStart(0, "div", 21);
|
|
129
|
+
i0.ɵɵrepeaterCreate(1, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_18_For_2_Template, 4, 4, "div", 22, _forTrack1);
|
|
130
|
+
i0.ɵɵelementEnd();
|
|
131
|
+
i0.ɵɵelementStart(3, "div", 23);
|
|
132
|
+
i0.ɵɵtext(4, "Tag weight / confidence (%)");
|
|
133
|
+
i0.ɵɵelementEnd();
|
|
134
|
+
} if (rf & 2) {
|
|
135
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
136
|
+
i0.ɵɵadvance();
|
|
137
|
+
i0.ɵɵrepeater(ctx_r1.HistogramBars);
|
|
138
|
+
} }
|
|
139
|
+
function ClassifyOverviewAnalyticsComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
140
|
+
i0.ɵɵelementStart(0, "div", 3)(1, "div", 5)(2, "h4", 6);
|
|
141
|
+
i0.ɵɵelement(3, "i", 7);
|
|
142
|
+
i0.ɵɵtext(4, " Top Tags");
|
|
143
|
+
i0.ɵɵelementEnd();
|
|
144
|
+
i0.ɵɵconditionalCreate(5, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_5_Template, 2, 0, "p", 8)(6, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_6_Template, 3, 0, "div", 9);
|
|
145
|
+
i0.ɵɵelementEnd();
|
|
146
|
+
i0.ɵɵelementStart(7, "div", 5)(8, "h4", 6);
|
|
147
|
+
i0.ɵɵelement(9, "i", 10);
|
|
148
|
+
i0.ɵɵtext(10, " Tags Over Time");
|
|
149
|
+
i0.ɵɵelementEnd();
|
|
150
|
+
i0.ɵɵconditionalCreate(11, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_11_Template, 2, 0, "p", 8)(12, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_12_Template, 9, 4);
|
|
151
|
+
i0.ɵɵelementEnd();
|
|
152
|
+
i0.ɵɵelementStart(13, "div", 5)(14, "h4", 6);
|
|
153
|
+
i0.ɵɵelement(15, "i", 11);
|
|
154
|
+
i0.ɵɵtext(16, " Confidence Distribution");
|
|
155
|
+
i0.ɵɵelementEnd();
|
|
156
|
+
i0.ɵɵconditionalCreate(17, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_17_Template, 2, 0, "p", 8)(18, ClassifyOverviewAnalyticsComponent_Conditional_3_Conditional_18_Template, 5, 0);
|
|
157
|
+
i0.ɵɵelementEnd()();
|
|
158
|
+
} if (rf & 2) {
|
|
159
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
160
|
+
i0.ɵɵadvance(5);
|
|
161
|
+
i0.ɵɵconditional(ctx_r1.DistributionBars.length === 0 ? 5 : 6);
|
|
162
|
+
i0.ɵɵadvance(6);
|
|
163
|
+
i0.ɵɵconditional(ctx_r1.LinePoints.length === 0 ? 11 : 12);
|
|
164
|
+
i0.ɵɵadvance(6);
|
|
165
|
+
i0.ɵɵconditional(ctx_r1.HistogramBars.length === 0 ? 17 : 18);
|
|
166
|
+
} }
|
|
167
|
+
export class ClassifyOverviewAnalyticsComponent extends BaseAngularComponent {
|
|
168
|
+
cdr = inject(ChangeDetectorRef);
|
|
169
|
+
async ngAfterViewInit() {
|
|
170
|
+
await this.Reload();
|
|
171
|
+
}
|
|
172
|
+
/** Number of distinct tags shown in the distribution chart. */
|
|
173
|
+
static TAG_DISTRIBUTION_LIMIT = 12;
|
|
174
|
+
/** Line-chart viewBox geometry. */
|
|
175
|
+
static LINE_WIDTH = 600;
|
|
176
|
+
static LINE_HEIGHT = 160;
|
|
177
|
+
static LINE_PAD = 8;
|
|
178
|
+
/** Optional analytics scope (source / content-type / date range). Re-loads on change. */
|
|
179
|
+
_scope = null;
|
|
180
|
+
set Scope(value) {
|
|
181
|
+
this._scope = value;
|
|
182
|
+
if (this._loadedOnce)
|
|
183
|
+
void this.Reload();
|
|
184
|
+
}
|
|
185
|
+
get Scope() {
|
|
186
|
+
return this._scope;
|
|
187
|
+
}
|
|
188
|
+
IsLoading = false;
|
|
189
|
+
HasData = false;
|
|
190
|
+
KPIs = { TotalItems: 0, TotalTags: 0, AvgTagsPerItem: 0, DistinctTags: 0 };
|
|
191
|
+
DistributionBars = [];
|
|
192
|
+
LinePoints = [];
|
|
193
|
+
LinePath = '';
|
|
194
|
+
HistogramBars = [];
|
|
195
|
+
// Template-facing formatters + geometry constants
|
|
196
|
+
FormatNumber = formatNumber;
|
|
197
|
+
LineWidth = ClassifyOverviewAnalyticsComponent.LINE_WIDTH;
|
|
198
|
+
LineHeight = ClassifyOverviewAnalyticsComponent.LINE_HEIGHT;
|
|
199
|
+
_loadedOnce = false;
|
|
200
|
+
/** Load (or reload) all analytics for the current scope. Public entry point for the parent. */
|
|
201
|
+
async Reload() {
|
|
202
|
+
this.IsLoading = true;
|
|
203
|
+
this.cdr.detectChanges();
|
|
204
|
+
const engine = ClassifyAnalyticsEngine.Instance;
|
|
205
|
+
const scope = this._scope ?? undefined;
|
|
206
|
+
const user = this.ProviderToUse.CurrentUser;
|
|
207
|
+
const provider = this.ProviderToUse;
|
|
208
|
+
const [kpis, distribution, overTime, histogram] = await Promise.all([
|
|
209
|
+
engine.GetKPIs(scope, user, provider),
|
|
210
|
+
engine.GetTagDistribution(scope, user, provider, ClassifyOverviewAnalyticsComponent.TAG_DISTRIBUTION_LIMIT),
|
|
211
|
+
engine.GetItemsOverTime('day', scope, user, provider),
|
|
212
|
+
engine.GetWeightHistogram(10, scope, user, provider),
|
|
213
|
+
]);
|
|
214
|
+
this.KPIs = kpis;
|
|
215
|
+
this.buildDistribution(distribution);
|
|
216
|
+
this.buildOverTime(overTime);
|
|
217
|
+
this.buildHistogram(histogram);
|
|
218
|
+
this.HasData = kpis.TotalTags > 0 || kpis.TotalItems > 0;
|
|
219
|
+
this._loadedOnce = true;
|
|
220
|
+
this.IsLoading = false;
|
|
221
|
+
this.cdr.detectChanges();
|
|
222
|
+
}
|
|
223
|
+
buildDistribution(entries) {
|
|
224
|
+
const max = entries.reduce((m, e) => Math.max(m, e.Count), 0) || 1;
|
|
225
|
+
this.DistributionBars = entries.map(e => ({
|
|
226
|
+
Tag: e.Tag,
|
|
227
|
+
Count: e.Count,
|
|
228
|
+
WidthPct: Math.round((e.Count / max) * 100),
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
buildOverTime(buckets) {
|
|
232
|
+
if (buckets.length === 0) {
|
|
233
|
+
this.LinePoints = [];
|
|
234
|
+
this.LinePath = '';
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const w = ClassifyOverviewAnalyticsComponent.LINE_WIDTH;
|
|
238
|
+
const h = ClassifyOverviewAnalyticsComponent.LINE_HEIGHT;
|
|
239
|
+
const pad = ClassifyOverviewAnalyticsComponent.LINE_PAD;
|
|
240
|
+
const max = buckets.reduce((m, b) => Math.max(m, b.Count), 0) || 1;
|
|
241
|
+
const innerW = w - pad * 2;
|
|
242
|
+
const innerH = h - pad * 2;
|
|
243
|
+
const stepX = buckets.length > 1 ? innerW / (buckets.length - 1) : 0;
|
|
244
|
+
this.LinePoints = buckets.map((b, i) => {
|
|
245
|
+
const x = pad + (buckets.length > 1 ? i * stepX : innerW / 2);
|
|
246
|
+
const y = pad + innerH - (b.Count / max) * innerH;
|
|
247
|
+
return { X: Math.round(x), Y: Math.round(y), Label: formatShortDate(b.BucketStart), Count: b.Count };
|
|
248
|
+
});
|
|
249
|
+
this.LinePath = this.LinePoints
|
|
250
|
+
.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.X},${p.Y}`)
|
|
251
|
+
.join(' ');
|
|
252
|
+
}
|
|
253
|
+
buildHistogram(bins) {
|
|
254
|
+
const max = bins.reduce((m, b) => Math.max(m, b.Count), 0) || 1;
|
|
255
|
+
this.HistogramBars = bins.map(b => ({
|
|
256
|
+
Label: `${Math.round(b.RangeStart * 100)}`,
|
|
257
|
+
Count: b.Count,
|
|
258
|
+
HeightPct: Math.round((b.Count / max) * 100),
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵClassifyOverviewAnalyticsComponent_BaseFactory; return function ClassifyOverviewAnalyticsComponent_Factory(__ngFactoryType__) { return (ɵClassifyOverviewAnalyticsComponent_BaseFactory || (ɵClassifyOverviewAnalyticsComponent_BaseFactory = i0.ɵɵgetInheritedFactory(ClassifyOverviewAnalyticsComponent)))(__ngFactoryType__ || ClassifyOverviewAnalyticsComponent); }; })();
|
|
262
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ClassifyOverviewAnalyticsComponent, selectors: [["classify-overview-analytics"]], inputs: { Scope: "Scope" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 1, consts: [[1, "coa-wrap"], ["text", "Loading analytics...", "size", "small"], [1, "coa-empty"], [1, "coa-charts"], [1, "fa-solid", "fa-chart-pie"], [1, "coa-chart-card"], [1, "coa-chart-title"], [1, "fa-solid", "fa-ranking-star"], [1, "coa-muted"], [1, "coa-bars"], [1, "fa-solid", "fa-chart-line"], [1, "fa-solid", "fa-chart-column"], [1, "coa-bar-row"], [1, "coa-bar-label", 3, "title"], [1, "coa-bar-track"], [1, "coa-bar-fill"], [1, "coa-bar-count"], ["preserveAspectRatio", "none", 1, "coa-line-svg"], ["fill", "none", 1, "coa-line-path"], ["r", "2.5", 1, "coa-line-dot"], [1, "coa-line-axis"], [1, "coa-histogram"], [1, "coa-hbar-col", 3, "title"], [1, "coa-hist-caption"], [1, "coa-hbar-fill"], [1, "coa-hbar-axis"]], template: function ClassifyOverviewAnalyticsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
263
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
264
|
+
i0.ɵɵconditionalCreate(1, ClassifyOverviewAnalyticsComponent_Conditional_1_Template, 1, 0, "mj-loading", 1)(2, ClassifyOverviewAnalyticsComponent_Conditional_2_Template, 4, 0, "div", 2)(3, ClassifyOverviewAnalyticsComponent_Conditional_3_Template, 19, 3, "div", 3);
|
|
265
|
+
i0.ɵɵelementEnd();
|
|
266
|
+
} if (rf & 2) {
|
|
267
|
+
i0.ɵɵadvance();
|
|
268
|
+
i0.ɵɵconditional(ctx.IsLoading ? 1 : !ctx.HasData ? 2 : 3);
|
|
269
|
+
} }, dependencies: [i1.LoadingComponent], styles: [".coa-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n\n\n.coa-kpi-strip[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 12px;\n}\n\n.coa-kpi-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 12px 14px;\n}\n\n.coa-kpi-value[_ngcontent-%COMP%] {\n font-size: 1.6rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n}\n\n.coa-kpi-label[_ngcontent-%COMP%] {\n margin-top: 4px;\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 5px;\n}\n\n.coa-kpi-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n\n\n.coa-charts[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 16px;\n}\n\n.coa-chart-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 12px 14px;\n min-width: 0;\n}\n\n.coa-chart-title[_ngcontent-%COMP%] {\n margin: 0 0 12px 0;\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.coa-chart-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.coa-muted[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.8rem;\n margin: 0;\n}\n\n\n\n.coa-bars[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.coa-bar-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 110px 1fr 48px;\n align-items: center;\n gap: 8px;\n}\n\n.coa-bar-label[_ngcontent-%COMP%] {\n font-size: 0.78rem;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.coa-bar-track[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-sm);\n height: 14px;\n overflow: hidden;\n}\n\n.coa-bar-fill[_ngcontent-%COMP%] {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: var(--mj-radius-sm);\n transition: width 0.3s ease;\n}\n\n.coa-bar-count[_ngcontent-%COMP%] {\n font-size: 0.76rem;\n color: var(--mj-text-muted);\n text-align: right;\n}\n\n\n\n.coa-line-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 160px;\n display: block;\n}\n\n.coa-line-path[_ngcontent-%COMP%] {\n stroke: var(--mj-brand-primary);\n stroke-width: 2;\n vector-effect: non-scaling-stroke;\n}\n\n.coa-line-dot[_ngcontent-%COMP%] {\n fill: var(--mj-brand-primary);\n}\n\n.coa-line-axis[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n margin-top: 4px;\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n\n\n.coa-histogram[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n gap: 4px;\n height: 150px;\n padding-top: 8px;\n}\n\n.coa-hbar-col[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n min-width: 0;\n}\n\n.coa-hbar-fill[_ngcontent-%COMP%] {\n width: 70%;\n min-height: 2px;\n background: var(--mj-brand-primary);\n border-radius: var(--mj-radius-sm) var(--mj-radius-sm) 0 0;\n transition: height 0.3s ease;\n}\n\n.coa-hbar-axis[_ngcontent-%COMP%] {\n margin-top: 4px;\n font-size: 0.66rem;\n color: var(--mj-text-muted);\n}\n\n.coa-hist-caption[_ngcontent-%COMP%] {\n margin-top: 6px;\n text-align: center;\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n\n\n.coa-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.coa-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.8rem;\n color: var(--mj-text-disabled);\n}\n\n.coa-empty[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.85rem;\n}"] });
|
|
270
|
+
}
|
|
271
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClassifyOverviewAnalyticsComponent, [{
|
|
272
|
+
type: Component,
|
|
273
|
+
args: [{ standalone: false, selector: 'classify-overview-analytics', template: "<div class=\"coa-wrap\">\n\n <!-- KPI cards removed: the Pipeline Monitor's top KPI strip is now the single\n canonical headline-metrics row (Active Sources / Content Items / Total Tags /\n Avg Tags per Item / Errors). This section renders charts only, eliminating the\n duplicate \"Content Items\" + \"Total Tags\" cards that previously appeared twice. -->\n\n @if (IsLoading) {\n <mj-loading text=\"Loading analytics...\" size=\"small\"></mj-loading>\n } @else if (!HasData) {\n <div class=\"coa-empty\">\n <i class=\"fa-solid fa-chart-pie\"></i>\n <p>No classification data yet. Run the pipeline to populate analytics.</p>\n </div>\n } @else {\n <div class=\"coa-charts\">\n\n <!-- Tag distribution (horizontal bars) -->\n <div class=\"coa-chart-card\">\n <h4 class=\"coa-chart-title\"><i class=\"fa-solid fa-ranking-star\"></i> Top Tags</h4>\n @if (DistributionBars.length === 0) {\n <p class=\"coa-muted\">No tags in scope.</p>\n } @else {\n <div class=\"coa-bars\">\n @for (bar of DistributionBars; track bar.Tag) {\n <div class=\"coa-bar-row\">\n <span class=\"coa-bar-label\" [title]=\"bar.Tag\">{{ bar.Tag }}</span>\n <div class=\"coa-bar-track\">\n <div class=\"coa-bar-fill\" [style.width.%]=\"bar.WidthPct\"></div>\n </div>\n <span class=\"coa-bar-count\">{{ FormatNumber(bar.Count) }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Items over time (line) -->\n <div class=\"coa-chart-card\">\n <h4 class=\"coa-chart-title\"><i class=\"fa-solid fa-chart-line\"></i> Tags Over Time</h4>\n @if (LinePoints.length === 0) {\n <p class=\"coa-muted\">No time-series data in scope.</p>\n } @else {\n <svg class=\"coa-line-svg\" [attr.viewBox]=\"'0 0 ' + LineWidth + ' ' + LineHeight\" preserveAspectRatio=\"none\">\n <path class=\"coa-line-path\" [attr.d]=\"LinePath\" fill=\"none\" />\n @for (pt of LinePoints; track pt.Label) {\n <circle class=\"coa-line-dot\" [attr.cx]=\"pt.X\" [attr.cy]=\"pt.Y\" r=\"2.5\">\n <title>{{ pt.Label }}: {{ FormatNumber(pt.Count) }}</title>\n </circle>\n }\n </svg>\n <div class=\"coa-line-axis\">\n <span>{{ LinePoints[0].Label }}</span>\n <span>{{ LinePoints[LinePoints.length - 1].Label }}</span>\n </div>\n }\n </div>\n\n <!-- Weight histogram (vertical bars) -->\n <div class=\"coa-chart-card\">\n <h4 class=\"coa-chart-title\"><i class=\"fa-solid fa-chart-column\"></i> Confidence Distribution</h4>\n @if (HistogramBars.length === 0) {\n <p class=\"coa-muted\">No weighted tags in scope.</p>\n } @else {\n <div class=\"coa-histogram\">\n @for (hbar of HistogramBars; track hbar.Label) {\n <div class=\"coa-hbar-col\" [title]=\"hbar.Label + '% confidence: ' + hbar.Count\">\n <div class=\"coa-hbar-fill\" [style.height.%]=\"hbar.HeightPct\"></div>\n <span class=\"coa-hbar-axis\">{{ hbar.Label }}</span>\n </div>\n }\n </div>\n <div class=\"coa-hist-caption\">Tag weight / confidence (%)</div>\n }\n </div>\n\n </div>\n }\n</div>\n", styles: [".coa-wrap {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* KPI cards */\n.coa-kpi-strip {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 12px;\n}\n\n.coa-kpi-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 12px 14px;\n}\n\n.coa-kpi-value {\n font-size: 1.6rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.1;\n}\n\n.coa-kpi-label {\n margin-top: 4px;\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n display: flex;\n align-items: center;\n gap: 5px;\n}\n\n.coa-kpi-label i {\n color: var(--mj-brand-primary);\n}\n\n/* Chart grid */\n.coa-charts {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 16px;\n}\n\n.coa-chart-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n padding: 12px 14px;\n min-width: 0;\n}\n\n.coa-chart-title {\n margin: 0 0 12px 0;\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.coa-chart-title i {\n color: var(--mj-brand-primary);\n}\n\n.coa-muted {\n color: var(--mj-text-muted);\n font-size: 0.8rem;\n margin: 0;\n}\n\n/* Tag distribution bars */\n.coa-bars {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.coa-bar-row {\n display: grid;\n grid-template-columns: 110px 1fr 48px;\n align-items: center;\n gap: 8px;\n}\n\n.coa-bar-label {\n font-size: 0.78rem;\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.coa-bar-track {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-sm);\n height: 14px;\n overflow: hidden;\n}\n\n.coa-bar-fill {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: var(--mj-radius-sm);\n transition: width 0.3s ease;\n}\n\n.coa-bar-count {\n font-size: 0.76rem;\n color: var(--mj-text-muted);\n text-align: right;\n}\n\n/* Line chart */\n.coa-line-svg {\n width: 100%;\n height: 160px;\n display: block;\n}\n\n.coa-line-path {\n stroke: var(--mj-brand-primary);\n stroke-width: 2;\n vector-effect: non-scaling-stroke;\n}\n\n.coa-line-dot {\n fill: var(--mj-brand-primary);\n}\n\n.coa-line-axis {\n display: flex;\n justify-content: space-between;\n margin-top: 4px;\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n/* Histogram */\n.coa-histogram {\n display: flex;\n align-items: flex-end;\n gap: 4px;\n height: 150px;\n padding-top: 8px;\n}\n\n.coa-hbar-col {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n min-width: 0;\n}\n\n.coa-hbar-fill {\n width: 70%;\n min-height: 2px;\n background: var(--mj-brand-primary);\n border-radius: var(--mj-radius-sm) var(--mj-radius-sm) 0 0;\n transition: height 0.3s ease;\n}\n\n.coa-hbar-axis {\n margin-top: 4px;\n font-size: 0.66rem;\n color: var(--mj-text-muted);\n}\n\n.coa-hist-caption {\n margin-top: 6px;\n text-align: center;\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n/* Empty state */\n.coa-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n\n.coa-empty i {\n font-size: 1.8rem;\n color: var(--mj-text-disabled);\n}\n\n.coa-empty p {\n margin: 0;\n font-size: 0.85rem;\n}\n"] }]
|
|
274
|
+
}], null, { Scope: [{
|
|
275
|
+
type: Input
|
|
276
|
+
}] }); })();
|
|
277
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ClassifyOverviewAnalyticsComponent, { className: "ClassifyOverviewAnalyticsComponent", filePath: "src/AI/components/autotagging/components/classify-overview-analytics.component.ts", lineNumber: 58 }); })();
|
|
278
|
+
//# sourceMappingURL=classify-overview-analytics.component.js.map
|
package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify-overview-analytics.component.js","sourceRoot":"","sources":["../../../../../src/AI/components/autotagging/components/classify-overview-analytics.component.ts","../../../../../src/AI/components/autotagging/components/classify-overview-analytics.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Classify · Overview Analytics (Phase 4 audit/analytics).\n *\n * KPI cards + three hand-rolled inline-SVG charts (tag distribution bar,\n * items-over-time line, weight histogram) for the classify dataset. All numbers\n * come from `ClassifyAnalyticsEngine` so agents and UI share one source of truth.\n *\n * The engine is framework-agnostic (server + client safe); this component simply\n * calls it with the current scope and the active metadata provider. Charts are\n * SVG built from typed view models — NO charting library.\n */\nimport {\n Component,\n Input,\n AfterViewInit,\n ChangeDetectorRef,\n inject,\n} from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport {\n ClassifyAnalyticsEngine,\n ClassifyAnalyticsScope,\n ClassifyKPIs,\n TagDistributionEntry,\n ItemsOverTimeBucket,\n WeightHistogramBin,\n} from '@memberjunction/tag-engine-base';\nimport { formatNumber, formatShortDate } from '../shared/classify.format';\n\n/** A bar in the tag-distribution chart, pre-scaled to the chart width. */\ninterface DistributionBar {\n Tag: string;\n Count: number;\n WidthPct: number;\n}\n\n/** A point in the items-over-time line chart, in SVG coordinate space. */\ninterface LinePoint {\n X: number;\n Y: number;\n Label: string;\n Count: number;\n}\n\n/** A bar in the weight histogram, pre-scaled to the chart height. */\ninterface HistogramBar {\n Label: string;\n Count: number;\n HeightPct: number;\n}\n\n@Component({\n standalone: false,\n selector: 'classify-overview-analytics',\n templateUrl: './classify-overview-analytics.component.html',\n styleUrls: ['./classify-overview-analytics.component.css'],\n})\nexport class ClassifyOverviewAnalyticsComponent extends BaseAngularComponent implements AfterViewInit {\n private cdr = inject(ChangeDetectorRef);\n\n async ngAfterViewInit(): Promise<void> {\n await this.Reload();\n }\n\n /** Number of distinct tags shown in the distribution chart. */\n private static readonly TAG_DISTRIBUTION_LIMIT = 12;\n /** Line-chart viewBox geometry. */\n private static readonly LINE_WIDTH = 600;\n private static readonly LINE_HEIGHT = 160;\n private static readonly LINE_PAD = 8;\n\n /** Optional analytics scope (source / content-type / date range). Re-loads on change. */\n private _scope: ClassifyAnalyticsScope | null = null;\n @Input()\n set Scope(value: ClassifyAnalyticsScope | null) {\n this._scope = value;\n if (this._loadedOnce) void this.Reload();\n }\n get Scope(): ClassifyAnalyticsScope | null {\n return this._scope;\n }\n\n public IsLoading = false;\n public HasData = false;\n\n public KPIs: ClassifyKPIs = { TotalItems: 0, TotalTags: 0, AvgTagsPerItem: 0, DistinctTags: 0 };\n\n public DistributionBars: DistributionBar[] = [];\n public LinePoints: LinePoint[] = [];\n public LinePath = '';\n public HistogramBars: HistogramBar[] = [];\n\n // Template-facing formatters + geometry constants\n public readonly FormatNumber = formatNumber;\n public readonly LineWidth = ClassifyOverviewAnalyticsComponent.LINE_WIDTH;\n public readonly LineHeight = ClassifyOverviewAnalyticsComponent.LINE_HEIGHT;\n\n private _loadedOnce = false;\n\n /** Load (or reload) all analytics for the current scope. Public entry point for the parent. */\n public async Reload(): Promise<void> {\n this.IsLoading = true;\n this.cdr.detectChanges();\n\n const engine = ClassifyAnalyticsEngine.Instance;\n const scope = this._scope ?? undefined;\n const user = this.ProviderToUse.CurrentUser;\n const provider = this.ProviderToUse;\n\n const [kpis, distribution, overTime, histogram] = await Promise.all([\n engine.GetKPIs(scope, user, provider),\n engine.GetTagDistribution(scope, user, provider, ClassifyOverviewAnalyticsComponent.TAG_DISTRIBUTION_LIMIT),\n engine.GetItemsOverTime('day', scope, user, provider),\n engine.GetWeightHistogram(10, scope, user, provider),\n ]);\n\n this.KPIs = kpis;\n this.buildDistribution(distribution);\n this.buildOverTime(overTime);\n this.buildHistogram(histogram);\n this.HasData = kpis.TotalTags > 0 || kpis.TotalItems > 0;\n\n this._loadedOnce = true;\n this.IsLoading = false;\n this.cdr.detectChanges();\n }\n\n private buildDistribution(entries: TagDistributionEntry[]): void {\n const max = entries.reduce((m, e) => Math.max(m, e.Count), 0) || 1;\n this.DistributionBars = entries.map(e => ({\n Tag: e.Tag,\n Count: e.Count,\n WidthPct: Math.round((e.Count / max) * 100),\n }));\n }\n\n private buildOverTime(buckets: ItemsOverTimeBucket[]): void {\n if (buckets.length === 0) {\n this.LinePoints = [];\n this.LinePath = '';\n return;\n }\n\n const w = ClassifyOverviewAnalyticsComponent.LINE_WIDTH;\n const h = ClassifyOverviewAnalyticsComponent.LINE_HEIGHT;\n const pad = ClassifyOverviewAnalyticsComponent.LINE_PAD;\n const max = buckets.reduce((m, b) => Math.max(m, b.Count), 0) || 1;\n const innerW = w - pad * 2;\n const innerH = h - pad * 2;\n const stepX = buckets.length > 1 ? innerW / (buckets.length - 1) : 0;\n\n this.LinePoints = buckets.map((b, i) => {\n const x = pad + (buckets.length > 1 ? i * stepX : innerW / 2);\n const y = pad + innerH - (b.Count / max) * innerH;\n return { X: Math.round(x), Y: Math.round(y), Label: formatShortDate(b.BucketStart), Count: b.Count };\n });\n\n this.LinePath = this.LinePoints\n .map((p, i) => `${i === 0 ? 'M' : 'L'}${p.X},${p.Y}`)\n .join(' ');\n }\n\n private buildHistogram(bins: WeightHistogramBin[]): void {\n const max = bins.reduce((m, b) => Math.max(m, b.Count), 0) || 1;\n this.HistogramBars = bins.map(b => ({\n Label: `${Math.round(b.RangeStart * 100)}`,\n Count: b.Count,\n HeightPct: Math.round((b.Count / max) * 100),\n }));\n }\n}\n","<div class=\"coa-wrap\">\n\n <!-- KPI cards removed: the Pipeline Monitor's top KPI strip is now the single\n canonical headline-metrics row (Active Sources / Content Items / Total Tags /\n Avg Tags per Item / Errors). This section renders charts only, eliminating the\n duplicate \"Content Items\" + \"Total Tags\" cards that previously appeared twice. -->\n\n @if (IsLoading) {\n <mj-loading text=\"Loading analytics...\" size=\"small\"></mj-loading>\n } @else if (!HasData) {\n <div class=\"coa-empty\">\n <i class=\"fa-solid fa-chart-pie\"></i>\n <p>No classification data yet. Run the pipeline to populate analytics.</p>\n </div>\n } @else {\n <div class=\"coa-charts\">\n\n <!-- Tag distribution (horizontal bars) -->\n <div class=\"coa-chart-card\">\n <h4 class=\"coa-chart-title\"><i class=\"fa-solid fa-ranking-star\"></i> Top Tags</h4>\n @if (DistributionBars.length === 0) {\n <p class=\"coa-muted\">No tags in scope.</p>\n } @else {\n <div class=\"coa-bars\">\n @for (bar of DistributionBars; track bar.Tag) {\n <div class=\"coa-bar-row\">\n <span class=\"coa-bar-label\" [title]=\"bar.Tag\">{{ bar.Tag }}</span>\n <div class=\"coa-bar-track\">\n <div class=\"coa-bar-fill\" [style.width.%]=\"bar.WidthPct\"></div>\n </div>\n <span class=\"coa-bar-count\">{{ FormatNumber(bar.Count) }}</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Items over time (line) -->\n <div class=\"coa-chart-card\">\n <h4 class=\"coa-chart-title\"><i class=\"fa-solid fa-chart-line\"></i> Tags Over Time</h4>\n @if (LinePoints.length === 0) {\n <p class=\"coa-muted\">No time-series data in scope.</p>\n } @else {\n <svg class=\"coa-line-svg\" [attr.viewBox]=\"'0 0 ' + LineWidth + ' ' + LineHeight\" preserveAspectRatio=\"none\">\n <path class=\"coa-line-path\" [attr.d]=\"LinePath\" fill=\"none\" />\n @for (pt of LinePoints; track pt.Label) {\n <circle class=\"coa-line-dot\" [attr.cx]=\"pt.X\" [attr.cy]=\"pt.Y\" r=\"2.5\">\n <title>{{ pt.Label }}: {{ FormatNumber(pt.Count) }}</title>\n </circle>\n }\n </svg>\n <div class=\"coa-line-axis\">\n <span>{{ LinePoints[0].Label }}</span>\n <span>{{ LinePoints[LinePoints.length - 1].Label }}</span>\n </div>\n }\n </div>\n\n <!-- Weight histogram (vertical bars) -->\n <div class=\"coa-chart-card\">\n <h4 class=\"coa-chart-title\"><i class=\"fa-solid fa-chart-column\"></i> Confidence Distribution</h4>\n @if (HistogramBars.length === 0) {\n <p class=\"coa-muted\">No weighted tags in scope.</p>\n } @else {\n <div class=\"coa-histogram\">\n @for (hbar of HistogramBars; track hbar.Label) {\n <div class=\"coa-hbar-col\" [title]=\"hbar.Label + '% confidence: ' + hbar.Count\">\n <div class=\"coa-hbar-fill\" [style.height.%]=\"hbar.HeightPct\"></div>\n <span class=\"coa-hbar-axis\">{{ hbar.Label }}</span>\n </div>\n }\n </div>\n <div class=\"coa-hist-caption\">Tag weight / confidence (%)</div>\n }\n </div>\n\n </div>\n }\n</div>\n"]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Classify · Seed-taxonomy review.
|
|
3
|
+
*
|
|
4
|
+
* Calls the server-side `GenerateSeedTaxonomy` GraphQL mutation (which samples a
|
|
5
|
+
* source's content and proposes a tag tree), renders the proposal as a checkbox
|
|
6
|
+
* tree with inline rename, and — on Accept — persists the selected nodes as
|
|
7
|
+
* `MJ: Tags` (parent/child wired via ParentID). Used standalone on the Tags /
|
|
8
|
+
* Taxonomy area and embedded inside the setup wizard's Taxonomy step.
|
|
9
|
+
*
|
|
10
|
+
* The mutation is invoked through the first-class transport helper
|
|
11
|
+
* `GraphQLClassifyClient` (constructed from the threaded `ProviderToUse`,
|
|
12
|
+
* narrowed to the concrete `GraphQLDataProvider` it is at runtime), which
|
|
13
|
+
* returns a strongly-typed `SeedTaxonomyResult` — no inline GraphQL or manual
|
|
14
|
+
* JSON parsing in the component.
|
|
15
|
+
*/
|
|
16
|
+
import { EventEmitter } from '@angular/core';
|
|
17
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
18
|
+
import * as i0 from "@angular/core";
|
|
19
|
+
/** Editable view-model node — adds selection + rename + a stable key for tracking. */
|
|
20
|
+
export interface SeedTaxonomyNode {
|
|
21
|
+
Key: string;
|
|
22
|
+
Name: string;
|
|
23
|
+
Description?: string;
|
|
24
|
+
MemberCount?: number;
|
|
25
|
+
Selected: boolean;
|
|
26
|
+
Renaming: boolean;
|
|
27
|
+
Depth: number;
|
|
28
|
+
Children: SeedTaxonomyNode[];
|
|
29
|
+
}
|
|
30
|
+
export declare class ClassifySeedTaxonomyComponent extends BaseAngularComponent {
|
|
31
|
+
private cdr;
|
|
32
|
+
/** The content source to sample for the taxonomy proposal. */
|
|
33
|
+
SourceID: string | null;
|
|
34
|
+
/** How many items to sample (passed to the mutation). */
|
|
35
|
+
SampleSize: number;
|
|
36
|
+
/** Optional parent tag ID under which accepted root nodes are created. */
|
|
37
|
+
ParentTagID: string | null;
|
|
38
|
+
/** Emitted after Accept persists tags, with the count created. */
|
|
39
|
+
Accepted: EventEmitter<{
|
|
40
|
+
Created: number;
|
|
41
|
+
}>;
|
|
42
|
+
IsGenerating: boolean;
|
|
43
|
+
IsAccepting: boolean;
|
|
44
|
+
ProposedNodes: SeedTaxonomyNode[];
|
|
45
|
+
HasGenerated: boolean;
|
|
46
|
+
LastMethod: string | null;
|
|
47
|
+
LastSampleSize: number | null;
|
|
48
|
+
private keySeq;
|
|
49
|
+
/** True when at least one node is checked. */
|
|
50
|
+
get HasSelection(): boolean;
|
|
51
|
+
/** Count of currently-selected nodes (template-facing). */
|
|
52
|
+
get SelectedCount(): number;
|
|
53
|
+
private countSelected;
|
|
54
|
+
/** Call the GenerateSeedTaxonomy mutation and render the proposal. */
|
|
55
|
+
Generate(): Promise<void>;
|
|
56
|
+
private toViewModel;
|
|
57
|
+
/** Toggle a node's selection, cascading to descendants. */
|
|
58
|
+
ToggleNode(node: SeedTaxonomyNode): void;
|
|
59
|
+
private setSelectedRecursive;
|
|
60
|
+
StartRename(node: SeedTaxonomyNode): void;
|
|
61
|
+
CommitRename(node: SeedTaxonomyNode, value: string): void;
|
|
62
|
+
/** Flatten the visible tree for the template (depth-first), preserving order. */
|
|
63
|
+
get FlatNodes(): SeedTaxonomyNode[];
|
|
64
|
+
/**
|
|
65
|
+
* Persist every selected node as an `MJ: Tags` record. Parent/child links use
|
|
66
|
+
* ParentID; root nodes use the optional ParentTagID input. Walks the tree
|
|
67
|
+
* top-down so a parent's saved ID is available when creating its children.
|
|
68
|
+
*/
|
|
69
|
+
AcceptSelected(): Promise<void>;
|
|
70
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ClassifySeedTaxonomyComponent, never>;
|
|
71
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ClassifySeedTaxonomyComponent, "classify-seed-taxonomy", never, { "SourceID": { "alias": "SourceID"; "required": false; }; "SampleSize": { "alias": "SampleSize"; "required": false; }; "ParentTagID": { "alias": "ParentTagID"; "required": false; }; }, { "Accepted": "Accepted"; }, never, never, false, never>;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=classify-seed-taxonomy.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify-seed-taxonomy.component.d.ts","sourceRoot":"","sources":["../../../../../src/AI/components/autotagging/components/classify-seed-taxonomy.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAgC,YAAY,EAAyB,MAAM,eAAe,CAAC;AAClG,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAUrE,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,qBAMa,6BAA8B,SAAQ,oBAAoB;IACnE,OAAO,CAAC,GAAG,CAA6B;IAExC,8DAA8D;IACrD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IACxC,yDAAyD;IAChD,UAAU,SAAM;IACzB,0EAA0E;IACjE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE3C,kEAAkE;IACxD,QAAQ;iBAA+B,MAAM;OAAM;IAEtD,YAAY,UAAS;IACrB,WAAW,UAAS;IACpB,aAAa,EAAE,gBAAgB,EAAE,CAAM;IACvC,YAAY,UAAS;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE5C,OAAO,CAAC,MAAM,CAAK;IAEnB,8CAA8C;IAC9C,IAAW,YAAY,IAAI,OAAO,CAEjC;IAED,2DAA2D;IAC3D,IAAW,aAAa,IAAI,MAAM,CAEjC;IAED,OAAO,CAAC,aAAa;IASrB,sEAAsE;IACzD,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCtC,OAAO,CAAC,WAAW;IAenB,2DAA2D;IACpD,UAAU,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAM/C,OAAO,CAAC,oBAAoB;IAKrB,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAKzC,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAOhE,iFAAiF;IACjF,IAAW,SAAS,IAAI,gBAAgB,EAAE,CAUzC;IAID;;;;OAIG;IACU,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;yCAzInC,6BAA6B;2CAA7B,6BAA6B;CAqMzC"}
|