@memberjunction/ng-dashboards 5.22.0 → 5.23.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/README.md +51 -0
- package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
- package/dist/AI/components/agents/agent-configuration.component.js +364 -362
- package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
- package/dist/AI/components/agents/agent-editor.component.js +2 -2
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +275 -64
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +2645 -436
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +240 -6
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +2166 -256
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +191 -197
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/models/model-management.component.js +9 -8
- package/dist/AI/components/models/model-management.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-management.component.js +305 -299
- package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
- package/dist/AI/components/system/system-configuration.component.js +319 -313
- package/dist/AI/components/system/system-configuration.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +1 -2
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +12 -27
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +10 -12
- package/dist/APIKeys/api-applications-panel.component.js.map +1 -1
- package/dist/APIKeys/api-key-create-dialog.component.js +13 -19
- package/dist/APIKeys/api-key-create-dialog.component.js.map +1 -1
- package/dist/APIKeys/api-key-edit-panel.component.js +12 -14
- package/dist/APIKeys/api-key-edit-panel.component.js.map +1 -1
- package/dist/APIKeys/api-scopes-panel.component.js +61 -68
- package/dist/APIKeys/api-scopes-panel.component.js.map +1 -1
- package/dist/APIKeys/api-usage-panel.component.js +10 -11
- package/dist/APIKeys/api-usage-panel.component.js.map +1 -1
- package/dist/Actions/components/actions-list-view.component.js +82 -96
- package/dist/Actions/components/actions-list-view.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +130 -134
- package/dist/Actions/components/actions-overview.component.js.map +1 -1
- package/dist/Actions/components/categories-list-view.component.d.ts.map +1 -1
- package/dist/Actions/components/categories-list-view.component.js +40 -46
- package/dist/Actions/components/categories-list-view.component.js.map +1 -1
- package/dist/Actions/components/code-management.component.js +2 -2
- package/dist/Actions/components/code-management.component.js.map +1 -1
- package/dist/Actions/components/entity-integration.component.js +2 -2
- package/dist/Actions/components/entity-integration.component.js.map +1 -1
- package/dist/Actions/components/execution-monitoring.component.js +127 -132
- package/dist/Actions/components/execution-monitoring.component.js.map +1 -1
- package/dist/Actions/components/executions-list-view.component.js +2 -2
- package/dist/Actions/components/executions-list-view.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-card.component.js +11 -17
- package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-explorer.component.js +5 -11
- package/dist/Actions/components/explorer/action-explorer.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-list-item.component.js +8 -10
- package/dist/Actions/components/explorer/action-list-item.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-toolbar.component.js +112 -133
- package/dist/Actions/components/explorer/action-toolbar.component.js.map +1 -1
- package/dist/Actions/components/explorer/action-tree-panel.component.js +63 -83
- package/dist/Actions/components/explorer/action-tree-panel.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-action-panel.component.js +17 -21
- package/dist/Actions/components/explorer/new-action-panel.component.js.map +1 -1
- package/dist/Actions/components/explorer/new-category-panel.component.js +17 -21
- package/dist/Actions/components/explorer/new-category-panel.component.js.map +1 -1
- package/dist/Actions/components/scheduled-actions.component.js +2 -2
- package/dist/Actions/components/scheduled-actions.component.js.map +1 -1
- package/dist/Actions/components/security-permissions.component.js +2 -2
- package/dist/Actions/components/security-permissions.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts +13 -5
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +168 -145
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts +4 -5
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +197 -200
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts +5 -7
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +142 -148
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/browser/component-browser.component.js +153 -166
- package/dist/ComponentStudio/components/browser/component-browser.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js +15 -20
- package/dist/ComponentStudio/components/editors/code-editor-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js +16 -21
- package/dist/ComponentStudio/components/editors/data-requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js +18 -23
- package/dist/ComponentStudio/components/editors/requirements-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/editors/spec-editor.component.js +25 -30
- package/dist/ComponentStudio/components/editors/spec-editor.component.js.map +1 -1
- package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js +10 -11
- package/dist/ComponentStudio/components/new-component-dialog/new-component-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js +24 -35
- package/dist/ComponentStudio/components/save-version-dialog/save-version-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/text-import-dialog.component.js +15 -17
- package/dist/ComponentStudio/components/text-import-dialog.component.js.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +7 -6
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +6 -5
- package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +7 -6
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js +9 -9
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js.map +1 -1
- package/dist/Home/home-dashboard.component.js +4 -4
- package/dist/Home/home-dashboard.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +4 -4
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +246 -259
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/widgets/integration-card.component.js +7 -9
- package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
- package/dist/Integration/integration.module.d.ts +6 -10
- package/dist/Integration/integration.module.d.ts.map +1 -1
- package/dist/Integration/integration.module.js +12 -20
- package/dist/Integration/integration.module.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +106 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +607 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +7 -2
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +59 -31
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/index.d.ts +1 -0
- package/dist/KnowledgeHub/index.d.ts.map +1 -1
- package/dist/KnowledgeHub/index.js +1 -0
- package/dist/KnowledgeHub/index.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +9 -7
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +5 -4
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-operations-resource.component.js +10 -9
- package/dist/Lists/components/lists-operations-resource.component.js.map +1 -1
- package/dist/MCP/components/mcp-connection-dialog.component.js +141 -132
- package/dist/MCP/components/mcp-connection-dialog.component.js.map +1 -1
- package/dist/MCP/components/mcp-log-detail-panel.component.js +4 -4
- package/dist/MCP/components/mcp-log-detail-panel.component.js.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +141 -128
- package/dist/MCP/components/mcp-server-dialog.component.js.map +1 -1
- package/dist/MCP/components/mcp-test-tool-dialog.component.js +210 -218
- package/dist/MCP/components/mcp-test-tool-dialog.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +2 -2
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/MCP/mcp.module.d.ts +6 -9
- package/dist/MCP/mcp.module.d.ts.map +1 -1
- package/dist/MCP/mcp.module.js +20 -22
- package/dist/MCP/mcp.module.js.map +1 -1
- package/dist/Scheduling/components/scheduling-activity.component.js +5 -4
- package/dist/Scheduling/components/scheduling-activity.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-jobs.component.js +6 -5
- package/dist/Scheduling/components/scheduling-jobs.component.js.map +1 -1
- package/dist/Scheduling/components/scheduling-overview.component.js +93 -92
- package/dist/Scheduling/components/scheduling-overview.component.js.map +1 -1
- package/dist/Testing/testing-dashboard.component.js +9 -10
- package/dist/Testing/testing-dashboard.component.js.map +1 -1
- package/dist/actions-dashboards.module.d.ts +8 -13
- package/dist/actions-dashboards.module.d.ts.map +1 -1
- package/dist/actions-dashboards.module.js +6 -27
- package/dist/actions-dashboards.module.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +16 -20
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +23 -44
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/communication-dashboards.module.d.ts +4 -8
- package/dist/communication-dashboards.module.d.ts.map +1 -1
- package/dist/communication-dashboards.module.js +0 -19
- package/dist/communication-dashboards.module.js.map +1 -1
- package/dist/component-studio-dashboards.module.d.ts +7 -11
- package/dist/component-studio-dashboards.module.d.ts.map +1 -1
- package/dist/component-studio-dashboards.module.js +22 -34
- package/dist/component-studio-dashboards.module.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +12 -18
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +15 -31
- package/dist/core-dashboards.module.js.map +1 -1
- package/dist/credentials-dashboards.module.d.ts +5 -8
- package/dist/credentials-dashboards.module.d.ts.map +1 -1
- package/dist/credentials-dashboards.module.js +3 -19
- package/dist/credentials-dashboards.module.js.map +1 -1
- package/dist/data-explorer-dashboards.module.d.ts +7 -13
- package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
- package/dist/data-explorer-dashboards.module.js +0 -27
- package/dist/data-explorer-dashboards.module.js.map +1 -1
- package/dist/lists-dashboards.module.d.ts +5 -8
- package/dist/lists-dashboards.module.d.ts.map +1 -1
- package/dist/lists-dashboards.module.js +3 -19
- package/dist/lists-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/dist/scheduling-dashboards.module.d.ts +6 -10
- package/dist/scheduling-dashboards.module.d.ts.map +1 -1
- package/dist/scheduling-dashboards.module.js +3 -23
- package/dist/scheduling-dashboards.module.js.map +1 -1
- package/dist/testing-dashboards.module.d.ts +7 -13
- package/dist/testing-dashboards.module.d.ts.map +1 -1
- package/dist/testing-dashboards.module.js +0 -27
- package/dist/testing-dashboards.module.js.map +1 -1
- package/package.json +47 -55
|
@@ -5,360 +5,2379 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
|
-
* @fileoverview Content Autotagging
|
|
8
|
+
* @fileoverview Content Autotagging Dashboard
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* and
|
|
10
|
+
* Full dashboard for the content autotagging pipeline with left-nav and 5 tabs:
|
|
11
|
+
* Pipeline Monitor, Sources Management, Content Types, Tag Library, Run History.
|
|
12
|
+
* Supports CRUD on sources and content types via slide-in forms,
|
|
13
|
+
* pipeline triggering with real-time GraphQL subscription progress.
|
|
13
14
|
*/
|
|
14
|
-
import { Component, ChangeDetectorRef, inject } from '@angular/core';
|
|
15
|
+
import { Component, ChangeDetectorRef, inject, ViewEncapsulation } from '@angular/core';
|
|
15
16
|
import { Subject } from 'rxjs';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { takeUntil } from 'rxjs/operators';
|
|
18
|
+
import { CompositeKey, Metadata, RunView } from '@memberjunction/core';
|
|
19
|
+
import { KnowledgeHubMetadataEngine } from '@memberjunction/core-entities';
|
|
20
|
+
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
21
|
+
import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';
|
|
22
|
+
import { GraphQLAIClient } from '@memberjunction/graphql-dataprovider';
|
|
23
|
+
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
24
|
+
import { AIEngineBase } from '@memberjunction/ai-engine-base';
|
|
19
25
|
import * as i0 from "@angular/core";
|
|
20
|
-
import * as i1 from "@
|
|
21
|
-
import * as i2 from "@
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
import * as i1 from "@angular/forms";
|
|
27
|
+
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
28
|
+
import * as i3 from "@memberjunction/ng-trees";
|
|
29
|
+
import * as i4 from "@angular/common";
|
|
30
|
+
const _forTrack0 = ($index, $item) => $item.Tab;
|
|
31
|
+
const _forTrack1 = ($index, $item) => $item.Label;
|
|
24
32
|
const _forTrack2 = ($index, $item) => $item.ID;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
const _forTrack3 = ($index, $item) => $item.Tag;
|
|
34
|
+
const _forTrack4 = ($index, $item) => $item.SourceName;
|
|
35
|
+
function AutotaggingPipelineResourceComponent_For_8_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
36
|
+
i0.ɵɵelementStart(0, "span", 14);
|
|
37
|
+
i0.ɵɵtext(1);
|
|
28
38
|
i0.ɵɵelementEnd();
|
|
39
|
+
} if (rf & 2) {
|
|
40
|
+
const item_r2 = i0.ɵɵnextContext().$implicit;
|
|
41
|
+
i0.ɵɵclassProp("at-nav-badge-live", item_r2.BadgeClass === "nav-badge-live");
|
|
42
|
+
i0.ɵɵadvance();
|
|
43
|
+
i0.ɵɵtextInterpolate(item_r2.BadgeText);
|
|
29
44
|
} }
|
|
30
|
-
function
|
|
45
|
+
function AutotaggingPipelineResourceComponent_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
31
46
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
32
|
-
i0.ɵɵelementStart(0, "div",
|
|
33
|
-
i0.ɵɵ
|
|
34
|
-
i0.ɵɵ
|
|
35
|
-
i0.ɵɵtext(
|
|
47
|
+
i0.ɵɵelementStart(0, "div", 7);
|
|
48
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_For_8_Template_div_click_0_listener() { const item_r2 = i0.ɵɵrestoreView(_r1).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.SwitchTab(item_r2.Tab)); });
|
|
49
|
+
i0.ɵɵelement(1, "i");
|
|
50
|
+
i0.ɵɵtext(2);
|
|
51
|
+
i0.ɵɵconditionalCreate(3, AutotaggingPipelineResourceComponent_For_8_Conditional_3_Template, 2, 3, "span", 13);
|
|
36
52
|
i0.ɵɵelementEnd();
|
|
37
|
-
i0.ɵɵelementStart(4, "button", 5);
|
|
38
|
-
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_2_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.RefreshData()); });
|
|
39
|
-
i0.ɵɵelement(5, "i", 6);
|
|
40
|
-
i0.ɵɵtext(6, " Retry ");
|
|
41
|
-
i0.ɵɵelementEnd()();
|
|
42
53
|
} if (rf & 2) {
|
|
43
|
-
const
|
|
44
|
-
i0.ɵɵ
|
|
45
|
-
i0.ɵɵ
|
|
54
|
+
const item_r2 = ctx.$implicit;
|
|
55
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
56
|
+
i0.ɵɵclassProp("active", ctx_r2.ActiveTab === item_r2.Tab);
|
|
57
|
+
i0.ɵɵadvance();
|
|
58
|
+
i0.ɵɵclassMap(item_r2.Icon);
|
|
59
|
+
i0.ɵɵadvance();
|
|
60
|
+
i0.ɵɵtextInterpolate1(" ", item_r2.Label, " ");
|
|
61
|
+
i0.ɵɵadvance();
|
|
62
|
+
i0.ɵɵconditional(item_r2.BadgeText ? 3 : -1);
|
|
46
63
|
} }
|
|
47
|
-
function
|
|
48
|
-
i0.ɵɵ
|
|
49
|
-
i0.ɵɵ
|
|
64
|
+
function AutotaggingPipelineResourceComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
i0.ɵɵelement(0, "i", 15);
|
|
66
|
+
i0.ɵɵtext(1, " Running... ");
|
|
67
|
+
} }
|
|
68
|
+
function AutotaggingPipelineResourceComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
69
|
+
i0.ɵɵelement(0, "i", 16);
|
|
70
|
+
i0.ɵɵtext(1, " Run Pipeline ");
|
|
71
|
+
} }
|
|
72
|
+
function AutotaggingPipelineResourceComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
73
|
+
i0.ɵɵelementStart(0, "div", 12);
|
|
74
|
+
i0.ɵɵelement(1, "mj-loading", 17);
|
|
50
75
|
i0.ɵɵelementEnd();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
i0.ɵɵ
|
|
76
|
+
} }
|
|
77
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_13_Conditional_6_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
78
|
+
i0.ɵɵelement(0, "i", 50);
|
|
79
|
+
} }
|
|
80
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_13_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
81
|
+
i0.ɵɵelementStart(0, "div", 49);
|
|
82
|
+
i0.ɵɵconditionalCreate(1, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_13_Conditional_6_Conditional_1_Template, 1, 0, "i", 50);
|
|
83
|
+
i0.ɵɵtext(2);
|
|
54
84
|
i0.ɵɵelementEnd();
|
|
55
|
-
i0.ɵɵelementStart(7, "span", 30);
|
|
56
|
-
i0.ɵɵtext(8);
|
|
57
|
-
i0.ɵɵelementEnd()()();
|
|
58
85
|
} if (rf & 2) {
|
|
59
|
-
const
|
|
60
|
-
i0.ɵɵ
|
|
61
|
-
i0.ɵɵadvance(
|
|
62
|
-
i0.ɵɵ
|
|
63
|
-
i0.ɵɵadvance(
|
|
64
|
-
i0.ɵɵ
|
|
65
|
-
i0.ɵɵadvance(3);
|
|
66
|
-
i0.ɵɵtextInterpolate(metric_r4.Label);
|
|
86
|
+
const kpi_r5 = i0.ɵɵnextContext().$implicit;
|
|
87
|
+
i0.ɵɵclassProp("up", kpi_r5.TrendUp);
|
|
88
|
+
i0.ɵɵadvance();
|
|
89
|
+
i0.ɵɵconditional(kpi_r5.TrendUp ? 1 : -1);
|
|
90
|
+
i0.ɵɵadvance();
|
|
91
|
+
i0.ɵɵtextInterpolate1(" ", kpi_r5.Trend, " ");
|
|
67
92
|
} }
|
|
68
|
-
function
|
|
69
|
-
i0.ɵɵ
|
|
93
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_13_Template(rf, ctx) { if (rf & 1) {
|
|
94
|
+
i0.ɵɵelementStart(0, "div", 26)(1, "div", 46);
|
|
95
|
+
i0.ɵɵtext(2);
|
|
96
|
+
i0.ɵɵpipe(3, "number");
|
|
97
|
+
i0.ɵɵelementEnd();
|
|
98
|
+
i0.ɵɵelementStart(4, "div", 47);
|
|
99
|
+
i0.ɵɵtext(5);
|
|
100
|
+
i0.ɵɵelementEnd();
|
|
101
|
+
i0.ɵɵconditionalCreate(6, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_13_Conditional_6_Template, 3, 4, "div", 48);
|
|
102
|
+
i0.ɵɵelementEnd();
|
|
70
103
|
} if (rf & 2) {
|
|
71
|
-
const
|
|
72
|
-
i0.ɵɵ
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
i0.ɵɵ
|
|
104
|
+
const kpi_r5 = ctx.$implicit;
|
|
105
|
+
i0.ɵɵadvance();
|
|
106
|
+
i0.ɵɵclassProp("at-kpi-error-value", kpi_r5.Label === "Errors" && kpi_r5.Value > 0);
|
|
107
|
+
i0.ɵɵadvance();
|
|
108
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(3, 5, kpi_r5.Value));
|
|
109
|
+
i0.ɵɵadvance(3);
|
|
110
|
+
i0.ɵɵtextInterpolate(kpi_r5.Label);
|
|
111
|
+
i0.ɵɵadvance();
|
|
112
|
+
i0.ɵɵconditional(kpi_r5.Trend ? 6 : -1);
|
|
76
113
|
} }
|
|
77
|
-
function
|
|
78
|
-
i0.ɵɵelementStart(0, "div",
|
|
79
|
-
i0.ɵɵ
|
|
114
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Conditional_16_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
115
|
+
i0.ɵɵelementStart(0, "div", 56);
|
|
116
|
+
i0.ɵɵtext(1);
|
|
80
117
|
i0.ɵɵelementEnd();
|
|
118
|
+
} if (rf & 2) {
|
|
119
|
+
const ctx_r2 = i0.ɵɵnextContext(4);
|
|
120
|
+
i0.ɵɵadvance();
|
|
121
|
+
i0.ɵɵtextInterpolate(ctx_r2.RunCurrentItem);
|
|
81
122
|
} }
|
|
82
|
-
function
|
|
83
|
-
i0.ɵɵelementStart(0, "div",
|
|
84
|
-
i0.ɵɵ
|
|
85
|
-
i0.ɵɵelementEnd();
|
|
86
|
-
i0.ɵɵelementStart(3, "span", 33);
|
|
87
|
-
i0.ɵɵtext(4);
|
|
123
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
124
|
+
i0.ɵɵelementStart(0, "div", 29)(1, "div", 51)(2, "span", 52);
|
|
125
|
+
i0.ɵɵtext(3);
|
|
88
126
|
i0.ɵɵelementEnd();
|
|
89
|
-
i0.ɵɵelementStart(
|
|
90
|
-
i0.ɵɵ
|
|
127
|
+
i0.ɵɵelementStart(4, "span", 53);
|
|
128
|
+
i0.ɵɵtext(5);
|
|
129
|
+
i0.ɵɵelementEnd()();
|
|
130
|
+
i0.ɵɵelementStart(6, "div", 54);
|
|
131
|
+
i0.ɵɵelement(7, "div", 55);
|
|
91
132
|
i0.ɵɵelementEnd();
|
|
92
|
-
i0.ɵɵ
|
|
133
|
+
i0.ɵɵconditionalCreate(8, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Conditional_16_Conditional_8_Template, 2, 1, "div", 56);
|
|
93
134
|
i0.ɵɵelementEnd();
|
|
94
|
-
i0.ɵɵconditionalCreate(9, AutotaggingPipelineResourceComponent_Conditional_3_For_17_Conditional_9_Template, 2, 0, "div", 36);
|
|
95
135
|
} if (rf & 2) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
i0.ɵɵclassMap("stage-" + stage_r5.Status);
|
|
100
|
-
i0.ɵɵadvance(2);
|
|
101
|
-
i0.ɵɵclassMap(stage_r5.Icon);
|
|
136
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
137
|
+
i0.ɵɵadvance(3);
|
|
138
|
+
i0.ɵɵtextInterpolate(ctx_r2.RunStage);
|
|
102
139
|
i0.ɵɵadvance(2);
|
|
103
|
-
i0.ɵɵ
|
|
140
|
+
i0.ɵɵtextInterpolate1("", ctx_r2.RunProgress, "%");
|
|
104
141
|
i0.ɵɵadvance(2);
|
|
105
|
-
i0.ɵɵ
|
|
106
|
-
i0.ɵɵadvance(
|
|
107
|
-
i0.ɵɵconditional(
|
|
142
|
+
i0.ɵɵstyleProp("width", ctx_r2.RunProgress, "%");
|
|
143
|
+
i0.ɵɵadvance();
|
|
144
|
+
i0.ɵɵconditional(ctx_r2.RunCurrentItem ? 8 : -1);
|
|
108
145
|
} }
|
|
109
|
-
function
|
|
110
|
-
i0.ɵɵelementStart(0, "div",
|
|
111
|
-
i0.ɵɵelement(1, "i",
|
|
146
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
147
|
+
i0.ɵɵelementStart(0, "div", 35);
|
|
148
|
+
i0.ɵɵelement(1, "i", 57);
|
|
112
149
|
i0.ɵɵelementStart(2, "p");
|
|
113
150
|
i0.ɵɵtext(3, "No processed items yet.");
|
|
114
151
|
i0.ɵɵelementEnd()();
|
|
115
152
|
} }
|
|
116
|
-
function
|
|
117
|
-
i0.ɵɵelementStart(0, "
|
|
153
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_25_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
154
|
+
i0.ɵɵelementStart(0, "span", 63);
|
|
155
|
+
i0.ɵɵtext(1);
|
|
156
|
+
i0.ɵɵelementEnd();
|
|
157
|
+
} if (rf & 2) {
|
|
158
|
+
const tag_r8 = ctx.$implicit;
|
|
159
|
+
i0.ɵɵadvance();
|
|
160
|
+
i0.ɵɵtextInterpolate(tag_r8);
|
|
161
|
+
} }
|
|
162
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_25_Template(rf, ctx) { if (rf & 1) {
|
|
163
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
164
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
165
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_25_Template_div_click_0_listener() { const $index_r7 = i0.ɵɵrestoreView(_r6).$index; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OpenFeedItemDetail($index_r7)); });
|
|
166
|
+
i0.ɵɵelement(1, "div", 59);
|
|
167
|
+
i0.ɵɵelementStart(2, "span", 60);
|
|
118
168
|
i0.ɵɵtext(3);
|
|
119
169
|
i0.ɵɵelementEnd();
|
|
120
|
-
i0.ɵɵelementStart(4, "span",
|
|
170
|
+
i0.ɵɵelementStart(4, "span", 61);
|
|
121
171
|
i0.ɵɵtext(5);
|
|
172
|
+
i0.ɵɵelementEnd();
|
|
173
|
+
i0.ɵɵelementStart(6, "div", 62);
|
|
174
|
+
i0.ɵɵrepeaterCreate(7, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_25_For_8_Template, 2, 1, "span", 63, i0.ɵɵrepeaterTrackByIdentity);
|
|
175
|
+
i0.ɵɵelementEnd();
|
|
176
|
+
i0.ɵɵelementStart(9, "span", 64);
|
|
177
|
+
i0.ɵɵtext(10);
|
|
122
178
|
i0.ɵɵelementEnd()();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
i0.ɵɵ
|
|
179
|
+
} if (rf & 2) {
|
|
180
|
+
const item_r9 = ctx.$implicit;
|
|
181
|
+
i0.ɵɵadvance();
|
|
182
|
+
i0.ɵɵclassMap(item_r9.Status);
|
|
183
|
+
i0.ɵɵadvance(2);
|
|
184
|
+
i0.ɵɵtextInterpolate(item_r9.Name);
|
|
185
|
+
i0.ɵɵadvance(2);
|
|
186
|
+
i0.ɵɵtextInterpolate(item_r9.SourceName);
|
|
187
|
+
i0.ɵɵadvance(2);
|
|
188
|
+
i0.ɵɵrepeater(item_r9.Tags);
|
|
189
|
+
i0.ɵɵadvance(3);
|
|
190
|
+
i0.ɵɵtextInterpolate(item_r9.TimeAgo);
|
|
191
|
+
} }
|
|
192
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_34_Template(rf, ctx) { if (rf & 1) {
|
|
193
|
+
i0.ɵɵelementStart(0, "div", 40)(1, "div", 65);
|
|
194
|
+
i0.ɵɵelement(2, "i");
|
|
126
195
|
i0.ɵɵelementEnd();
|
|
127
|
-
i0.ɵɵelementStart(
|
|
128
|
-
i0.ɵɵ
|
|
129
|
-
i0.ɵɵtext(12);
|
|
196
|
+
i0.ɵɵelementStart(3, "div", 66)(4, "div", 67);
|
|
197
|
+
i0.ɵɵtext(5);
|
|
130
198
|
i0.ɵɵelementEnd();
|
|
131
|
-
i0.ɵɵelementStart(
|
|
132
|
-
i0.ɵɵ
|
|
133
|
-
i0.ɵɵ
|
|
199
|
+
i0.ɵɵelementStart(6, "div", 68);
|
|
200
|
+
i0.ɵɵtext(7);
|
|
201
|
+
i0.ɵɵelementEnd()();
|
|
202
|
+
i0.ɵɵelement(8, "div", 69);
|
|
134
203
|
i0.ɵɵelementEnd();
|
|
135
|
-
i0.ɵɵelementStart(16, "span", 47);
|
|
136
|
-
i0.ɵɵtext(17);
|
|
137
|
-
i0.ɵɵelementEnd()()();
|
|
138
204
|
} if (rf & 2) {
|
|
139
|
-
const
|
|
140
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
205
|
+
const source_r10 = ctx.$implicit;
|
|
141
206
|
i0.ɵɵadvance(2);
|
|
142
|
-
i0.ɵɵ
|
|
143
|
-
i0.ɵɵadvance();
|
|
144
|
-
i0.ɵɵtextInterpolate(item_r8.Name);
|
|
145
|
-
i0.ɵɵadvance();
|
|
146
|
-
i0.ɵɵclassMap(ctx_r1.GetStatusClass(item_r8.Status));
|
|
147
|
-
i0.ɵɵadvance();
|
|
148
|
-
i0.ɵɵtextInterpolate1(" ", item_r8.Status, " ");
|
|
149
|
-
i0.ɵɵadvance(4);
|
|
150
|
-
i0.ɵɵtextInterpolate1(" ", item_r8.SourceName, " ");
|
|
151
|
-
i0.ɵɵadvance(3);
|
|
152
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.FormatDuration(item_r8.ProcessingTimeMs), " ");
|
|
207
|
+
i0.ɵɵclassMap(source_r10.Icon);
|
|
153
208
|
i0.ɵɵadvance(3);
|
|
154
|
-
i0.ɵɵ
|
|
209
|
+
i0.ɵɵtextInterpolate(source_r10.Name);
|
|
155
210
|
i0.ɵɵadvance(2);
|
|
156
|
-
i0.ɵɵ
|
|
211
|
+
i0.ɵɵtextInterpolate(source_r10.Meta);
|
|
212
|
+
i0.ɵɵadvance();
|
|
213
|
+
i0.ɵɵclassMap(source_r10.StatusClass);
|
|
157
214
|
} }
|
|
158
|
-
function
|
|
159
|
-
i0.ɵɵelementStart(0, "
|
|
160
|
-
i0.ɵɵ
|
|
161
|
-
i0.ɵɵ
|
|
162
|
-
|
|
215
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_41_Template(rf, ctx) { if (rf & 1) {
|
|
216
|
+
i0.ɵɵelementStart(0, "span", 70);
|
|
217
|
+
i0.ɵɵtext(1);
|
|
218
|
+
i0.ɵɵelementEnd();
|
|
219
|
+
} if (rf & 2) {
|
|
220
|
+
const tag_r11 = ctx.$implicit;
|
|
221
|
+
i0.ɵɵclassMap(tag_r11.SizeClass);
|
|
222
|
+
i0.ɵɵstyleProp("opacity", 0.4 + tag_r11.AvgWeight * 0.6);
|
|
223
|
+
i0.ɵɵproperty("title", "Weight: " + tag_r11.AvgWeight.toFixed(2));
|
|
224
|
+
i0.ɵɵadvance();
|
|
225
|
+
i0.ɵɵtextInterpolate(tag_r11.Tag);
|
|
226
|
+
} }
|
|
227
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
228
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
229
|
+
i0.ɵɵelementStart(0, "div", 18)(1, "div")(2, "div", 19);
|
|
230
|
+
i0.ɵɵtext(3, "Pipeline Monitor");
|
|
231
|
+
i0.ɵɵelementEnd();
|
|
232
|
+
i0.ɵɵelementStart(4, "div", 20);
|
|
233
|
+
i0.ɵɵtext(5, "Real-time processing status and recent activity");
|
|
234
|
+
i0.ɵɵelementEnd()();
|
|
235
|
+
i0.ɵɵelementStart(6, "div", 21)(7, "button", 22);
|
|
236
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.LoadPipelineData()); });
|
|
237
|
+
i0.ɵɵelement(8, "i", 23);
|
|
238
|
+
i0.ɵɵtext(9, " Refresh ");
|
|
239
|
+
i0.ɵɵelementEnd()()();
|
|
240
|
+
i0.ɵɵelementStart(10, "div", 24)(11, "div", 25);
|
|
241
|
+
i0.ɵɵrepeaterCreate(12, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_13_Template, 7, 7, "div", 26, _forTrack1);
|
|
242
|
+
i0.ɵɵelementEnd();
|
|
243
|
+
i0.ɵɵelementStart(14, "div", 27)(15, "div", 28);
|
|
244
|
+
i0.ɵɵconditionalCreate(16, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Conditional_16_Template, 9, 5, "div", 29);
|
|
245
|
+
i0.ɵɵelementStart(17, "div", 30)(18, "div", 31)(19, "span", 32);
|
|
246
|
+
i0.ɵɵelement(20, "i", 33);
|
|
247
|
+
i0.ɵɵtext(21, " Recent Processing");
|
|
248
|
+
i0.ɵɵelementEnd()();
|
|
249
|
+
i0.ɵɵelementStart(22, "div", 34);
|
|
250
|
+
i0.ɵɵconditionalCreate(23, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Conditional_23_Template, 4, 0, "div", 35);
|
|
251
|
+
i0.ɵɵrepeaterCreate(24, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_25_Template, 11, 5, "div", 36, i0.ɵɵrepeaterTrackByIndex);
|
|
252
|
+
i0.ɵɵelementEnd()()();
|
|
253
|
+
i0.ɵɵelementStart(26, "div", 37)(27, "div", 38)(28, "div", 31)(29, "span", 32);
|
|
254
|
+
i0.ɵɵelement(30, "i", 39);
|
|
255
|
+
i0.ɵɵtext(31, " Sources");
|
|
163
256
|
i0.ɵɵelementEnd()();
|
|
257
|
+
i0.ɵɵelementStart(32, "div", 34);
|
|
258
|
+
i0.ɵɵrepeaterCreate(33, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_34_Template, 9, 6, "div", 40, _forTrack2);
|
|
259
|
+
i0.ɵɵelementEnd()();
|
|
260
|
+
i0.ɵɵelementStart(35, "div", 41)(36, "div", 42);
|
|
261
|
+
i0.ɵɵelement(37, "i", 43);
|
|
262
|
+
i0.ɵɵtext(38, " Trending Tags");
|
|
263
|
+
i0.ɵɵelementEnd();
|
|
264
|
+
i0.ɵɵelementStart(39, "div", 44);
|
|
265
|
+
i0.ɵɵrepeaterCreate(40, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_For_41_Template, 2, 6, "span", 45, _forTrack3);
|
|
266
|
+
i0.ɵɵelementEnd()()()()();
|
|
267
|
+
} if (rf & 2) {
|
|
268
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
269
|
+
i0.ɵɵadvance(12);
|
|
270
|
+
i0.ɵɵrepeater(ctx_r2.KPIMetrics);
|
|
271
|
+
i0.ɵɵadvance(4);
|
|
272
|
+
i0.ɵɵconditional(ctx_r2.IsRunning ? 16 : -1);
|
|
273
|
+
i0.ɵɵadvance(7);
|
|
274
|
+
i0.ɵɵconditional(ctx_r2.FeedItems.length === 0 ? 23 : -1);
|
|
275
|
+
i0.ɵɵadvance();
|
|
276
|
+
i0.ɵɵrepeater(ctx_r2.FeedItems);
|
|
277
|
+
i0.ɵɵadvance(9);
|
|
278
|
+
i0.ɵɵrepeater(ctx_r2.SourceMinis);
|
|
279
|
+
i0.ɵɵadvance(7);
|
|
280
|
+
i0.ɵɵrepeater(ctx_r2.TrendingTags);
|
|
164
281
|
} }
|
|
165
|
-
function
|
|
166
|
-
i0.ɵɵelementStart(0, "div",
|
|
282
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
283
|
+
i0.ɵɵelementStart(0, "div", 85);
|
|
284
|
+
i0.ɵɵtext(1);
|
|
285
|
+
i0.ɵɵelementEnd();
|
|
286
|
+
} if (rf & 2) {
|
|
287
|
+
const card_r14 = i0.ɵɵnextContext().$implicit;
|
|
288
|
+
i0.ɵɵadvance();
|
|
289
|
+
i0.ɵɵtextInterpolate(card_r14.URL);
|
|
290
|
+
} }
|
|
291
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Template(rf, ctx) { if (rf & 1) {
|
|
292
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
293
|
+
i0.ɵɵelementStart(0, "div", 79);
|
|
294
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Template_div_click_0_listener() { const card_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OpenSourceDetail(card_r14)); });
|
|
295
|
+
i0.ɵɵelementStart(1, "div", 80)(2, "div", 81);
|
|
167
296
|
i0.ɵɵelement(3, "i");
|
|
168
297
|
i0.ɵɵelementEnd();
|
|
169
|
-
i0.ɵɵelementStart(4, "div"
|
|
298
|
+
i0.ɵɵelementStart(4, "div")(5, "div", 82);
|
|
170
299
|
i0.ɵɵtext(6);
|
|
171
300
|
i0.ɵɵelementEnd();
|
|
172
|
-
i0.ɵɵelementStart(7, "
|
|
301
|
+
i0.ɵɵelementStart(7, "div", 83);
|
|
173
302
|
i0.ɵɵtext(8);
|
|
174
303
|
i0.ɵɵelementEnd()();
|
|
175
|
-
i0.ɵɵelementStart(9, "
|
|
176
|
-
i0.ɵɵ
|
|
304
|
+
i0.ɵɵelementStart(9, "div", 84);
|
|
305
|
+
i0.ɵɵelement(10, "div", 69);
|
|
306
|
+
i0.ɵɵtext(11);
|
|
177
307
|
i0.ɵɵelementEnd()();
|
|
178
|
-
i0.ɵɵ
|
|
179
|
-
i0.ɵɵ
|
|
180
|
-
i0.ɵɵtext(
|
|
308
|
+
i0.ɵɵconditionalCreate(12, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Conditional_12_Template, 2, 1, "div", 85);
|
|
309
|
+
i0.ɵɵelementStart(13, "div", 86)(14, "div", 87)(15, "div", 88);
|
|
310
|
+
i0.ɵɵtext(16);
|
|
181
311
|
i0.ɵɵelementEnd();
|
|
182
|
-
i0.ɵɵelementStart(
|
|
183
|
-
i0.ɵɵ
|
|
184
|
-
i0.ɵɵ
|
|
185
|
-
i0.ɵɵ
|
|
312
|
+
i0.ɵɵelementStart(17, "div", 89);
|
|
313
|
+
i0.ɵɵtext(18, "Items");
|
|
314
|
+
i0.ɵɵelementEnd()();
|
|
315
|
+
i0.ɵɵelementStart(19, "div", 87)(20, "div", 88);
|
|
316
|
+
i0.ɵɵtext(21);
|
|
317
|
+
i0.ɵɵelementEnd();
|
|
318
|
+
i0.ɵɵelementStart(22, "div", 89);
|
|
319
|
+
i0.ɵɵtext(23, "Tags");
|
|
320
|
+
i0.ɵɵelementEnd()();
|
|
321
|
+
i0.ɵɵelementStart(24, "div", 87)(25, "div", 88);
|
|
322
|
+
i0.ɵɵtext(26);
|
|
323
|
+
i0.ɵɵelementEnd();
|
|
324
|
+
i0.ɵɵelementStart(27, "div", 89);
|
|
325
|
+
i0.ɵɵtext(28, "Avg Tags");
|
|
326
|
+
i0.ɵɵelementEnd()();
|
|
327
|
+
i0.ɵɵelementStart(29, "div", 87)(30, "div", 88);
|
|
328
|
+
i0.ɵɵtext(31);
|
|
329
|
+
i0.ɵɵelementEnd();
|
|
330
|
+
i0.ɵɵelementStart(32, "div", 89);
|
|
331
|
+
i0.ɵɵtext(33, "Last Run");
|
|
332
|
+
i0.ɵɵelementEnd()()();
|
|
333
|
+
i0.ɵɵelementStart(34, "div", 90)(35, "button", 91);
|
|
334
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Template_button_click_35_listener($event) { const card_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); ctx_r2.OpenEditSourceForm(card_r14); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
335
|
+
i0.ɵɵelement(36, "i", 92);
|
|
336
|
+
i0.ɵɵtext(37, " Edit");
|
|
337
|
+
i0.ɵɵelementEnd();
|
|
338
|
+
i0.ɵɵelementStart(38, "button", 91);
|
|
339
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Template_button_click_38_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r2 = i0.ɵɵnextContext(3); ctx_r2.RunPipeline(); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
340
|
+
i0.ɵɵelement(39, "i", 16);
|
|
341
|
+
i0.ɵɵtext(40, " Run");
|
|
342
|
+
i0.ɵɵelementEnd();
|
|
343
|
+
i0.ɵɵelementStart(41, "button", 93);
|
|
344
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Template_button_click_41_listener($event) { const card_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); ctx_r2.DeleteSource(card_r14); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
345
|
+
i0.ɵɵelement(42, "i", 94);
|
|
346
|
+
i0.ɵɵtext(43, " Delete");
|
|
186
347
|
i0.ɵɵelementEnd()()();
|
|
187
348
|
} if (rf & 2) {
|
|
188
|
-
const
|
|
189
|
-
const
|
|
349
|
+
const card_r14 = ctx.$implicit;
|
|
350
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
190
351
|
i0.ɵɵadvance(3);
|
|
191
|
-
i0.ɵɵclassMap(
|
|
352
|
+
i0.ɵɵclassMap(card_r14.Icon);
|
|
192
353
|
i0.ɵɵadvance(3);
|
|
193
|
-
i0.ɵɵtextInterpolate(
|
|
354
|
+
i0.ɵɵtextInterpolate(card_r14.Name);
|
|
194
355
|
i0.ɵɵadvance(2);
|
|
195
|
-
i0.ɵɵ
|
|
356
|
+
i0.ɵɵtextInterpolate2("", card_r14.SourceTypeName, " \u00B7 ", card_r14.FileTypeName);
|
|
196
357
|
i0.ɵɵadvance();
|
|
197
|
-
i0.ɵɵclassMap(
|
|
358
|
+
i0.ɵɵclassMap(card_r14.StatusClass);
|
|
198
359
|
i0.ɵɵadvance();
|
|
199
|
-
i0.ɵɵ
|
|
360
|
+
i0.ɵɵclassMap(card_r14.StatusClass);
|
|
361
|
+
i0.ɵɵadvance();
|
|
362
|
+
i0.ɵɵtextInterpolate1(" ", card_r14.StatusLabel, " ");
|
|
363
|
+
i0.ɵɵadvance();
|
|
364
|
+
i0.ɵɵconditional(card_r14.URL ? 12 : -1);
|
|
200
365
|
i0.ɵɵadvance(4);
|
|
201
|
-
i0.ɵɵ
|
|
366
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatNumber(card_r14.ItemCount));
|
|
367
|
+
i0.ɵɵadvance(5);
|
|
368
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatNumber(card_r14.TagCount));
|
|
369
|
+
i0.ɵɵadvance(5);
|
|
370
|
+
i0.ɵɵtextInterpolate(card_r14.AvgTags);
|
|
371
|
+
i0.ɵɵadvance(5);
|
|
372
|
+
i0.ɵɵtextInterpolate(card_r14.LastRunAgo);
|
|
373
|
+
} }
|
|
374
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
375
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
376
|
+
i0.ɵɵelementStart(0, "div", 18)(1, "div")(2, "div", 19);
|
|
377
|
+
i0.ɵɵtext(3, "Content Sources");
|
|
378
|
+
i0.ɵɵelementEnd();
|
|
379
|
+
i0.ɵɵelementStart(4, "div", 20);
|
|
380
|
+
i0.ɵɵtext(5, "Configure where content is ingested from");
|
|
381
|
+
i0.ɵɵelementEnd()();
|
|
382
|
+
i0.ɵɵelementStart(6, "div", 21)(7, "button", 71);
|
|
383
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenAddSourceForm()); });
|
|
384
|
+
i0.ɵɵelement(8, "i", 72);
|
|
385
|
+
i0.ɵɵtext(9, " Add Source ");
|
|
386
|
+
i0.ɵɵelementEnd()()();
|
|
387
|
+
i0.ɵɵelementStart(10, "div", 24)(11, "div", 73);
|
|
388
|
+
i0.ɵɵrepeaterCreate(12, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_For_13_Template, 44, 15, "div", 74, _forTrack2);
|
|
389
|
+
i0.ɵɵelementStart(14, "div", 75);
|
|
390
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_Template_div_click_14_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenAddSourceForm()); });
|
|
391
|
+
i0.ɵɵelement(15, "i", 76);
|
|
392
|
+
i0.ɵɵelementStart(16, "span", 77);
|
|
393
|
+
i0.ɵɵtext(17, "Add Content Source");
|
|
394
|
+
i0.ɵɵelementEnd();
|
|
395
|
+
i0.ɵɵelementStart(18, "span", 78);
|
|
396
|
+
i0.ɵɵtext(19, "Web, RSS, Email, Files, API");
|
|
397
|
+
i0.ɵɵelementEnd()()()();
|
|
398
|
+
} if (rf & 2) {
|
|
399
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
400
|
+
i0.ɵɵadvance(12);
|
|
401
|
+
i0.ɵɵrepeater(ctx_r2.SourceCards);
|
|
402
|
+
} }
|
|
403
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_2_For_13_Template(rf, ctx) { if (rf & 1) {
|
|
404
|
+
const _r16 = i0.ɵɵgetCurrentView();
|
|
405
|
+
i0.ɵɵelementStart(0, "div", 96)(1, "div", 98)(2, "span", 99);
|
|
406
|
+
i0.ɵɵtext(3);
|
|
407
|
+
i0.ɵɵelementEnd();
|
|
408
|
+
i0.ɵɵelementStart(4, "span", 100);
|
|
409
|
+
i0.ɵɵtext(5);
|
|
410
|
+
i0.ɵɵelementEnd()();
|
|
411
|
+
i0.ɵɵelementStart(6, "div", 101)(7, "span", 102);
|
|
412
|
+
i0.ɵɵtext(8, "Description");
|
|
413
|
+
i0.ɵɵelementEnd();
|
|
414
|
+
i0.ɵɵelementStart(9, "span", 103);
|
|
415
|
+
i0.ɵɵtext(10);
|
|
416
|
+
i0.ɵɵelementEnd()();
|
|
417
|
+
i0.ɵɵelementStart(11, "div", 101)(12, "span", 102);
|
|
418
|
+
i0.ɵɵtext(13, "Sources Using");
|
|
419
|
+
i0.ɵɵelementEnd();
|
|
420
|
+
i0.ɵɵelementStart(14, "span", 103);
|
|
421
|
+
i0.ɵɵtext(15);
|
|
422
|
+
i0.ɵɵelementEnd()();
|
|
423
|
+
i0.ɵɵelementStart(16, "div", 101)(17, "span", 102);
|
|
424
|
+
i0.ɵɵtext(18, "Items Tagged");
|
|
425
|
+
i0.ɵɵelementEnd();
|
|
426
|
+
i0.ɵɵelementStart(19, "span", 103);
|
|
427
|
+
i0.ɵɵtext(20);
|
|
428
|
+
i0.ɵɵelementEnd()();
|
|
429
|
+
i0.ɵɵelementStart(21, "div", 104);
|
|
430
|
+
i0.ɵɵelement(22, "i", 3);
|
|
431
|
+
i0.ɵɵelementStart(23, "span");
|
|
432
|
+
i0.ɵɵtext(24);
|
|
433
|
+
i0.ɵɵelementEnd();
|
|
434
|
+
i0.ɵɵelementStart(25, "div", 105);
|
|
435
|
+
i0.ɵɵelement(26, "div", 106);
|
|
436
|
+
i0.ɵɵelementEnd();
|
|
437
|
+
i0.ɵɵelementStart(27, "span");
|
|
438
|
+
i0.ɵɵtext(28);
|
|
439
|
+
i0.ɵɵelementEnd();
|
|
440
|
+
i0.ɵɵelementStart(29, "span", 107);
|
|
441
|
+
i0.ɵɵtext(30, "tags/item");
|
|
442
|
+
i0.ɵɵelementEnd()();
|
|
443
|
+
i0.ɵɵelementStart(31, "div", 108)(32, "button", 91);
|
|
444
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_2_For_13_Template_button_click_32_listener() { const card_r17 = i0.ɵɵrestoreView(_r16).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OpenEditTypeForm(card_r17)); });
|
|
445
|
+
i0.ɵɵelement(33, "i", 92);
|
|
446
|
+
i0.ɵɵtext(34, " Edit");
|
|
447
|
+
i0.ɵɵelementEnd()()();
|
|
448
|
+
} if (rf & 2) {
|
|
449
|
+
const card_r17 = ctx.$implicit;
|
|
450
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
202
451
|
i0.ɵɵadvance(3);
|
|
203
|
-
i0.ɵɵ
|
|
452
|
+
i0.ɵɵtextInterpolate(card_r17.Name);
|
|
453
|
+
i0.ɵɵadvance(2);
|
|
454
|
+
i0.ɵɵtextInterpolate(card_r17.AIModelName);
|
|
455
|
+
i0.ɵɵadvance(5);
|
|
456
|
+
i0.ɵɵtextInterpolate(card_r17.Description || "\u2014");
|
|
457
|
+
i0.ɵɵadvance(5);
|
|
458
|
+
i0.ɵɵtextInterpolate(card_r17.SourcesUsing);
|
|
459
|
+
i0.ɵɵadvance(5);
|
|
460
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatNumber(card_r17.ItemsTagged));
|
|
461
|
+
i0.ɵɵadvance(4);
|
|
462
|
+
i0.ɵɵtextInterpolate(card_r17.MinTags);
|
|
463
|
+
i0.ɵɵadvance(2);
|
|
464
|
+
i0.ɵɵstyleProp("left", card_r17.RangeLeftPct, "%")("right", card_r17.RangeRightPct, "%");
|
|
465
|
+
i0.ɵɵadvance(2);
|
|
466
|
+
i0.ɵɵtextInterpolate(card_r17.MaxTags);
|
|
467
|
+
} }
|
|
468
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
469
|
+
const _r15 = i0.ɵɵgetCurrentView();
|
|
470
|
+
i0.ɵɵelementStart(0, "div", 18)(1, "div")(2, "div", 19);
|
|
471
|
+
i0.ɵɵtext(3, "Content Types");
|
|
472
|
+
i0.ɵɵelementEnd();
|
|
473
|
+
i0.ɵɵelementStart(4, "div", 20);
|
|
474
|
+
i0.ɵɵtext(5, "Configure AI tagging rules per content category");
|
|
475
|
+
i0.ɵɵelementEnd()();
|
|
476
|
+
i0.ɵɵelementStart(6, "div", 21)(7, "button", 71);
|
|
477
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenAddTypeForm()); });
|
|
478
|
+
i0.ɵɵelement(8, "i", 72);
|
|
479
|
+
i0.ɵɵtext(9, " Add Type ");
|
|
480
|
+
i0.ɵɵelementEnd()()();
|
|
481
|
+
i0.ɵɵelementStart(10, "div", 24)(11, "div", 95);
|
|
482
|
+
i0.ɵɵrepeaterCreate(12, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_2_For_13_Template, 35, 11, "div", 96, _forTrack2);
|
|
483
|
+
i0.ɵɵelementStart(14, "div", 97);
|
|
484
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_2_Template_div_click_14_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenAddTypeForm()); });
|
|
485
|
+
i0.ɵɵelement(15, "i", 76);
|
|
486
|
+
i0.ɵɵelementStart(16, "span", 77);
|
|
487
|
+
i0.ɵɵtext(17, "Add Content Type");
|
|
488
|
+
i0.ɵɵelementEnd();
|
|
489
|
+
i0.ɵɵelementStart(18, "span", 78);
|
|
490
|
+
i0.ɵɵtext(19, "Configure tagging rules");
|
|
491
|
+
i0.ɵɵelementEnd()()()();
|
|
492
|
+
} if (rf & 2) {
|
|
493
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
494
|
+
i0.ɵɵadvance(12);
|
|
495
|
+
i0.ɵɵrepeater(ctx_r2.ContentTypeCards);
|
|
204
496
|
} }
|
|
205
|
-
function
|
|
206
|
-
|
|
207
|
-
i0.ɵɵ
|
|
208
|
-
i0.ɵɵ
|
|
209
|
-
i0.ɵɵelementStart(3, "
|
|
210
|
-
i0.ɵɵtext(4
|
|
497
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_For_30_Template(rf, ctx) { if (rf & 1) {
|
|
498
|
+
i0.ɵɵelementStart(0, "tr")(1, "td", 121);
|
|
499
|
+
i0.ɵɵtext(2);
|
|
500
|
+
i0.ɵɵelementEnd();
|
|
501
|
+
i0.ɵɵelementStart(3, "td");
|
|
502
|
+
i0.ɵɵtext(4);
|
|
503
|
+
i0.ɵɵelementEnd();
|
|
504
|
+
i0.ɵɵelementStart(5, "td")(6, "div", 122)(7, "div", 123);
|
|
505
|
+
i0.ɵɵelement(8, "div", 124);
|
|
506
|
+
i0.ɵɵelementEnd();
|
|
507
|
+
i0.ɵɵelementStart(9, "span", 125);
|
|
508
|
+
i0.ɵɵtext(10);
|
|
509
|
+
i0.ɵɵelementEnd()()();
|
|
510
|
+
i0.ɵɵelementStart(11, "td")(12, "div", 126);
|
|
511
|
+
i0.ɵɵelement(13, "div", 127);
|
|
211
512
|
i0.ɵɵelementEnd()();
|
|
212
|
-
i0.ɵɵelementStart(
|
|
213
|
-
i0.ɵɵ
|
|
214
|
-
i0.ɵɵ
|
|
215
|
-
i0.ɵɵ
|
|
513
|
+
i0.ɵɵelementStart(14, "td");
|
|
514
|
+
i0.ɵɵtext(15);
|
|
515
|
+
i0.ɵɵelementEnd();
|
|
516
|
+
i0.ɵɵelementStart(16, "td");
|
|
517
|
+
i0.ɵɵtext(17);
|
|
216
518
|
i0.ɵɵelementEnd()();
|
|
217
|
-
|
|
218
|
-
|
|
519
|
+
} if (rf & 2) {
|
|
520
|
+
const row_r19 = ctx.$implicit;
|
|
521
|
+
i0.ɵɵadvance(2);
|
|
522
|
+
i0.ɵɵtextInterpolate(row_r19.Tag);
|
|
523
|
+
i0.ɵɵadvance(2);
|
|
524
|
+
i0.ɵɵtextInterpolate(row_r19.UsageCount);
|
|
525
|
+
i0.ɵɵadvance(4);
|
|
526
|
+
i0.ɵɵstyleProp("width", row_r19.AvgWeight * 100, "%");
|
|
527
|
+
i0.ɵɵclassProp("at-weight-high", row_r19.AvgWeight >= 0.7)("at-weight-medium", row_r19.AvgWeight >= 0.4 && row_r19.AvgWeight < 0.7)("at-weight-low", row_r19.AvgWeight < 0.4);
|
|
528
|
+
i0.ɵɵadvance(2);
|
|
529
|
+
i0.ɵɵtextInterpolate(row_r19.AvgWeight.toFixed(2));
|
|
530
|
+
i0.ɵɵadvance(3);
|
|
531
|
+
i0.ɵɵstyleProp("width", row_r19.BarWidthPct, "%");
|
|
532
|
+
i0.ɵɵadvance(2);
|
|
533
|
+
i0.ɵɵtextInterpolate(row_r19.TopSource);
|
|
534
|
+
i0.ɵɵadvance(2);
|
|
535
|
+
i0.ɵɵtextInterpolate(row_r19.FirstSeen);
|
|
536
|
+
} }
|
|
537
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_For_38_Template(rf, ctx) { if (rf & 1) {
|
|
538
|
+
i0.ɵɵelementStart(0, "span", 70);
|
|
539
|
+
i0.ɵɵtext(1);
|
|
219
540
|
i0.ɵɵelementEnd();
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
i0.ɵɵ
|
|
541
|
+
} if (rf & 2) {
|
|
542
|
+
const tag_r20 = ctx.$implicit;
|
|
543
|
+
i0.ɵɵclassMap(tag_r20.SizeClass);
|
|
544
|
+
i0.ɵɵstyleProp("opacity", 0.4 + tag_r20.AvgWeight * 0.6);
|
|
545
|
+
i0.ɵɵproperty("title", "Weight: " + tag_r20.AvgWeight.toFixed(2));
|
|
546
|
+
i0.ɵɵadvance();
|
|
547
|
+
i0.ɵɵtextInterpolate(tag_r20.Tag);
|
|
548
|
+
} }
|
|
549
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_For_45_Template(rf, ctx) { if (rf & 1) {
|
|
550
|
+
i0.ɵɵelementStart(0, "div", 120)(1, "span");
|
|
551
|
+
i0.ɵɵtext(2);
|
|
223
552
|
i0.ɵɵelementEnd();
|
|
224
|
-
i0.ɵɵelementStart(
|
|
225
|
-
i0.ɵɵ
|
|
553
|
+
i0.ɵɵelementStart(3, "strong");
|
|
554
|
+
i0.ɵɵtext(4);
|
|
226
555
|
i0.ɵɵelementEnd()();
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
i0.ɵɵ
|
|
556
|
+
} if (rf & 2) {
|
|
557
|
+
const s_r21 = ctx.$implicit;
|
|
558
|
+
i0.ɵɵadvance(2);
|
|
559
|
+
i0.ɵɵtextInterpolate(s_r21.SourceName);
|
|
560
|
+
i0.ɵɵadvance(2);
|
|
561
|
+
i0.ɵɵtextInterpolate(s_r21.Count);
|
|
562
|
+
} }
|
|
563
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
564
|
+
const _r18 = i0.ɵɵgetCurrentView();
|
|
565
|
+
i0.ɵɵelementStart(0, "div", 18)(1, "div")(2, "div", 19);
|
|
566
|
+
i0.ɵɵtext(3, "Tag Library");
|
|
230
567
|
i0.ɵɵelementEnd();
|
|
231
|
-
i0.ɵɵelementStart(
|
|
232
|
-
i0.ɵɵ
|
|
233
|
-
i0.ɵɵrepeaterCreate(25, AutotaggingPipelineResourceComponent_Conditional_3_For_26_Template, 18, 9, "div", 21, i0.ɵɵrepeaterTrackByIndex);
|
|
568
|
+
i0.ɵɵelementStart(4, "div", 20);
|
|
569
|
+
i0.ɵɵtext(5);
|
|
234
570
|
i0.ɵɵelementEnd()();
|
|
235
|
-
i0.ɵɵelementStart(
|
|
236
|
-
i0.ɵɵ
|
|
237
|
-
i0.ɵɵ
|
|
571
|
+
i0.ɵɵelementStart(6, "div", 21)(7, "input", 109);
|
|
572
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_Template_input_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r18); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.TagSearchQuery, $event) || (ctx_r2.TagSearchQuery = $event); return i0.ɵɵresetView($event); });
|
|
573
|
+
i0.ɵɵlistener("input", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_Template_input_input_7_listener() { i0.ɵɵrestoreView(_r18); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FilterTags()); });
|
|
574
|
+
i0.ɵɵelementEnd()()();
|
|
575
|
+
i0.ɵɵelementStart(8, "div", 24)(9, "div", 110)(10, "div", 111)(11, "div", 38)(12, "div", 112)(13, "table", 113)(14, "thead")(15, "tr")(16, "th");
|
|
576
|
+
i0.ɵɵtext(17, "Tag");
|
|
577
|
+
i0.ɵɵelementEnd();
|
|
578
|
+
i0.ɵɵelementStart(18, "th");
|
|
579
|
+
i0.ɵɵtext(19, "Count");
|
|
580
|
+
i0.ɵɵelementEnd();
|
|
581
|
+
i0.ɵɵelementStart(20, "th");
|
|
582
|
+
i0.ɵɵtext(21, "Avg Weight");
|
|
583
|
+
i0.ɵɵelementEnd();
|
|
584
|
+
i0.ɵɵelementStart(22, "th");
|
|
585
|
+
i0.ɵɵtext(23, "Distribution");
|
|
238
586
|
i0.ɵɵelementEnd();
|
|
239
|
-
i0.ɵɵelementStart(
|
|
240
|
-
i0.ɵɵ
|
|
241
|
-
i0.ɵɵ
|
|
587
|
+
i0.ɵɵelementStart(24, "th");
|
|
588
|
+
i0.ɵɵtext(25, "Top Source");
|
|
589
|
+
i0.ɵɵelementEnd();
|
|
590
|
+
i0.ɵɵelementStart(26, "th");
|
|
591
|
+
i0.ɵɵtext(27, "First Seen");
|
|
242
592
|
i0.ɵɵelementEnd()()();
|
|
593
|
+
i0.ɵɵelementStart(28, "tbody");
|
|
594
|
+
i0.ɵɵrepeaterCreate(29, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_For_30_Template, 18, 15, "tr", null, _forTrack3);
|
|
595
|
+
i0.ɵɵelementEnd()()()()();
|
|
596
|
+
i0.ɵɵelementStart(31, "div", 114)(32, "div", 41)(33, "div", 115);
|
|
597
|
+
i0.ɵɵelement(34, "i", 116);
|
|
598
|
+
i0.ɵɵtext(35, " Tag Cloud");
|
|
599
|
+
i0.ɵɵelementEnd();
|
|
600
|
+
i0.ɵɵelementStart(36, "div", 44);
|
|
601
|
+
i0.ɵɵrepeaterCreate(37, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_For_38_Template, 2, 6, "span", 45, _forTrack3);
|
|
602
|
+
i0.ɵɵelementEnd()();
|
|
603
|
+
i0.ɵɵelementStart(39, "div", 117)(40, "div", 42);
|
|
604
|
+
i0.ɵɵelement(41, "i", 118);
|
|
605
|
+
i0.ɵɵtext(42, " By Source");
|
|
606
|
+
i0.ɵɵelementEnd();
|
|
607
|
+
i0.ɵɵelementStart(43, "div", 119);
|
|
608
|
+
i0.ɵɵrepeaterCreate(44, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_For_45_Template, 5, 2, "div", 120, _forTrack4);
|
|
609
|
+
i0.ɵɵelementEnd()()()()();
|
|
243
610
|
} if (rf & 2) {
|
|
244
|
-
const
|
|
245
|
-
i0.ɵɵadvance(
|
|
246
|
-
i0.ɵɵ
|
|
247
|
-
i0.ɵɵadvance(
|
|
248
|
-
i0.ɵɵ
|
|
611
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
612
|
+
i0.ɵɵadvance(5);
|
|
613
|
+
i0.ɵɵtextInterpolate1("", ctx_r2.TagRows.length, " unique tags across all content sources");
|
|
614
|
+
i0.ɵɵadvance(2);
|
|
615
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.TagSearchQuery);
|
|
616
|
+
i0.ɵɵadvance(22);
|
|
617
|
+
i0.ɵɵrepeater(ctx_r2.FilteredTagRows);
|
|
249
618
|
i0.ɵɵadvance(8);
|
|
250
|
-
i0.ɵɵ
|
|
619
|
+
i0.ɵɵrepeater(ctx_r2.TagCloud);
|
|
620
|
+
i0.ɵɵadvance(7);
|
|
621
|
+
i0.ɵɵrepeater(ctx_r2.TagsBySource);
|
|
622
|
+
} }
|
|
623
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_For_11_Template(rf, ctx) { if (rf & 1) {
|
|
624
|
+
i0.ɵɵelementStart(0, "option", 130);
|
|
625
|
+
i0.ɵɵtext(1);
|
|
626
|
+
i0.ɵɵelementEnd();
|
|
627
|
+
} if (rf & 2) {
|
|
628
|
+
const s_r23 = ctx.$implicit;
|
|
629
|
+
i0.ɵɵproperty("value", s_r23);
|
|
630
|
+
i0.ɵɵadvance();
|
|
631
|
+
i0.ɵɵtextInterpolate(s_r23);
|
|
632
|
+
} }
|
|
633
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_For_43_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
634
|
+
i0.ɵɵelement(0, "i", 137);
|
|
635
|
+
} }
|
|
636
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_For_43_Template(rf, ctx) { if (rf & 1) {
|
|
637
|
+
i0.ɵɵelementStart(0, "tr")(1, "td")(2, "span", 136);
|
|
638
|
+
i0.ɵɵconditionalCreate(3, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_For_43_Conditional_3_Template, 1, 0, "i", 137);
|
|
639
|
+
i0.ɵɵtext(4);
|
|
640
|
+
i0.ɵɵelementEnd()();
|
|
641
|
+
i0.ɵɵelementStart(5, "td", 138);
|
|
642
|
+
i0.ɵɵtext(6);
|
|
643
|
+
i0.ɵɵelementEnd();
|
|
644
|
+
i0.ɵɵelementStart(7, "td");
|
|
645
|
+
i0.ɵɵtext(8);
|
|
646
|
+
i0.ɵɵelementEnd();
|
|
647
|
+
i0.ɵɵelementStart(9, "td", 139);
|
|
648
|
+
i0.ɵɵtext(10);
|
|
649
|
+
i0.ɵɵelementEnd();
|
|
650
|
+
i0.ɵɵelementStart(11, "td");
|
|
651
|
+
i0.ɵɵtext(12);
|
|
652
|
+
i0.ɵɵelementEnd();
|
|
653
|
+
i0.ɵɵelementStart(13, "td");
|
|
654
|
+
i0.ɵɵtext(14);
|
|
655
|
+
i0.ɵɵelementEnd();
|
|
656
|
+
i0.ɵɵelementStart(15, "td");
|
|
657
|
+
i0.ɵɵtext(16);
|
|
658
|
+
i0.ɵɵelementEnd()();
|
|
659
|
+
} if (rf & 2) {
|
|
660
|
+
const row_r24 = ctx.$implicit;
|
|
661
|
+
i0.ɵɵadvance(2);
|
|
662
|
+
i0.ɵɵclassMap(row_r24.StatusClass);
|
|
663
|
+
i0.ɵɵadvance();
|
|
664
|
+
i0.ɵɵconditional(row_r24.StatusClass === "running" ? 3 : -1);
|
|
665
|
+
i0.ɵɵadvance();
|
|
666
|
+
i0.ɵɵtextInterpolate1(" ", row_r24.Status, " ");
|
|
667
|
+
i0.ɵɵadvance(2);
|
|
668
|
+
i0.ɵɵtextInterpolate(row_r24.SourceName);
|
|
669
|
+
i0.ɵɵadvance(2);
|
|
670
|
+
i0.ɵɵtextInterpolate(row_r24.StartedDisplay);
|
|
671
|
+
i0.ɵɵadvance(2);
|
|
672
|
+
i0.ɵɵtextInterpolate(row_r24.Duration);
|
|
673
|
+
i0.ɵɵadvance(2);
|
|
674
|
+
i0.ɵɵtextInterpolate(row_r24.Items);
|
|
675
|
+
i0.ɵɵadvance(2);
|
|
676
|
+
i0.ɵɵtextInterpolate(row_r24.Tags);
|
|
251
677
|
i0.ɵɵadvance();
|
|
252
|
-
i0.ɵɵ
|
|
678
|
+
i0.ɵɵclassMap(row_r24.ErrorClass);
|
|
679
|
+
i0.ɵɵadvance();
|
|
680
|
+
i0.ɵɵtextInterpolate(row_r24.Errors);
|
|
681
|
+
} }
|
|
682
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
683
|
+
const _r22 = i0.ɵɵgetCurrentView();
|
|
684
|
+
i0.ɵɵelementStart(0, "div", 18)(1, "div")(2, "div", 19);
|
|
685
|
+
i0.ɵɵtext(3, "Run History");
|
|
686
|
+
i0.ɵɵelementEnd();
|
|
687
|
+
i0.ɵɵelementStart(4, "div", 20);
|
|
688
|
+
i0.ɵɵtext(5, "Processing run log across all content sources");
|
|
689
|
+
i0.ɵɵelementEnd()();
|
|
690
|
+
i0.ɵɵelementStart(6, "div", 21)(7, "select", 128);
|
|
691
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_Template_select_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r22); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.HistorySourceFilter, $event) || (ctx_r2.HistorySourceFilter = $event); return i0.ɵɵresetView($event); });
|
|
692
|
+
i0.ɵɵlistener("change", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_Template_select_change_7_listener() { i0.ɵɵrestoreView(_r22); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FilterRunHistory()); });
|
|
693
|
+
i0.ɵɵelementStart(8, "option", 129);
|
|
694
|
+
i0.ɵɵtext(9, "All Sources");
|
|
695
|
+
i0.ɵɵelementEnd();
|
|
696
|
+
i0.ɵɵrepeaterCreate(10, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_For_11_Template, 2, 2, "option", 130, i0.ɵɵrepeaterTrackByIdentity);
|
|
697
|
+
i0.ɵɵelementEnd();
|
|
698
|
+
i0.ɵɵelementStart(12, "select", 128);
|
|
699
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_Template_select_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r22); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.HistoryStatusFilter, $event) || (ctx_r2.HistoryStatusFilter = $event); return i0.ɵɵresetView($event); });
|
|
700
|
+
i0.ɵɵlistener("change", function AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_Template_select_change_12_listener() { i0.ɵɵrestoreView(_r22); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FilterRunHistory()); });
|
|
701
|
+
i0.ɵɵelementStart(13, "option", 129);
|
|
702
|
+
i0.ɵɵtext(14, "All Status");
|
|
703
|
+
i0.ɵɵelementEnd();
|
|
704
|
+
i0.ɵɵelementStart(15, "option", 131);
|
|
705
|
+
i0.ɵɵtext(16, "Complete");
|
|
706
|
+
i0.ɵɵelementEnd();
|
|
707
|
+
i0.ɵɵelementStart(17, "option", 132);
|
|
708
|
+
i0.ɵɵtext(18, "Failed");
|
|
709
|
+
i0.ɵɵelementEnd();
|
|
710
|
+
i0.ɵɵelementStart(19, "option", 133);
|
|
711
|
+
i0.ɵɵtext(20, "Running");
|
|
712
|
+
i0.ɵɵelementEnd()()()();
|
|
713
|
+
i0.ɵɵelementStart(21, "div", 24)(22, "div", 38)(23, "div", 134)(24, "table", 135)(25, "thead")(26, "tr")(27, "th");
|
|
714
|
+
i0.ɵɵtext(28, "Status");
|
|
715
|
+
i0.ɵɵelementEnd();
|
|
716
|
+
i0.ɵɵelementStart(29, "th");
|
|
717
|
+
i0.ɵɵtext(30, "Source");
|
|
718
|
+
i0.ɵɵelementEnd();
|
|
719
|
+
i0.ɵɵelementStart(31, "th");
|
|
720
|
+
i0.ɵɵtext(32, "Started");
|
|
721
|
+
i0.ɵɵelementEnd();
|
|
722
|
+
i0.ɵɵelementStart(33, "th");
|
|
723
|
+
i0.ɵɵtext(34, "Duration");
|
|
724
|
+
i0.ɵɵelementEnd();
|
|
725
|
+
i0.ɵɵelementStart(35, "th");
|
|
726
|
+
i0.ɵɵtext(36, "Items");
|
|
727
|
+
i0.ɵɵelementEnd();
|
|
728
|
+
i0.ɵɵelementStart(37, "th");
|
|
729
|
+
i0.ɵɵtext(38, "Tags");
|
|
730
|
+
i0.ɵɵelementEnd();
|
|
731
|
+
i0.ɵɵelementStart(39, "th");
|
|
732
|
+
i0.ɵɵtext(40, "Errors");
|
|
733
|
+
i0.ɵɵelementEnd()()();
|
|
734
|
+
i0.ɵɵelementStart(41, "tbody");
|
|
735
|
+
i0.ɵɵrepeaterCreate(42, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_For_43_Template, 17, 12, "tr", null, _forTrack2);
|
|
736
|
+
i0.ɵɵelementEnd()()()()();
|
|
737
|
+
} if (rf & 2) {
|
|
738
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
253
739
|
i0.ɵɵadvance(7);
|
|
254
|
-
i0.ɵɵ
|
|
740
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.HistorySourceFilter);
|
|
741
|
+
i0.ɵɵadvance(3);
|
|
742
|
+
i0.ɵɵrepeater(ctx_r2.HistorySourceOptions);
|
|
743
|
+
i0.ɵɵadvance(2);
|
|
744
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.HistoryStatusFilter);
|
|
745
|
+
i0.ɵɵadvance(30);
|
|
746
|
+
i0.ɵɵrepeater(ctx_r2.FilteredRunRows);
|
|
747
|
+
} }
|
|
748
|
+
function AutotaggingPipelineResourceComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
749
|
+
i0.ɵɵconditionalCreate(0, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_0_Template, 42, 2);
|
|
750
|
+
i0.ɵɵconditionalCreate(1, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_1_Template, 20, 0);
|
|
751
|
+
i0.ɵɵconditionalCreate(2, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_2_Template, 20, 0);
|
|
752
|
+
i0.ɵɵconditionalCreate(3, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_3_Template, 46, 2);
|
|
753
|
+
i0.ɵɵconditionalCreate(4, AutotaggingPipelineResourceComponent_Conditional_19_Conditional_4_Template, 44, 2);
|
|
754
|
+
} if (rf & 2) {
|
|
755
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
756
|
+
i0.ɵɵconditional(ctx_r2.ActiveTab === "pipeline" ? 0 : -1);
|
|
757
|
+
i0.ɵɵadvance();
|
|
758
|
+
i0.ɵɵconditional(ctx_r2.ActiveTab === "sources" ? 1 : -1);
|
|
759
|
+
i0.ɵɵadvance();
|
|
760
|
+
i0.ɵɵconditional(ctx_r2.ActiveTab === "types" ? 2 : -1);
|
|
761
|
+
i0.ɵɵadvance();
|
|
762
|
+
i0.ɵɵconditional(ctx_r2.ActiveTab === "tags" ? 3 : -1);
|
|
255
763
|
i0.ɵɵadvance();
|
|
256
|
-
i0.ɵɵ
|
|
764
|
+
i0.ɵɵconditional(ctx_r2.ActiveTab === "history" ? 4 : -1);
|
|
257
765
|
} }
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
766
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
767
|
+
i0.ɵɵtext(0, " Add Content Source ");
|
|
768
|
+
} }
|
|
769
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
770
|
+
i0.ɵɵtext(0, " Edit Content Source ");
|
|
771
|
+
} }
|
|
772
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
773
|
+
i0.ɵɵtext(0, " Add Content Type ");
|
|
774
|
+
} }
|
|
775
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
776
|
+
i0.ɵɵtext(0, " Edit Content Type ");
|
|
777
|
+
} }
|
|
778
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_11_Template(rf, ctx) { if (rf & 1) {
|
|
779
|
+
i0.ɵɵelementStart(0, "option", 130);
|
|
780
|
+
i0.ɵɵtext(1);
|
|
781
|
+
i0.ɵɵelementEnd();
|
|
782
|
+
} if (rf & 2) {
|
|
783
|
+
const opt_r27 = ctx.$implicit;
|
|
784
|
+
i0.ɵɵproperty("value", opt_r27.ID);
|
|
785
|
+
i0.ɵɵadvance();
|
|
786
|
+
i0.ɵɵtextInterpolate(opt_r27.Name);
|
|
787
|
+
} }
|
|
788
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_19_Template(rf, ctx) { if (rf & 1) {
|
|
789
|
+
i0.ɵɵelementStart(0, "option", 130);
|
|
790
|
+
i0.ɵɵtext(1);
|
|
791
|
+
i0.ɵɵelementEnd();
|
|
792
|
+
} if (rf & 2) {
|
|
793
|
+
const opt_r28 = ctx.$implicit;
|
|
794
|
+
i0.ɵɵproperty("value", opt_r28.ID);
|
|
795
|
+
i0.ɵɵadvance();
|
|
796
|
+
i0.ɵɵtextInterpolate(opt_r28.Name);
|
|
797
|
+
} }
|
|
798
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_27_Template(rf, ctx) { if (rf & 1) {
|
|
799
|
+
i0.ɵɵelementStart(0, "option", 130);
|
|
800
|
+
i0.ɵɵtext(1);
|
|
801
|
+
i0.ɵɵelementEnd();
|
|
802
|
+
} if (rf & 2) {
|
|
803
|
+
const opt_r29 = ctx.$implicit;
|
|
804
|
+
i0.ɵɵproperty("value", opt_r29.ID);
|
|
805
|
+
i0.ɵɵadvance();
|
|
806
|
+
i0.ɵɵtextInterpolate(opt_r29.Name);
|
|
807
|
+
} }
|
|
808
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_45_Template(rf, ctx) { if (rf & 1) {
|
|
809
|
+
i0.ɵɵelementStart(0, "option", 130);
|
|
810
|
+
i0.ɵɵtext(1);
|
|
811
|
+
i0.ɵɵelementEnd();
|
|
812
|
+
} if (rf & 2) {
|
|
813
|
+
const opt_r30 = ctx.$implicit;
|
|
814
|
+
i0.ɵɵproperty("value", opt_r30.ID);
|
|
815
|
+
i0.ɵɵadvance();
|
|
816
|
+
i0.ɵɵtextInterpolate(opt_r30.Name);
|
|
817
|
+
} }
|
|
818
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Conditional_50_Template(rf, ctx) { if (rf & 1) {
|
|
819
|
+
i0.ɵɵelement(0, "i", 15);
|
|
820
|
+
i0.ɵɵtext(1, " Saving... ");
|
|
821
|
+
} }
|
|
822
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Conditional_51_Template(rf, ctx) { if (rf & 1) {
|
|
823
|
+
i0.ɵɵelement(0, "i", 155);
|
|
824
|
+
i0.ɵɵtext(1, " Save ");
|
|
825
|
+
} }
|
|
826
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
827
|
+
const _r26 = i0.ɵɵgetCurrentView();
|
|
828
|
+
i0.ɵɵelementStart(0, "div", 146)(1, "label", 147);
|
|
829
|
+
i0.ɵɵtext(2, "Name");
|
|
830
|
+
i0.ɵɵelementEnd();
|
|
831
|
+
i0.ɵɵelementStart(3, "input", 148);
|
|
832
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormSourceName, $event) || (ctx_r2.FormSourceName = $event); return i0.ɵɵresetView($event); });
|
|
833
|
+
i0.ɵɵelementEnd()();
|
|
834
|
+
i0.ɵɵelementStart(4, "div", 146)(5, "label", 147);
|
|
835
|
+
i0.ɵɵtext(6, "Source Type");
|
|
836
|
+
i0.ɵɵelementEnd();
|
|
837
|
+
i0.ɵɵelementStart(7, "select", 149);
|
|
838
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_select_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormSourceTypeID, $event) || (ctx_r2.FormSourceTypeID = $event); return i0.ɵɵresetView($event); });
|
|
839
|
+
i0.ɵɵelementStart(8, "option", 129);
|
|
840
|
+
i0.ɵɵtext(9, "Select source type...");
|
|
841
|
+
i0.ɵɵelementEnd();
|
|
842
|
+
i0.ɵɵrepeaterCreate(10, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_11_Template, 2, 2, "option", 130, _forTrack2);
|
|
843
|
+
i0.ɵɵelementEnd()();
|
|
844
|
+
i0.ɵɵelementStart(12, "div", 146)(13, "label", 147);
|
|
845
|
+
i0.ɵɵtext(14, "Content Type");
|
|
846
|
+
i0.ɵɵelementEnd();
|
|
847
|
+
i0.ɵɵelementStart(15, "select", 149);
|
|
848
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_select_ngModelChange_15_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormContentTypeID, $event) || (ctx_r2.FormContentTypeID = $event); return i0.ɵɵresetView($event); });
|
|
849
|
+
i0.ɵɵelementStart(16, "option", 129);
|
|
850
|
+
i0.ɵɵtext(17, "Select content type...");
|
|
851
|
+
i0.ɵɵelementEnd();
|
|
852
|
+
i0.ɵɵrepeaterCreate(18, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_19_Template, 2, 2, "option", 130, _forTrack2);
|
|
853
|
+
i0.ɵɵelementEnd()();
|
|
854
|
+
i0.ɵɵelementStart(20, "div", 146)(21, "label", 147);
|
|
855
|
+
i0.ɵɵtext(22, "File Type");
|
|
856
|
+
i0.ɵɵelementEnd();
|
|
857
|
+
i0.ɵɵelementStart(23, "select", 149);
|
|
858
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_select_ngModelChange_23_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormFileTypeID, $event) || (ctx_r2.FormFileTypeID = $event); return i0.ɵɵresetView($event); });
|
|
859
|
+
i0.ɵɵelementStart(24, "option", 129);
|
|
860
|
+
i0.ɵɵtext(25, "Select file type...");
|
|
861
|
+
i0.ɵɵelementEnd();
|
|
862
|
+
i0.ɵɵrepeaterCreate(26, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_27_Template, 2, 2, "option", 130, _forTrack2);
|
|
863
|
+
i0.ɵɵelementEnd()();
|
|
864
|
+
i0.ɵɵelementStart(28, "div", 146)(29, "label", 147);
|
|
865
|
+
i0.ɵɵtext(30, "URL");
|
|
866
|
+
i0.ɵɵelementEnd();
|
|
867
|
+
i0.ɵɵelementStart(31, "input", 150);
|
|
868
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_input_ngModelChange_31_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormSourceURL, $event) || (ctx_r2.FormSourceURL = $event); return i0.ɵɵresetView($event); });
|
|
869
|
+
i0.ɵɵelementEnd()();
|
|
870
|
+
i0.ɵɵelementStart(32, "div", 146)(33, "label", 147);
|
|
871
|
+
i0.ɵɵtext(34, "Embedding Model Override");
|
|
872
|
+
i0.ɵɵelementEnd();
|
|
873
|
+
i0.ɵɵelementStart(35, "mj-tree-dropdown", 151);
|
|
874
|
+
i0.ɵɵlistener("ValueChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_mj_tree_dropdown_ValueChange_35_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FormSourceEmbeddingModelID = ctx_r2.FromCompositeKey($event)); });
|
|
875
|
+
i0.ɵɵelementEnd();
|
|
876
|
+
i0.ɵɵelementStart(36, "span", 152);
|
|
877
|
+
i0.ɵɵtext(37, "Overrides Content Type default");
|
|
878
|
+
i0.ɵɵelementEnd()();
|
|
879
|
+
i0.ɵɵelementStart(38, "div", 146)(39, "label", 147);
|
|
880
|
+
i0.ɵɵtext(40, "Vector Index Override");
|
|
881
|
+
i0.ɵɵelementEnd();
|
|
882
|
+
i0.ɵɵelementStart(41, "select", 149);
|
|
883
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_select_ngModelChange_41_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormSourceVectorIndexID, $event) || (ctx_r2.FormSourceVectorIndexID = $event); return i0.ɵɵresetView($event); });
|
|
884
|
+
i0.ɵɵelementStart(42, "option", 129);
|
|
885
|
+
i0.ɵɵtext(43, "Use system default");
|
|
886
|
+
i0.ɵɵelementEnd();
|
|
887
|
+
i0.ɵɵrepeaterCreate(44, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_For_45_Template, 2, 2, "option", 130, _forTrack2);
|
|
888
|
+
i0.ɵɵelementEnd();
|
|
889
|
+
i0.ɵɵelementStart(46, "span", 152);
|
|
890
|
+
i0.ɵɵtext(47, "Overrides Content Type default");
|
|
891
|
+
i0.ɵɵelementEnd()();
|
|
892
|
+
i0.ɵɵelementStart(48, "div", 153)(49, "button", 154);
|
|
893
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_button_click_49_listener() { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SaveSource()); });
|
|
894
|
+
i0.ɵɵconditionalCreate(50, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Conditional_50_Template, 2, 0)(51, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Conditional_51_Template, 2, 0);
|
|
895
|
+
i0.ɵɵelementEnd();
|
|
896
|
+
i0.ɵɵelementStart(52, "button", 22);
|
|
897
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template_button_click_52_listener() { i0.ɵɵrestoreView(_r26); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.CloseForm()); });
|
|
898
|
+
i0.ɵɵtext(53, "Cancel");
|
|
899
|
+
i0.ɵɵelementEnd()();
|
|
900
|
+
} if (rf & 2) {
|
|
901
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
902
|
+
i0.ɵɵadvance(3);
|
|
903
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormSourceName);
|
|
904
|
+
i0.ɵɵadvance(4);
|
|
905
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormSourceTypeID);
|
|
906
|
+
i0.ɵɵadvance(3);
|
|
907
|
+
i0.ɵɵrepeater(ctx_r2.SourceTypeOptions);
|
|
908
|
+
i0.ɵɵadvance(5);
|
|
909
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormContentTypeID);
|
|
910
|
+
i0.ɵɵadvance(3);
|
|
911
|
+
i0.ɵɵrepeater(ctx_r2.ContentTypeOptions);
|
|
912
|
+
i0.ɵɵadvance(5);
|
|
913
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormFileTypeID);
|
|
914
|
+
i0.ɵɵadvance(3);
|
|
915
|
+
i0.ɵɵrepeater(ctx_r2.FileTypeOptions);
|
|
916
|
+
i0.ɵɵadvance(5);
|
|
917
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormSourceURL);
|
|
918
|
+
i0.ɵɵadvance(4);
|
|
919
|
+
i0.ɵɵproperty("BranchConfig", ctx_r2.AIModelVendorBranch)("LeafConfig", ctx_r2.EmbeddingModelsLeaf)("Clearable", true)("Value", ctx_r2.ToCompositeKey(ctx_r2.FormSourceEmbeddingModelID));
|
|
920
|
+
i0.ɵɵadvance(6);
|
|
921
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormSourceVectorIndexID);
|
|
922
|
+
i0.ɵɵadvance(3);
|
|
923
|
+
i0.ɵɵrepeater(ctx_r2.VectorIndexOptions);
|
|
924
|
+
i0.ɵɵadvance(5);
|
|
925
|
+
i0.ɵɵproperty("disabled", ctx_r2.FormSaving);
|
|
926
|
+
i0.ɵɵadvance();
|
|
927
|
+
i0.ɵɵconditional(ctx_r2.FormSaving ? 50 : 51);
|
|
928
|
+
} }
|
|
929
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_For_32_Template(rf, ctx) { if (rf & 1) {
|
|
930
|
+
i0.ɵɵelementStart(0, "option", 130);
|
|
931
|
+
i0.ɵɵtext(1);
|
|
932
|
+
i0.ɵɵelementEnd();
|
|
933
|
+
} if (rf & 2) {
|
|
934
|
+
const opt_r32 = ctx.$implicit;
|
|
935
|
+
i0.ɵɵproperty("value", opt_r32.ID);
|
|
936
|
+
i0.ɵɵadvance();
|
|
937
|
+
i0.ɵɵtextInterpolate(opt_r32.Name);
|
|
938
|
+
} }
|
|
939
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Conditional_35_Template(rf, ctx) { if (rf & 1) {
|
|
940
|
+
i0.ɵɵelement(0, "i", 15);
|
|
941
|
+
i0.ɵɵtext(1, " Saving... ");
|
|
942
|
+
} }
|
|
943
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Conditional_36_Template(rf, ctx) { if (rf & 1) {
|
|
944
|
+
i0.ɵɵelement(0, "i", 155);
|
|
945
|
+
i0.ɵɵtext(1, " Save ");
|
|
946
|
+
} }
|
|
947
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
948
|
+
const _r31 = i0.ɵɵgetCurrentView();
|
|
949
|
+
i0.ɵɵelementStart(0, "div", 146)(1, "label", 147);
|
|
950
|
+
i0.ɵɵtext(2, "Name");
|
|
951
|
+
i0.ɵɵelementEnd();
|
|
952
|
+
i0.ɵɵelementStart(3, "input", 156);
|
|
953
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormTypeName, $event) || (ctx_r2.FormTypeName = $event); return i0.ɵɵresetView($event); });
|
|
954
|
+
i0.ɵɵelementEnd()();
|
|
955
|
+
i0.ɵɵelementStart(4, "div", 146)(5, "label", 147);
|
|
956
|
+
i0.ɵɵtext(6, "Description");
|
|
957
|
+
i0.ɵɵelementEnd();
|
|
958
|
+
i0.ɵɵelementStart(7, "textarea", 157);
|
|
959
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_textarea_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormTypeDescription, $event) || (ctx_r2.FormTypeDescription = $event); return i0.ɵɵresetView($event); });
|
|
960
|
+
i0.ɵɵelementEnd()();
|
|
961
|
+
i0.ɵɵelementStart(8, "div", 146)(9, "label", 147);
|
|
962
|
+
i0.ɵɵtext(10, "AI Model (for tagging)");
|
|
963
|
+
i0.ɵɵelementEnd();
|
|
964
|
+
i0.ɵɵelementStart(11, "mj-tree-dropdown", 158);
|
|
965
|
+
i0.ɵɵlistener("ValueChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_mj_tree_dropdown_ValueChange_11_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FormTypeAIModelID = ctx_r2.FromCompositeKey($event)); });
|
|
966
|
+
i0.ɵɵelementEnd()();
|
|
967
|
+
i0.ɵɵelementStart(12, "div", 159)(13, "div", 160)(14, "label", 147);
|
|
968
|
+
i0.ɵɵtext(15, "Min Tags");
|
|
969
|
+
i0.ɵɵelementEnd();
|
|
970
|
+
i0.ɵɵelementStart(16, "input", 161);
|
|
971
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_input_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormTypeMinTags, $event) || (ctx_r2.FormTypeMinTags = $event); return i0.ɵɵresetView($event); });
|
|
972
|
+
i0.ɵɵelementEnd()();
|
|
973
|
+
i0.ɵɵelementStart(17, "div", 160)(18, "label", 147);
|
|
974
|
+
i0.ɵɵtext(19, "Max Tags");
|
|
975
|
+
i0.ɵɵelementEnd();
|
|
976
|
+
i0.ɵɵelementStart(20, "input", 162);
|
|
977
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_input_ngModelChange_20_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormTypeMaxTags, $event) || (ctx_r2.FormTypeMaxTags = $event); return i0.ɵɵresetView($event); });
|
|
978
|
+
i0.ɵɵelementEnd()()();
|
|
979
|
+
i0.ɵɵelementStart(21, "div", 146)(22, "label", 147);
|
|
980
|
+
i0.ɵɵtext(23, "Embedding Model");
|
|
981
|
+
i0.ɵɵelementEnd();
|
|
982
|
+
i0.ɵɵelementStart(24, "mj-tree-dropdown", 151);
|
|
983
|
+
i0.ɵɵlistener("ValueChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_mj_tree_dropdown_ValueChange_24_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FormTypeEmbeddingModelID = ctx_r2.FromCompositeKey($event)); });
|
|
984
|
+
i0.ɵɵelementEnd()();
|
|
985
|
+
i0.ɵɵelementStart(25, "div", 146)(26, "label", 147);
|
|
986
|
+
i0.ɵɵtext(27, "Vector Index");
|
|
987
|
+
i0.ɵɵelementEnd();
|
|
988
|
+
i0.ɵɵelementStart(28, "select", 149);
|
|
989
|
+
i0.ɵɵtwoWayListener("ngModelChange", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_select_ngModelChange_28_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r2.FormTypeVectorIndexID, $event) || (ctx_r2.FormTypeVectorIndexID = $event); return i0.ɵɵresetView($event); });
|
|
990
|
+
i0.ɵɵelementStart(29, "option", 129);
|
|
991
|
+
i0.ɵɵtext(30, "Use system default");
|
|
992
|
+
i0.ɵɵelementEnd();
|
|
993
|
+
i0.ɵɵrepeaterCreate(31, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_For_32_Template, 2, 2, "option", 130, _forTrack2);
|
|
994
|
+
i0.ɵɵelementEnd()();
|
|
995
|
+
i0.ɵɵelementStart(33, "div", 153)(34, "button", 154);
|
|
996
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_button_click_34_listener() { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.SaveContentType()); });
|
|
997
|
+
i0.ɵɵconditionalCreate(35, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Conditional_35_Template, 2, 0)(36, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Conditional_36_Template, 2, 0);
|
|
998
|
+
i0.ɵɵelementEnd();
|
|
999
|
+
i0.ɵɵelementStart(37, "button", 22);
|
|
1000
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template_button_click_37_listener() { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.CloseForm()); });
|
|
1001
|
+
i0.ɵɵtext(38, "Cancel");
|
|
1002
|
+
i0.ɵɵelementEnd()();
|
|
1003
|
+
} if (rf & 2) {
|
|
1004
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
1005
|
+
i0.ɵɵadvance(3);
|
|
1006
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormTypeName);
|
|
1007
|
+
i0.ɵɵadvance(4);
|
|
1008
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormTypeDescription);
|
|
1009
|
+
i0.ɵɵadvance(4);
|
|
1010
|
+
i0.ɵɵproperty("BranchConfig", ctx_r2.AIModelVendorBranch)("LeafConfig", ctx_r2.AllModelsLeaf)("Clearable", true)("Value", ctx_r2.ToCompositeKey(ctx_r2.FormTypeAIModelID));
|
|
1011
|
+
i0.ɵɵadvance(5);
|
|
1012
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormTypeMinTags);
|
|
1013
|
+
i0.ɵɵadvance(4);
|
|
1014
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormTypeMaxTags);
|
|
1015
|
+
i0.ɵɵadvance(4);
|
|
1016
|
+
i0.ɵɵproperty("BranchConfig", ctx_r2.AIModelVendorBranch)("LeafConfig", ctx_r2.EmbeddingModelsLeaf)("Clearable", true)("Value", ctx_r2.ToCompositeKey(ctx_r2.FormTypeEmbeddingModelID));
|
|
1017
|
+
i0.ɵɵadvance(4);
|
|
1018
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r2.FormTypeVectorIndexID);
|
|
1019
|
+
i0.ɵɵadvance(3);
|
|
1020
|
+
i0.ɵɵrepeater(ctx_r2.VectorIndexOptions);
|
|
1021
|
+
i0.ɵɵadvance(3);
|
|
1022
|
+
i0.ɵɵproperty("disabled", ctx_r2.FormSaving);
|
|
1023
|
+
i0.ɵɵadvance();
|
|
1024
|
+
i0.ɵɵconditional(ctx_r2.FormSaving ? 35 : 36);
|
|
1025
|
+
} }
|
|
1026
|
+
function AutotaggingPipelineResourceComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
1027
|
+
const _r25 = i0.ɵɵgetCurrentView();
|
|
1028
|
+
i0.ɵɵelementStart(0, "div", 140);
|
|
1029
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_20_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r25); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.CloseForm()); });
|
|
1030
|
+
i0.ɵɵelementEnd();
|
|
1031
|
+
i0.ɵɵelementStart(1, "div", 141)(2, "div", 142)(3, "h3");
|
|
1032
|
+
i0.ɵɵconditionalCreate(4, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_4_Template, 1, 0)(5, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_5_Template, 1, 0)(6, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_6_Template, 1, 0)(7, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_7_Template, 1, 0);
|
|
1033
|
+
i0.ɵɵelementEnd();
|
|
1034
|
+
i0.ɵɵelementStart(8, "button", 143);
|
|
1035
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_20_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r25); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.CloseForm()); });
|
|
1036
|
+
i0.ɵɵelement(9, "i", 144);
|
|
1037
|
+
i0.ɵɵelementEnd()();
|
|
1038
|
+
i0.ɵɵelementStart(10, "div", 145);
|
|
1039
|
+
i0.ɵɵconditionalCreate(11, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_11_Template, 54, 12);
|
|
1040
|
+
i0.ɵɵconditionalCreate(12, AutotaggingPipelineResourceComponent_Conditional_20_Conditional_12_Template, 39, 15);
|
|
1041
|
+
i0.ɵɵelementEnd()();
|
|
1042
|
+
} if (rf & 2) {
|
|
1043
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
1044
|
+
i0.ɵɵadvance(4);
|
|
1045
|
+
i0.ɵɵconditional(ctx_r2.FormMode === "add-source" ? 4 : ctx_r2.FormMode === "edit-source" ? 5 : ctx_r2.FormMode === "add-type" ? 6 : ctx_r2.FormMode === "edit-type" ? 7 : -1);
|
|
1046
|
+
i0.ɵɵadvance(7);
|
|
1047
|
+
i0.ɵɵconditional(ctx_r2.FormMode === "add-source" || ctx_r2.FormMode === "edit-source" ? 11 : -1);
|
|
1048
|
+
i0.ɵɵadvance();
|
|
1049
|
+
i0.ɵɵconditional(ctx_r2.FormMode === "add-type" || ctx_r2.FormMode === "edit-type" ? 12 : -1);
|
|
1050
|
+
} }
|
|
1051
|
+
function AutotaggingPipelineResourceComponent_Conditional_21_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
1052
|
+
i0.ɵɵelementStart(0, "span", 170);
|
|
1053
|
+
i0.ɵɵelement(1, "i", 181);
|
|
1054
|
+
i0.ɵɵtext(2);
|
|
1055
|
+
i0.ɵɵelementEnd();
|
|
1056
|
+
} if (rf & 2) {
|
|
1057
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
1058
|
+
i0.ɵɵadvance(2);
|
|
1059
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.SelectedFeedItem.FileTypeName);
|
|
1060
|
+
} }
|
|
1061
|
+
function AutotaggingPipelineResourceComponent_Conditional_21_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
1062
|
+
i0.ɵɵelementStart(0, "div", 171)(1, "div", 172);
|
|
1063
|
+
i0.ɵɵtext(2, "URL");
|
|
1064
|
+
i0.ɵɵelementEnd();
|
|
1065
|
+
i0.ɵɵelementStart(3, "a", 182);
|
|
1066
|
+
i0.ɵɵtext(4);
|
|
1067
|
+
i0.ɵɵelement(5, "i", 183);
|
|
1068
|
+
i0.ɵɵelementEnd()();
|
|
1069
|
+
} if (rf & 2) {
|
|
1070
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
1071
|
+
i0.ɵɵadvance(3);
|
|
1072
|
+
i0.ɵɵproperty("href", ctx_r2.SelectedFeedItem.URL, i0.ɵɵsanitizeUrl);
|
|
1073
|
+
i0.ɵɵadvance();
|
|
1074
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.SelectedFeedItem.URL, " ");
|
|
1075
|
+
} }
|
|
1076
|
+
function AutotaggingPipelineResourceComponent_Conditional_21_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
1077
|
+
i0.ɵɵelementStart(0, "div", 171)(1, "div", 172);
|
|
1078
|
+
i0.ɵɵtext(2, "Content Preview");
|
|
1079
|
+
i0.ɵɵelementEnd();
|
|
1080
|
+
i0.ɵɵelementStart(3, "div", 184);
|
|
1081
|
+
i0.ɵɵtext(4);
|
|
1082
|
+
i0.ɵɵelementEnd()();
|
|
1083
|
+
} if (rf & 2) {
|
|
1084
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
1085
|
+
i0.ɵɵadvance(4);
|
|
1086
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedFeedItem.TextContent);
|
|
1087
|
+
} }
|
|
1088
|
+
function AutotaggingPipelineResourceComponent_Conditional_21_Conditional_20_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
1089
|
+
i0.ɵɵelementStart(0, "span", 186);
|
|
1090
|
+
i0.ɵɵtext(1);
|
|
1091
|
+
i0.ɵɵelementEnd();
|
|
1092
|
+
} if (rf & 2) {
|
|
1093
|
+
const tag_r34 = ctx.$implicit;
|
|
1094
|
+
i0.ɵɵadvance();
|
|
1095
|
+
i0.ɵɵtextInterpolate(tag_r34);
|
|
1096
|
+
} }
|
|
1097
|
+
function AutotaggingPipelineResourceComponent_Conditional_21_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
1098
|
+
i0.ɵɵelementStart(0, "div", 171)(1, "div", 172);
|
|
1099
|
+
i0.ɵɵtext(2);
|
|
1100
|
+
i0.ɵɵelementEnd();
|
|
1101
|
+
i0.ɵɵelementStart(3, "div", 185);
|
|
1102
|
+
i0.ɵɵrepeaterCreate(4, AutotaggingPipelineResourceComponent_Conditional_21_Conditional_20_For_5_Template, 2, 1, "span", 186, i0.ɵɵrepeaterTrackByIdentity);
|
|
1103
|
+
i0.ɵɵelementEnd()();
|
|
1104
|
+
} if (rf & 2) {
|
|
1105
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
1106
|
+
i0.ɵɵadvance(2);
|
|
1107
|
+
i0.ɵɵtextInterpolate1("Tags (", ctx_r2.SelectedFeedItem.Tags.length, ")");
|
|
1108
|
+
i0.ɵɵadvance(2);
|
|
1109
|
+
i0.ɵɵrepeater(ctx_r2.SelectedFeedItem.Tags);
|
|
1110
|
+
} }
|
|
1111
|
+
function AutotaggingPipelineResourceComponent_Conditional_21_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
1112
|
+
i0.ɵɵelementStart(0, "div", 174)(1, "span", 175);
|
|
1113
|
+
i0.ɵɵtext(2, "Checksum");
|
|
1114
|
+
i0.ɵɵelementEnd();
|
|
1115
|
+
i0.ɵɵelementStart(3, "span", 187);
|
|
1116
|
+
i0.ɵɵtext(4);
|
|
1117
|
+
i0.ɵɵelementEnd()();
|
|
1118
|
+
} if (rf & 2) {
|
|
1119
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
1120
|
+
i0.ɵɵadvance(4);
|
|
1121
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedFeedItem.Checksum);
|
|
1122
|
+
} }
|
|
1123
|
+
function AutotaggingPipelineResourceComponent_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
1124
|
+
const _r33 = i0.ɵɵgetCurrentView();
|
|
1125
|
+
i0.ɵɵelementStart(0, "div", 140);
|
|
1126
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_21_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r33); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.CloseItemDetail()); });
|
|
1127
|
+
i0.ɵɵelementEnd();
|
|
1128
|
+
i0.ɵɵelementStart(1, "div", 163)(2, "div", 142)(3, "h3");
|
|
1129
|
+
i0.ɵɵelement(4, "i", 164);
|
|
1130
|
+
i0.ɵɵtext(5, " Content Item");
|
|
1131
|
+
i0.ɵɵelementEnd();
|
|
1132
|
+
i0.ɵɵelementStart(6, "button", 143);
|
|
1133
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_21_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r33); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.CloseItemDetail()); });
|
|
1134
|
+
i0.ɵɵelement(7, "i", 144);
|
|
1135
|
+
i0.ɵɵelementEnd()();
|
|
1136
|
+
i0.ɵɵelementStart(8, "div", 145)(9, "div", 165)(10, "h4", 166);
|
|
1137
|
+
i0.ɵɵtext(11);
|
|
1138
|
+
i0.ɵɵelementEnd();
|
|
1139
|
+
i0.ɵɵelementStart(12, "div", 167)(13, "span", 168);
|
|
1140
|
+
i0.ɵɵtext(14);
|
|
1141
|
+
i0.ɵɵelementEnd();
|
|
1142
|
+
i0.ɵɵelementStart(15, "span", 169);
|
|
1143
|
+
i0.ɵɵtext(16);
|
|
1144
|
+
i0.ɵɵelementEnd();
|
|
1145
|
+
i0.ɵɵconditionalCreate(17, AutotaggingPipelineResourceComponent_Conditional_21_Conditional_17_Template, 3, 1, "span", 170);
|
|
1146
|
+
i0.ɵɵelementEnd()();
|
|
1147
|
+
i0.ɵɵconditionalCreate(18, AutotaggingPipelineResourceComponent_Conditional_21_Conditional_18_Template, 6, 2, "div", 171);
|
|
1148
|
+
i0.ɵɵconditionalCreate(19, AutotaggingPipelineResourceComponent_Conditional_21_Conditional_19_Template, 5, 1, "div", 171);
|
|
1149
|
+
i0.ɵɵconditionalCreate(20, AutotaggingPipelineResourceComponent_Conditional_21_Conditional_20_Template, 6, 1, "div", 171);
|
|
1150
|
+
i0.ɵɵelementStart(21, "div", 171)(22, "div", 172);
|
|
1151
|
+
i0.ɵɵtext(23, "Metadata");
|
|
1152
|
+
i0.ɵɵelementEnd();
|
|
1153
|
+
i0.ɵɵelementStart(24, "div", 173);
|
|
1154
|
+
i0.ɵɵconditionalCreate(25, AutotaggingPipelineResourceComponent_Conditional_21_Conditional_25_Template, 5, 1, "div", 174);
|
|
1155
|
+
i0.ɵɵelementStart(26, "div", 174)(27, "span", 175);
|
|
1156
|
+
i0.ɵɵtext(28, "Created");
|
|
1157
|
+
i0.ɵɵelementEnd();
|
|
1158
|
+
i0.ɵɵelementStart(29, "span", 176);
|
|
1159
|
+
i0.ɵɵtext(30);
|
|
1160
|
+
i0.ɵɵelementEnd()();
|
|
1161
|
+
i0.ɵɵelementStart(31, "div", 174)(32, "span", 175);
|
|
1162
|
+
i0.ɵɵtext(33, "Updated");
|
|
1163
|
+
i0.ɵɵelementEnd();
|
|
1164
|
+
i0.ɵɵelementStart(34, "span", 176);
|
|
1165
|
+
i0.ɵɵtext(35);
|
|
1166
|
+
i0.ɵɵelementEnd()()()();
|
|
1167
|
+
i0.ɵɵelementStart(36, "div", 177)(37, "button", 71);
|
|
1168
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_21_Template_button_click_37_listener() { i0.ɵɵrestoreView(_r33); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.OpenRecordFromItem(ctx_r2.SelectedFeedItem)); });
|
|
1169
|
+
i0.ɵɵelement(38, "i", 178);
|
|
1170
|
+
i0.ɵɵtext(39, " Open Record ");
|
|
1171
|
+
i0.ɵɵelementEnd();
|
|
1172
|
+
i0.ɵɵelementStart(40, "button", 179);
|
|
1173
|
+
i0.ɵɵelement(41, "i", 180);
|
|
1174
|
+
i0.ɵɵtext(42, " See Similar Items ");
|
|
1175
|
+
i0.ɵɵelementEnd()()()();
|
|
1176
|
+
} if (rf & 2) {
|
|
1177
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
1178
|
+
i0.ɵɵadvance(11);
|
|
1179
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedFeedItem.Name);
|
|
1180
|
+
i0.ɵɵadvance(3);
|
|
1181
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedFeedItem.SourceName);
|
|
1182
|
+
i0.ɵɵadvance(2);
|
|
1183
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedFeedItem.ContentTypeName);
|
|
1184
|
+
i0.ɵɵadvance();
|
|
1185
|
+
i0.ɵɵconditional(ctx_r2.SelectedFeedItem.FileTypeName ? 17 : -1);
|
|
1186
|
+
i0.ɵɵadvance();
|
|
1187
|
+
i0.ɵɵconditional(ctx_r2.SelectedFeedItem.URL ? 18 : -1);
|
|
1188
|
+
i0.ɵɵadvance();
|
|
1189
|
+
i0.ɵɵconditional(ctx_r2.SelectedFeedItem.TextContent ? 19 : -1);
|
|
1190
|
+
i0.ɵɵadvance();
|
|
1191
|
+
i0.ɵɵconditional(ctx_r2.SelectedFeedItem.Tags.length > 0 ? 20 : -1);
|
|
1192
|
+
i0.ɵɵadvance(5);
|
|
1193
|
+
i0.ɵɵconditional(ctx_r2.SelectedFeedItem.Checksum ? 25 : -1);
|
|
1194
|
+
i0.ɵɵadvance(5);
|
|
1195
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedFeedItem.CreatedAt);
|
|
1196
|
+
i0.ɵɵadvance(5);
|
|
1197
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedFeedItem.UpdatedAt);
|
|
1198
|
+
} }
|
|
1199
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
1200
|
+
i0.ɵɵelementStart(0, "div", 12);
|
|
1201
|
+
i0.ɵɵelement(1, "mj-loading", 188);
|
|
1202
|
+
i0.ɵɵelementEnd();
|
|
1203
|
+
} }
|
|
1204
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
1205
|
+
i0.ɵɵelementStart(0, "div", 174)(1, "span", 175);
|
|
1206
|
+
i0.ɵɵtext(2, "URL");
|
|
1207
|
+
i0.ɵɵelementEnd();
|
|
1208
|
+
i0.ɵɵelementStart(3, "a", 199);
|
|
1209
|
+
i0.ɵɵtext(4);
|
|
1210
|
+
i0.ɵɵelementEnd()();
|
|
1211
|
+
} if (rf & 2) {
|
|
1212
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
1213
|
+
i0.ɵɵadvance(3);
|
|
1214
|
+
i0.ɵɵproperty("href", ctx_r2.SelectedSource.URL, i0.ɵɵsanitizeUrl);
|
|
1215
|
+
i0.ɵɵadvance();
|
|
1216
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.URL);
|
|
1217
|
+
} }
|
|
1218
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_69_Template(rf, ctx) { if (rf & 1) {
|
|
1219
|
+
i0.ɵɵelementStart(0, "div", 196)(1, "p");
|
|
1220
|
+
i0.ɵɵtext(2, "No content items yet.");
|
|
1221
|
+
i0.ɵɵelementEnd()();
|
|
1222
|
+
} }
|
|
1223
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_For_71_Template(rf, ctx) { if (rf & 1) {
|
|
1224
|
+
const _r37 = i0.ɵɵgetCurrentView();
|
|
1225
|
+
i0.ɵɵelementStart(0, "div", 200);
|
|
1226
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_For_71_Template_div_click_0_listener() { const ci_r38 = i0.ɵɵrestoreView(_r37).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.OpenContentItemDetail(ci_r38)); });
|
|
1227
|
+
i0.ɵɵelement(1, "div", 59);
|
|
1228
|
+
i0.ɵɵelementStart(2, "span", 201);
|
|
1229
|
+
i0.ɵɵtext(3);
|
|
1230
|
+
i0.ɵɵelementEnd();
|
|
1231
|
+
i0.ɵɵelementStart(4, "span", 202);
|
|
1232
|
+
i0.ɵɵtext(5);
|
|
1233
|
+
i0.ɵɵelementEnd();
|
|
1234
|
+
i0.ɵɵelementStart(6, "span", 203);
|
|
1235
|
+
i0.ɵɵtext(7);
|
|
1236
|
+
i0.ɵɵelementEnd()();
|
|
1237
|
+
} if (rf & 2) {
|
|
1238
|
+
const ci_r38 = ctx.$implicit;
|
|
1239
|
+
i0.ɵɵadvance();
|
|
1240
|
+
i0.ɵɵclassMap(ci_r38.StatusDot);
|
|
1241
|
+
i0.ɵɵadvance(2);
|
|
1242
|
+
i0.ɵɵtextInterpolate(ci_r38.Name);
|
|
1243
|
+
i0.ɵɵadvance(2);
|
|
1244
|
+
i0.ɵɵtextInterpolate1("", ci_r38.TagCount, " tags");
|
|
1245
|
+
i0.ɵɵadvance(2);
|
|
1246
|
+
i0.ɵɵtextInterpolate(ci_r38.UpdatedAt);
|
|
1247
|
+
} }
|
|
1248
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_72_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
1249
|
+
i0.ɵɵelementStart(0, "div", 205)(1, "span", 136);
|
|
1250
|
+
i0.ɵɵtext(2);
|
|
1251
|
+
i0.ɵɵelementEnd();
|
|
1252
|
+
i0.ɵɵelementStart(3, "span", 206);
|
|
1253
|
+
i0.ɵɵtext(4);
|
|
1254
|
+
i0.ɵɵelementEnd();
|
|
1255
|
+
i0.ɵɵelementStart(5, "span", 207);
|
|
1256
|
+
i0.ɵɵtext(6);
|
|
1257
|
+
i0.ɵɵelementEnd();
|
|
1258
|
+
i0.ɵɵelementStart(7, "span", 208);
|
|
1259
|
+
i0.ɵɵtext(8);
|
|
1260
|
+
i0.ɵɵelementEnd()();
|
|
1261
|
+
} if (rf & 2) {
|
|
1262
|
+
const run_r39 = ctx.$implicit;
|
|
1263
|
+
i0.ɵɵadvance();
|
|
1264
|
+
i0.ɵɵclassMap(run_r39.StatusClass);
|
|
1265
|
+
i0.ɵɵadvance();
|
|
1266
|
+
i0.ɵɵtextInterpolate(run_r39.Status);
|
|
1267
|
+
i0.ɵɵadvance(2);
|
|
1268
|
+
i0.ɵɵtextInterpolate(run_r39.StartedDisplay);
|
|
1269
|
+
i0.ɵɵadvance(2);
|
|
1270
|
+
i0.ɵɵtextInterpolate(run_r39.Duration);
|
|
1271
|
+
i0.ɵɵadvance(2);
|
|
1272
|
+
i0.ɵɵtextInterpolate1("", run_r39.Items, " items");
|
|
1273
|
+
} }
|
|
1274
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_72_Template(rf, ctx) { if (rf & 1) {
|
|
1275
|
+
i0.ɵɵelementStart(0, "div", 171)(1, "div", 172);
|
|
1276
|
+
i0.ɵɵtext(2, "Recent Runs");
|
|
1277
|
+
i0.ɵɵelementEnd();
|
|
1278
|
+
i0.ɵɵelementStart(3, "div", 204);
|
|
1279
|
+
i0.ɵɵrepeaterCreate(4, AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_72_For_5_Template, 9, 6, "div", 205, _forTrack2);
|
|
1280
|
+
i0.ɵɵelementEnd()();
|
|
1281
|
+
} if (rf & 2) {
|
|
1282
|
+
const ctx_r2 = i0.ɵɵnextContext(3);
|
|
1283
|
+
i0.ɵɵadvance(4);
|
|
1284
|
+
i0.ɵɵrepeater(ctx_r2.SelectedSource.RunHistory);
|
|
1285
|
+
} }
|
|
1286
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
1287
|
+
const _r36 = i0.ɵɵgetCurrentView();
|
|
1288
|
+
i0.ɵɵelementStart(0, "div", 189)(1, "div", 81);
|
|
1289
|
+
i0.ɵɵelement(2, "i");
|
|
1290
|
+
i0.ɵɵelementEnd();
|
|
1291
|
+
i0.ɵɵelementStart(3, "div")(4, "h4", 166);
|
|
1292
|
+
i0.ɵɵtext(5);
|
|
1293
|
+
i0.ɵɵelementEnd();
|
|
1294
|
+
i0.ɵɵelementStart(6, "div", 167)(7, "span", 169);
|
|
1295
|
+
i0.ɵɵtext(8);
|
|
1296
|
+
i0.ɵɵelementEnd();
|
|
1297
|
+
i0.ɵɵelementStart(9, "span", 190);
|
|
1298
|
+
i0.ɵɵtext(10);
|
|
1299
|
+
i0.ɵɵelementEnd()()()();
|
|
1300
|
+
i0.ɵɵelementStart(11, "div", 171)(12, "div", 172);
|
|
1301
|
+
i0.ɵɵtext(13, "Configuration");
|
|
1302
|
+
i0.ɵɵelementEnd();
|
|
1303
|
+
i0.ɵɵelementStart(14, "div", 173);
|
|
1304
|
+
i0.ɵɵconditionalCreate(15, AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_15_Template, 5, 2, "div", 174);
|
|
1305
|
+
i0.ɵɵelementStart(16, "div", 174)(17, "span", 175);
|
|
1306
|
+
i0.ɵɵtext(18, "Content Type");
|
|
1307
|
+
i0.ɵɵelementEnd();
|
|
1308
|
+
i0.ɵɵelementStart(19, "span", 176);
|
|
1309
|
+
i0.ɵɵtext(20);
|
|
1310
|
+
i0.ɵɵelementEnd()();
|
|
1311
|
+
i0.ɵɵelementStart(21, "div", 174)(22, "span", 175);
|
|
1312
|
+
i0.ɵɵtext(23, "File Type");
|
|
1313
|
+
i0.ɵɵelementEnd();
|
|
1314
|
+
i0.ɵɵelementStart(24, "span", 176);
|
|
1315
|
+
i0.ɵɵtext(25);
|
|
1316
|
+
i0.ɵɵelementEnd()();
|
|
1317
|
+
i0.ɵɵelementStart(26, "div", 174)(27, "span", 175);
|
|
1318
|
+
i0.ɵɵtext(28, "Embedding Model");
|
|
1319
|
+
i0.ɵɵelementEnd();
|
|
1320
|
+
i0.ɵɵelementStart(29, "span", 176);
|
|
1321
|
+
i0.ɵɵtext(30);
|
|
1322
|
+
i0.ɵɵelementEnd()();
|
|
1323
|
+
i0.ɵɵelementStart(31, "div", 174)(32, "span", 175);
|
|
1324
|
+
i0.ɵɵtext(33, "Vector Index");
|
|
1325
|
+
i0.ɵɵelementEnd();
|
|
1326
|
+
i0.ɵɵelementStart(34, "span", 176);
|
|
1327
|
+
i0.ɵɵtext(35);
|
|
1328
|
+
i0.ɵɵelementEnd()()()();
|
|
1329
|
+
i0.ɵɵelementStart(36, "div", 171)(37, "div", 172);
|
|
1330
|
+
i0.ɵɵtext(38, "Statistics");
|
|
1331
|
+
i0.ɵɵelementEnd();
|
|
1332
|
+
i0.ɵɵelementStart(39, "div", 191)(40, "div", 192)(41, "div", 193);
|
|
1333
|
+
i0.ɵɵtext(42);
|
|
1334
|
+
i0.ɵɵelementEnd();
|
|
1335
|
+
i0.ɵɵelementStart(43, "div", 194);
|
|
1336
|
+
i0.ɵɵtext(44, "Items");
|
|
1337
|
+
i0.ɵɵelementEnd()();
|
|
1338
|
+
i0.ɵɵelementStart(45, "div", 192)(46, "div", 193);
|
|
1339
|
+
i0.ɵɵtext(47);
|
|
1340
|
+
i0.ɵɵelementEnd();
|
|
1341
|
+
i0.ɵɵelementStart(48, "div", 194);
|
|
1342
|
+
i0.ɵɵtext(49, "Tags");
|
|
1343
|
+
i0.ɵɵelementEnd()();
|
|
1344
|
+
i0.ɵɵelementStart(50, "div", 192)(51, "div", 193);
|
|
1345
|
+
i0.ɵɵtext(52);
|
|
1346
|
+
i0.ɵɵelementEnd();
|
|
1347
|
+
i0.ɵɵelementStart(53, "div", 194);
|
|
1348
|
+
i0.ɵɵtext(54, "Avg Tags");
|
|
1349
|
+
i0.ɵɵelementEnd()();
|
|
1350
|
+
i0.ɵɵelementStart(55, "div", 192)(56, "div", 193);
|
|
1351
|
+
i0.ɵɵtext(57);
|
|
1352
|
+
i0.ɵɵelementEnd();
|
|
1353
|
+
i0.ɵɵelementStart(58, "div", 194);
|
|
1354
|
+
i0.ɵɵtext(59, "Last Run");
|
|
1355
|
+
i0.ɵɵelementEnd()();
|
|
1356
|
+
i0.ɵɵelementStart(60, "div", 192)(61, "div", 193);
|
|
1357
|
+
i0.ɵɵtext(62);
|
|
1358
|
+
i0.ɵɵelementEnd();
|
|
1359
|
+
i0.ɵɵelementStart(63, "div", 194);
|
|
1360
|
+
i0.ɵɵtext(64, "Errors");
|
|
1361
|
+
i0.ɵɵelementEnd()()()();
|
|
1362
|
+
i0.ɵɵelementStart(65, "div", 171)(66, "div", 172);
|
|
1363
|
+
i0.ɵɵtext(67);
|
|
1364
|
+
i0.ɵɵelementEnd();
|
|
1365
|
+
i0.ɵɵelementStart(68, "div", 195);
|
|
1366
|
+
i0.ɵɵconditionalCreate(69, AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_69_Template, 3, 0, "div", 196);
|
|
1367
|
+
i0.ɵɵrepeaterCreate(70, AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_For_71_Template, 8, 5, "div", 197, _forTrack2);
|
|
1368
|
+
i0.ɵɵelementEnd()();
|
|
1369
|
+
i0.ɵɵconditionalCreate(72, AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Conditional_72_Template, 6, 0, "div", 171);
|
|
1370
|
+
i0.ɵɵelementStart(73, "div", 177)(74, "button", 71);
|
|
1371
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Template_button_click_74_listener() { i0.ɵɵrestoreView(_r36); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.OpenEditSourceFromDetail()); });
|
|
1372
|
+
i0.ɵɵelement(75, "i", 92);
|
|
1373
|
+
i0.ɵɵtext(76, " Edit ");
|
|
1374
|
+
i0.ɵɵelementEnd();
|
|
1375
|
+
i0.ɵɵelementStart(77, "button", 22);
|
|
1376
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Template_button_click_77_listener() { i0.ɵɵrestoreView(_r36); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.RunSourceFromDetail()); });
|
|
1377
|
+
i0.ɵɵelement(78, "i", 16);
|
|
1378
|
+
i0.ɵɵtext(79, " Run Now ");
|
|
1379
|
+
i0.ɵɵelementEnd();
|
|
1380
|
+
i0.ɵɵelementStart(80, "button", 198);
|
|
1381
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Template_button_click_80_listener() { i0.ɵɵrestoreView(_r36); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.DeleteSourceFromDetail()); });
|
|
1382
|
+
i0.ɵɵelement(81, "i", 94);
|
|
1383
|
+
i0.ɵɵtext(82, " Delete ");
|
|
1384
|
+
i0.ɵɵelementEnd()();
|
|
1385
|
+
} if (rf & 2) {
|
|
1386
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
1387
|
+
i0.ɵɵadvance(2);
|
|
1388
|
+
i0.ɵɵclassMap(ctx_r2.SelectedSource.Icon);
|
|
1389
|
+
i0.ɵɵadvance(3);
|
|
1390
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.Name);
|
|
1391
|
+
i0.ɵɵadvance(3);
|
|
1392
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.SourceTypeName);
|
|
1393
|
+
i0.ɵɵadvance();
|
|
1394
|
+
i0.ɵɵclassMap("at-detail-badge-status-" + ctx_r2.SelectedSource.StatusClass);
|
|
1395
|
+
i0.ɵɵadvance();
|
|
1396
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r2.SelectedSource.StatusLabel, " ");
|
|
1397
|
+
i0.ɵɵadvance(5);
|
|
1398
|
+
i0.ɵɵconditional(ctx_r2.SelectedSource.URL ? 15 : -1);
|
|
1399
|
+
i0.ɵɵadvance(5);
|
|
1400
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.ContentTypeName);
|
|
1401
|
+
i0.ɵɵadvance(5);
|
|
1402
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.FileTypeName);
|
|
1403
|
+
i0.ɵɵadvance(5);
|
|
1404
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.EmbeddingModelName);
|
|
1405
|
+
i0.ɵɵadvance(5);
|
|
1406
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.VectorIndexName);
|
|
1407
|
+
i0.ɵɵadvance(7);
|
|
1408
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatNumber(ctx_r2.SelectedSource.ItemCount));
|
|
1409
|
+
i0.ɵɵadvance(5);
|
|
1410
|
+
i0.ɵɵtextInterpolate(ctx_r2.formatNumber(ctx_r2.SelectedSource.TagCount));
|
|
1411
|
+
i0.ɵɵadvance(5);
|
|
1412
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.AvgTags);
|
|
1413
|
+
i0.ɵɵadvance(5);
|
|
1414
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.LastRunAgo);
|
|
1415
|
+
i0.ɵɵadvance(4);
|
|
1416
|
+
i0.ɵɵclassProp("at-kpi-error-value", ctx_r2.SelectedSource.ErrorCount > 0);
|
|
1417
|
+
i0.ɵɵadvance();
|
|
1418
|
+
i0.ɵɵtextInterpolate(ctx_r2.SelectedSource.ErrorCount);
|
|
1419
|
+
i0.ɵɵadvance(5);
|
|
1420
|
+
i0.ɵɵtextInterpolate1("Content Library (", ctx_r2.SelectedSource.ContentItems.length, ")");
|
|
1421
|
+
i0.ɵɵadvance(2);
|
|
1422
|
+
i0.ɵɵconditional(ctx_r2.SelectedSource.ContentItems.length === 0 ? 69 : -1);
|
|
1423
|
+
i0.ɵɵadvance();
|
|
1424
|
+
i0.ɵɵrepeater(ctx_r2.SelectedSource.ContentItems);
|
|
1425
|
+
i0.ɵɵadvance(2);
|
|
1426
|
+
i0.ɵɵconditional(ctx_r2.SelectedSource.RunHistory.length > 0 ? 72 : -1);
|
|
1427
|
+
} }
|
|
1428
|
+
function AutotaggingPipelineResourceComponent_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
1429
|
+
const _r35 = i0.ɵɵgetCurrentView();
|
|
1430
|
+
i0.ɵɵelementStart(0, "div", 140);
|
|
1431
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_22_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r35); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.CloseSourceDetail()); });
|
|
1432
|
+
i0.ɵɵelementEnd();
|
|
1433
|
+
i0.ɵɵelementStart(1, "div", 163)(2, "div", 142)(3, "h3");
|
|
1434
|
+
i0.ɵɵelement(4, "i", 39);
|
|
1435
|
+
i0.ɵɵtext(5, " Source Detail");
|
|
1436
|
+
i0.ɵɵelementEnd();
|
|
1437
|
+
i0.ɵɵelementStart(6, "button", 143);
|
|
1438
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Conditional_22_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r35); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.CloseSourceDetail()); });
|
|
1439
|
+
i0.ɵɵelement(7, "i", 144);
|
|
1440
|
+
i0.ɵɵelementEnd()();
|
|
1441
|
+
i0.ɵɵelementStart(8, "div", 145);
|
|
1442
|
+
i0.ɵɵconditionalCreate(9, AutotaggingPipelineResourceComponent_Conditional_22_Conditional_9_Template, 2, 0, "div", 12);
|
|
1443
|
+
i0.ɵɵconditionalCreate(10, AutotaggingPipelineResourceComponent_Conditional_22_Conditional_10_Template, 83, 22);
|
|
1444
|
+
i0.ɵɵelementEnd()();
|
|
1445
|
+
} if (rf & 2) {
|
|
1446
|
+
const ctx_r2 = i0.ɵɵnextContext();
|
|
1447
|
+
i0.ɵɵadvance(9);
|
|
1448
|
+
i0.ɵɵconditional(ctx_r2.SourceDetailLoading ? 9 : -1);
|
|
1449
|
+
i0.ɵɵadvance();
|
|
1450
|
+
i0.ɵɵconditional(!ctx_r2.SourceDetailLoading && ctx_r2.SelectedSource ? 10 : -1);
|
|
1451
|
+
} }
|
|
1452
|
+
let AutotaggingPipelineResourceComponent = class AutotaggingPipelineResourceComponent extends BaseResourceComponent {
|
|
1453
|
+
destroy$ = new Subject();
|
|
1454
|
+
cdr = inject(ChangeDetectorRef);
|
|
1455
|
+
navigationService = inject(NavigationService);
|
|
1456
|
+
// ── Global state ──
|
|
1457
|
+
IsLoading = true;
|
|
1458
|
+
// ── Tab state ──
|
|
1459
|
+
ActiveTab = 'pipeline';
|
|
1460
|
+
tabDataLoaded = new Set();
|
|
1461
|
+
// ── Left nav ──
|
|
1462
|
+
NavItems = [];
|
|
1463
|
+
// ── Pipeline tab ──
|
|
1464
|
+
KPIMetrics = [];
|
|
1465
|
+
PipelineStages = [];
|
|
1466
|
+
FeedItems = [];
|
|
1467
|
+
SourceMinis = [];
|
|
1468
|
+
TrendingTags = [];
|
|
1469
|
+
// Pipeline run state
|
|
1470
|
+
IsRunning = false;
|
|
1471
|
+
RunProgress = 0;
|
|
1472
|
+
RunStage = '';
|
|
1473
|
+
RunCurrentItem = '';
|
|
1474
|
+
// ── Sources tab ──
|
|
1475
|
+
SourceCards = [];
|
|
1476
|
+
// ── Content Types tab ──
|
|
1477
|
+
ContentTypeCards = [];
|
|
1478
|
+
// ── Tag Library tab ──
|
|
1479
|
+
TagRows = [];
|
|
1480
|
+
TagCloud = [];
|
|
1481
|
+
TagsBySource = [];
|
|
1482
|
+
TagSearchQuery = '';
|
|
1483
|
+
FilteredTagRows = [];
|
|
1484
|
+
// ── Run History tab ──
|
|
1485
|
+
RunHistoryRows = [];
|
|
1486
|
+
HistorySourceFilter = '';
|
|
1487
|
+
HistoryStatusFilter = '';
|
|
1488
|
+
FilteredRunRows = [];
|
|
1489
|
+
HistorySourceOptions = [];
|
|
1490
|
+
// ── Slide-in form ──
|
|
1491
|
+
FormMode = 'none';
|
|
1492
|
+
FormSaving = false;
|
|
1493
|
+
// Source form fields
|
|
1494
|
+
FormSourceName = '';
|
|
1495
|
+
FormSourceTypeID = '';
|
|
1496
|
+
FormContentTypeID = '';
|
|
1497
|
+
FormFileTypeID = '';
|
|
1498
|
+
FormSourceURL = '';
|
|
1499
|
+
EditingSourceID = '';
|
|
1500
|
+
// Content Type form fields
|
|
1501
|
+
FormTypeName = '';
|
|
1502
|
+
FormTypeDescription = '';
|
|
1503
|
+
FormTypeAIModelID = '';
|
|
1504
|
+
FormTypeMinTags = 1;
|
|
1505
|
+
FormTypeMaxTags = 10;
|
|
1506
|
+
EditingTypeID = '';
|
|
1507
|
+
// Embedding model + vector index form fields (Content Type)
|
|
1508
|
+
FormTypeEmbeddingModelID = '';
|
|
1509
|
+
FormTypeVectorIndexID = '';
|
|
1510
|
+
// Embedding model + vector index form fields (Content Source overrides)
|
|
1511
|
+
FormSourceEmbeddingModelID = '';
|
|
1512
|
+
FormSourceVectorIndexID = '';
|
|
1513
|
+
// ── Detail panels ──
|
|
1514
|
+
SelectedFeedItem = null;
|
|
1515
|
+
ShowItemDetail = false;
|
|
1516
|
+
SelectedSource = null;
|
|
1517
|
+
ShowSourceDetail = false;
|
|
1518
|
+
SourceDetailLoading = false;
|
|
1519
|
+
// Dropdown options for forms
|
|
1520
|
+
SourceTypeOptions = [];
|
|
1521
|
+
ContentTypeOptions = [];
|
|
1522
|
+
FileTypeOptions = [];
|
|
1523
|
+
AIModelOptions = [];
|
|
1524
|
+
EmbeddingModelOptions = [];
|
|
1525
|
+
VectorIndexOptions = [];
|
|
1526
|
+
// Tree-dropdown configs for AI model selection (vendor → model grouping)
|
|
1527
|
+
AIModelVendorBranch = {
|
|
1528
|
+
EntityName: 'MJ: AI Vendors',
|
|
1529
|
+
DisplayField: 'Name',
|
|
1530
|
+
IDField: 'ID',
|
|
1531
|
+
DefaultIcon: 'fa-solid fa-building',
|
|
1532
|
+
OrderBy: 'Name ASC',
|
|
1533
|
+
};
|
|
1534
|
+
AllModelsLeaf = {
|
|
1535
|
+
EntityName: 'MJ: AI Models',
|
|
1536
|
+
ParentField: '',
|
|
1537
|
+
DisplayField: 'Name',
|
|
1538
|
+
IDField: 'ID',
|
|
1539
|
+
DefaultIcon: 'fa-solid fa-brain',
|
|
1540
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
1541
|
+
JunctionConfig: {
|
|
1542
|
+
EntityName: 'MJ: AI Model Vendors',
|
|
1543
|
+
LeafForeignKey: 'ModelID',
|
|
1544
|
+
BranchForeignKey: 'VendorID',
|
|
1545
|
+
},
|
|
1546
|
+
};
|
|
1547
|
+
EmbeddingModelsLeaf = {
|
|
1548
|
+
EntityName: 'MJ: AI Models',
|
|
1549
|
+
ParentField: '',
|
|
1550
|
+
DisplayField: 'Name',
|
|
1551
|
+
IDField: 'ID',
|
|
1552
|
+
DefaultIcon: 'fa-solid fa-vector-square',
|
|
1553
|
+
ExtraFilter: "AIModelType = 'Embeddings'",
|
|
1554
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
1555
|
+
JunctionConfig: {
|
|
1556
|
+
EntityName: 'MJ: AI Model Vendors',
|
|
1557
|
+
LeafForeignKey: 'ModelID',
|
|
1558
|
+
BranchForeignKey: 'VendorID',
|
|
1559
|
+
},
|
|
1560
|
+
};
|
|
1561
|
+
// ── Raw data cache ──
|
|
1562
|
+
contentSourcesRaw = [];
|
|
1563
|
+
contentItemsRaw = [];
|
|
1564
|
+
contentTagsRaw = [];
|
|
1565
|
+
contentRunsRaw = [];
|
|
1566
|
+
contentSourceTypesRaw = [];
|
|
1567
|
+
contentTypesRaw = [];
|
|
1568
|
+
contentFileTypesRaw = [];
|
|
1569
|
+
aiModelsRaw = [];
|
|
1570
|
+
// ── Lifecycle ──
|
|
1571
|
+
async ngAfterViewInit() {
|
|
1572
|
+
await this.LoadPipelineData();
|
|
1573
|
+
this.tabDataLoaded.add('pipeline');
|
|
1574
|
+
this.IsLoading = false;
|
|
1575
|
+
this.cdr.detectChanges();
|
|
1576
|
+
this.NotifyLoadComplete();
|
|
1577
|
+
}
|
|
1578
|
+
ngOnDestroy() {
|
|
1579
|
+
this.destroy$.next();
|
|
1580
|
+
this.destroy$.complete();
|
|
1581
|
+
}
|
|
1582
|
+
async GetResourceDisplayName(_data) {
|
|
1583
|
+
return 'Content Autotagging';
|
|
1584
|
+
}
|
|
1585
|
+
async GetResourceIconClass(_data) {
|
|
1586
|
+
return 'fa-solid fa-tags';
|
|
1587
|
+
}
|
|
1588
|
+
// ── Tab switching ──
|
|
1589
|
+
async SwitchTab(tab) {
|
|
1590
|
+
if (tab === this.ActiveTab)
|
|
1591
|
+
return;
|
|
1592
|
+
this.ActiveTab = tab;
|
|
1593
|
+
this.cdr.detectChanges();
|
|
1594
|
+
if (!this.tabDataLoaded.has(tab)) {
|
|
1595
|
+
await this.loadTabData(tab);
|
|
1596
|
+
this.tabDataLoaded.add(tab);
|
|
1597
|
+
this.cdr.detectChanges();
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
async loadTabData(tab) {
|
|
1601
|
+
switch (tab) {
|
|
1602
|
+
case 'pipeline':
|
|
1603
|
+
await this.LoadPipelineData();
|
|
1604
|
+
break;
|
|
1605
|
+
case 'sources':
|
|
1606
|
+
await this.loadSourcesData();
|
|
1607
|
+
break;
|
|
1608
|
+
case 'types':
|
|
1609
|
+
await this.loadContentTypesData();
|
|
1610
|
+
break;
|
|
1611
|
+
case 'tags':
|
|
1612
|
+
await this.loadTagLibraryData();
|
|
1613
|
+
break;
|
|
1614
|
+
case 'history':
|
|
1615
|
+
await this.loadRunHistoryData();
|
|
1616
|
+
break;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
// ════════════════════════════════════════════
|
|
1620
|
+
// PIPELINE TAB — Data Loading & Building
|
|
1621
|
+
// ════════════════════════════════════════════
|
|
1622
|
+
async LoadPipelineData() {
|
|
1623
|
+
try {
|
|
1624
|
+
const rv = new RunView();
|
|
1625
|
+
const [sourcesResult, itemsResult, runsResult, tagsResult, sourceTypesResult, contentTypesResult] = await rv.RunViews([
|
|
1626
|
+
{ EntityName: 'MJ: Content Sources', OrderBy: 'Name', ResultType: 'simple' },
|
|
1627
|
+
{ EntityName: 'MJ: Content Items', OrderBy: '__mj_UpdatedAt DESC', MaxRows: 200, ResultType: 'simple', Fields: ['ID', 'Name', 'ContentSourceID', 'ContentSource', 'ContentSourceType', 'ContentType', 'ContentFileType', 'URL', 'TextContent', 'Checksum', '__mj_CreatedAt', '__mj_UpdatedAt'] },
|
|
1628
|
+
{ EntityName: 'MJ: Content Process Runs', OrderBy: 'StartTime DESC', MaxRows: 100, ResultType: 'simple' },
|
|
1629
|
+
{ EntityName: 'MJ: Content Item Tags', ResultType: 'simple', Fields: ['ID', 'ItemID', 'Tag', 'Weight', '__mj_CreatedAt'] },
|
|
1630
|
+
{ EntityName: 'MJ: Content Source Types', ResultType: 'simple' },
|
|
1631
|
+
{ EntityName: 'MJ: Content Types', ResultType: 'simple' }
|
|
1632
|
+
]);
|
|
325
1633
|
this.contentSourcesRaw = sourcesResult.Success ? sourcesResult.Results : [];
|
|
326
|
-
this.
|
|
327
|
-
this.
|
|
328
|
-
this.
|
|
329
|
-
this.
|
|
1634
|
+
this.contentItemsRaw = itemsResult.Success ? itemsResult.Results : [];
|
|
1635
|
+
this.contentRunsRaw = runsResult.Success ? runsResult.Results : [];
|
|
1636
|
+
this.contentTagsRaw = tagsResult.Success ? tagsResult.Results : [];
|
|
1637
|
+
this.contentSourceTypesRaw = sourceTypesResult.Success ? sourceTypesResult.Results : [];
|
|
1638
|
+
this.contentTypesRaw = contentTypesResult.Success ? contentTypesResult.Results : [];
|
|
1639
|
+
this.buildNavItems();
|
|
330
1640
|
this.buildKPIMetrics();
|
|
331
1641
|
this.buildPipelineStages();
|
|
332
|
-
this.
|
|
333
|
-
this.
|
|
1642
|
+
this.buildFeedItems();
|
|
1643
|
+
this.buildSourceMinis();
|
|
1644
|
+
this.buildTrendingTags();
|
|
1645
|
+
}
|
|
1646
|
+
catch (error) {
|
|
1647
|
+
console.error('[Autotagging] Error loading pipeline data:', error);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
buildNavItems() {
|
|
1651
|
+
this.NavItems = [
|
|
1652
|
+
{ Tab: 'pipeline', Icon: 'fa-solid fa-gauge-high', Label: 'Pipeline', BadgeText: this.IsRunning ? 'Live' : '', BadgeClass: 'nav-badge-live' },
|
|
1653
|
+
{ Tab: 'sources', Icon: 'fa-solid fa-database', Label: 'Sources', BadgeText: String(this.contentSourcesRaw.length), BadgeClass: '' },
|
|
1654
|
+
{ Tab: 'types', Icon: 'fa-solid fa-sliders', Label: 'Content Types', BadgeText: String(this.contentTypesRaw.length), BadgeClass: '' },
|
|
1655
|
+
{ Tab: 'tags', Icon: 'fa-solid fa-tag', Label: 'Tag Library', BadgeText: String(this.contentTagsRaw.length), BadgeClass: '' },
|
|
1656
|
+
];
|
|
1657
|
+
}
|
|
1658
|
+
buildKPIMetrics() {
|
|
1659
|
+
const sourceCount = this.contentSourcesRaw.length;
|
|
1660
|
+
const itemCount = this.contentItemsRaw.length;
|
|
1661
|
+
const tagCount = this.contentTagsRaw.length;
|
|
1662
|
+
const errorCount = this.contentRunsRaw.filter(r => r['Status']?.toLowerCase() === 'error' || r['Status']?.toLowerCase() === 'failed').length;
|
|
1663
|
+
this.KPIMetrics = [
|
|
1664
|
+
{ Label: 'Active Sources', Value: sourceCount, Icon: 'fa-solid fa-satellite-dish', Trend: '', TrendUp: true },
|
|
1665
|
+
{ Label: 'Content Items', Value: itemCount, Icon: 'fa-solid fa-file-lines', Trend: '', TrendUp: true },
|
|
1666
|
+
{ Label: 'Tags Generated', Value: tagCount, Icon: 'fa-solid fa-tags', Trend: tagCount > 0 && itemCount > 0 ? `${(tagCount / itemCount).toFixed(1)} avg/item` : '', TrendUp: true },
|
|
1667
|
+
{ Label: 'Errors', Value: errorCount, Icon: 'fa-solid fa-circle-exclamation', Trend: '', TrendUp: false }
|
|
1668
|
+
];
|
|
1669
|
+
}
|
|
1670
|
+
buildPipelineStages() {
|
|
1671
|
+
this.PipelineStages = [
|
|
1672
|
+
{ Name: 'Ingest', Icon: 'fa-solid fa-download', Status: 'idle', Count: '\u2014' },
|
|
1673
|
+
{ Name: 'Extract', Icon: 'fa-solid fa-file-lines', Status: 'idle', Count: '\u2014' },
|
|
1674
|
+
{ Name: 'Chunk', Icon: 'fa-solid fa-scissors', Status: 'idle', Count: '\u2014' },
|
|
1675
|
+
{ Name: 'Tag', Icon: 'fa-solid fa-tags', Status: 'idle', Count: '\u2014' },
|
|
1676
|
+
{ Name: 'Vectorize', Icon: 'fa-solid fa-vector-square', Status: 'idle', Count: '\u2014' }
|
|
1677
|
+
];
|
|
1678
|
+
}
|
|
1679
|
+
buildFeedItems() {
|
|
1680
|
+
const tagsByItem = this.countTagsByItem();
|
|
1681
|
+
this.FeedItems = this.contentItemsRaw.slice(0, 50).map(item => {
|
|
1682
|
+
const itemId = item['ID'];
|
|
1683
|
+
const itemTags = this.getTopTagsForItem(itemId, 3);
|
|
1684
|
+
return {
|
|
1685
|
+
Name: item['Name'] ?? 'Unnamed Item',
|
|
1686
|
+
SourceName: item['ContentSource'] ?? 'Unknown',
|
|
1687
|
+
Tags: itemTags,
|
|
1688
|
+
TimeAgo: this.formatRelativeTime(item['__mj_UpdatedAt']),
|
|
1689
|
+
Status: this.inferItemStatus(tagsByItem.get(itemId) ?? 0)
|
|
1690
|
+
};
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
buildSourceMinis() {
|
|
1694
|
+
const itemCountBySource = this.countItemsBySource();
|
|
1695
|
+
this.SourceMinis = this.contentSourcesRaw.map(source => {
|
|
1696
|
+
const id = source['ID'];
|
|
1697
|
+
const itemCount = itemCountBySource.get(id) ?? 0;
|
|
1698
|
+
const typeName = source['ContentSourceType'] ?? 'Unknown';
|
|
1699
|
+
return {
|
|
1700
|
+
ID: id,
|
|
1701
|
+
Name: source['Name'] ?? 'Unnamed',
|
|
1702
|
+
Icon: this.GetSourceTypeIcon(typeName),
|
|
1703
|
+
Meta: `${this.formatNumber(itemCount)} items`,
|
|
1704
|
+
StatusClass: 'active'
|
|
1705
|
+
};
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
buildTrendingTags() {
|
|
1709
|
+
const tagCounts = this.countAllTags();
|
|
1710
|
+
const avgWeights = this.computeAvgWeights();
|
|
1711
|
+
const scored = Array.from(tagCounts.entries()).map(([tag, count]) => {
|
|
1712
|
+
const weight = avgWeights.get(tag) ?? 1.0;
|
|
1713
|
+
return { tag, count, weight, score: count * weight };
|
|
1714
|
+
}).sort((a, b) => b.score - a.score).slice(0, 12);
|
|
1715
|
+
const maxScore = scored.length > 0 ? scored[0].score : 1;
|
|
1716
|
+
this.TrendingTags = scored.map(s => ({
|
|
1717
|
+
Tag: s.tag,
|
|
1718
|
+
AvgWeight: s.weight,
|
|
1719
|
+
SizeClass: s.score >= maxScore * 0.7 ? 'large' : s.score >= maxScore * 0.3 ? '' : 'small'
|
|
1720
|
+
}));
|
|
1721
|
+
}
|
|
1722
|
+
// ════════════════════════════════════════════
|
|
1723
|
+
// SOURCES TAB
|
|
1724
|
+
// ════════════════════════════════════════════
|
|
1725
|
+
async loadSourcesData() {
|
|
1726
|
+
await this.ensureBaseDataLoaded();
|
|
1727
|
+
this.buildSourceCards();
|
|
1728
|
+
}
|
|
1729
|
+
buildSourceCards() {
|
|
1730
|
+
const itemCountBySource = this.countItemsBySource();
|
|
1731
|
+
const tagCountBySource = this.countTagsBySource();
|
|
1732
|
+
const lastRunBySource = this.getLastRunBySource();
|
|
1733
|
+
this.SourceCards = this.contentSourcesRaw.map(source => {
|
|
1734
|
+
const id = source['ID'];
|
|
1735
|
+
const itemCount = itemCountBySource.get(id) ?? 0;
|
|
1736
|
+
const tagCount = tagCountBySource.get(id) ?? 0;
|
|
1737
|
+
const avgTags = itemCount > 0 ? (tagCount / itemCount).toFixed(1) : '0';
|
|
1738
|
+
const lastRun = lastRunBySource.get(id);
|
|
1739
|
+
const typeName = source['ContentSourceType'] ?? 'Unknown';
|
|
1740
|
+
const lastRunStatus = lastRun ? lastRun['Status']?.toLowerCase() : null;
|
|
1741
|
+
const hasError = lastRunStatus === 'error' || lastRunStatus === 'failed';
|
|
1742
|
+
return {
|
|
1743
|
+
ID: id,
|
|
1744
|
+
Name: source['Name'] ?? 'Unnamed Source',
|
|
1745
|
+
SourceTypeName: typeName,
|
|
1746
|
+
ContentTypeName: source['ContentType'] ?? 'Unknown',
|
|
1747
|
+
FileTypeName: source['ContentFileType'] ?? 'Unknown',
|
|
1748
|
+
Icon: this.GetSourceTypeIcon(typeName),
|
|
1749
|
+
StatusClass: hasError ? 'error' : 'active',
|
|
1750
|
+
StatusLabel: hasError ? 'Error' : 'Active',
|
|
1751
|
+
URL: source['URL'] ?? '',
|
|
1752
|
+
ItemCount: itemCount,
|
|
1753
|
+
TagCount: tagCount,
|
|
1754
|
+
AvgTags: avgTags,
|
|
1755
|
+
LastRunAgo: lastRun ? this.formatRelativeTime(lastRun['StartTime']) : 'Never',
|
|
1756
|
+
ContentSourceTypeID: source['ContentSourceTypeID'],
|
|
1757
|
+
ContentTypeID: source['ContentTypeID'],
|
|
1758
|
+
ContentFileTypeID: source['ContentFileTypeID'],
|
|
1759
|
+
EmbeddingModelID: source['EmbeddingModelID'] ?? '',
|
|
1760
|
+
VectorIndexID: source['VectorIndexID'] ?? ''
|
|
1761
|
+
};
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
// ════════════════════════════════════════════
|
|
1765
|
+
// CONTENT TYPES TAB
|
|
1766
|
+
// ════════════════════════════════════════════
|
|
1767
|
+
async loadContentTypesData() {
|
|
1768
|
+
if (this.contentTypesRaw.length === 0) {
|
|
1769
|
+
const rv = new RunView();
|
|
1770
|
+
const result = await rv.RunView({ EntityName: 'MJ: Content Types', ResultType: 'simple' });
|
|
1771
|
+
if (result.Success)
|
|
1772
|
+
this.contentTypesRaw = result.Results;
|
|
1773
|
+
}
|
|
1774
|
+
await this.ensureBaseDataLoaded();
|
|
1775
|
+
this.buildContentTypeCards();
|
|
1776
|
+
}
|
|
1777
|
+
buildContentTypeCards() {
|
|
1778
|
+
const sourcesUsingByType = this.countSourcesByContentType();
|
|
1779
|
+
const itemsByType = this.countItemsByContentType();
|
|
1780
|
+
this.ContentTypeCards = this.contentTypesRaw.map(ct => {
|
|
1781
|
+
const id = ct['ID'];
|
|
1782
|
+
const minTags = ct['MinTags'] ?? 1;
|
|
1783
|
+
const maxTags = ct['MaxTags'] ?? 10;
|
|
1784
|
+
const range = 15; // max possible
|
|
1785
|
+
return {
|
|
1786
|
+
ID: id,
|
|
1787
|
+
Name: ct['Name'] ?? 'Unnamed',
|
|
1788
|
+
Description: ct['Description'] ?? '',
|
|
1789
|
+
AIModelName: ct['AIModel'] ?? 'Default Model',
|
|
1790
|
+
AIModelID: ct['AIModelID'] ?? '',
|
|
1791
|
+
MinTags: minTags,
|
|
1792
|
+
MaxTags: maxTags,
|
|
1793
|
+
SourcesUsing: sourcesUsingByType.get(id) ?? 0,
|
|
1794
|
+
ItemsTagged: itemsByType.get(id) ?? 0,
|
|
1795
|
+
RangeLeftPct: Math.round((minTags / range) * 100),
|
|
1796
|
+
RangeRightPct: Math.round(100 - (maxTags / range) * 100),
|
|
1797
|
+
EmbeddingModelID: ct['EmbeddingModelID'] ?? '',
|
|
1798
|
+
VectorIndexID: ct['VectorIndexID'] ?? ''
|
|
1799
|
+
};
|
|
1800
|
+
});
|
|
1801
|
+
}
|
|
1802
|
+
// ════════════════════════════════════════════
|
|
1803
|
+
// TAG LIBRARY TAB
|
|
1804
|
+
// ════════════════════════════════════════════
|
|
1805
|
+
async loadTagLibraryData() {
|
|
1806
|
+
await this.ensureBaseDataLoaded();
|
|
1807
|
+
this.buildTagRows();
|
|
1808
|
+
this.buildTagCloud();
|
|
1809
|
+
this.buildTagsBySource();
|
|
1810
|
+
this.FilteredTagRows = this.TagRows;
|
|
1811
|
+
}
|
|
1812
|
+
buildTagRows() {
|
|
1813
|
+
const tagCounts = this.countAllTags();
|
|
1814
|
+
const avgWeights = this.computeAvgWeights();
|
|
1815
|
+
const tagSourceMap = this.getTopSourcePerTag();
|
|
1816
|
+
const tagFirstSeen = this.getFirstSeenPerTag();
|
|
1817
|
+
const sorted = Array.from(tagCounts.entries()).sort((a, b) => b[1] - a[1]);
|
|
1818
|
+
const maxCount = sorted.length > 0 ? sorted[0][1] : 1;
|
|
1819
|
+
this.TagRows = sorted.map(([tag, count]) => ({
|
|
1820
|
+
Tag: tag,
|
|
1821
|
+
UsageCount: count,
|
|
1822
|
+
AvgWeight: avgWeights.get(tag) ?? 1.0,
|
|
1823
|
+
BarWidthPct: Math.round((count / maxCount) * 100),
|
|
1824
|
+
TopSource: tagSourceMap.get(tag) ?? 'Unknown',
|
|
1825
|
+
FirstSeen: tagFirstSeen.get(tag) ?? ''
|
|
1826
|
+
}));
|
|
1827
|
+
}
|
|
1828
|
+
buildTagCloud() {
|
|
1829
|
+
const tagCounts = this.countAllTags();
|
|
1830
|
+
const avgWeights = this.computeAvgWeights();
|
|
1831
|
+
// Sort by a combined score: usage count * avg weight (so high-weight, high-count tags bubble up)
|
|
1832
|
+
const scored = Array.from(tagCounts.entries()).map(([tag, count]) => {
|
|
1833
|
+
const weight = avgWeights.get(tag) ?? 1.0;
|
|
1834
|
+
return { tag, count, weight, score: count * weight };
|
|
1835
|
+
}).sort((a, b) => b.score - a.score).slice(0, 20);
|
|
1836
|
+
const maxScore = scored.length > 0 ? scored[0].score : 1;
|
|
1837
|
+
this.TagCloud = scored.map(s => ({
|
|
1838
|
+
Tag: s.tag,
|
|
1839
|
+
AvgWeight: s.weight,
|
|
1840
|
+
SizeClass: s.score >= maxScore * 0.7 ? 'large' : s.score >= maxScore * 0.3 ? '' : 'small'
|
|
1841
|
+
}));
|
|
1842
|
+
}
|
|
1843
|
+
buildTagsBySource() {
|
|
1844
|
+
const sourceTagCounts = new Map();
|
|
1845
|
+
const itemSourceMap = new Map();
|
|
1846
|
+
for (const item of this.contentItemsRaw) {
|
|
1847
|
+
itemSourceMap.set(item['ID'], item['ContentSource'] ?? 'Unknown');
|
|
1848
|
+
}
|
|
1849
|
+
for (const tag of this.contentTagsRaw) {
|
|
1850
|
+
const source = itemSourceMap.get(tag['ItemID']) ?? 'Unknown';
|
|
1851
|
+
sourceTagCounts.set(source, (sourceTagCounts.get(source) ?? 0) + 1);
|
|
1852
|
+
}
|
|
1853
|
+
this.TagsBySource = Array.from(sourceTagCounts.entries())
|
|
1854
|
+
.sort((a, b) => b[1] - a[1])
|
|
1855
|
+
.map(([name, count]) => ({ SourceName: name, Count: count }));
|
|
1856
|
+
}
|
|
1857
|
+
/** Convert a string ID to a CompositeKey for tree-dropdown binding */
|
|
1858
|
+
ToCompositeKey(id) {
|
|
1859
|
+
if (!id)
|
|
1860
|
+
return null;
|
|
1861
|
+
return new CompositeKey([{ FieldName: 'ID', Value: id }]);
|
|
1862
|
+
}
|
|
1863
|
+
/** Extract the ID string from a CompositeKey (from tree-dropdown ValueChange) */
|
|
1864
|
+
FromCompositeKey(key) {
|
|
1865
|
+
if (!key)
|
|
1866
|
+
return '';
|
|
1867
|
+
const ck = Array.isArray(key) ? key[0] : key;
|
|
1868
|
+
if (!ck?.KeyValuePairs?.length)
|
|
1869
|
+
return '';
|
|
1870
|
+
return String(ck.KeyValuePairs[0].Value || '');
|
|
1871
|
+
}
|
|
1872
|
+
FilterTags() {
|
|
1873
|
+
const q = this.TagSearchQuery.toLowerCase().trim();
|
|
1874
|
+
this.FilteredTagRows = q
|
|
1875
|
+
? this.TagRows.filter(r => r.Tag.toLowerCase().includes(q))
|
|
1876
|
+
: this.TagRows;
|
|
1877
|
+
this.cdr.detectChanges();
|
|
1878
|
+
}
|
|
1879
|
+
// ════════════════════════════════════════════
|
|
1880
|
+
// RUN HISTORY TAB
|
|
1881
|
+
// ════════════════════════════════════════════
|
|
1882
|
+
async loadRunHistoryData() {
|
|
1883
|
+
if (this.contentRunsRaw.length === 0) {
|
|
1884
|
+
const rv = new RunView();
|
|
1885
|
+
const result = await rv.RunView({
|
|
1886
|
+
EntityName: 'MJ: Content Process Runs',
|
|
1887
|
+
OrderBy: 'StartTime DESC',
|
|
1888
|
+
MaxRows: 200,
|
|
1889
|
+
ResultType: 'simple'
|
|
1890
|
+
});
|
|
1891
|
+
if (result.Success)
|
|
1892
|
+
this.contentRunsRaw = result.Results;
|
|
1893
|
+
}
|
|
1894
|
+
this.buildRunHistoryRows();
|
|
1895
|
+
this.buildHistorySourceOptions();
|
|
1896
|
+
this.FilteredRunRows = this.RunHistoryRows;
|
|
1897
|
+
}
|
|
1898
|
+
buildRunHistoryRows() {
|
|
1899
|
+
this.RunHistoryRows = this.contentRunsRaw.map(run => {
|
|
1900
|
+
const status = run['Status'] ?? 'Unknown';
|
|
1901
|
+
const startTime = run['StartTime'];
|
|
1902
|
+
const endTime = run['EndTime'];
|
|
1903
|
+
const duration = this.computeDuration(startTime, endTime);
|
|
1904
|
+
const processedItems = run['ProcessedItems'];
|
|
1905
|
+
const statusLower = status.toLowerCase();
|
|
1906
|
+
const isFailed = statusLower === 'error' || statusLower === 'failed';
|
|
1907
|
+
const isRunning = statusLower === 'running' || statusLower === 'processing';
|
|
1908
|
+
return {
|
|
1909
|
+
ID: run['ID'],
|
|
1910
|
+
Status: this.displayStatus(status),
|
|
1911
|
+
StatusClass: isFailed ? 'failed' : isRunning ? 'running' : 'complete',
|
|
1912
|
+
SourceName: run['Source'] ?? 'Unknown',
|
|
1913
|
+
StartedDisplay: startTime ? this.formatDate(startTime) : '\u2014',
|
|
1914
|
+
Duration: duration,
|
|
1915
|
+
Items: processedItems != null ? this.formatNumber(processedItems) : '\u2014',
|
|
1916
|
+
Tags: '\u2014',
|
|
1917
|
+
Errors: isFailed ? status : '0',
|
|
1918
|
+
ErrorClass: isFailed ? 'run-error-text' : ''
|
|
1919
|
+
};
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
buildHistorySourceOptions() {
|
|
1923
|
+
const sources = new Set();
|
|
1924
|
+
for (const run of this.contentRunsRaw) {
|
|
1925
|
+
const s = run['Source'];
|
|
1926
|
+
if (s)
|
|
1927
|
+
sources.add(s);
|
|
1928
|
+
}
|
|
1929
|
+
this.HistorySourceOptions = Array.from(sources).sort();
|
|
1930
|
+
}
|
|
1931
|
+
FilterRunHistory() {
|
|
1932
|
+
this.FilteredRunRows = this.RunHistoryRows.filter(row => {
|
|
1933
|
+
if (this.HistorySourceFilter && row.SourceName !== this.HistorySourceFilter)
|
|
1934
|
+
return false;
|
|
1935
|
+
if (this.HistoryStatusFilter && row.StatusClass !== this.HistoryStatusFilter)
|
|
1936
|
+
return false;
|
|
1937
|
+
return true;
|
|
1938
|
+
});
|
|
1939
|
+
this.cdr.detectChanges();
|
|
1940
|
+
}
|
|
1941
|
+
// ════════════════════════════════════════════
|
|
1942
|
+
// SLIDE-IN FORM — Sources
|
|
1943
|
+
// ════════════════════════════════════════════
|
|
1944
|
+
async OpenAddSourceForm() {
|
|
1945
|
+
await this.ensureFormDropdownsLoaded();
|
|
1946
|
+
this.resetSourceForm();
|
|
1947
|
+
this.FormMode = 'add-source';
|
|
1948
|
+
this.cdr.detectChanges();
|
|
1949
|
+
}
|
|
1950
|
+
async OpenEditSourceForm(card) {
|
|
1951
|
+
await this.ensureFormDropdownsLoaded();
|
|
1952
|
+
this.FormSourceName = card.Name;
|
|
1953
|
+
this.FormSourceTypeID = card.ContentSourceTypeID;
|
|
1954
|
+
this.FormContentTypeID = card.ContentTypeID;
|
|
1955
|
+
this.FormFileTypeID = card.ContentFileTypeID;
|
|
1956
|
+
this.FormSourceURL = card.URL;
|
|
1957
|
+
this.FormSourceEmbeddingModelID = card.EmbeddingModelID ?? '';
|
|
1958
|
+
this.FormSourceVectorIndexID = card.VectorIndexID ?? '';
|
|
1959
|
+
this.EditingSourceID = card.ID;
|
|
1960
|
+
this.FormMode = 'edit-source';
|
|
1961
|
+
this.cdr.detectChanges();
|
|
1962
|
+
}
|
|
1963
|
+
async SaveSource() {
|
|
1964
|
+
if (this.FormSaving)
|
|
1965
|
+
return;
|
|
1966
|
+
this.FormSaving = true;
|
|
1967
|
+
this.cdr.detectChanges();
|
|
1968
|
+
try {
|
|
1969
|
+
const md = new Metadata();
|
|
1970
|
+
const entity = await md.GetEntityObject('MJ: Content Sources');
|
|
1971
|
+
if (this.FormMode === 'edit-source' && this.EditingSourceID) {
|
|
1972
|
+
await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: this.EditingSourceID }]));
|
|
1973
|
+
}
|
|
1974
|
+
else {
|
|
1975
|
+
entity.NewRecord();
|
|
1976
|
+
}
|
|
1977
|
+
entity.Set('Name', this.FormSourceName);
|
|
1978
|
+
entity.Set('ContentSourceTypeID', this.FormSourceTypeID);
|
|
1979
|
+
entity.Set('ContentTypeID', this.FormContentTypeID);
|
|
1980
|
+
entity.Set('ContentFileTypeID', this.FormFileTypeID);
|
|
1981
|
+
entity.Set('URL', this.FormSourceURL);
|
|
1982
|
+
entity.Set('EmbeddingModelID', this.FormSourceEmbeddingModelID || null);
|
|
1983
|
+
entity.Set('VectorIndexID', this.FormSourceVectorIndexID || null);
|
|
1984
|
+
const saved = await entity.Save();
|
|
1985
|
+
if (saved) {
|
|
1986
|
+
MJNotificationService.Instance.CreateSimpleNotification(this.FormMode === 'edit-source' ? 'Source updated' : 'Source created', 'success', 2500);
|
|
1987
|
+
this.CloseForm();
|
|
1988
|
+
await this.refreshSourcesTab();
|
|
1989
|
+
}
|
|
1990
|
+
else {
|
|
1991
|
+
MJNotificationService.Instance.CreateSimpleNotification('Failed to save source', 'error', 3000);
|
|
1992
|
+
}
|
|
334
1993
|
}
|
|
335
1994
|
catch (error) {
|
|
336
|
-
|
|
337
|
-
|
|
1995
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
1996
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 4000);
|
|
338
1997
|
}
|
|
339
1998
|
finally {
|
|
340
|
-
this.
|
|
1999
|
+
this.FormSaving = false;
|
|
341
2000
|
this.cdr.detectChanges();
|
|
342
2001
|
}
|
|
343
2002
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
2003
|
+
async DeleteSource(card) {
|
|
2004
|
+
if (!confirm(`Delete source "${card.Name}"? This cannot be undone.`))
|
|
2005
|
+
return;
|
|
2006
|
+
try {
|
|
2007
|
+
const md = new Metadata();
|
|
2008
|
+
const entity = await md.GetEntityObject('MJ: Content Sources');
|
|
2009
|
+
await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: card.ID }]));
|
|
2010
|
+
const deleted = await entity.Delete();
|
|
2011
|
+
if (deleted) {
|
|
2012
|
+
MJNotificationService.Instance.CreateSimpleNotification('Source deleted', 'success', 2500);
|
|
2013
|
+
await this.refreshSourcesTab();
|
|
2014
|
+
}
|
|
2015
|
+
else {
|
|
2016
|
+
MJNotificationService.Instance.CreateSimpleNotification('Failed to delete source', 'error', 3000);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
catch (error) {
|
|
2020
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
2021
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 4000);
|
|
2022
|
+
}
|
|
347
2023
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
2024
|
+
// ════════════════════════════════════════════
|
|
2025
|
+
// SLIDE-IN FORM — Content Types
|
|
2026
|
+
// ════════════════════════════════════════════
|
|
2027
|
+
async OpenAddTypeForm() {
|
|
2028
|
+
await this.ensureFormDropdownsLoaded();
|
|
2029
|
+
this.resetTypeForm();
|
|
2030
|
+
this.FormMode = 'add-type';
|
|
2031
|
+
this.cdr.detectChanges();
|
|
2032
|
+
}
|
|
2033
|
+
async OpenEditTypeForm(card) {
|
|
2034
|
+
await this.ensureFormDropdownsLoaded();
|
|
2035
|
+
this.FormTypeName = card.Name;
|
|
2036
|
+
this.FormTypeDescription = card.Description;
|
|
2037
|
+
this.FormTypeAIModelID = card.AIModelID;
|
|
2038
|
+
this.FormTypeMinTags = card.MinTags;
|
|
2039
|
+
this.FormTypeMaxTags = card.MaxTags;
|
|
2040
|
+
this.FormTypeEmbeddingModelID = card.EmbeddingModelID ?? '';
|
|
2041
|
+
this.FormTypeVectorIndexID = card.VectorIndexID ?? '';
|
|
2042
|
+
this.EditingTypeID = card.ID;
|
|
2043
|
+
this.FormMode = 'edit-type';
|
|
2044
|
+
this.cdr.detectChanges();
|
|
2045
|
+
}
|
|
2046
|
+
async SaveContentType() {
|
|
2047
|
+
if (this.FormSaving)
|
|
2048
|
+
return;
|
|
2049
|
+
this.FormSaving = true;
|
|
2050
|
+
this.cdr.detectChanges();
|
|
2051
|
+
try {
|
|
2052
|
+
const md = new Metadata();
|
|
2053
|
+
const entity = await md.GetEntityObject('MJ: Content Types');
|
|
2054
|
+
if (this.FormMode === 'edit-type' && this.EditingTypeID) {
|
|
2055
|
+
await entity.InnerLoad(new CompositeKey([{ FieldName: 'ID', Value: this.EditingTypeID }]));
|
|
2056
|
+
}
|
|
2057
|
+
else {
|
|
2058
|
+
entity.NewRecord();
|
|
2059
|
+
}
|
|
2060
|
+
entity.Set('Name', this.FormTypeName);
|
|
2061
|
+
entity.Set('Description', this.FormTypeDescription);
|
|
2062
|
+
entity.Set('AIModelID', this.FormTypeAIModelID);
|
|
2063
|
+
entity.Set('MinTags', this.FormTypeMinTags);
|
|
2064
|
+
entity.Set('MaxTags', this.FormTypeMaxTags);
|
|
2065
|
+
entity.Set('EmbeddingModelID', this.FormTypeEmbeddingModelID || null);
|
|
2066
|
+
entity.Set('VectorIndexID', this.FormTypeVectorIndexID || null);
|
|
2067
|
+
const saved = await entity.Save();
|
|
2068
|
+
if (saved) {
|
|
2069
|
+
MJNotificationService.Instance.CreateSimpleNotification(this.FormMode === 'edit-type' ? 'Content type updated' : 'Content type created', 'success', 2500);
|
|
2070
|
+
this.CloseForm();
|
|
2071
|
+
await this.refreshContentTypesTab();
|
|
2072
|
+
}
|
|
2073
|
+
else {
|
|
2074
|
+
MJNotificationService.Instance.CreateSimpleNotification('Failed to save content type', 'error', 3000);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
catch (error) {
|
|
2078
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
2079
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Error: ${msg}`, 'error', 4000);
|
|
2080
|
+
}
|
|
2081
|
+
finally {
|
|
2082
|
+
this.FormSaving = false;
|
|
2083
|
+
this.cdr.detectChanges();
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
CloseForm() {
|
|
2087
|
+
this.FormMode = 'none';
|
|
2088
|
+
this.cdr.detectChanges();
|
|
2089
|
+
}
|
|
2090
|
+
// ════════════════════════════════════════════
|
|
2091
|
+
// PIPELINE RUN
|
|
2092
|
+
// ════════════════════════════════════════════
|
|
2093
|
+
async RunPipeline() {
|
|
2094
|
+
if (this.IsRunning)
|
|
2095
|
+
return;
|
|
2096
|
+
const provider = Metadata.Provider;
|
|
2097
|
+
if (!provider)
|
|
2098
|
+
return;
|
|
2099
|
+
this.IsRunning = true;
|
|
2100
|
+
this.RunProgress = 0;
|
|
2101
|
+
this.RunStage = 'Starting...';
|
|
2102
|
+
this.RunCurrentItem = '';
|
|
2103
|
+
this.cdr.detectChanges();
|
|
2104
|
+
try {
|
|
2105
|
+
const aiClient = new GraphQLAIClient(provider);
|
|
2106
|
+
const result = await aiClient.RunAutotagPipeline();
|
|
2107
|
+
if (!result.Success || !result.PipelineRunID) {
|
|
2108
|
+
this.IsRunning = false;
|
|
2109
|
+
this.RunStage = '';
|
|
2110
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Pipeline failed: ${result.ErrorMessage ?? 'Unknown error'}`, 'error', 5000);
|
|
2111
|
+
this.cdr.detectChanges();
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
this.subscribeToPipelineProgress(result.PipelineRunID);
|
|
2115
|
+
}
|
|
2116
|
+
catch (error) {
|
|
2117
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
2118
|
+
console.error('[Autotagging] Error starting pipeline:', msg);
|
|
2119
|
+
this.IsRunning = false;
|
|
2120
|
+
this.RunStage = '';
|
|
2121
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Pipeline error: ${msg}`, 'error', 5000);
|
|
2122
|
+
this.cdr.detectChanges();
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
subscribeToPipelineProgress(pipelineRunID) {
|
|
2126
|
+
const provider = Metadata.Provider;
|
|
2127
|
+
const subscriptionQuery = `
|
|
2128
|
+
subscription PipelineProgress($pipelineRunID: String!) {
|
|
2129
|
+
PipelineProgress(pipelineRunID: $pipelineRunID) {
|
|
2130
|
+
PipelineRunID
|
|
2131
|
+
Stage
|
|
2132
|
+
TotalItems
|
|
2133
|
+
ProcessedItems
|
|
2134
|
+
CurrentItem
|
|
2135
|
+
PercentComplete
|
|
2136
|
+
ElapsedMs
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
`;
|
|
2140
|
+
let idleTimer = null;
|
|
2141
|
+
const finishPipeline = (success) => {
|
|
2142
|
+
if (idleTimer)
|
|
2143
|
+
clearTimeout(idleTimer);
|
|
2144
|
+
rxSub?.unsubscribe();
|
|
2145
|
+
Promise.resolve().then(async () => {
|
|
2146
|
+
this.IsRunning = false;
|
|
2147
|
+
this.RunStage = success ? 'Complete' : 'Error';
|
|
2148
|
+
this.RunProgress = success ? 100 : 0;
|
|
2149
|
+
for (const stage of this.PipelineStages) {
|
|
2150
|
+
stage.Status = 'idle';
|
|
2151
|
+
stage.Count = '\u2014';
|
|
2152
|
+
}
|
|
2153
|
+
if (success) {
|
|
2154
|
+
this.tabDataLoaded.clear();
|
|
2155
|
+
await this.LoadPipelineData();
|
|
2156
|
+
this.tabDataLoaded.add('pipeline');
|
|
2157
|
+
MJNotificationService.Instance.CreateSimpleNotification('Pipeline complete', 'success', 3000);
|
|
2158
|
+
}
|
|
2159
|
+
this.cdr.detectChanges();
|
|
2160
|
+
});
|
|
2161
|
+
};
|
|
2162
|
+
const resetIdleTimer = () => {
|
|
2163
|
+
if (idleTimer)
|
|
2164
|
+
clearTimeout(idleTimer);
|
|
2165
|
+
idleTimer = setTimeout(() => {
|
|
2166
|
+
if (this.IsRunning)
|
|
2167
|
+
finishPipeline(true);
|
|
2168
|
+
}, 30000);
|
|
2169
|
+
};
|
|
2170
|
+
resetIdleTimer();
|
|
2171
|
+
const sub = provider.subscribe(subscriptionQuery, { pipelineRunID });
|
|
2172
|
+
const rxSub = sub.pipe(takeUntil(this.destroy$)).subscribe({
|
|
2173
|
+
next: (data) => {
|
|
2174
|
+
const progress = data['PipelineProgress'];
|
|
2175
|
+
if (!progress)
|
|
2176
|
+
return;
|
|
2177
|
+
const stage = progress['Stage'];
|
|
2178
|
+
const pct = progress['PercentComplete'];
|
|
2179
|
+
const currentItem = progress['CurrentItem'];
|
|
2180
|
+
this.RunProgress = pct;
|
|
2181
|
+
this.RunStage = this.formatStageName(stage);
|
|
2182
|
+
this.RunCurrentItem = currentItem ?? '';
|
|
2183
|
+
this.updateStagesForActiveRun(stage);
|
|
2184
|
+
this.cdr.detectChanges();
|
|
2185
|
+
if (stage === 'complete') {
|
|
2186
|
+
finishPipeline(true);
|
|
2187
|
+
}
|
|
2188
|
+
else if (stage === 'error') {
|
|
2189
|
+
finishPipeline(false);
|
|
2190
|
+
}
|
|
2191
|
+
else {
|
|
2192
|
+
resetIdleTimer();
|
|
2193
|
+
}
|
|
2194
|
+
},
|
|
2195
|
+
error: (err) => {
|
|
2196
|
+
console.error('[Autotagging] Pipeline subscription error:', err);
|
|
2197
|
+
finishPipeline(false);
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
updateStagesForActiveRun(activeStageCode) {
|
|
2202
|
+
const stageCodeToName = {
|
|
2203
|
+
'ingest': 'Ingest', 'extract': 'Extract', 'chunk': 'Chunk',
|
|
2204
|
+
'tag': 'Tag', 'autotag': 'Tag', 'vectorize': 'Vectorize'
|
|
2205
|
+
};
|
|
2206
|
+
const activeName = stageCodeToName[activeStageCode] ?? '';
|
|
2207
|
+
let passedActive = false;
|
|
2208
|
+
for (const stage of this.PipelineStages) {
|
|
2209
|
+
if (stage.Name === activeName) {
|
|
2210
|
+
stage.Status = 'active';
|
|
2211
|
+
passedActive = true;
|
|
2212
|
+
}
|
|
2213
|
+
else if (!passedActive) {
|
|
2214
|
+
stage.Status = 'complete';
|
|
2215
|
+
}
|
|
2216
|
+
else {
|
|
2217
|
+
stage.Status = 'idle';
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
formatStageName(stage) {
|
|
2222
|
+
const map = {
|
|
2223
|
+
'extract': 'Extracting content', 'autotag': 'Running autotaggers',
|
|
2224
|
+
'vectorize': 'Vectorizing content', 'complete': 'Complete',
|
|
2225
|
+
'error': 'Error', 'ingest': 'Ingesting', 'chunk': 'Chunking',
|
|
2226
|
+
'tag': 'Tagging'
|
|
2227
|
+
};
|
|
2228
|
+
return map[stage] ?? stage;
|
|
2229
|
+
}
|
|
2230
|
+
// ════════════════════════════════════════════
|
|
2231
|
+
// HELPER — Aggregation utilities
|
|
2232
|
+
// ════════════════════════════════════════════
|
|
2233
|
+
countTagsByItem() {
|
|
2234
|
+
const counts = new Map();
|
|
2235
|
+
for (const tag of this.contentTagsRaw) {
|
|
2236
|
+
const itemId = tag['ItemID'];
|
|
2237
|
+
if (itemId)
|
|
2238
|
+
counts.set(itemId, (counts.get(itemId) ?? 0) + 1);
|
|
2239
|
+
}
|
|
2240
|
+
return counts;
|
|
2241
|
+
}
|
|
2242
|
+
getTopTagsForItem(itemId, max) {
|
|
2243
|
+
const tags = [];
|
|
2244
|
+
for (const tag of this.contentTagsRaw) {
|
|
2245
|
+
if (tag['ItemID'] === itemId) {
|
|
2246
|
+
tags.push(tag['Tag']);
|
|
2247
|
+
if (tags.length >= max)
|
|
2248
|
+
break;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
return tags;
|
|
2252
|
+
}
|
|
2253
|
+
countItemsBySource() {
|
|
2254
|
+
const counts = new Map();
|
|
2255
|
+
for (const item of this.contentItemsRaw) {
|
|
2256
|
+
const sourceId = item['ContentSourceID'];
|
|
2257
|
+
if (sourceId)
|
|
2258
|
+
counts.set(sourceId, (counts.get(sourceId) ?? 0) + 1);
|
|
2259
|
+
}
|
|
2260
|
+
return counts;
|
|
2261
|
+
}
|
|
2262
|
+
countTagsBySource() {
|
|
2263
|
+
const itemSourceMap = new Map();
|
|
2264
|
+
for (const item of this.contentItemsRaw) {
|
|
2265
|
+
itemSourceMap.set(item['ID'], item['ContentSourceID']);
|
|
2266
|
+
}
|
|
2267
|
+
const counts = new Map();
|
|
2268
|
+
for (const tag of this.contentTagsRaw) {
|
|
2269
|
+
const sourceId = itemSourceMap.get(tag['ItemID']);
|
|
2270
|
+
if (sourceId)
|
|
2271
|
+
counts.set(sourceId, (counts.get(sourceId) ?? 0) + 1);
|
|
2272
|
+
}
|
|
2273
|
+
return counts;
|
|
2274
|
+
}
|
|
2275
|
+
getLastRunBySource() {
|
|
2276
|
+
const map = new Map();
|
|
2277
|
+
for (const run of this.contentRunsRaw) {
|
|
2278
|
+
const sourceId = run['SourceID'];
|
|
2279
|
+
if (sourceId && !map.has(sourceId)) {
|
|
2280
|
+
map.set(sourceId, run);
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
return map;
|
|
2284
|
+
}
|
|
2285
|
+
countAllTags() {
|
|
2286
|
+
const counts = new Map();
|
|
2287
|
+
for (const tag of this.contentTagsRaw) {
|
|
2288
|
+
const t = tag['Tag'];
|
|
2289
|
+
if (t)
|
|
2290
|
+
counts.set(t, (counts.get(t) ?? 0) + 1);
|
|
2291
|
+
}
|
|
2292
|
+
return counts;
|
|
2293
|
+
}
|
|
2294
|
+
/** Compute average weight per tag across all occurrences */
|
|
2295
|
+
computeAvgWeights() {
|
|
2296
|
+
const sums = new Map();
|
|
2297
|
+
const counts = new Map();
|
|
2298
|
+
for (const tag of this.contentTagsRaw) {
|
|
2299
|
+
const t = tag['Tag'];
|
|
2300
|
+
const w = Number(tag['Weight'] ?? 0.5);
|
|
2301
|
+
if (t) {
|
|
2302
|
+
sums.set(t, (sums.get(t) ?? 0) + w);
|
|
2303
|
+
counts.set(t, (counts.get(t) ?? 0) + 1);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
const avgs = new Map();
|
|
2307
|
+
for (const [t, sum] of sums) {
|
|
2308
|
+
avgs.set(t, Math.round((sum / (counts.get(t) ?? 1)) * 100) / 100);
|
|
2309
|
+
}
|
|
2310
|
+
return avgs;
|
|
2311
|
+
}
|
|
2312
|
+
getTopSourcePerTag() {
|
|
2313
|
+
const tagSourceCounts = new Map();
|
|
2314
|
+
const itemSourceMap = new Map();
|
|
2315
|
+
for (const item of this.contentItemsRaw) {
|
|
2316
|
+
itemSourceMap.set(item['ID'], item['ContentSource'] ?? 'Unknown');
|
|
2317
|
+
}
|
|
2318
|
+
for (const tag of this.contentTagsRaw) {
|
|
2319
|
+
const t = tag['Tag'];
|
|
2320
|
+
const source = itemSourceMap.get(tag['ItemID']) ?? 'Unknown';
|
|
2321
|
+
if (!tagSourceCounts.has(t))
|
|
2322
|
+
tagSourceCounts.set(t, new Map());
|
|
2323
|
+
const inner = tagSourceCounts.get(t);
|
|
2324
|
+
inner.set(source, (inner.get(source) ?? 0) + 1);
|
|
2325
|
+
}
|
|
2326
|
+
const result = new Map();
|
|
2327
|
+
for (const [tag, sourceCounts] of tagSourceCounts) {
|
|
2328
|
+
let maxSource = '';
|
|
2329
|
+
let maxCount = 0;
|
|
2330
|
+
for (const [source, count] of sourceCounts) {
|
|
2331
|
+
if (count > maxCount) {
|
|
2332
|
+
maxSource = source;
|
|
2333
|
+
maxCount = count;
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
result.set(tag, maxSource);
|
|
2337
|
+
}
|
|
2338
|
+
return result;
|
|
2339
|
+
}
|
|
2340
|
+
getFirstSeenPerTag() {
|
|
2341
|
+
const result = new Map();
|
|
2342
|
+
for (const tag of this.contentTagsRaw) {
|
|
2343
|
+
const t = tag['Tag'];
|
|
2344
|
+
if (t && !result.has(t)) {
|
|
2345
|
+
const date = tag['__mj_CreatedAt'];
|
|
2346
|
+
result.set(t, date ? this.formatShortDate(date) : '');
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
return result;
|
|
2350
|
+
}
|
|
2351
|
+
countSourcesByContentType() {
|
|
2352
|
+
const counts = new Map();
|
|
2353
|
+
for (const source of this.contentSourcesRaw) {
|
|
2354
|
+
const typeId = source['ContentTypeID'];
|
|
2355
|
+
if (typeId)
|
|
2356
|
+
counts.set(typeId, (counts.get(typeId) ?? 0) + 1);
|
|
2357
|
+
}
|
|
2358
|
+
return counts;
|
|
2359
|
+
}
|
|
2360
|
+
countItemsByContentType() {
|
|
2361
|
+
const counts = new Map();
|
|
2362
|
+
for (const item of this.contentItemsRaw) {
|
|
2363
|
+
const typeId = item['ContentTypeID'];
|
|
2364
|
+
if (typeId)
|
|
2365
|
+
counts.set(typeId, (counts.get(typeId) ?? 0) + 1);
|
|
2366
|
+
}
|
|
2367
|
+
return counts;
|
|
355
2368
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
2369
|
+
inferItemStatus(tagCount) {
|
|
2370
|
+
return tagCount > 0 ? 'complete' : 'processing';
|
|
2371
|
+
}
|
|
2372
|
+
// ════════════════════════════════════════════
|
|
2373
|
+
// HELPER — Formatting
|
|
2374
|
+
// ════════════════════════════════════════════
|
|
2375
|
+
formatRelativeTime(dateStr) {
|
|
2376
|
+
if (!dateStr)
|
|
359
2377
|
return 'Never';
|
|
360
2378
|
const now = new Date();
|
|
361
|
-
const
|
|
2379
|
+
const then = new Date(dateStr);
|
|
2380
|
+
const diffMs = now.getTime() - then.getTime();
|
|
362
2381
|
const diffMins = Math.floor(diffMs / 60000);
|
|
363
2382
|
if (diffMins < 1)
|
|
364
2383
|
return 'Just now';
|
|
@@ -370,203 +2389,393 @@ let AutotaggingPipelineResourceComponent = class AutotaggingPipelineResourceComp
|
|
|
370
2389
|
const diffDays = Math.floor(diffHours / 24);
|
|
371
2390
|
return `${diffDays}d ago`;
|
|
372
2391
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
2392
|
+
formatNumber(n) {
|
|
2393
|
+
return n.toLocaleString();
|
|
2394
|
+
}
|
|
2395
|
+
formatShortDate(dateStr) {
|
|
2396
|
+
try {
|
|
2397
|
+
const d = new Date(dateStr);
|
|
2398
|
+
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
2399
|
+
}
|
|
2400
|
+
catch {
|
|
2401
|
+
return '';
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
formatDate(dateStr) {
|
|
2405
|
+
try {
|
|
2406
|
+
const d = new Date(dateStr);
|
|
2407
|
+
return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });
|
|
2408
|
+
}
|
|
2409
|
+
catch {
|
|
2410
|
+
return dateStr;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
computeDuration(start, end) {
|
|
2414
|
+
if (!start)
|
|
2415
|
+
return '\u2014';
|
|
2416
|
+
const s = new Date(start);
|
|
2417
|
+
const e = end ? new Date(end) : new Date();
|
|
2418
|
+
const ms = e.getTime() - s.getTime();
|
|
2419
|
+
if (ms < 1000)
|
|
2420
|
+
return `${ms}ms`;
|
|
2421
|
+
if (ms < 60000)
|
|
2422
|
+
return `${Math.round(ms / 1000)}s`;
|
|
2423
|
+
const mins = Math.floor(ms / 60000);
|
|
2424
|
+
const secs = Math.round((ms % 60000) / 1000);
|
|
2425
|
+
return `${mins}m ${secs}s`;
|
|
2426
|
+
}
|
|
2427
|
+
displayStatus(status) {
|
|
2428
|
+
const lower = status.toLowerCase();
|
|
2429
|
+
if (lower === 'complete' || lower === 'completed' || lower === 'done')
|
|
2430
|
+
return 'Complete';
|
|
2431
|
+
if (lower === 'error' || lower === 'failed')
|
|
2432
|
+
return 'Failed';
|
|
2433
|
+
if (lower === 'running' || lower === 'processing')
|
|
2434
|
+
return 'Running';
|
|
2435
|
+
return status;
|
|
2436
|
+
}
|
|
390
2437
|
GetSourceTypeIcon(typeName) {
|
|
391
2438
|
const iconMap = {
|
|
392
|
-
'Web': 'fa-solid fa-globe',
|
|
393
|
-
'API': 'fa-solid fa-plug',
|
|
394
|
-
'
|
|
395
|
-
'
|
|
396
|
-
'
|
|
397
|
-
'RSS': 'fa-solid fa-rss',
|
|
398
|
-
'CMS': 'fa-solid fa-newspaper'
|
|
2439
|
+
'Web': 'fa-solid fa-globe', 'Web Crawler': 'fa-solid fa-globe',
|
|
2440
|
+
'API': 'fa-solid fa-plug', 'Database': 'fa-solid fa-database',
|
|
2441
|
+
'File': 'fa-solid fa-file-alt', 'Email': 'fa-solid fa-envelope',
|
|
2442
|
+
'RSS': 'fa-solid fa-rss', 'RSS Feed': 'fa-solid fa-rss',
|
|
2443
|
+
'CMS': 'fa-solid fa-newspaper', 'PDF': 'fa-solid fa-file-pdf'
|
|
399
2444
|
};
|
|
400
2445
|
return iconMap[typeName] ?? 'fa-solid fa-folder';
|
|
401
2446
|
}
|
|
402
|
-
//
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
{
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
},
|
|
428
|
-
{
|
|
429
|
-
Label: 'Errors',
|
|
430
|
-
Value: errorCount,
|
|
431
|
-
Icon: 'fa-solid fa-circle-exclamation',
|
|
432
|
-
ColorClass: errorCount > 0 ? 'kpi-error' : 'kpi-success'
|
|
2447
|
+
// ════════════════════════════════════════════
|
|
2448
|
+
// HELPER — Data loading
|
|
2449
|
+
// ════════════════════════════════════════════
|
|
2450
|
+
async ensureBaseDataLoaded() {
|
|
2451
|
+
if (this.contentSourcesRaw.length > 0 && this.contentItemsRaw.length > 0)
|
|
2452
|
+
return;
|
|
2453
|
+
await this.LoadPipelineData();
|
|
2454
|
+
}
|
|
2455
|
+
async ensureFormDropdownsLoaded() {
|
|
2456
|
+
try {
|
|
2457
|
+
// Use KnowledgeHubMetadataEngine for cached reference data — instant, no RunView needed
|
|
2458
|
+
const engine = KnowledgeHubMetadataEngine.Instance;
|
|
2459
|
+
await engine.Config(false); // no-op if already loaded
|
|
2460
|
+
this.SourceTypeOptions = engine.ContentSourceTypes.map(t => ({ ID: t.ID, Name: t.Name }));
|
|
2461
|
+
this.ContentTypeOptions = engine.ContentTypes.map(t => ({ ID: t.ID, Name: t.Name }));
|
|
2462
|
+
this.FileTypeOptions = engine.ContentFileTypes.map(t => ({ ID: t.ID, Name: t.Name }));
|
|
2463
|
+
this.VectorIndexOptions = engine.VectorIndexes.map(vi => ({ ID: vi.ID, Name: vi.Name }));
|
|
2464
|
+
// AI Models from AIEngineBase (already cached)
|
|
2465
|
+
if (this.AIModelOptions.length === 0) {
|
|
2466
|
+
const aiEngine = AIEngineBase.Instance;
|
|
2467
|
+
await aiEngine.Config(false);
|
|
2468
|
+
this.AIModelOptions = aiEngine.Models.map(m => ({ ID: m.ID, Name: m.Name }));
|
|
2469
|
+
this.EmbeddingModelOptions = aiEngine.Models
|
|
2470
|
+
.filter(m => m.AIModelType?.trim().toLowerCase() === 'embeddings')
|
|
2471
|
+
.map(m => ({ ID: m.ID, Name: m.Name }));
|
|
433
2472
|
}
|
|
434
|
-
|
|
2473
|
+
}
|
|
2474
|
+
catch (error) {
|
|
2475
|
+
console.error('[Autotagging] Error loading form dropdowns:', error);
|
|
2476
|
+
}
|
|
435
2477
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
this.
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
];
|
|
2478
|
+
resetSourceForm() {
|
|
2479
|
+
this.FormSourceName = '';
|
|
2480
|
+
this.FormSourceTypeID = '';
|
|
2481
|
+
this.FormContentTypeID = '';
|
|
2482
|
+
this.FormFileTypeID = '';
|
|
2483
|
+
this.FormSourceURL = '';
|
|
2484
|
+
this.FormSourceEmbeddingModelID = '';
|
|
2485
|
+
this.FormSourceVectorIndexID = '';
|
|
2486
|
+
this.EditingSourceID = '';
|
|
446
2487
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
return groups;
|
|
457
|
-
}
|
|
458
|
-
/** Create a pipeline stage object from run data */
|
|
459
|
-
createStage(name, icon, runsByStage) {
|
|
460
|
-
const stageRuns = runsByStage.get(name) ?? [];
|
|
461
|
-
const activeRuns = stageRuns.filter((r) => r['Status'] === 'Processing' || r['Status'] === 'Running');
|
|
462
|
-
const errorRuns = stageRuns.filter((r) => r['Status'] === 'Error');
|
|
463
|
-
let status = 'idle';
|
|
464
|
-
if (errorRuns.length > 0)
|
|
465
|
-
status = 'error';
|
|
466
|
-
else if (activeRuns.length > 0)
|
|
467
|
-
status = 'active';
|
|
468
|
-
return { Name: name, Icon: icon, ActiveCount: activeRuns.length, Status: status };
|
|
469
|
-
}
|
|
470
|
-
/** Build the recent processing feed from content items and tags */
|
|
471
|
-
buildProcessedItems() {
|
|
472
|
-
const tagCountByItem = this.countTagsByItem();
|
|
473
|
-
this.ProcessedItems = this.contentItems.slice(0, 50).map((item) => {
|
|
474
|
-
const itemId = item['ID'];
|
|
475
|
-
return {
|
|
476
|
-
Name: item['Name'] ?? 'Unnamed Item',
|
|
477
|
-
SourceName: item['ContentSource'] ?? item['ContentSourceID'] ?? 'Unknown',
|
|
478
|
-
ProcessingTimeMs: item['ProcessingTimeMs'] ?? 0,
|
|
479
|
-
Status: this.mapItemStatus(item['Status']),
|
|
480
|
-
TagCount: tagCountByItem.get(itemId) ?? 0,
|
|
481
|
-
ProcessedAt: item['__mj_CreatedAt'] ? new Date(item['__mj_CreatedAt']) : new Date()
|
|
482
|
-
};
|
|
483
|
-
});
|
|
2488
|
+
resetTypeForm() {
|
|
2489
|
+
this.FormTypeName = '';
|
|
2490
|
+
this.FormTypeDescription = '';
|
|
2491
|
+
this.FormTypeAIModelID = '';
|
|
2492
|
+
this.FormTypeMinTags = 1;
|
|
2493
|
+
this.FormTypeMaxTags = 10;
|
|
2494
|
+
this.FormTypeEmbeddingModelID = '';
|
|
2495
|
+
this.FormTypeVectorIndexID = '';
|
|
2496
|
+
this.EditingTypeID = '';
|
|
484
2497
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
2498
|
+
async refreshSourcesTab() {
|
|
2499
|
+
this.tabDataLoaded.delete('sources');
|
|
2500
|
+
this.tabDataLoaded.delete('pipeline');
|
|
2501
|
+
const rv = new RunView();
|
|
2502
|
+
const result = await rv.RunView({ EntityName: 'MJ: Content Sources', OrderBy: 'Name', ResultType: 'simple' });
|
|
2503
|
+
if (result.Success)
|
|
2504
|
+
this.contentSourcesRaw = result.Results;
|
|
2505
|
+
this.buildSourceCards();
|
|
2506
|
+
this.buildNavItems();
|
|
2507
|
+
this.cdr.detectChanges();
|
|
2508
|
+
}
|
|
2509
|
+
async refreshContentTypesTab() {
|
|
2510
|
+
this.tabDataLoaded.delete('types');
|
|
2511
|
+
const rv = new RunView();
|
|
2512
|
+
const result = await rv.RunView({ EntityName: 'MJ: Content Types', ResultType: 'simple' });
|
|
2513
|
+
if (result.Success)
|
|
2514
|
+
this.contentTypesRaw = result.Results;
|
|
2515
|
+
this.buildContentTypeCards();
|
|
2516
|
+
this.cdr.detectChanges();
|
|
2517
|
+
}
|
|
2518
|
+
// ════════════════════════════════════════════
|
|
2519
|
+
// DETAIL PANELS — Feed Item / Content Item
|
|
2520
|
+
// ════════════════════════════════════════════
|
|
2521
|
+
OpenFeedItemDetail(index) {
|
|
2522
|
+
const feed = this.FeedItems[index];
|
|
2523
|
+
if (!feed)
|
|
2524
|
+
return;
|
|
2525
|
+
const rawItem = this.contentItemsRaw[index];
|
|
2526
|
+
if (!rawItem)
|
|
2527
|
+
return;
|
|
2528
|
+
const itemId = rawItem['ID'];
|
|
2529
|
+
const allTags = this.getAllTagsForItem(itemId);
|
|
2530
|
+
const tagCount = allTags.length;
|
|
2531
|
+
this.SelectedFeedItem = {
|
|
2532
|
+
ID: itemId,
|
|
2533
|
+
Name: feed.Name,
|
|
2534
|
+
SourceName: feed.SourceName,
|
|
2535
|
+
SourceTypeName: rawItem['ContentSourceType'] ?? 'Unknown',
|
|
2536
|
+
ContentTypeName: rawItem['ContentType'] ?? 'Unknown',
|
|
2537
|
+
FileTypeName: rawItem['ContentFileType'] ?? '',
|
|
2538
|
+
URL: rawItem['URL'] ?? '',
|
|
2539
|
+
TextContent: rawItem['TextContent'] ?? '',
|
|
2540
|
+
Checksum: rawItem['Checksum'] ?? '',
|
|
2541
|
+
Tags: allTags,
|
|
2542
|
+
CreatedAt: this.formatDate(rawItem['__mj_CreatedAt'] ?? ''),
|
|
2543
|
+
UpdatedAt: this.formatDate(rawItem['__mj_UpdatedAt'] ?? ''),
|
|
2544
|
+
ContentSourceID: rawItem['ContentSourceID'] ?? '',
|
|
2545
|
+
StatusDot: feed.Status,
|
|
2546
|
+
TagCount: tagCount
|
|
2547
|
+
};
|
|
2548
|
+
this.ShowItemDetail = true;
|
|
2549
|
+
this.cdr.detectChanges();
|
|
2550
|
+
}
|
|
2551
|
+
OpenContentItemDetail(item) {
|
|
2552
|
+
this.SelectedFeedItem = item;
|
|
2553
|
+
this.ShowItemDetail = true;
|
|
2554
|
+
this.cdr.detectChanges();
|
|
2555
|
+
}
|
|
2556
|
+
CloseItemDetail() {
|
|
2557
|
+
this.ShowItemDetail = false;
|
|
2558
|
+
this.SelectedFeedItem = null;
|
|
2559
|
+
this.cdr.detectChanges();
|
|
2560
|
+
}
|
|
2561
|
+
OpenRecordFromItem(item) {
|
|
2562
|
+
const md = new Metadata();
|
|
2563
|
+
const pkey = new CompositeKey();
|
|
2564
|
+
pkey.KeyValuePairs = [{ FieldName: 'ID', Value: item.ID }];
|
|
2565
|
+
this.navigationService.OpenEntityRecord('MJ: Content Items', pkey);
|
|
2566
|
+
}
|
|
2567
|
+
getAllTagsForItem(itemId) {
|
|
2568
|
+
const tags = [];
|
|
2569
|
+
for (const tag of this.contentTagsRaw) {
|
|
2570
|
+
if (tag['ItemID'] === itemId) {
|
|
2571
|
+
tags.push(tag['Tag']);
|
|
492
2572
|
}
|
|
493
2573
|
}
|
|
494
|
-
return
|
|
2574
|
+
return tags;
|
|
495
2575
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
2576
|
+
// ════════════════════════════════════════════
|
|
2577
|
+
// DETAIL PANELS — Source Detail
|
|
2578
|
+
// ════════════════════════════════════════════
|
|
2579
|
+
async OpenSourceDetail(card) {
|
|
2580
|
+
this.SourceDetailLoading = true;
|
|
2581
|
+
this.ShowSourceDetail = true;
|
|
2582
|
+
this.cdr.detectChanges();
|
|
2583
|
+
try {
|
|
2584
|
+
const sourceItems = await this.loadContentItemsForSource(card.ID);
|
|
2585
|
+
const sourceRuns = await this.loadRunHistoryForSource(card.ID);
|
|
2586
|
+
const embeddingModelName = this.resolveEmbeddingModelName(card.EmbeddingModelID);
|
|
2587
|
+
const vectorIndexName = this.resolveVectorIndexName(card.VectorIndexID);
|
|
2588
|
+
const errorCount = sourceRuns.filter(r => r.StatusClass === 'failed').length;
|
|
2589
|
+
this.SelectedSource = {
|
|
2590
|
+
ID: card.ID,
|
|
2591
|
+
Name: card.Name,
|
|
2592
|
+
SourceTypeName: card.SourceTypeName,
|
|
2593
|
+
FileTypeName: card.FileTypeName,
|
|
2594
|
+
ContentTypeName: card.ContentTypeName,
|
|
2595
|
+
StatusClass: card.StatusClass,
|
|
2596
|
+
StatusLabel: card.StatusLabel,
|
|
2597
|
+
Icon: card.Icon,
|
|
2598
|
+
URL: card.URL,
|
|
2599
|
+
EmbeddingModelName: embeddingModelName,
|
|
2600
|
+
VectorIndexName: vectorIndexName,
|
|
2601
|
+
ItemCount: card.ItemCount,
|
|
2602
|
+
TagCount: card.TagCount,
|
|
2603
|
+
AvgTags: card.AvgTags,
|
|
2604
|
+
LastRunAgo: card.LastRunAgo,
|
|
2605
|
+
ErrorCount: errorCount,
|
|
2606
|
+
ContentItems: sourceItems,
|
|
2607
|
+
RunHistory: sourceRuns
|
|
2608
|
+
};
|
|
2609
|
+
}
|
|
2610
|
+
catch (error) {
|
|
2611
|
+
console.error('[Autotagging] Error loading source detail:', error);
|
|
2612
|
+
}
|
|
2613
|
+
finally {
|
|
2614
|
+
this.SourceDetailLoading = false;
|
|
2615
|
+
this.cdr.detectChanges();
|
|
2616
|
+
}
|
|
506
2617
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
2618
|
+
CloseSourceDetail() {
|
|
2619
|
+
this.ShowSourceDetail = false;
|
|
2620
|
+
this.SelectedSource = null;
|
|
2621
|
+
this.cdr.detectChanges();
|
|
2622
|
+
}
|
|
2623
|
+
OpenRecordFromSource(source) {
|
|
2624
|
+
const pkey = new CompositeKey();
|
|
2625
|
+
pkey.KeyValuePairs = [{ FieldName: 'ID', Value: source.ID }];
|
|
2626
|
+
this.navigationService.OpenEntityRecord('MJ: Content Sources', pkey);
|
|
2627
|
+
}
|
|
2628
|
+
OpenEditSourceFromDetail() {
|
|
2629
|
+
if (!this.SelectedSource)
|
|
2630
|
+
return;
|
|
2631
|
+
const card = this.SourceCards.find(c => UUIDsEqual(c.ID, this.SelectedSource.ID));
|
|
2632
|
+
if (card) {
|
|
2633
|
+
this.CloseSourceDetail();
|
|
2634
|
+
this.OpenEditSourceForm(card);
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
async RunSourceFromDetail() {
|
|
2638
|
+
this.CloseSourceDetail();
|
|
2639
|
+
await this.RunPipeline();
|
|
2640
|
+
}
|
|
2641
|
+
async DeleteSourceFromDetail() {
|
|
2642
|
+
if (!this.SelectedSource)
|
|
2643
|
+
return;
|
|
2644
|
+
const card = this.SourceCards.find(c => UUIDsEqual(c.ID, this.SelectedSource.ID));
|
|
2645
|
+
if (card) {
|
|
2646
|
+
this.CloseSourceDetail();
|
|
2647
|
+
await this.DeleteSource(card);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
async loadContentItemsForSource(sourceId) {
|
|
2651
|
+
const rv = new RunView();
|
|
2652
|
+
const result = await rv.RunView({
|
|
2653
|
+
EntityName: 'MJ: Content Items',
|
|
2654
|
+
ExtraFilter: `ContentSourceID='${sourceId}'`,
|
|
2655
|
+
OrderBy: '__mj_UpdatedAt DESC',
|
|
2656
|
+
MaxRows: 100,
|
|
2657
|
+
ResultType: 'simple'
|
|
2658
|
+
});
|
|
2659
|
+
if (!result.Success)
|
|
2660
|
+
return [];
|
|
2661
|
+
const tagsByItem = this.countTagsByItem();
|
|
2662
|
+
return result.Results.map(item => {
|
|
2663
|
+
const itemId = item['ID'];
|
|
2664
|
+
const allTags = this.getAllTagsForItem(itemId);
|
|
2665
|
+
const tagCount = tagsByItem.get(itemId) ?? allTags.length;
|
|
514
2666
|
return {
|
|
515
|
-
ID:
|
|
516
|
-
Name:
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
2667
|
+
ID: itemId,
|
|
2668
|
+
Name: item['Name'] ?? 'Unnamed',
|
|
2669
|
+
SourceName: item['ContentSource'] ?? '',
|
|
2670
|
+
SourceTypeName: item['ContentSourceType'] ?? '',
|
|
2671
|
+
ContentTypeName: item['ContentType'] ?? '',
|
|
2672
|
+
FileTypeName: item['ContentFileType'] ?? '',
|
|
2673
|
+
URL: item['URL'] ?? '',
|
|
2674
|
+
TextContent: item['TextContent'] ?? '',
|
|
2675
|
+
Checksum: item['Checksum'] ?? '',
|
|
2676
|
+
Tags: allTags,
|
|
2677
|
+
CreatedAt: this.formatDate(item['__mj_CreatedAt'] ?? ''),
|
|
2678
|
+
UpdatedAt: this.formatDate(item['__mj_UpdatedAt'] ?? ''),
|
|
2679
|
+
ContentSourceID: sourceId,
|
|
2680
|
+
StatusDot: tagCount > 0 ? 'complete' : 'processing',
|
|
2681
|
+
TagCount: tagCount
|
|
522
2682
|
};
|
|
523
2683
|
});
|
|
524
2684
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
2685
|
+
async loadRunHistoryForSource(sourceId) {
|
|
2686
|
+
const rv = new RunView();
|
|
2687
|
+
const result = await rv.RunView({
|
|
2688
|
+
EntityName: 'MJ: Content Process Runs',
|
|
2689
|
+
ExtraFilter: `SourceID='${sourceId}'`,
|
|
2690
|
+
OrderBy: 'StartTime DESC',
|
|
2691
|
+
MaxRows: 10,
|
|
2692
|
+
ResultType: 'simple'
|
|
2693
|
+
});
|
|
2694
|
+
if (!result.Success)
|
|
2695
|
+
return [];
|
|
2696
|
+
return result.Results.map(run => {
|
|
2697
|
+
const status = run['Status'] ?? 'Unknown';
|
|
2698
|
+
const startTime = run['StartTime'];
|
|
2699
|
+
const endTime = run['EndTime'];
|
|
2700
|
+
const duration = this.computeDuration(startTime, endTime);
|
|
2701
|
+
const processedItems = run['ProcessedItems'];
|
|
2702
|
+
const statusLower = status.toLowerCase();
|
|
2703
|
+
const isFailed = statusLower === 'error' || statusLower === 'failed';
|
|
2704
|
+
const isRunning = statusLower === 'running' || statusLower === 'processing';
|
|
2705
|
+
return {
|
|
2706
|
+
ID: run['ID'],
|
|
2707
|
+
Status: this.displayStatus(status),
|
|
2708
|
+
StatusClass: isFailed ? 'failed' : isRunning ? 'running' : 'complete',
|
|
2709
|
+
SourceName: run['Source'] ?? 'Unknown',
|
|
2710
|
+
StartedDisplay: startTime ? this.formatDate(startTime) : '\u2014',
|
|
2711
|
+
Duration: duration,
|
|
2712
|
+
Items: processedItems != null ? this.formatNumber(processedItems) : '\u2014',
|
|
2713
|
+
Tags: '\u2014',
|
|
2714
|
+
Errors: isFailed ? status : '0',
|
|
2715
|
+
ErrorClass: isFailed ? 'run-error-text' : ''
|
|
2716
|
+
};
|
|
2717
|
+
});
|
|
532
2718
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
counts.set(sourceId, (counts.get(sourceId) ?? 0) + 1);
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
return counts;
|
|
2719
|
+
resolveEmbeddingModelName(modelId) {
|
|
2720
|
+
if (!modelId)
|
|
2721
|
+
return 'System default';
|
|
2722
|
+
const aiEngine = AIEngineBase.Instance;
|
|
2723
|
+
const model = aiEngine.Models.find(m => UUIDsEqual(m.ID, modelId));
|
|
2724
|
+
return model ? model.Name : 'Unknown';
|
|
543
2725
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
return 'Active';
|
|
551
|
-
if (normalized === 'error' || normalized === 'failed')
|
|
552
|
-
return 'Error';
|
|
553
|
-
return 'Paused';
|
|
2726
|
+
resolveVectorIndexName(indexId) {
|
|
2727
|
+
if (!indexId)
|
|
2728
|
+
return 'System default';
|
|
2729
|
+
const engine = KnowledgeHubMetadataEngine.Instance;
|
|
2730
|
+
const idx = engine.GetVectorIndexById(indexId);
|
|
2731
|
+
return idx ? idx.Name : 'Unknown';
|
|
554
2732
|
}
|
|
555
2733
|
static ɵfac = /*@__PURE__*/ (() => { let ɵAutotaggingPipelineResourceComponent_BaseFactory; return function AutotaggingPipelineResourceComponent_Factory(__ngFactoryType__) { return (ɵAutotaggingPipelineResourceComponent_BaseFactory || (ɵAutotaggingPipelineResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(AutotaggingPipelineResourceComponent)))(__ngFactoryType__ || AutotaggingPipelineResourceComponent); }; })();
|
|
556
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AutotaggingPipelineResourceComponent, selectors: [["app-autotagging-pipeline-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
557
|
-
i0.ɵɵelementStart(0, "div", 0);
|
|
558
|
-
i0.ɵɵ
|
|
559
|
-
i0.ɵɵ
|
|
560
|
-
i0.ɵɵ
|
|
2734
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AutotaggingPipelineResourceComponent, selectors: [["app-autotagging-pipeline-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 23, vars: 9, consts: [[1, "at-dashboard"], [1, "at-left-nav"], [1, "at-left-nav-header"], [1, "fa-solid", "fa-tags"], [1, "at-left-nav-items"], [1, "at-nav-item", 3, "active"], [1, "at-nav-divider"], [1, "at-nav-item", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "at-left-nav-footer"], [1, "at-run-pipeline-btn", 3, "click", "disabled"], [1, "at-main-area"], [1, "at-loading-overlay"], [1, "at-nav-badge", 3, "at-nav-badge-live"], [1, "at-nav-badge"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-play"], ["text", "Loading autotagging data..."], [1, "at-page-header"], [1, "at-page-title"], [1, "at-page-subtitle"], [1, "at-page-actions"], [1, "at-action-btn", "at-secondary-btn", 3, "click"], [1, "fa-solid", "fa-arrows-rotate"], [1, "at-page-body"], [1, "at-kpi-strip"], [1, "at-kpi-card"], [1, "at-pipeline-layout"], [1, "at-pipeline-center"], [1, "at-progress-section"], [1, "at-card", 2, "flex", "1"], [1, "at-card-header"], [1, "at-card-title"], [1, "fa-solid", "fa-bolt"], [1, "at-card-body"], [1, "at-empty-state"], [1, "at-feed-item", "at-feed-item-clickable"], [1, "at-pipeline-right"], [1, "at-card"], [1, "fa-solid", "fa-database"], [1, "at-source-mini"], [1, "at-card", "at-tag-cloud-card"], [1, "at-card-title", 2, "margin-bottom", "10px"], [1, "fa-solid", "fa-chart-bar"], [1, "at-tag-cloud"], [1, "at-tag-pill", 3, "class", "opacity", "title"], [1, "at-kpi-value"], [1, "at-kpi-label"], [1, "at-kpi-trend", 3, "up"], [1, "at-kpi-trend"], [1, "fa-solid", "fa-arrow-up"], [1, "at-progress-header"], [1, "at-progress-stage-label"], [1, "at-progress-pct"], [1, "at-progress-bar"], [1, "at-progress-fill"], [1, "at-progress-current"], [1, "fa-solid", "fa-inbox"], [1, "at-feed-item", "at-feed-item-clickable", 3, "click"], [1, "at-feed-status-dot"], [1, "at-feed-item-name"], [1, "at-feed-item-source"], [1, "at-feed-item-tags"], [1, "at-feed-tag"], [1, "at-feed-item-time"], [1, "at-source-mini-icon"], [1, "at-source-mini-info"], [1, "at-source-mini-name"], [1, "at-source-mini-meta"], [1, "at-source-mini-status"], [1, "at-tag-pill", 3, "title"], [1, "at-action-btn", "at-primary-btn", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "at-sources-grid"], [1, "at-source-card-full", "at-source-card-clickable"], [1, "at-add-source-card", 3, "click"], [1, "fa-solid", "fa-plus-circle"], [2, "font-size", "0.85rem", "font-weight", "600"], [2, "font-size", "0.72rem"], [1, "at-source-card-full", "at-source-card-clickable", 3, "click"], [1, "at-source-card-header"], [1, "at-source-card-icon"], [1, "at-source-card-title"], [1, "at-source-card-type"], [1, "at-source-card-status"], [1, "at-source-card-url"], [1, "at-source-card-stats"], [1, "at-source-stat"], [1, "at-source-stat-value"], [1, "at-source-stat-label"], [1, "at-source-card-actions"], [1, "at-source-action-btn", 3, "click"], [1, "fa-solid", "fa-pen"], [1, "at-source-action-btn", "at-source-delete-btn", 3, "click"], [1, "fa-solid", "fa-trash"], [1, "at-ct-grid"], [1, "at-ct-card"], [1, "at-add-type-card", 3, "click"], [1, "at-ct-card-header"], [1, "at-ct-card-name"], [1, "at-ct-card-model"], [1, "at-ct-field"], [1, "at-ct-field-label"], [1, "at-ct-field-value"], [1, "at-ct-tag-range"], [1, "at-ct-tag-range-bar"], [1, "at-ct-tag-range-fill"], [1, "at-ct-range-suffix"], [1, "at-source-card-actions", 2, "margin-top", "10px"], ["type", "text", "placeholder", "Search tags...", 1, "at-search-input", 3, "ngModelChange", "input", "ngModel"], [1, "at-tag-lib-layout"], [1, "at-tag-lib-main"], [1, "at-card-body", 2, "max-height", "500px", "overflow-y", "auto"], [1, "at-tag-table"], [1, "at-tag-lib-sidebar"], [1, "at-card-title", 2, "margin-bottom", "12px"], [1, "fa-solid", "fa-cloud"], [1, "at-card", 2, "padding", "16px", "margin-top", "12px"], [1, "fa-solid", "fa-chart-pie"], [1, "at-tags-by-source"], [1, "at-tag-source-row"], [1, "at-tag-name-cell"], [1, "at-weight-indicator"], [1, "at-weight-bar"], [1, "at-weight-bar-fill"], [1, "at-weight-value"], [1, "at-tag-bar"], [1, "at-tag-bar-fill"], [1, "at-filter-select", 3, "ngModelChange", "change", "ngModel"], ["value", ""], [3, "value"], ["value", "complete"], ["value", "failed"], ["value", "running"], [1, "at-card-body", 2, "max-height", "600px", "overflow-y", "auto"], [1, "at-run-table"], [1, "at-run-status-badge"], [1, "fa-solid", "fa-spinner", "fa-spin", 2, "font-size", "0.55rem"], [1, "at-run-source-name"], [1, "at-run-duration"], [1, "at-slide-overlay", 3, "click"], [1, "at-slide-panel"], [1, "at-slide-header"], [1, "at-slide-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "at-slide-body"], [1, "at-form-group"], [1, "at-form-label"], ["type", "text", "placeholder", "Source name", 1, "at-form-input", 3, "ngModelChange", "ngModel"], [1, "at-form-select", 3, "ngModelChange", "ngModel"], ["type", "text", "placeholder", "https://...", 1, "at-form-input", 3, "ngModelChange", "ngModel"], ["SelectionMode", "single", "SelectableTypes", "leaf", "Placeholder", "Use system default", 3, "ValueChange", "BranchConfig", "LeafConfig", "Clearable", "Value"], [1, "at-form-hint"], [1, "at-form-actions"], [1, "at-action-btn", "at-primary-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-check"], ["type", "text", "placeholder", "Content type name", 1, "at-form-input", 3, "ngModelChange", "ngModel"], ["rows", "3", "placeholder", "Description...", 1, "at-form-textarea", 3, "ngModelChange", "ngModel"], ["SelectionMode", "single", "SelectableTypes", "leaf", "Placeholder", "Select AI model...", 3, "ValueChange", "BranchConfig", "LeafConfig", "Clearable", "Value"], [1, "at-form-row"], [1, "at-form-group", 2, "flex", "1"], ["type", "number", "min", "0", 1, "at-form-input", 3, "ngModelChange", "ngModel"], ["type", "number", "min", "1", 1, "at-form-input", 3, "ngModelChange", "ngModel"], [1, "at-slide-panel", "at-detail-panel"], [1, "fa-solid", "fa-file-lines"], [1, "at-detail-item-header"], [1, "at-detail-item-name"], [1, "at-detail-badges"], [1, "at-detail-badge", "at-detail-badge-source"], [1, "at-detail-badge", "at-detail-badge-type"], [1, "at-detail-badge", "at-detail-badge-file"], [1, "at-detail-section"], [1, "at-detail-section-label"], [1, "at-detail-meta-grid"], [1, "at-detail-meta-row"], [1, "at-detail-meta-key"], [1, "at-detail-meta-value"], [1, "at-detail-actions"], [1, "fa-solid", "fa-external-link-alt"], ["disabled", "", 1, "at-action-btn", "at-secondary-btn"], [1, "fa-solid", "fa-magnifying-glass"], [1, "fa-solid", "fa-file"], ["target", "_blank", 1, "at-detail-link", 3, "href"], [1, "fa-solid", "fa-external-link-alt", 2, "font-size", "0.65rem", "margin-left", "4px"], [1, "at-detail-text-preview"], [1, "at-detail-tags"], [1, "at-tag-pill"], [1, "at-detail-meta-value", "at-detail-meta-mono"], ["text", "Loading source details..."], [1, "at-detail-source-header"], [1, "at-detail-badge"], [1, "at-detail-stats-strip"], [1, "at-detail-stat"], [1, "at-detail-stat-value"], [1, "at-detail-stat-label"], [1, "at-detail-content-list"], [1, "at-empty-state", 2, "padding", "16px"], [1, "at-detail-content-item"], [1, "at-action-btn", "at-secondary-btn", "at-source-delete-btn", 3, "click"], ["target", "_blank", 1, "at-detail-link", "at-detail-meta-value", 3, "href"], [1, "at-detail-content-item", 3, "click"], [1, "at-detail-content-item-name"], [1, "at-detail-content-item-tags"], [1, "at-detail-content-item-time"], [1, "at-detail-run-history"], [1, "at-detail-run-row"], [1, "at-detail-run-time"], [1, "at-detail-run-duration"], [1, "at-detail-run-items"]], template: function AutotaggingPipelineResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2735
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h2");
|
|
2736
|
+
i0.ɵɵelement(4, "i", 3);
|
|
2737
|
+
i0.ɵɵtext(5, " Autotagging");
|
|
2738
|
+
i0.ɵɵelementEnd()();
|
|
2739
|
+
i0.ɵɵelementStart(6, "div", 4);
|
|
2740
|
+
i0.ɵɵrepeaterCreate(7, AutotaggingPipelineResourceComponent_For_8_Template, 4, 6, "div", 5, _forTrack0);
|
|
2741
|
+
i0.ɵɵelement(9, "div", 6);
|
|
2742
|
+
i0.ɵɵelementStart(10, "div", 7);
|
|
2743
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Template_div_click_10_listener() { return ctx.SwitchTab("history"); });
|
|
2744
|
+
i0.ɵɵelement(11, "i", 8);
|
|
2745
|
+
i0.ɵɵtext(12, " Run History ");
|
|
2746
|
+
i0.ɵɵelementEnd()();
|
|
2747
|
+
i0.ɵɵelementStart(13, "div", 9)(14, "button", 10);
|
|
2748
|
+
i0.ɵɵlistener("click", function AutotaggingPipelineResourceComponent_Template_button_click_14_listener() { return ctx.RunPipeline(); });
|
|
2749
|
+
i0.ɵɵconditionalCreate(15, AutotaggingPipelineResourceComponent_Conditional_15_Template, 2, 0)(16, AutotaggingPipelineResourceComponent_Conditional_16_Template, 2, 0);
|
|
2750
|
+
i0.ɵɵelementEnd()()();
|
|
2751
|
+
i0.ɵɵelementStart(17, "div", 11);
|
|
2752
|
+
i0.ɵɵconditionalCreate(18, AutotaggingPipelineResourceComponent_Conditional_18_Template, 2, 0, "div", 12);
|
|
2753
|
+
i0.ɵɵconditionalCreate(19, AutotaggingPipelineResourceComponent_Conditional_19_Template, 5, 5);
|
|
2754
|
+
i0.ɵɵelementEnd();
|
|
2755
|
+
i0.ɵɵconditionalCreate(20, AutotaggingPipelineResourceComponent_Conditional_20_Template, 13, 3);
|
|
2756
|
+
i0.ɵɵconditionalCreate(21, AutotaggingPipelineResourceComponent_Conditional_21_Template, 43, 10);
|
|
2757
|
+
i0.ɵɵconditionalCreate(22, AutotaggingPipelineResourceComponent_Conditional_22_Template, 11, 2);
|
|
561
2758
|
i0.ɵɵelementEnd();
|
|
562
2759
|
} if (rf & 2) {
|
|
2760
|
+
i0.ɵɵadvance(7);
|
|
2761
|
+
i0.ɵɵrepeater(ctx.NavItems);
|
|
2762
|
+
i0.ɵɵadvance(3);
|
|
2763
|
+
i0.ɵɵclassProp("active", ctx.ActiveTab === "history");
|
|
2764
|
+
i0.ɵɵadvance(4);
|
|
2765
|
+
i0.ɵɵproperty("disabled", ctx.IsRunning);
|
|
2766
|
+
i0.ɵɵadvance();
|
|
2767
|
+
i0.ɵɵconditional(ctx.IsRunning ? 15 : 16);
|
|
2768
|
+
i0.ɵɵadvance(3);
|
|
2769
|
+
i0.ɵɵconditional(ctx.IsLoading ? 18 : -1);
|
|
2770
|
+
i0.ɵɵadvance();
|
|
2771
|
+
i0.ɵɵconditional(!ctx.IsLoading ? 19 : -1);
|
|
563
2772
|
i0.ɵɵadvance();
|
|
564
|
-
i0.ɵɵconditional(ctx.
|
|
2773
|
+
i0.ɵɵconditional(ctx.FormMode !== "none" ? 20 : -1);
|
|
565
2774
|
i0.ɵɵadvance();
|
|
566
|
-
i0.ɵɵconditional(ctx.
|
|
2775
|
+
i0.ɵɵconditional(ctx.ShowItemDetail && ctx.SelectedFeedItem ? 21 : -1);
|
|
567
2776
|
i0.ɵɵadvance();
|
|
568
|
-
i0.ɵɵconditional(
|
|
569
|
-
} }, dependencies: [i1.LoadingComponent, i2.DecimalPipe], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\n display: block;\n height: 100%;\n overflow: hidden;\n}\n\n\n\n\n.autotagging-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 20px;\n gap: 20px;\n overflow-y: auto;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n}\n\n\n\n\n.loading-overlay[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n}\n\n.error-banner[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 6px;\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.error-banner[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.error-banner[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n\n\n\n.header-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.header-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.header-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.header-title[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.refresh-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\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-size: 13px;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.refresh-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n\n\n\n.kpi-strip[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n border-radius: 8px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n transition: box-shadow 0.15s;\n}\n\n.kpi-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.kpi-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.kpi-brand[_ngcontent-%COMP%] .kpi-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.kpi-info[_ngcontent-%COMP%] .kpi-icon[_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.kpi-success[_ngcontent-%COMP%] .kpi-icon[_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.kpi-error[_ngcontent-%COMP%] .kpi-icon[_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.kpi-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n line-height: 1.2;\n color: var(--mj-text-primary);\n}\n\n.kpi-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n\n\n\n\n.pipeline-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 18px 20px;\n}\n\n.section-title[_ngcontent-%COMP%] {\n margin: 0 0 14px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.pipeline-flow[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.pipeline-stage[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 14px 20px;\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n min-width: 100px;\n position: relative;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n\n.stage-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-text-muted);\n}\n\n.stage-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.stage-count[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.stage-indicator[_ngcontent-%COMP%] {\n position: absolute;\n bottom: 0;\n left: 10%;\n right: 10%;\n height: 3px;\n border-radius: 3px 3px 0 0;\n background: var(--mj-border-subtle);\n transition: background 0.2s;\n}\n\n\n\n\n.stage-active[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 1px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.stage-active[_ngcontent-%COMP%] .stage-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.stage-active[_ngcontent-%COMP%] .stage-count[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.stage-active[_ngcontent-%COMP%] .stage-indicator[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.stage-error[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error);\n}\n\n.stage-error[_ngcontent-%COMP%] .stage-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.stage-error[_ngcontent-%COMP%] .stage-indicator[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n}\n\n.stage-connector[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n color: var(--mj-text-disabled);\n font-size: 12px;\n}\n\n\n\n\n.main-content[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 320px;\n gap: 20px;\n flex: 1;\n min-height: 0;\n}\n\n\n\n\n.feed-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.feed-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.feed-item[_ngcontent-%COMP%] {\n padding: 10px 12px;\n border-radius: 6px;\n transition: background 0.1s;\n}\n\n.feed-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.feed-item-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n}\n\n.feed-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 70%;\n}\n\n.feed-item-status[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.feed-item-details[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n flex-wrap: wrap;\n}\n\n.feed-detail[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.feed-detail[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.feed-time[_ngcontent-%COMP%] {\n margin-left: auto;\n}\n\n\n\n\n.sources-panel[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.sources-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.source-card[_ngcontent-%COMP%] {\n padding: 12px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n transition: border-color 0.15s;\n}\n\n.source-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-default);\n}\n\n.source-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 8px;\n}\n\n.source-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.source-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n}\n\n.source-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.source-type[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.source-status[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n flex-shrink: 0;\n}\n\n.source-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n}\n\n.source-meta-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.source-meta-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n\n.status-success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.status-processing[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border: 1px solid var(--mj-status-info-border);\n}\n\n.status-error[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.status-warning[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n.status-default[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n border: 1px solid var(--mj-border-subtle);\n}\n\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n}\n\n\n\n\n@media (max-width: 1100px) {\n .main-content[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 768px) {\n .kpi-strip[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .pipeline-flow[_ngcontent-%COMP%] {\n gap: 6px;\n }\n\n .pipeline-stage[_ngcontent-%COMP%] {\n min-width: 80px;\n padding: 10px 12px;\n }\n}\n\n@media (max-width: 480px) {\n .kpi-strip[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .pipeline-stage[_ngcontent-%COMP%] {\n min-width: 70px;\n }\n\n .header-row[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n }\n}"] });
|
|
2777
|
+
i0.ɵɵconditional(ctx.ShowSourceDetail ? 22 : -1);
|
|
2778
|
+
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.NumberValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.MinValidator, i1.NgModel, i2.LoadingComponent, i3.TreeDropdownComponent, i4.DecimalPipe], styles: ["/* ============================================================\n Content Autotagging Dashboard\n All colors use MJ design tokens \u2014 no hardcoded hex values.\n All classes prefixed with at- to prevent leaking (ViewEncapsulation.None).\n ============================================================ */\n\n/* \u2500\u2500 Root layout \u2500\u2500 */\n\n.at-dashboard {\n display: flex;\n height: 100%;\n overflow: hidden;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 LEFT NAV \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-left-nav {\n 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 flex-shrink: 0;\n}\n\n.at-left-nav-header {\n padding: 16px 16px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.at-left-nav-header h2 {\n font-size: 0.95rem;\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n color: var(--mj-text-primary);\n}\n\n.at-left-nav-header h2 i {\n color: var(--mj-brand-primary);\n}\n\n.at-left-nav-items {\n flex: 1;\n padding: 8px;\n overflow-y: auto;\n}\n\n.at-nav-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n border-radius: 8px;\n font-size: 0.82rem;\n font-weight: 500;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.12s ease;\n margin-bottom: 2px;\n}\n\n.at-nav-item:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n}\n\n.at-nav-item.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.at-nav-item i {\n width: 18px;\n text-align: center;\n font-size: 0.8rem;\n}\n\n.at-nav-badge {\n margin-left: auto;\n background: var(--mj-bg-surface-sunken);\n padding: 1px 7px;\n border-radius: 10px;\n font-size: 0.65rem;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n\n.at-nav-item.active .at-nav-badge {\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-nav-badge-live {\n background: var(--mj-status-success-bg) !important;\n color: var(--mj-status-success-text) !important;\n}\n\n.at-nav-divider {\n height: 1px;\n background: var(--mj-border-subtle);\n margin: 8px 12px;\n}\n\n.at-left-nav-footer {\n padding: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.at-run-pipeline-btn {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 10px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 0.82rem;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.at-run-pipeline-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.at-run-pipeline-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 MAIN CONTENT AREA \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-main-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.at-loading-overlay {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n.at-page-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.at-page-title {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-page-subtitle {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.at-page-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.at-page-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px 20px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 SHARED COMPONENTS \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n border: 1px solid;\n border-radius: 7px;\n cursor: pointer;\n font-size: 0.78rem;\n font-weight: 500;\n transition: all 0.15s ease;\n}\n\n.at-primary-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.at-primary-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.at-primary-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.at-secondary-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n\n.at-secondary-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.at-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.at-card-title {\n font-size: 0.82rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-primary);\n}\n\n.at-card-title i {\n color: var(--mj-brand-primary);\n font-size: 0.75rem;\n}\n\n.at-card-body {\n padding: 0;\n}\n\n.at-empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n}\n\n.at-empty-state i {\n font-size: 28px;\n}\n\n.at-empty-state p {\n margin: 0;\n font-size: 13px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 KPI STRIP \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-kpi-strip {\n display: flex;\n gap: 12px;\n margin-bottom: 16px;\n}\n\n.at-kpi-card {\n flex: 1;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 14px 16px;\n}\n\n.at-kpi-value {\n font-size: 1.4rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-kpi-error-value {\n color: var(--mj-status-error-text);\n}\n\n.at-kpi-label {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.at-kpi-trend {\n font-size: 0.68rem;\n margin-top: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n color: var(--mj-text-muted);\n}\n\n.at-kpi-trend.up {\n color: var(--mj-status-success-text);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 PIPELINE TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-pipeline-layout {\n display: flex;\n gap: 16px;\n}\n\n.at-pipeline-center {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n}\n\n.at-pipeline-right {\n width: 320px;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n/* Pipeline Stages */\n\n.at-pipeline-stages {\n display: flex;\n gap: 0;\n align-items: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 12px 16px;\n}\n\n.at-pipeline-stage {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n\n.at-pipeline-stage-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n font-size: 0.85rem;\n}\n\n.stage-idle .at-pipeline-stage-icon {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.stage-active .at-pipeline-stage-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n animation: at-pulse 1.5s infinite;\n}\n\n.stage-complete .at-pipeline-stage-icon {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n@keyframes at-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-brand-primary) 30%, transparent); }\n 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--mj-brand-primary) 0%, transparent); }\n}\n\n.at-pipeline-stage-name {\n font-size: 0.68rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.at-pipeline-stage-count {\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.at-pipeline-arrow {\n width: 24px;\n text-align: center;\n color: var(--mj-text-disabled);\n font-size: 0.6rem;\n}\n\n/* Progress section */\n\n.at-progress-section {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 10px 16px;\n}\n\n.at-progress-header {\n display: flex;\n justify-content: space-between;\n font-size: 0.75rem;\n margin-bottom: 4px;\n}\n\n.at-progress-stage-label {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.at-progress-pct {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.at-progress-bar {\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n}\n\n.at-progress-fill {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 2px;\n transition: width 0.3s ease;\n}\n\n.at-progress-current {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n margin-top: 4px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Feed items */\n\n.at-feed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.at-feed-item:last-child {\n border-bottom: none;\n}\n\n.at-feed-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.at-feed-status-dot.complete {\n background: var(--mj-status-success);\n}\n\n.at-feed-status-dot.processing {\n background: var(--mj-brand-primary);\n animation: at-pulse 1.5s infinite;\n}\n\n.at-feed-status-dot.error {\n background: var(--mj-status-error);\n}\n\n.at-feed-item-name {\n flex: 1;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n\n.at-feed-item-source {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n min-width: 100px;\n}\n\n.at-feed-item-tags {\n display: flex;\n gap: 4px;\n}\n\n.at-feed-tag {\n padding: 1px 6px;\n border-radius: 3px;\n font-size: 0.62rem;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-feed-item-time {\n color: var(--mj-text-muted);\n font-size: 0.68rem;\n white-space: nowrap;\n min-width: 60px;\n text-align: right;\n}\n\n/* Source mini cards (right panel) */\n\n.at-source-mini {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.at-source-mini:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-source-mini:last-child {\n border-bottom: none;\n}\n\n.at-source-mini-icon {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.72rem;\n flex-shrink: 0;\n}\n\n.at-source-mini-info {\n flex: 1;\n min-width: 0;\n}\n\n.at-source-mini-name {\n font-size: 0.78rem;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n\n.at-source-mini-meta {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.at-source-mini-status {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.at-source-mini-status.active {\n background: var(--mj-status-success);\n}\n\n.at-source-mini-status.error {\n background: var(--mj-status-error);\n}\n\n.at-source-mini-status.inactive {\n background: var(--mj-text-disabled);\n}\n\n/* Tag cloud card */\n\n.at-tag-cloud-card {\n padding: 16px;\n}\n\n.at-tag-cloud {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n}\n\n.at-tag-pill {\n padding: 4px 12px;\n border-radius: 14px;\n font-size: 0.72rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-subtle);\n cursor: pointer;\n transition: all 0.12s ease;\n}\n\n.at-tag-pill:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-tag-pill.large {\n font-size: 0.85rem;\n padding: 5px 14px;\n}\n\n.at-tag-pill.small {\n font-size: 0.65rem;\n padding: 3px 8px;\n color: var(--mj-text-muted);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 SOURCES TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-sources-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 12px;\n}\n\n.at-source-card-full {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 16px;\n transition: border-color 0.15s ease;\n}\n\n.at-source-card-full:hover {\n border-color: var(--mj-border-default);\n}\n\n.at-source-card-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 12px;\n}\n\n.at-source-card-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 1rem;\n flex-shrink: 0;\n}\n\n.at-source-card-title {\n font-size: 0.9rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-source-card-type {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n}\n\n.at-source-card-status {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 0.7rem;\n font-weight: 500;\n}\n\n.at-source-card-status.active {\n color: var(--mj-status-success-text);\n}\n\n.at-source-card-status.error {\n color: var(--mj-status-error-text);\n}\n\n.at-source-card-status.inactive {\n color: var(--mj-text-disabled);\n}\n\n.at-source-card-url {\n font-size: 0.7rem;\n color: var(--mj-brand-primary);\n margin-bottom: 10px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.at-source-card-stats {\n display: flex;\n gap: 16px;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.at-source-stat {\n display: flex;\n flex-direction: column;\n}\n\n.at-source-stat-value {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-source-stat-label {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.at-source-card-actions {\n display: flex;\n gap: 6px;\n margin-top: 10px;\n}\n\n.at-source-action-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n padding: 6px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 0.7rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n transition: all 0.12s ease;\n}\n\n.at-source-action-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-source-delete-btn:hover {\n border-color: var(--mj-status-error);\n color: var(--mj-status-error-text);\n}\n\n.at-add-source-card {\n background: none;\n border: 2px dashed var(--mj-border-default);\n border-radius: 10px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 40px;\n cursor: pointer;\n transition: all 0.15s ease;\n color: var(--mj-text-muted);\n min-height: 200px;\n}\n\n.at-add-source-card:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-add-source-card i {\n font-size: 1.5rem;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 CONTENT TYPES TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-ct-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n}\n\n.at-ct-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 16px;\n}\n\n.at-ct-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.at-ct-card-name {\n font-size: 0.9rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-ct-card-model {\n font-size: 0.68rem;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.at-ct-field {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.at-ct-field:last-child {\n border-bottom: none;\n}\n\n.at-ct-field-label {\n color: var(--mj-text-muted);\n}\n\n.at-ct-field-value {\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.at-ct-tag-range {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n padding: 8px 10px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n font-size: 0.75rem;\n color: var(--mj-text-primary);\n}\n\n.at-ct-tag-range i {\n color: var(--mj-brand-primary);\n}\n\n.at-ct-tag-range-bar {\n flex: 1;\n height: 6px;\n background: var(--mj-bg-surface);\n border-radius: 3px;\n position: relative;\n}\n\n.at-ct-tag-range-fill {\n position: absolute;\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 3px;\n}\n\n.at-ct-range-suffix {\n color: var(--mj-text-muted);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 TAG LIBRARY TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-tag-lib-layout {\n display: flex;\n gap: 16px;\n}\n\n.at-tag-lib-main {\n flex: 1;\n}\n\n.at-tag-lib-sidebar {\n width: 280px;\n flex-shrink: 0;\n}\n\n.at-tag-table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.at-tag-table th {\n text-align: left;\n padding: 8px 12px;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-elevated);\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.at-tag-table td {\n padding: 10px 12px;\n font-size: 0.8rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.at-tag-table tr:hover td {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-tag-name-cell {\n font-weight: 600;\n}\n\n.at-tag-bar {\n width: 80px;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n display: inline-block;\n vertical-align: middle;\n}\n\n.at-tag-bar-fill {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 3px;\n}\n\n/* Weight indicator in tag table */\n.at-weight-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.at-weight-bar {\n width: 50px;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n overflow: hidden;\n}\n\n.at-weight-bar-fill {\n height: 100%;\n border-radius: 3px;\n transition: width 0.2s ease;\n}\n\n.at-weight-bar-fill.at-weight-high {\n background: var(--mj-status-success);\n}\n\n.at-weight-bar-fill.at-weight-medium {\n background: var(--mj-status-warning);\n}\n\n.at-weight-bar-fill.at-weight-low {\n background: var(--mj-status-error);\n}\n\n.at-weight-value {\n font-size: 0.7rem;\n font-weight: 600;\n color: var(--mj-text-muted);\n min-width: 28px;\n}\n\n.at-tags-by-source {\n font-size: 0.78rem;\n}\n\n.at-tag-source-row {\n display: flex;\n justify-content: space-between;\n padding: 5px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.at-tag-source-row:last-child {\n border-bottom: none;\n}\n\n.at-search-input {\n padding: 7px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.8rem;\n width: 200px;\n outline: none;\n}\n\n.at-search-input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.at-search-input:focus {\n border-color: var(--mj-brand-primary);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 RUN HISTORY TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-run-table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.at-run-table th {\n text-align: left;\n padding: 10px 14px;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-elevated);\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.at-run-table td {\n padding: 12px 14px;\n font-size: 0.8rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.at-run-table tr:hover td {\n background: var(--mj-bg-surface-hover);\n cursor: pointer;\n}\n\n.at-run-status-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 0.7rem;\n font-weight: 600;\n}\n\n.at-run-status-badge.complete {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.at-run-status-badge.failed {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.at-run-status-badge.running {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-run-duration {\n color: var(--mj-text-muted);\n font-size: 0.75rem;\n}\n\n.at-run-source-name {\n font-weight: 500;\n}\n\n.at-run-error-text {\n color: var(--mj-status-error-text);\n}\n\n.at-filter-select {\n padding: 7px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.78rem;\n outline: none;\n}\n\n.at-filter-select:focus {\n border-color: var(--mj-brand-primary);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 SLIDE-IN FORM PANEL \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-slide-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n}\n\n.at-slide-panel {\n position: fixed;\n right: 0;\n top: 0;\n bottom: 0;\n width: 420px;\n max-width: 100vw;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 24px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n}\n\n.at-slide-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.at-slide-header h3 {\n margin: 0;\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-slide-close {\n background: none;\n border: none;\n font-size: 1.1rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px;\n}\n\n.at-slide-close:hover {\n color: var(--mj-text-primary);\n}\n\n.at-slide-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n.at-form-group {\n margin-bottom: 16px;\n}\n\n.at-form-label {\n display: block;\n font-size: 0.78rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 6px;\n}\n\n.at-form-input,\n.at-form-select,\n.at-form-textarea {\n width: 100%;\n padding: 9px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n font-size: 0.82rem;\n outline: none;\n font-family: inherit;\n}\n\n.at-form-input:focus,\n.at-form-select:focus,\n.at-form-textarea:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.at-form-input::placeholder,\n.at-form-textarea::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.at-form-textarea {\n resize: vertical;\n}\n\n.at-form-row {\n display: flex;\n gap: 12px;\n}\n\n.at-form-actions {\n display: flex;\n gap: 8px;\n margin-top: 24px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 RESPONSIVE \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@media (max-width: 1100px) {\n .at-pipeline-layout {\n flex-direction: column;\n }\n\n .at-pipeline-right {\n width: 100%;\n flex-direction: row;\n }\n\n .at-tag-lib-layout {\n flex-direction: column;\n }\n\n .at-tag-lib-sidebar {\n width: 100%;\n }\n}\n\n@media (max-width: 768px) {\n .at-left-nav {\n width: 180px;\n }\n\n .at-kpi-strip {\n flex-wrap: wrap;\n }\n\n .at-kpi-card {\n min-width: 140px;\n }\n\n .at-sources-grid {\n grid-template-columns: 1fr;\n }\n\n .at-ct-grid {\n grid-template-columns: 1fr;\n }\n\n .at-slide-panel {\n width: 100vw;\n }\n}\n\n@media (max-width: 480px) {\n .at-left-nav {\n width: 56px;\n }\n\n .at-left-nav-header h2 {\n font-size: 0;\n }\n\n .at-left-nav-header h2 i {\n font-size: 1rem;\n }\n\n .at-nav-item {\n justify-content: center;\n padding: 10px;\n font-size: 0;\n }\n\n .at-nav-item i {\n font-size: 1rem;\n }\n\n .at-nav-badge {\n display: none;\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Slide-in Form Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-slide-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.35);\n z-index: 9999;\n animation: at-fade-in 0.2s ease;\n}\n\n@keyframes at-fade-in { from { opacity: 0; } to { opacity: 1; } }\n\n.at-slide-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 420px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0, 0, 0, 0.4);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n animation: at-slide-in 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes at-slide-in { from { transform: translateX(100%); } to { transform: translateX(0); } }\n\n.at-slide-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.at-slide-header h3 {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-slide-close {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n transition: all 0.15s ease;\n}\n\n.at-slide-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.at-slide-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.at-form-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.at-form-label {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.at-form-input,\n.at-form-select,\n.at-form-textarea {\n padding: 9px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n font-size: 0.85rem;\n outline: none;\n transition: border-color 0.15s ease;\n font-family: inherit;\n}\n\n.at-form-input:focus,\n.at-form-select:focus,\n.at-form-textarea:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.at-form-select {\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M3 5l3 3 3-3'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 10px center;\n padding-right: 30px;\n}\n\n.at-form-textarea {\n resize: vertical;\n min-height: 70px;\n}\n\n.at-form-row {\n display: flex;\n gap: 12px;\n}\n\n.at-form-actions {\n display: flex;\n gap: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-subtle);\n margin-top: 8px;\n}\n\n.at-form-actions .at-action-btn {\n flex: 1;\n justify-content: center;\n}\n\n/* Also add empty state for Content Types (matching Sources) */\n.at-add-type-card {\n background: none;\n border: 2px dashed var(--mj-border-default);\n border-radius: 10px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 40px;\n cursor: pointer;\n transition: all 0.15s ease;\n color: var(--mj-text-muted);\n min-height: 200px;\n}\n\n.at-add-type-card:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-add-type-card i {\n font-size: 1.5rem;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 FORKED PIPELINE STAGES \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-pipeline-stages-forked {\n display: flex;\n align-items: center;\n gap: 0;\n}\n\n.at-pipeline-fork {\n display: flex;\n align-items: center;\n gap: 0;\n flex: 2;\n}\n\n.at-pipeline-fork-lines {\n width: 28px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n position: relative;\n flex-shrink: 0;\n}\n\n.at-pipeline-fork-line {\n height: 2px;\n background: var(--mj-border-default);\n width: 100%;\n position: relative;\n}\n\n.at-pipeline-fork-line::before {\n content: '';\n position: absolute;\n width: 2px;\n height: 12px;\n background: var(--mj-border-default);\n left: 0;\n}\n\n.at-fork-top::before {\n bottom: 0;\n left: 0;\n}\n\n.at-fork-bottom::before {\n top: 0;\n left: 0;\n}\n\n.at-pipeline-fork-branches {\n display: flex;\n flex-direction: column;\n gap: 8px;\n flex: 1;\n}\n\n.at-pipeline-fork-branches .at-pipeline-stage {\n flex: none;\n padding: 6px 0;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 CLICKABLE FEED ITEMS \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-feed-item-clickable {\n cursor: pointer;\n}\n\n.at-feed-item-clickable:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 CLICKABLE SOURCE CARDS \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-source-card-clickable {\n cursor: pointer;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 FORM HINT \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-form-hint {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 2px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 DETAIL PANEL (wider) \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-detail-panel {\n width: 500px;\n}\n\n/* \u2500\u2500 Detail: Item header \u2500\u2500 */\n\n.at-detail-item-header {\n margin-bottom: 8px;\n}\n\n.at-detail-item-name {\n font-size: 1.05rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 6px 0;\n word-break: break-word;\n}\n\n.at-detail-badges {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.at-detail-badge {\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 0.7rem;\n font-weight: 600;\n}\n\n.at-detail-badge-source {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-detail-badge-type {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.at-detail-badge-file {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.at-detail-badge-status-active {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.at-detail-badge-status-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.at-detail-badge-status-inactive {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n}\n\n/* \u2500\u2500 Detail: Sections \u2500\u2500 */\n\n.at-detail-section {\n margin-bottom: 4px;\n}\n\n.at-detail-section-label {\n font-size: 0.72rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: var(--mj-text-muted);\n margin-bottom: 6px;\n}\n\n.at-detail-link {\n font-size: 0.8rem;\n color: var(--mj-brand-primary);\n text-decoration: none;\n word-break: break-all;\n}\n\n.at-detail-link:hover {\n text-decoration: underline;\n}\n\n/* \u2500\u2500 Detail: Text preview \u2500\u2500 */\n\n.at-detail-text-preview {\n max-height: 200px;\n overflow-y: auto;\n padding: 10px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n font-size: 0.78rem;\n font-family: 'SF Mono', 'Cascadia Code', 'Menlo', monospace;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.5;\n}\n\n/* \u2500\u2500 Detail: Tags \u2500\u2500 */\n\n.at-detail-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n}\n\n/* \u2500\u2500 Detail: Meta grid \u2500\u2500 */\n\n.at-detail-meta-grid {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.at-detail-meta-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.at-detail-meta-row:last-child {\n border-bottom: none;\n}\n\n.at-detail-meta-key {\n color: var(--mj-text-muted);\n font-weight: 500;\n flex-shrink: 0;\n margin-right: 12px;\n}\n\n.at-detail-meta-value {\n color: var(--mj-text-primary);\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.at-detail-meta-mono {\n font-family: 'SF Mono', 'Cascadia Code', 'Menlo', monospace;\n font-size: 0.72rem;\n}\n\n/* \u2500\u2500 Detail: Actions \u2500\u2500 */\n\n.at-detail-actions {\n display: flex;\n gap: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-subtle);\n margin-top: 8px;\n}\n\n.at-detail-actions .at-action-btn {\n flex: 1;\n justify-content: center;\n}\n\n/* \u2500\u2500 Detail: Source header \u2500\u2500 */\n\n.at-detail-source-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n/* \u2500\u2500 Detail: Stats strip \u2500\u2500 */\n\n.at-detail-stats-strip {\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.at-detail-stat {\n flex: 1;\n min-width: 60px;\n text-align: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 8px 6px;\n}\n\n.at-detail-stat-value {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-detail-stat-label {\n font-size: 0.62rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n/* \u2500\u2500 Detail: Content Library \u2500\u2500 */\n\n.at-detail-content-list {\n max-height: 250px;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n}\n\n.at-detail-content-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.at-detail-content-item:last-child {\n border-bottom: none;\n}\n\n.at-detail-content-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-detail-content-item-name {\n flex: 1;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.at-detail-content-item-tags {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.at-detail-content-item-time {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n/* \u2500\u2500 Detail: Run history \u2500\u2500 */\n\n.at-detail-run-history {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n max-height: 200px;\n overflow-y: auto;\n}\n\n.at-detail-run-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.75rem;\n}\n\n.at-detail-run-row:last-child {\n border-bottom: none;\n}\n\n.at-detail-run-time {\n color: var(--mj-text-secondary);\n flex: 1;\n}\n\n.at-detail-run-duration {\n color: var(--mj-text-muted);\n}\n\n.at-detail-run-items {\n color: var(--mj-text-muted);\n}\n\n@media (max-width: 600px) {\n .at-slide-panel {\n width: 100%;\n }\n\n .at-detail-panel {\n width: 100%;\n }\n}\n"], encapsulation: 2 });
|
|
570
2779
|
};
|
|
571
2780
|
AutotaggingPipelineResourceComponent = __decorate([
|
|
572
2781
|
RegisterClass(BaseResourceComponent, 'AutotaggingPipelineResource')
|
|
@@ -574,9 +2783,9 @@ AutotaggingPipelineResourceComponent = __decorate([
|
|
|
574
2783
|
export { AutotaggingPipelineResourceComponent };
|
|
575
2784
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AutotaggingPipelineResourceComponent, [{
|
|
576
2785
|
type: Component,
|
|
577
|
-
args: [{ standalone: false, selector: 'app-autotagging-pipeline-resource', template: "<!-- Content Autotagging Pipeline Monitor -->\n<div class=\"autotagging-container\">\n @if (IsLoading) {\n <div class=\"loading-overlay\">\n <mj-loading text=\"Loading pipeline data...\"></mj-loading>\n </div>\n }\n\n @if (ErrorMessage) {\n <div class=\"error-banner\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <span>{{ ErrorMessage }}</span>\n <button class=\"refresh-btn\" (click)=\"RefreshData()\">\n <i class=\"fa-solid fa-rotate-right\"></i> Retry\n </button>\n </div>\n }\n\n @if (!IsLoading) {\n <!-- Header -->\n <div class=\"header-row\">\n <div class=\"header-title\">\n <i class=\"fa-solid fa-tags header-icon\"></i>\n <h2>Content Autotagging Pipeline</h2>\n </div>\n <button class=\"refresh-btn\" (click)=\"RefreshData()\">\n <i class=\"fa-solid fa-rotate-right\"></i> Refresh\n </button>\n </div>\n\n <!-- KPI Strip -->\n <div class=\"kpi-strip\">\n @for (metric of KPIMetrics; track metric.Label) {\n <div class=\"kpi-card\" [class]=\"metric.ColorClass\">\n <div class=\"kpi-icon\">\n <i [class]=\"metric.Icon\"></i>\n </div>\n <div class=\"kpi-content\">\n <span class=\"kpi-value\">{{ metric.Value | number }}</span>\n <span class=\"kpi-label\">{{ metric.Label }}</span>\n </div>\n </div>\n }\n </div>\n\n <!-- Pipeline Stages Visualization -->\n <div class=\"pipeline-section\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-diagram-project\"></i> Pipeline Stages\n </h3>\n <div class=\"pipeline-flow\">\n @for (stage of PipelineStages; track stage.Name; let last = $last) {\n <div class=\"pipeline-stage\" [class]=\"'stage-' + stage.Status\">\n <div class=\"stage-icon\">\n <i [class]=\"stage.Icon\"></i>\n </div>\n <span class=\"stage-name\">{{ stage.Name }}</span>\n <span class=\"stage-count\">\n @if (stage.ActiveCount > 0) {\n {{ stage.ActiveCount }} active\n } @else {\n Idle\n }\n </span>\n <div class=\"stage-indicator\"></div>\n </div>\n @if (!last) {\n <div class=\"stage-connector\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Main content area: Feed + Sources sidebar -->\n <div class=\"main-content\">\n <!-- Recent Processing Feed -->\n <div class=\"feed-section\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i> Recent Processing\n </h3>\n <div class=\"feed-list\">\n @if (ProcessedItems.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No processed items yet.</p>\n </div>\n }\n @for (item of ProcessedItems; track $index) {\n <div class=\"feed-item\">\n <div class=\"feed-item-header\">\n <span class=\"feed-item-name\" [title]=\"item.Name\">{{ item.Name }}</span>\n <span class=\"feed-item-status\" [class]=\"GetStatusClass(item.Status)\">\n {{ item.Status }}\n </span>\n </div>\n <div class=\"feed-item-details\">\n <span class=\"feed-detail\">\n <i class=\"fa-solid fa-database\"></i> {{ item.SourceName }}\n </span>\n <span class=\"feed-detail\">\n <i class=\"fa-solid fa-stopwatch\"></i> {{ FormatDuration(item.ProcessingTimeMs) }}\n </span>\n <span class=\"feed-detail\">\n <i class=\"fa-solid fa-tags\"></i> {{ item.TagCount }} tags\n </span>\n <span class=\"feed-detail feed-time\">\n {{ FormatRelativeTime(item.ProcessedAt) }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Source Configuration Panel (right sidebar) -->\n <div class=\"sources-panel\">\n <h3 class=\"section-title\">\n <i class=\"fa-solid fa-gear\"></i> Content Sources\n </h3>\n <div class=\"sources-list\">\n @if (ContentSources.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-plug-circle-xmark\"></i>\n <p>No sources configured.</p>\n </div>\n }\n @for (source of ContentSources; track source.ID) {\n <div class=\"source-card\">\n <div class=\"source-header\">\n <div class=\"source-icon\">\n <i [class]=\"source.TypeIcon\"></i>\n </div>\n <div class=\"source-info\">\n <span class=\"source-name\">{{ source.Name }}</span>\n <span class=\"source-type\">{{ source.TypeName }}</span>\n </div>\n <span class=\"source-status\" [class]=\"GetStatusClass(source.Status)\">\n {{ source.Status }}\n </span>\n </div>\n <div class=\"source-meta\">\n <span class=\"source-meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ FormatRelativeTime(source.LastRunAt) }}\n </span>\n <span class=\"source-meta-item\">\n <i class=\"fa-solid fa-file-lines\"></i>\n {{ source.ItemCount | number }} items\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n }\n</div>\n", styles: ["/* ============================================================\n Content Autotagging Pipeline Monitor\n All colors use MJ design tokens \u2014 no hardcoded hex values.\n ============================================================ */\n\n:host {\n display: block;\n height: 100%;\n overflow: hidden;\n}\n\n/* ---- Container ---- */\n\n.autotagging-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 20px;\n gap: 20px;\n overflow-y: auto;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n}\n\n/* ---- Loading & Error ---- */\n\n.loading-overlay {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n}\n\n.error-banner {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n border-radius: 6px;\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.error-banner i {\n font-size: 16px;\n}\n\n.error-banner span {\n flex: 1;\n}\n\n/* ---- Header ---- */\n\n.header-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.header-title {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.header-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.header-title h2 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.refresh-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 14px;\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-size: 13px;\n transition: background 0.15s, border-color 0.15s;\n}\n\n.refresh-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n/* ---- KPI Strip ---- */\n\n.kpi-strip {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n border-radius: 8px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n transition: box-shadow 0.15s;\n}\n\n.kpi-card:hover {\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n.kpi-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 10px;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.kpi-brand .kpi-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.kpi-info .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-info) 12%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.kpi-success .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-success) 12%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.kpi-error .kpi-icon {\n background: color-mix(in srgb, var(--mj-status-error) 12%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.kpi-content {\n display: flex;\n flex-direction: column;\n}\n\n.kpi-value {\n font-size: 22px;\n font-weight: 700;\n line-height: 1.2;\n color: var(--mj-text-primary);\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n\n/* ---- Pipeline Stages ---- */\n\n.pipeline-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 18px 20px;\n}\n\n.section-title {\n margin: 0 0 14px 0;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.section-title i {\n color: var(--mj-text-muted);\n}\n\n.pipeline-flow {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.pipeline-stage {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 14px 20px;\n border-radius: 8px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n min-width: 100px;\n position: relative;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n\n.stage-icon {\n font-size: 20px;\n color: var(--mj-text-muted);\n}\n\n.stage-name {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.stage-count {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.stage-indicator {\n position: absolute;\n bottom: 0;\n left: 10%;\n right: 10%;\n height: 3px;\n border-radius: 3px 3px 0 0;\n background: var(--mj-border-subtle);\n transition: background 0.2s;\n}\n\n/* Stage status variants */\n\n.stage-active {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 1px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.stage-active .stage-icon {\n color: var(--mj-brand-primary);\n}\n\n.stage-active .stage-count {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.stage-active .stage-indicator {\n background: var(--mj-brand-primary);\n}\n\n.stage-error {\n border-color: var(--mj-status-error);\n}\n\n.stage-error .stage-icon {\n color: var(--mj-status-error);\n}\n\n.stage-error .stage-indicator {\n background: var(--mj-status-error);\n}\n\n.stage-connector {\n display: flex;\n align-items: center;\n color: var(--mj-text-disabled);\n font-size: 12px;\n}\n\n/* ---- Main Content Area (Feed + Sources) ---- */\n\n.main-content {\n display: grid;\n grid-template-columns: 1fr 320px;\n gap: 20px;\n flex: 1;\n min-height: 0;\n}\n\n/* ---- Recent Processing Feed ---- */\n\n.feed-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.feed-list {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.feed-item {\n padding: 10px 12px;\n border-radius: 6px;\n transition: background 0.1s;\n}\n\n.feed-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.feed-item-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n}\n\n.feed-item-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n max-width: 70%;\n}\n\n.feed-item-status {\n font-size: 11px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.feed-item-details {\n display: flex;\n align-items: center;\n gap: 14px;\n flex-wrap: wrap;\n}\n\n.feed-detail {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.feed-detail i {\n font-size: 10px;\n}\n\n.feed-time {\n margin-left: auto;\n}\n\n/* ---- Source Configuration Panel ---- */\n\n.sources-panel {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.sources-list {\n flex: 1;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.source-card {\n padding: 12px;\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n transition: border-color 0.15s;\n}\n\n.source-card:hover {\n border-color: var(--mj-border-default);\n}\n\n.source-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 8px;\n}\n\n.source-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.source-info {\n display: flex;\n flex-direction: column;\n flex: 1;\n min-width: 0;\n}\n\n.source-name {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.source-type {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.source-status {\n font-size: 11px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n flex-shrink: 0;\n}\n\n.source-meta {\n display: flex;\n align-items: center;\n gap: 14px;\n}\n\n.source-meta-item {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.source-meta-item i {\n font-size: 10px;\n}\n\n/* ---- Status Color Variants ---- */\n\n.status-success {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.status-processing {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border: 1px solid var(--mj-status-info-border);\n}\n\n.status-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.status-warning {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n.status-default {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n border: 1px solid var(--mj-border-subtle);\n}\n\n/* ---- Empty State ---- */\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n}\n\n.empty-state i {\n font-size: 28px;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 13px;\n}\n\n/* ---- Responsive ---- */\n\n@media (max-width: 1100px) {\n .main-content {\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 768px) {\n .kpi-strip {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .pipeline-flow {\n gap: 6px;\n }\n\n .pipeline-stage {\n min-width: 80px;\n padding: 10px 12px;\n }\n}\n\n@media (max-width: 480px) {\n .kpi-strip {\n grid-template-columns: 1fr;\n }\n\n .pipeline-stage {\n min-width: 70px;\n }\n\n .header-row {\n flex-direction: column;\n align-items: flex-start;\n gap: 10px;\n }\n}\n"] }]
|
|
2786
|
+
args: [{ standalone: false, selector: 'app-autotagging-pipeline-resource', encapsulation: ViewEncapsulation.None, template: "<!-- Content Autotagging Dashboard -->\n<div class=\"at-dashboard\">\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 LEFT NAV \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"at-left-nav\">\n <div class=\"at-left-nav-header\">\n <h2><i class=\"fa-solid fa-tags\"></i> Autotagging</h2>\n </div>\n <div class=\"at-left-nav-items\">\n @for (item of NavItems; track item.Tab) {\n <div class=\"at-nav-item\" [class.active]=\"ActiveTab === item.Tab\" (click)=\"SwitchTab(item.Tab)\">\n <i [class]=\"item.Icon\"></i> {{ item.Label }}\n @if (item.BadgeText) {\n <span class=\"at-nav-badge\" [class.at-nav-badge-live]=\"item.BadgeClass === 'nav-badge-live'\">{{ item.BadgeText }}</span>\n }\n </div>\n }\n <div class=\"at-nav-divider\"></div>\n <div class=\"at-nav-item\" [class.active]=\"ActiveTab === 'history'\" (click)=\"SwitchTab('history')\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i> Run History\n </div>\n </div>\n <div class=\"at-left-nav-footer\">\n <button class=\"at-run-pipeline-btn\" (click)=\"RunPipeline()\" [disabled]=\"IsRunning\">\n @if (IsRunning) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Running...\n } @else {\n <i class=\"fa-solid fa-play\"></i> Run Pipeline\n }\n </button>\n </div>\n </div>\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 MAIN AREA \u2550\u2550\u2550\u2550\u2550\u2550 -->\n <div class=\"at-main-area\">\n\n @if (IsLoading) {\n <div class=\"at-loading-overlay\">\n <mj-loading text=\"Loading autotagging data...\"></mj-loading>\n </div>\n }\n\n @if (!IsLoading) {\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- TAB 1: PIPELINE MONITOR -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (ActiveTab === 'pipeline') {\n <div class=\"at-page-header\">\n <div>\n <div class=\"at-page-title\">Pipeline Monitor</div>\n <div class=\"at-page-subtitle\">Real-time processing status and recent activity</div>\n </div>\n <div class=\"at-page-actions\">\n <button class=\"at-action-btn at-secondary-btn\" (click)=\"LoadPipelineData()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i> Refresh\n </button>\n </div>\n </div>\n <div class=\"at-page-body\">\n <!-- KPIs -->\n <div class=\"at-kpi-strip\">\n @for (kpi of KPIMetrics; track kpi.Label) {\n <div class=\"at-kpi-card\">\n <div class=\"at-kpi-value\" [class.at-kpi-error-value]=\"kpi.Label === 'Errors' && kpi.Value > 0\">{{ kpi.Value | number }}</div>\n <div class=\"at-kpi-label\">{{ kpi.Label }}</div>\n @if (kpi.Trend) {\n <div class=\"at-kpi-trend\" [class.up]=\"kpi.TrendUp\">\n @if (kpi.TrendUp) { <i class=\"fa-solid fa-arrow-up\"></i> }\n {{ kpi.Trend }}\n </div>\n }\n </div>\n }\n </div>\n\n <div class=\"at-pipeline-layout\">\n <div class=\"at-pipeline-center\">\n <!-- Pipeline stages visualization hidden for now \u2014 can re-enable with animation later -->\n\n <!-- Progress bar (visible during run) -->\n @if (IsRunning) {\n <div class=\"at-progress-section\">\n <div class=\"at-progress-header\">\n <span class=\"at-progress-stage-label\">{{ RunStage }}</span>\n <span class=\"at-progress-pct\">{{ RunProgress }}%</span>\n </div>\n <div class=\"at-progress-bar\"><div class=\"at-progress-fill\" [style.width.%]=\"RunProgress\"></div></div>\n @if (RunCurrentItem) {\n <div class=\"at-progress-current\">{{ RunCurrentItem }}</div>\n }\n </div>\n }\n\n <!-- Recent Processing Feed -->\n <div class=\"at-card\" style=\"flex: 1;\">\n <div class=\"at-card-header\">\n <span class=\"at-card-title\"><i class=\"fa-solid fa-bolt\"></i> Recent Processing</span>\n </div>\n <div class=\"at-card-body\">\n @if (FeedItems.length === 0) {\n <div class=\"at-empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No processed items yet.</p>\n </div>\n }\n @for (item of FeedItems; track $index) {\n <div class=\"at-feed-item at-feed-item-clickable\" (click)=\"OpenFeedItemDetail($index)\">\n <div class=\"at-feed-status-dot\" [class]=\"item.Status\"></div>\n <span class=\"at-feed-item-name\">{{ item.Name }}</span>\n <span class=\"at-feed-item-source\">{{ item.SourceName }}</span>\n <div class=\"at-feed-item-tags\">\n @for (tag of item.Tags; track tag) {\n <span class=\"at-feed-tag\">{{ tag }}</span>\n }\n </div>\n <span class=\"at-feed-item-time\">{{ item.TimeAgo }}</span>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Right sidebar -->\n <div class=\"at-pipeline-right\">\n <!-- Sources Quick List -->\n <div class=\"at-card\">\n <div class=\"at-card-header\">\n <span class=\"at-card-title\"><i class=\"fa-solid fa-database\"></i> Sources</span>\n </div>\n <div class=\"at-card-body\">\n @for (source of SourceMinis; track source.ID) {\n <div class=\"at-source-mini\">\n <div class=\"at-source-mini-icon\"><i [class]=\"source.Icon\"></i></div>\n <div class=\"at-source-mini-info\">\n <div class=\"at-source-mini-name\">{{ source.Name }}</div>\n <div class=\"at-source-mini-meta\">{{ source.Meta }}</div>\n </div>\n <div class=\"at-source-mini-status\" [class]=\"source.StatusClass\"></div>\n </div>\n }\n </div>\n </div>\n <!-- Trending Tags -->\n <div class=\"at-card at-tag-cloud-card\">\n <div class=\"at-card-title\" style=\"margin-bottom: 10px;\"><i class=\"fa-solid fa-chart-bar\"></i> Trending Tags</div>\n <div class=\"at-tag-cloud\">\n @for (tag of TrendingTags; track tag.Tag) {\n <span class=\"at-tag-pill\" [class]=\"tag.SizeClass\"\n [style.opacity]=\"0.4 + tag.AvgWeight * 0.6\"\n [title]=\"'Weight: ' + tag.AvgWeight.toFixed(2)\">{{ tag.Tag }}</span>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- TAB 2: SOURCES -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (ActiveTab === 'sources') {\n <div class=\"at-page-header\">\n <div>\n <div class=\"at-page-title\">Content Sources</div>\n <div class=\"at-page-subtitle\">Configure where content is ingested from</div>\n </div>\n <div class=\"at-page-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"OpenAddSourceForm()\">\n <i class=\"fa-solid fa-plus\"></i> Add Source\n </button>\n </div>\n </div>\n <div class=\"at-page-body\">\n <div class=\"at-sources-grid\">\n @for (card of SourceCards; track card.ID) {\n <div class=\"at-source-card-full at-source-card-clickable\" (click)=\"OpenSourceDetail(card)\">\n <div class=\"at-source-card-header\">\n <div class=\"at-source-card-icon\"><i [class]=\"card.Icon\"></i></div>\n <div>\n <div class=\"at-source-card-title\">{{ card.Name }}</div>\n <div class=\"at-source-card-type\">{{ card.SourceTypeName }} \u00B7 {{ card.FileTypeName }}</div>\n </div>\n <div class=\"at-source-card-status\" [class]=\"card.StatusClass\">\n <div class=\"at-source-mini-status\" [class]=\"card.StatusClass\"></div>\n {{ card.StatusLabel }}\n </div>\n </div>\n @if (card.URL) {\n <div class=\"at-source-card-url\">{{ card.URL }}</div>\n }\n <div class=\"at-source-card-stats\">\n <div class=\"at-source-stat\">\n <div class=\"at-source-stat-value\">{{ formatNumber(card.ItemCount) }}</div>\n <div class=\"at-source-stat-label\">Items</div>\n </div>\n <div class=\"at-source-stat\">\n <div class=\"at-source-stat-value\">{{ formatNumber(card.TagCount) }}</div>\n <div class=\"at-source-stat-label\">Tags</div>\n </div>\n <div class=\"at-source-stat\">\n <div class=\"at-source-stat-value\">{{ card.AvgTags }}</div>\n <div class=\"at-source-stat-label\">Avg Tags</div>\n </div>\n <div class=\"at-source-stat\">\n <div class=\"at-source-stat-value\">{{ card.LastRunAgo }}</div>\n <div class=\"at-source-stat-label\">Last Run</div>\n </div>\n </div>\n <div class=\"at-source-card-actions\">\n <button class=\"at-source-action-btn\" (click)=\"OpenEditSourceForm(card); $event.stopPropagation()\"><i class=\"fa-solid fa-pen\"></i> Edit</button>\n <button class=\"at-source-action-btn\" (click)=\"RunPipeline(); $event.stopPropagation()\"><i class=\"fa-solid fa-play\"></i> Run</button>\n <button class=\"at-source-action-btn at-source-delete-btn\" (click)=\"DeleteSource(card); $event.stopPropagation()\"><i class=\"fa-solid fa-trash\"></i> Delete</button>\n </div>\n </div>\n }\n\n <!-- Add Source Card -->\n <div class=\"at-add-source-card\" (click)=\"OpenAddSourceForm()\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n <span style=\"font-size: 0.85rem; font-weight: 600;\">Add Content Source</span>\n <span style=\"font-size: 0.72rem;\">Web, RSS, Email, Files, API</span>\n </div>\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- TAB 3: CONTENT TYPES -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (ActiveTab === 'types') {\n <div class=\"at-page-header\">\n <div>\n <div class=\"at-page-title\">Content Types</div>\n <div class=\"at-page-subtitle\">Configure AI tagging rules per content category</div>\n </div>\n <div class=\"at-page-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"OpenAddTypeForm()\">\n <i class=\"fa-solid fa-plus\"></i> Add Type\n </button>\n </div>\n </div>\n <div class=\"at-page-body\">\n <div class=\"at-ct-grid\">\n @for (card of ContentTypeCards; track card.ID) {\n <div class=\"at-ct-card\">\n <div class=\"at-ct-card-header\">\n <span class=\"at-ct-card-name\">{{ card.Name }}</span>\n <span class=\"at-ct-card-model\">{{ card.AIModelName }}</span>\n </div>\n <div class=\"at-ct-field\">\n <span class=\"at-ct-field-label\">Description</span>\n <span class=\"at-ct-field-value\">{{ card.Description || '\\u2014' }}</span>\n </div>\n <div class=\"at-ct-field\">\n <span class=\"at-ct-field-label\">Sources Using</span>\n <span class=\"at-ct-field-value\">{{ card.SourcesUsing }}</span>\n </div>\n <div class=\"at-ct-field\">\n <span class=\"at-ct-field-label\">Items Tagged</span>\n <span class=\"at-ct-field-value\">{{ formatNumber(card.ItemsTagged) }}</span>\n </div>\n <div class=\"at-ct-tag-range\">\n <i class=\"fa-solid fa-tags\"></i>\n <span>{{ card.MinTags }}</span>\n <div class=\"at-ct-tag-range-bar\">\n <div class=\"at-ct-tag-range-fill\" [style.left.%]=\"card.RangeLeftPct\" [style.right.%]=\"card.RangeRightPct\"></div>\n </div>\n <span>{{ card.MaxTags }}</span>\n <span class=\"at-ct-range-suffix\">tags/item</span>\n </div>\n <div class=\"at-source-card-actions\" style=\"margin-top: 10px;\">\n <button class=\"at-source-action-btn\" (click)=\"OpenEditTypeForm(card)\"><i class=\"fa-solid fa-pen\"></i> Edit</button>\n </div>\n </div>\n }\n <!-- Add Content Type Card -->\n <div class=\"at-add-type-card\" (click)=\"OpenAddTypeForm()\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n <span style=\"font-size: 0.85rem; font-weight: 600;\">Add Content Type</span>\n <span style=\"font-size: 0.72rem;\">Configure tagging rules</span>\n </div>\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- TAB 4: TAG LIBRARY -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (ActiveTab === 'tags') {\n <div class=\"at-page-header\">\n <div>\n <div class=\"at-page-title\">Tag Library</div>\n <div class=\"at-page-subtitle\">{{ TagRows.length }} unique tags across all content sources</div>\n </div>\n <div class=\"at-page-actions\">\n <input type=\"text\" class=\"at-search-input\" placeholder=\"Search tags...\"\n [(ngModel)]=\"TagSearchQuery\" (input)=\"FilterTags()\">\n </div>\n </div>\n <div class=\"at-page-body\">\n <div class=\"at-tag-lib-layout\">\n <div class=\"at-tag-lib-main\">\n <div class=\"at-card\">\n <div class=\"at-card-body\" style=\"max-height: 500px; overflow-y: auto;\">\n <table class=\"at-tag-table\">\n <thead>\n <tr>\n <th>Tag</th>\n <th>Count</th>\n <th>Avg Weight</th>\n <th>Distribution</th>\n <th>Top Source</th>\n <th>First Seen</th>\n </tr>\n </thead>\n <tbody>\n @for (row of FilteredTagRows; track row.Tag) {\n <tr>\n <td class=\"at-tag-name-cell\">{{ row.Tag }}</td>\n <td>{{ row.UsageCount }}</td>\n <td>\n <div class=\"at-weight-indicator\">\n <div class=\"at-weight-bar\">\n <div class=\"at-weight-bar-fill\" [style.width.%]=\"row.AvgWeight * 100\"\n [class.at-weight-high]=\"row.AvgWeight >= 0.7\"\n [class.at-weight-medium]=\"row.AvgWeight >= 0.4 && row.AvgWeight < 0.7\"\n [class.at-weight-low]=\"row.AvgWeight < 0.4\"></div>\n </div>\n <span class=\"at-weight-value\">{{ row.AvgWeight.toFixed(2) }}</span>\n </div>\n </td>\n <td>\n <div class=\"at-tag-bar\">\n <div class=\"at-tag-bar-fill\" [style.width.%]=\"row.BarWidthPct\"></div>\n </div>\n </td>\n <td>{{ row.TopSource }}</td>\n <td>{{ row.FirstSeen }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n </div>\n <div class=\"at-tag-lib-sidebar\">\n <div class=\"at-card at-tag-cloud-card\">\n <div class=\"at-card-title\" style=\"margin-bottom: 12px;\"><i class=\"fa-solid fa-cloud\"></i> Tag Cloud</div>\n <div class=\"at-tag-cloud\">\n @for (tag of TagCloud; track tag.Tag) {\n <span class=\"at-tag-pill\" [class]=\"tag.SizeClass\"\n [style.opacity]=\"0.4 + tag.AvgWeight * 0.6\"\n [title]=\"'Weight: ' + tag.AvgWeight.toFixed(2)\">{{ tag.Tag }}</span>\n }\n </div>\n </div>\n <div class=\"at-card\" style=\"padding: 16px; margin-top: 12px;\">\n <div class=\"at-card-title\" style=\"margin-bottom: 10px;\"><i class=\"fa-solid fa-chart-pie\"></i> By Source</div>\n <div class=\"at-tags-by-source\">\n @for (s of TagsBySource; track s.SourceName) {\n <div class=\"at-tag-source-row\">\n <span>{{ s.SourceName }}</span>\n <strong>{{ s.Count }}</strong>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n <!-- TAB 5: RUN HISTORY -->\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (ActiveTab === 'history') {\n <div class=\"at-page-header\">\n <div>\n <div class=\"at-page-title\">Run History</div>\n <div class=\"at-page-subtitle\">Processing run log across all content sources</div>\n </div>\n <div class=\"at-page-actions\">\n <select class=\"at-filter-select\" [(ngModel)]=\"HistorySourceFilter\" (change)=\"FilterRunHistory()\">\n <option value=\"\">All Sources</option>\n @for (s of HistorySourceOptions; track s) {\n <option [value]=\"s\">{{ s }}</option>\n }\n </select>\n <select class=\"at-filter-select\" [(ngModel)]=\"HistoryStatusFilter\" (change)=\"FilterRunHistory()\">\n <option value=\"\">All Status</option>\n <option value=\"complete\">Complete</option>\n <option value=\"failed\">Failed</option>\n <option value=\"running\">Running</option>\n </select>\n </div>\n </div>\n <div class=\"at-page-body\">\n <div class=\"at-card\">\n <div class=\"at-card-body\" style=\"max-height: 600px; overflow-y: auto;\">\n <table class=\"at-run-table\">\n <thead>\n <tr>\n <th>Status</th>\n <th>Source</th>\n <th>Started</th>\n <th>Duration</th>\n <th>Items</th>\n <th>Tags</th>\n <th>Errors</th>\n </tr>\n </thead>\n <tbody>\n @for (row of FilteredRunRows; track row.ID) {\n <tr>\n <td>\n <span class=\"at-run-status-badge\" [class]=\"row.StatusClass\">\n @if (row.StatusClass === 'running') {\n <i class=\"fa-solid fa-spinner fa-spin\" style=\"font-size: 0.55rem\"></i>\n }\n {{ row.Status }}\n </span>\n </td>\n <td class=\"at-run-source-name\">{{ row.SourceName }}</td>\n <td>{{ row.StartedDisplay }}</td>\n <td class=\"at-run-duration\">{{ row.Duration }}</td>\n <td>{{ row.Items }}</td>\n <td>{{ row.Tags }}</td>\n <td [class]=\"row.ErrorClass\">{{ row.Errors }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n </div>\n }\n }\n </div>\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 SLIDE-IN FORM OVERLAY \u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (FormMode !== 'none') {\n <div class=\"at-slide-overlay\" (click)=\"CloseForm()\"></div>\n <div class=\"at-slide-panel\">\n <div class=\"at-slide-header\">\n <h3>\n @if (FormMode === 'add-source') { Add Content Source }\n @else if (FormMode === 'edit-source') { Edit Content Source }\n @else if (FormMode === 'add-type') { Add Content Type }\n @else if (FormMode === 'edit-type') { Edit Content Type }\n </h3>\n <button class=\"at-slide-close\" (click)=\"CloseForm()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n <div class=\"at-slide-body\">\n\n <!-- Source form -->\n @if (FormMode === 'add-source' || FormMode === 'edit-source') {\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Name</label>\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"FormSourceName\" placeholder=\"Source name\">\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Source Type</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceTypeID\">\n <option value=\"\">Select source type...</option>\n @for (opt of SourceTypeOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Content Type</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormContentTypeID\">\n <option value=\"\">Select content type...</option>\n @for (opt of ContentTypeOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">File Type</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormFileTypeID\">\n <option value=\"\">Select file type...</option>\n @for (opt of FileTypeOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">URL</label>\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"FormSourceURL\" placeholder=\"https://...\">\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Embedding Model Override</label>\n <mj-tree-dropdown\n [BranchConfig]=\"AIModelVendorBranch\"\n [LeafConfig]=\"EmbeddingModelsLeaf\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n Placeholder=\"Use system default\"\n [Clearable]=\"true\"\n [Value]=\"ToCompositeKey(FormSourceEmbeddingModelID)\"\n (ValueChange)=\"FormSourceEmbeddingModelID = FromCompositeKey($event)\">\n </mj-tree-dropdown>\n <span class=\"at-form-hint\">Overrides Content Type default</span>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Vector Index Override</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormSourceVectorIndexID\">\n <option value=\"\">Use system default</option>\n @for (opt of VectorIndexOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n <span class=\"at-form-hint\">Overrides Content Type default</span>\n </div>\n <div class=\"at-form-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"SaveSource()\" [disabled]=\"FormSaving\">\n @if (FormSaving) { <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving... }\n @else { <i class=\"fa-solid fa-check\"></i> Save }\n </button>\n <button class=\"at-action-btn at-secondary-btn\" (click)=\"CloseForm()\">Cancel</button>\n </div>\n }\n\n <!-- Content Type form -->\n @if (FormMode === 'add-type' || FormMode === 'edit-type') {\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Name</label>\n <input type=\"text\" class=\"at-form-input\" [(ngModel)]=\"FormTypeName\" placeholder=\"Content type name\">\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Description</label>\n <textarea class=\"at-form-textarea\" [(ngModel)]=\"FormTypeDescription\" rows=\"3\" placeholder=\"Description...\"></textarea>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">AI Model (for tagging)</label>\n <mj-tree-dropdown\n [BranchConfig]=\"AIModelVendorBranch\"\n [LeafConfig]=\"AllModelsLeaf\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n Placeholder=\"Select AI model...\"\n [Clearable]=\"true\"\n [Value]=\"ToCompositeKey(FormTypeAIModelID)\"\n (ValueChange)=\"FormTypeAIModelID = FromCompositeKey($event)\">\n </mj-tree-dropdown>\n </div>\n <div class=\"at-form-row\">\n <div class=\"at-form-group\" style=\"flex: 1;\">\n <label class=\"at-form-label\">Min Tags</label>\n <input type=\"number\" class=\"at-form-input\" [(ngModel)]=\"FormTypeMinTags\" min=\"0\">\n </div>\n <div class=\"at-form-group\" style=\"flex: 1;\">\n <label class=\"at-form-label\">Max Tags</label>\n <input type=\"number\" class=\"at-form-input\" [(ngModel)]=\"FormTypeMaxTags\" min=\"1\">\n </div>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Embedding Model</label>\n <mj-tree-dropdown\n [BranchConfig]=\"AIModelVendorBranch\"\n [LeafConfig]=\"EmbeddingModelsLeaf\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n Placeholder=\"Use system default\"\n [Clearable]=\"true\"\n [Value]=\"ToCompositeKey(FormTypeEmbeddingModelID)\"\n (ValueChange)=\"FormTypeEmbeddingModelID = FromCompositeKey($event)\">\n </mj-tree-dropdown>\n </div>\n <div class=\"at-form-group\">\n <label class=\"at-form-label\">Vector Index</label>\n <select class=\"at-form-select\" [(ngModel)]=\"FormTypeVectorIndexID\">\n <option value=\"\">Use system default</option>\n @for (opt of VectorIndexOptions; track opt.ID) {\n <option [value]=\"opt.ID\">{{ opt.Name }}</option>\n }\n </select>\n </div>\n <div class=\"at-form-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"SaveContentType()\" [disabled]=\"FormSaving\">\n @if (FormSaving) { <i class=\"fa-solid fa-spinner fa-spin\"></i> Saving... }\n @else { <i class=\"fa-solid fa-check\"></i> Save }\n </button>\n <button class=\"at-action-btn at-secondary-btn\" (click)=\"CloseForm()\">Cancel</button>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 ITEM DETAIL SLIDE-IN \u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (ShowItemDetail && SelectedFeedItem) {\n <div class=\"at-slide-overlay\" (click)=\"CloseItemDetail()\"></div>\n <div class=\"at-slide-panel at-detail-panel\">\n <div class=\"at-slide-header\">\n <h3><i class=\"fa-solid fa-file-lines\"></i> Content Item</h3>\n <button class=\"at-slide-close\" (click)=\"CloseItemDetail()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n <div class=\"at-slide-body\">\n <!-- Header -->\n <div class=\"at-detail-item-header\">\n <h4 class=\"at-detail-item-name\">{{ SelectedFeedItem.Name }}</h4>\n <div class=\"at-detail-badges\">\n <span class=\"at-detail-badge at-detail-badge-source\">{{ SelectedFeedItem.SourceName }}</span>\n <span class=\"at-detail-badge at-detail-badge-type\">{{ SelectedFeedItem.ContentTypeName }}</span>\n @if (SelectedFeedItem.FileTypeName) {\n <span class=\"at-detail-badge at-detail-badge-file\"><i class=\"fa-solid fa-file\"></i> {{ SelectedFeedItem.FileTypeName }}</span>\n }\n </div>\n </div>\n\n <!-- URL -->\n @if (SelectedFeedItem.URL) {\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">URL</div>\n <a [href]=\"SelectedFeedItem.URL\" target=\"_blank\" class=\"at-detail-link\">\n {{ SelectedFeedItem.URL }}\n <i class=\"fa-solid fa-external-link-alt\" style=\"font-size: 0.65rem; margin-left: 4px;\"></i>\n </a>\n </div>\n }\n\n <!-- Text Preview -->\n @if (SelectedFeedItem.TextContent) {\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">Content Preview</div>\n <div class=\"at-detail-text-preview\">{{ SelectedFeedItem.TextContent }}</div>\n </div>\n }\n\n <!-- Tags -->\n @if (SelectedFeedItem.Tags.length > 0) {\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">Tags ({{ SelectedFeedItem.Tags.length }})</div>\n <div class=\"at-detail-tags\">\n @for (tag of SelectedFeedItem.Tags; track tag) {\n <span class=\"at-tag-pill\">{{ tag }}</span>\n }\n </div>\n </div>\n }\n\n <!-- Metadata -->\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">Metadata</div>\n <div class=\"at-detail-meta-grid\">\n @if (SelectedFeedItem.Checksum) {\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">Checksum</span>\n <span class=\"at-detail-meta-value at-detail-meta-mono\">{{ SelectedFeedItem.Checksum }}</span>\n </div>\n }\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">Created</span>\n <span class=\"at-detail-meta-value\">{{ SelectedFeedItem.CreatedAt }}</span>\n </div>\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">Updated</span>\n <span class=\"at-detail-meta-value\">{{ SelectedFeedItem.UpdatedAt }}</span>\n </div>\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"at-detail-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"OpenRecordFromItem(SelectedFeedItem)\">\n <i class=\"fa-solid fa-external-link-alt\"></i> Open Record\n </button>\n <button class=\"at-action-btn at-secondary-btn\" disabled>\n <i class=\"fa-solid fa-magnifying-glass\"></i> See Similar Items\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550\u2550\u2550\u2550 SOURCE DETAIL SLIDE-IN \u2550\u2550\u2550\u2550\u2550\u2550 -->\n @if (ShowSourceDetail) {\n <div class=\"at-slide-overlay\" (click)=\"CloseSourceDetail()\"></div>\n <div class=\"at-slide-panel at-detail-panel\">\n <div class=\"at-slide-header\">\n <h3><i class=\"fa-solid fa-database\"></i> Source Detail</h3>\n <button class=\"at-slide-close\" (click)=\"CloseSourceDetail()\"><i class=\"fa-solid fa-times\"></i></button>\n </div>\n <div class=\"at-slide-body\">\n @if (SourceDetailLoading) {\n <div class=\"at-loading-overlay\">\n <mj-loading text=\"Loading source details...\"></mj-loading>\n </div>\n }\n @if (!SourceDetailLoading && SelectedSource) {\n <!-- Source Header -->\n <div class=\"at-detail-source-header\">\n <div class=\"at-source-card-icon\"><i [class]=\"SelectedSource.Icon\"></i></div>\n <div>\n <h4 class=\"at-detail-item-name\">{{ SelectedSource.Name }}</h4>\n <div class=\"at-detail-badges\">\n <span class=\"at-detail-badge at-detail-badge-type\">{{ SelectedSource.SourceTypeName }}</span>\n <span class=\"at-detail-badge\" [class]=\"'at-detail-badge-status-' + SelectedSource.StatusClass\">\n {{ SelectedSource.StatusLabel }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Configuration -->\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">Configuration</div>\n <div class=\"at-detail-meta-grid\">\n @if (SelectedSource.URL) {\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">URL</span>\n <a [href]=\"SelectedSource.URL\" target=\"_blank\" class=\"at-detail-link at-detail-meta-value\">{{ SelectedSource.URL }}</a>\n </div>\n }\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">Content Type</span>\n <span class=\"at-detail-meta-value\">{{ SelectedSource.ContentTypeName }}</span>\n </div>\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">File Type</span>\n <span class=\"at-detail-meta-value\">{{ SelectedSource.FileTypeName }}</span>\n </div>\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">Embedding Model</span>\n <span class=\"at-detail-meta-value\">{{ SelectedSource.EmbeddingModelName }}</span>\n </div>\n <div class=\"at-detail-meta-row\">\n <span class=\"at-detail-meta-key\">Vector Index</span>\n <span class=\"at-detail-meta-value\">{{ SelectedSource.VectorIndexName }}</span>\n </div>\n </div>\n </div>\n\n <!-- Stats -->\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">Statistics</div>\n <div class=\"at-detail-stats-strip\">\n <div class=\"at-detail-stat\">\n <div class=\"at-detail-stat-value\">{{ formatNumber(SelectedSource.ItemCount) }}</div>\n <div class=\"at-detail-stat-label\">Items</div>\n </div>\n <div class=\"at-detail-stat\">\n <div class=\"at-detail-stat-value\">{{ formatNumber(SelectedSource.TagCount) }}</div>\n <div class=\"at-detail-stat-label\">Tags</div>\n </div>\n <div class=\"at-detail-stat\">\n <div class=\"at-detail-stat-value\">{{ SelectedSource.AvgTags }}</div>\n <div class=\"at-detail-stat-label\">Avg Tags</div>\n </div>\n <div class=\"at-detail-stat\">\n <div class=\"at-detail-stat-value\">{{ SelectedSource.LastRunAgo }}</div>\n <div class=\"at-detail-stat-label\">Last Run</div>\n </div>\n <div class=\"at-detail-stat\">\n <div class=\"at-detail-stat-value\" [class.at-kpi-error-value]=\"SelectedSource.ErrorCount > 0\">{{ SelectedSource.ErrorCount }}</div>\n <div class=\"at-detail-stat-label\">Errors</div>\n </div>\n </div>\n </div>\n\n <!-- Content Library -->\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">Content Library ({{ SelectedSource.ContentItems.length }})</div>\n <div class=\"at-detail-content-list\">\n @if (SelectedSource.ContentItems.length === 0) {\n <div class=\"at-empty-state\" style=\"padding: 16px;\">\n <p>No content items yet.</p>\n </div>\n }\n @for (ci of SelectedSource.ContentItems; track ci.ID) {\n <div class=\"at-detail-content-item\" (click)=\"OpenContentItemDetail(ci)\">\n <div class=\"at-feed-status-dot\" [class]=\"ci.StatusDot\"></div>\n <span class=\"at-detail-content-item-name\">{{ ci.Name }}</span>\n <span class=\"at-detail-content-item-tags\">{{ ci.TagCount }} tags</span>\n <span class=\"at-detail-content-item-time\">{{ ci.UpdatedAt }}</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Run History -->\n @if (SelectedSource.RunHistory.length > 0) {\n <div class=\"at-detail-section\">\n <div class=\"at-detail-section-label\">Recent Runs</div>\n <div class=\"at-detail-run-history\">\n @for (run of SelectedSource.RunHistory; track run.ID) {\n <div class=\"at-detail-run-row\">\n <span class=\"at-run-status-badge\" [class]=\"run.StatusClass\">{{ run.Status }}</span>\n <span class=\"at-detail-run-time\">{{ run.StartedDisplay }}</span>\n <span class=\"at-detail-run-duration\">{{ run.Duration }}</span>\n <span class=\"at-detail-run-items\">{{ run.Items }} items</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Actions -->\n <div class=\"at-detail-actions\">\n <button class=\"at-action-btn at-primary-btn\" (click)=\"OpenEditSourceFromDetail()\">\n <i class=\"fa-solid fa-pen\"></i> Edit\n </button>\n <button class=\"at-action-btn at-secondary-btn\" (click)=\"RunSourceFromDetail()\">\n <i class=\"fa-solid fa-play\"></i> Run Now\n </button>\n <button class=\"at-action-btn at-secondary-btn at-source-delete-btn\" (click)=\"DeleteSourceFromDetail()\">\n <i class=\"fa-solid fa-trash\"></i> Delete\n </button>\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: ["/* ============================================================\n Content Autotagging Dashboard\n All colors use MJ design tokens \u2014 no hardcoded hex values.\n All classes prefixed with at- to prevent leaking (ViewEncapsulation.None).\n ============================================================ */\n\n/* \u2500\u2500 Root layout \u2500\u2500 */\n\n.at-dashboard {\n display: flex;\n height: 100%;\n overflow: hidden;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 LEFT NAV \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-left-nav {\n 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 flex-shrink: 0;\n}\n\n.at-left-nav-header {\n padding: 16px 16px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.at-left-nav-header h2 {\n font-size: 0.95rem;\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n color: var(--mj-text-primary);\n}\n\n.at-left-nav-header h2 i {\n color: var(--mj-brand-primary);\n}\n\n.at-left-nav-items {\n flex: 1;\n padding: 8px;\n overflow-y: auto;\n}\n\n.at-nav-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n border-radius: 8px;\n font-size: 0.82rem;\n font-weight: 500;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.12s ease;\n margin-bottom: 2px;\n}\n\n.at-nav-item:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-secondary);\n}\n\n.at-nav-item.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.at-nav-item i {\n width: 18px;\n text-align: center;\n font-size: 0.8rem;\n}\n\n.at-nav-badge {\n margin-left: auto;\n background: var(--mj-bg-surface-sunken);\n padding: 1px 7px;\n border-radius: 10px;\n font-size: 0.65rem;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n\n.at-nav-item.active .at-nav-badge {\n background: color-mix(in srgb, var(--mj-brand-primary) 18%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-nav-badge-live {\n background: var(--mj-status-success-bg) !important;\n color: var(--mj-status-success-text) !important;\n}\n\n.at-nav-divider {\n height: 1px;\n background: var(--mj-border-subtle);\n margin: 8px 12px;\n}\n\n.at-left-nav-footer {\n padding: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.at-run-pipeline-btn {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 10px;\n border: none;\n border-radius: 8px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 0.82rem;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.at-run-pipeline-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.at-run-pipeline-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 MAIN CONTENT AREA \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-main-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.at-loading-overlay {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n.at-page-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.at-page-title {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-page-subtitle {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.at-page-actions {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.at-page-body {\n flex: 1;\n overflow-y: auto;\n padding: 16px 20px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 SHARED COMPONENTS \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 7px 14px;\n border: 1px solid;\n border-radius: 7px;\n cursor: pointer;\n font-size: 0.78rem;\n font-weight: 500;\n transition: all 0.15s ease;\n}\n\n.at-primary-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.at-primary-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.at-primary-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.at-secondary-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n\n.at-secondary-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.at-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.at-card-title {\n font-size: 0.82rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-primary);\n}\n\n.at-card-title i {\n color: var(--mj-brand-primary);\n font-size: 0.75rem;\n}\n\n.at-card-body {\n padding: 0;\n}\n\n.at-empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n}\n\n.at-empty-state i {\n font-size: 28px;\n}\n\n.at-empty-state p {\n margin: 0;\n font-size: 13px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 KPI STRIP \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-kpi-strip {\n display: flex;\n gap: 12px;\n margin-bottom: 16px;\n}\n\n.at-kpi-card {\n flex: 1;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 14px 16px;\n}\n\n.at-kpi-value {\n font-size: 1.4rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-kpi-error-value {\n color: var(--mj-status-error-text);\n}\n\n.at-kpi-label {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.at-kpi-trend {\n font-size: 0.68rem;\n margin-top: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n color: var(--mj-text-muted);\n}\n\n.at-kpi-trend.up {\n color: var(--mj-status-success-text);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 PIPELINE TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-pipeline-layout {\n display: flex;\n gap: 16px;\n}\n\n.at-pipeline-center {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n}\n\n.at-pipeline-right {\n width: 320px;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n/* Pipeline Stages */\n\n.at-pipeline-stages {\n display: flex;\n gap: 0;\n align-items: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 12px 16px;\n}\n\n.at-pipeline-stage {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n\n.at-pipeline-stage-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n font-size: 0.85rem;\n}\n\n.stage-idle .at-pipeline-stage-icon {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.stage-active .at-pipeline-stage-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n animation: at-pulse 1.5s infinite;\n}\n\n.stage-complete .at-pipeline-stage-icon {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n@keyframes at-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--mj-brand-primary) 30%, transparent); }\n 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--mj-brand-primary) 0%, transparent); }\n}\n\n.at-pipeline-stage-name {\n font-size: 0.68rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.at-pipeline-stage-count {\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.at-pipeline-arrow {\n width: 24px;\n text-align: center;\n color: var(--mj-text-disabled);\n font-size: 0.6rem;\n}\n\n/* Progress section */\n\n.at-progress-section {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 10px 16px;\n}\n\n.at-progress-header {\n display: flex;\n justify-content: space-between;\n font-size: 0.75rem;\n margin-bottom: 4px;\n}\n\n.at-progress-stage-label {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.at-progress-pct {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.at-progress-bar {\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n}\n\n.at-progress-fill {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 2px;\n transition: width 0.3s ease;\n}\n\n.at-progress-current {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n margin-top: 4px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Feed items */\n\n.at-feed-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.at-feed-item:last-child {\n border-bottom: none;\n}\n\n.at-feed-status-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.at-feed-status-dot.complete {\n background: var(--mj-status-success);\n}\n\n.at-feed-status-dot.processing {\n background: var(--mj-brand-primary);\n animation: at-pulse 1.5s infinite;\n}\n\n.at-feed-status-dot.error {\n background: var(--mj-status-error);\n}\n\n.at-feed-item-name {\n flex: 1;\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n\n.at-feed-item-source {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n min-width: 100px;\n}\n\n.at-feed-item-tags {\n display: flex;\n gap: 4px;\n}\n\n.at-feed-tag {\n padding: 1px 6px;\n border-radius: 3px;\n font-size: 0.62rem;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-feed-item-time {\n color: var(--mj-text-muted);\n font-size: 0.68rem;\n white-space: nowrap;\n min-width: 60px;\n text-align: right;\n}\n\n/* Source mini cards (right panel) */\n\n.at-source-mini {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.at-source-mini:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-source-mini:last-child {\n border-bottom: none;\n}\n\n.at-source-mini-icon {\n width: 28px;\n height: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.72rem;\n flex-shrink: 0;\n}\n\n.at-source-mini-info {\n flex: 1;\n min-width: 0;\n}\n\n.at-source-mini-name {\n font-size: 0.78rem;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--mj-text-primary);\n}\n\n.at-source-mini-meta {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.at-source-mini-status {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n}\n\n.at-source-mini-status.active {\n background: var(--mj-status-success);\n}\n\n.at-source-mini-status.error {\n background: var(--mj-status-error);\n}\n\n.at-source-mini-status.inactive {\n background: var(--mj-text-disabled);\n}\n\n/* Tag cloud card */\n\n.at-tag-cloud-card {\n padding: 16px;\n}\n\n.at-tag-cloud {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n}\n\n.at-tag-pill {\n padding: 4px 12px;\n border-radius: 14px;\n font-size: 0.72rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-subtle);\n cursor: pointer;\n transition: all 0.12s ease;\n}\n\n.at-tag-pill:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-tag-pill.large {\n font-size: 0.85rem;\n padding: 5px 14px;\n}\n\n.at-tag-pill.small {\n font-size: 0.65rem;\n padding: 3px 8px;\n color: var(--mj-text-muted);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 SOURCES TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-sources-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));\n gap: 12px;\n}\n\n.at-source-card-full {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 16px;\n transition: border-color 0.15s ease;\n}\n\n.at-source-card-full:hover {\n border-color: var(--mj-border-default);\n}\n\n.at-source-card-header {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 12px;\n}\n\n.at-source-card-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 1rem;\n flex-shrink: 0;\n}\n\n.at-source-card-title {\n font-size: 0.9rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-source-card-type {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n}\n\n.at-source-card-status {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 0.7rem;\n font-weight: 500;\n}\n\n.at-source-card-status.active {\n color: var(--mj-status-success-text);\n}\n\n.at-source-card-status.error {\n color: var(--mj-status-error-text);\n}\n\n.at-source-card-status.inactive {\n color: var(--mj-text-disabled);\n}\n\n.at-source-card-url {\n font-size: 0.7rem;\n color: var(--mj-brand-primary);\n margin-bottom: 10px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.at-source-card-stats {\n display: flex;\n gap: 16px;\n padding-top: 10px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.at-source-stat {\n display: flex;\n flex-direction: column;\n}\n\n.at-source-stat-value {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-source-stat-label {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.at-source-card-actions {\n display: flex;\n gap: 6px;\n margin-top: 10px;\n}\n\n.at-source-action-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n padding: 6px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 0.7rem;\n cursor: pointer;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n transition: all 0.12s ease;\n}\n\n.at-source-action-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-source-delete-btn:hover {\n border-color: var(--mj-status-error);\n color: var(--mj-status-error-text);\n}\n\n.at-add-source-card {\n background: none;\n border: 2px dashed var(--mj-border-default);\n border-radius: 10px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 40px;\n cursor: pointer;\n transition: all 0.15s ease;\n color: var(--mj-text-muted);\n min-height: 200px;\n}\n\n.at-add-source-card:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-add-source-card i {\n font-size: 1.5rem;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 CONTENT TYPES TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-ct-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 12px;\n}\n\n.at-ct-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n padding: 16px;\n}\n\n.at-ct-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 10px;\n}\n\n.at-ct-card-name {\n font-size: 0.9rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-ct-card-model {\n font-size: 0.68rem;\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.at-ct-field {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.at-ct-field:last-child {\n border-bottom: none;\n}\n\n.at-ct-field-label {\n color: var(--mj-text-muted);\n}\n\n.at-ct-field-value {\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.at-ct-tag-range {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n padding: 8px 10px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n font-size: 0.75rem;\n color: var(--mj-text-primary);\n}\n\n.at-ct-tag-range i {\n color: var(--mj-brand-primary);\n}\n\n.at-ct-tag-range-bar {\n flex: 1;\n height: 6px;\n background: var(--mj-bg-surface);\n border-radius: 3px;\n position: relative;\n}\n\n.at-ct-tag-range-fill {\n position: absolute;\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 3px;\n}\n\n.at-ct-range-suffix {\n color: var(--mj-text-muted);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 TAG LIBRARY TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-tag-lib-layout {\n display: flex;\n gap: 16px;\n}\n\n.at-tag-lib-main {\n flex: 1;\n}\n\n.at-tag-lib-sidebar {\n width: 280px;\n flex-shrink: 0;\n}\n\n.at-tag-table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.at-tag-table th {\n text-align: left;\n padding: 8px 12px;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-elevated);\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.at-tag-table td {\n padding: 10px 12px;\n font-size: 0.8rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.at-tag-table tr:hover td {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-tag-name-cell {\n font-weight: 600;\n}\n\n.at-tag-bar {\n width: 80px;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n display: inline-block;\n vertical-align: middle;\n}\n\n.at-tag-bar-fill {\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 3px;\n}\n\n/* Weight indicator in tag table */\n.at-weight-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.at-weight-bar {\n width: 50px;\n height: 6px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 3px;\n overflow: hidden;\n}\n\n.at-weight-bar-fill {\n height: 100%;\n border-radius: 3px;\n transition: width 0.2s ease;\n}\n\n.at-weight-bar-fill.at-weight-high {\n background: var(--mj-status-success);\n}\n\n.at-weight-bar-fill.at-weight-medium {\n background: var(--mj-status-warning);\n}\n\n.at-weight-bar-fill.at-weight-low {\n background: var(--mj-status-error);\n}\n\n.at-weight-value {\n font-size: 0.7rem;\n font-weight: 600;\n color: var(--mj-text-muted);\n min-width: 28px;\n}\n\n.at-tags-by-source {\n font-size: 0.78rem;\n}\n\n.at-tag-source-row {\n display: flex;\n justify-content: space-between;\n padding: 5px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.at-tag-source-row:last-child {\n border-bottom: none;\n}\n\n.at-search-input {\n padding: 7px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.8rem;\n width: 200px;\n outline: none;\n}\n\n.at-search-input::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.at-search-input:focus {\n border-color: var(--mj-brand-primary);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 RUN HISTORY TAB \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-run-table {\n width: 100%;\n border-collapse: collapse;\n}\n\n.at-run-table th {\n text-align: left;\n padding: 10px 14px;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-elevated);\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.at-run-table td {\n padding: 12px 14px;\n font-size: 0.8rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n\n.at-run-table tr:hover td {\n background: var(--mj-bg-surface-hover);\n cursor: pointer;\n}\n\n.at-run-status-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 0.7rem;\n font-weight: 600;\n}\n\n.at-run-status-badge.complete {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.at-run-status-badge.failed {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.at-run-status-badge.running {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-run-duration {\n color: var(--mj-text-muted);\n font-size: 0.75rem;\n}\n\n.at-run-source-name {\n font-weight: 500;\n}\n\n.at-run-error-text {\n color: var(--mj-status-error-text);\n}\n\n.at-filter-select {\n padding: 7px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 0.78rem;\n outline: none;\n}\n\n.at-filter-select:focus {\n border-color: var(--mj-brand-primary);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 SLIDE-IN FORM PANEL \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-slide-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 1000;\n}\n\n.at-slide-panel {\n position: fixed;\n right: 0;\n top: 0;\n bottom: 0;\n width: 420px;\n max-width: 100vw;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 1001;\n display: flex;\n flex-direction: column;\n box-shadow: -4px 0 24px color-mix(in srgb, var(--mj-text-primary) 15%, transparent);\n}\n\n.at-slide-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.at-slide-header h3 {\n margin: 0;\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-slide-close {\n background: none;\n border: none;\n font-size: 1.1rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px;\n}\n\n.at-slide-close:hover {\n color: var(--mj-text-primary);\n}\n\n.at-slide-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n.at-form-group {\n margin-bottom: 16px;\n}\n\n.at-form-label {\n display: block;\n font-size: 0.78rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n margin-bottom: 6px;\n}\n\n.at-form-input,\n.at-form-select,\n.at-form-textarea {\n width: 100%;\n padding: 9px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n font-size: 0.82rem;\n outline: none;\n font-family: inherit;\n}\n\n.at-form-input:focus,\n.at-form-select:focus,\n.at-form-textarea:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.at-form-input::placeholder,\n.at-form-textarea::placeholder {\n color: var(--mj-text-disabled);\n}\n\n.at-form-textarea {\n resize: vertical;\n}\n\n.at-form-row {\n display: flex;\n gap: 12px;\n}\n\n.at-form-actions {\n display: flex;\n gap: 8px;\n margin-top: 24px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 RESPONSIVE \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n@media (max-width: 1100px) {\n .at-pipeline-layout {\n flex-direction: column;\n }\n\n .at-pipeline-right {\n width: 100%;\n flex-direction: row;\n }\n\n .at-tag-lib-layout {\n flex-direction: column;\n }\n\n .at-tag-lib-sidebar {\n width: 100%;\n }\n}\n\n@media (max-width: 768px) {\n .at-left-nav {\n width: 180px;\n }\n\n .at-kpi-strip {\n flex-wrap: wrap;\n }\n\n .at-kpi-card {\n min-width: 140px;\n }\n\n .at-sources-grid {\n grid-template-columns: 1fr;\n }\n\n .at-ct-grid {\n grid-template-columns: 1fr;\n }\n\n .at-slide-panel {\n width: 100vw;\n }\n}\n\n@media (max-width: 480px) {\n .at-left-nav {\n width: 56px;\n }\n\n .at-left-nav-header h2 {\n font-size: 0;\n }\n\n .at-left-nav-header h2 i {\n font-size: 1rem;\n }\n\n .at-nav-item {\n justify-content: center;\n padding: 10px;\n font-size: 0;\n }\n\n .at-nav-item i {\n font-size: 1rem;\n }\n\n .at-nav-badge {\n display: none;\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Slide-in Form Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-slide-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.35);\n z-index: 9999;\n animation: at-fade-in 0.2s ease;\n}\n\n@keyframes at-fade-in { from { opacity: 0; } to { opacity: 1; } }\n\n.at-slide-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 420px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0, 0, 0, 0.4);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n animation: at-slide-in 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n@keyframes at-slide-in { from { transform: translateX(100%); } to { transform: translateX(0); } }\n\n.at-slide-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.at-slide-header h3 {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-slide-close {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n transition: all 0.15s ease;\n}\n\n.at-slide-close:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.at-slide-body {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.at-form-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.at-form-label {\n font-size: 0.75rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.at-form-input,\n.at-form-select,\n.at-form-textarea {\n padding: 9px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 7px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-primary);\n font-size: 0.85rem;\n outline: none;\n transition: border-color 0.15s ease;\n font-family: inherit;\n}\n\n.at-form-input:focus,\n.at-form-select:focus,\n.at-form-textarea:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.at-form-select {\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M3 5l3 3 3-3'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 10px center;\n padding-right: 30px;\n}\n\n.at-form-textarea {\n resize: vertical;\n min-height: 70px;\n}\n\n.at-form-row {\n display: flex;\n gap: 12px;\n}\n\n.at-form-actions {\n display: flex;\n gap: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-subtle);\n margin-top: 8px;\n}\n\n.at-form-actions .at-action-btn {\n flex: 1;\n justify-content: center;\n}\n\n/* Also add empty state for Content Types (matching Sources) */\n.at-add-type-card {\n background: none;\n border: 2px dashed var(--mj-border-default);\n border-radius: 10px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 40px;\n cursor: pointer;\n transition: all 0.15s ease;\n color: var(--mj-text-muted);\n min-height: 200px;\n}\n\n.at-add-type-card:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.at-add-type-card i {\n font-size: 1.5rem;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 FORKED PIPELINE STAGES \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-pipeline-stages-forked {\n display: flex;\n align-items: center;\n gap: 0;\n}\n\n.at-pipeline-fork {\n display: flex;\n align-items: center;\n gap: 0;\n flex: 2;\n}\n\n.at-pipeline-fork-lines {\n width: 28px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n position: relative;\n flex-shrink: 0;\n}\n\n.at-pipeline-fork-line {\n height: 2px;\n background: var(--mj-border-default);\n width: 100%;\n position: relative;\n}\n\n.at-pipeline-fork-line::before {\n content: '';\n position: absolute;\n width: 2px;\n height: 12px;\n background: var(--mj-border-default);\n left: 0;\n}\n\n.at-fork-top::before {\n bottom: 0;\n left: 0;\n}\n\n.at-fork-bottom::before {\n top: 0;\n left: 0;\n}\n\n.at-pipeline-fork-branches {\n display: flex;\n flex-direction: column;\n gap: 8px;\n flex: 1;\n}\n\n.at-pipeline-fork-branches .at-pipeline-stage {\n flex: none;\n padding: 6px 0;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 CLICKABLE FEED ITEMS \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-feed-item-clickable {\n cursor: pointer;\n}\n\n.at-feed-item-clickable:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 CLICKABLE SOURCE CARDS \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-source-card-clickable {\n cursor: pointer;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 FORM HINT \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-form-hint {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 2px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 DETAIL PANEL (wider) \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.at-detail-panel {\n width: 500px;\n}\n\n/* \u2500\u2500 Detail: Item header \u2500\u2500 */\n\n.at-detail-item-header {\n margin-bottom: 8px;\n}\n\n.at-detail-item-name {\n font-size: 1.05rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin: 0 0 6px 0;\n word-break: break-word;\n}\n\n.at-detail-badges {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.at-detail-badge {\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 0.7rem;\n font-weight: 600;\n}\n\n.at-detail-badge-source {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.at-detail-badge-type {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.at-detail-badge-file {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.at-detail-badge-status-active {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.at-detail-badge-status-error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.at-detail-badge-status-inactive {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n}\n\n/* \u2500\u2500 Detail: Sections \u2500\u2500 */\n\n.at-detail-section {\n margin-bottom: 4px;\n}\n\n.at-detail-section-label {\n font-size: 0.72rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: var(--mj-text-muted);\n margin-bottom: 6px;\n}\n\n.at-detail-link {\n font-size: 0.8rem;\n color: var(--mj-brand-primary);\n text-decoration: none;\n word-break: break-all;\n}\n\n.at-detail-link:hover {\n text-decoration: underline;\n}\n\n/* \u2500\u2500 Detail: Text preview \u2500\u2500 */\n\n.at-detail-text-preview {\n max-height: 200px;\n overflow-y: auto;\n padding: 10px 12px;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 6px;\n font-size: 0.78rem;\n font-family: 'SF Mono', 'Cascadia Code', 'Menlo', monospace;\n color: var(--mj-text-primary);\n white-space: pre-wrap;\n word-break: break-word;\n line-height: 1.5;\n}\n\n/* \u2500\u2500 Detail: Tags \u2500\u2500 */\n\n.at-detail-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n}\n\n/* \u2500\u2500 Detail: Meta grid \u2500\u2500 */\n\n.at-detail-meta-grid {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.at-detail-meta-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.at-detail-meta-row:last-child {\n border-bottom: none;\n}\n\n.at-detail-meta-key {\n color: var(--mj-text-muted);\n font-weight: 500;\n flex-shrink: 0;\n margin-right: 12px;\n}\n\n.at-detail-meta-value {\n color: var(--mj-text-primary);\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.at-detail-meta-mono {\n font-family: 'SF Mono', 'Cascadia Code', 'Menlo', monospace;\n font-size: 0.72rem;\n}\n\n/* \u2500\u2500 Detail: Actions \u2500\u2500 */\n\n.at-detail-actions {\n display: flex;\n gap: 8px;\n padding-top: 8px;\n border-top: 1px solid var(--mj-border-subtle);\n margin-top: 8px;\n}\n\n.at-detail-actions .at-action-btn {\n flex: 1;\n justify-content: center;\n}\n\n/* \u2500\u2500 Detail: Source header \u2500\u2500 */\n\n.at-detail-source-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n/* \u2500\u2500 Detail: Stats strip \u2500\u2500 */\n\n.at-detail-stats-strip {\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.at-detail-stat {\n flex: 1;\n min-width: 60px;\n text-align: center;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n padding: 8px 6px;\n}\n\n.at-detail-stat-value {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.at-detail-stat-label {\n font-size: 0.62rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n/* \u2500\u2500 Detail: Content Library \u2500\u2500 */\n\n.at-detail-content-list {\n max-height: 250px;\n overflow-y: auto;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n}\n\n.at-detail-content-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.at-detail-content-item:last-child {\n border-bottom: none;\n}\n\n.at-detail-content-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.at-detail-content-item-name {\n flex: 1;\n font-weight: 500;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.at-detail-content-item-tags {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.at-detail-content-item-time {\n font-size: 0.68rem;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n/* \u2500\u2500 Detail: Run history \u2500\u2500 */\n\n.at-detail-run-history {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n max-height: 200px;\n overflow-y: auto;\n}\n\n.at-detail-run-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.75rem;\n}\n\n.at-detail-run-row:last-child {\n border-bottom: none;\n}\n\n.at-detail-run-time {\n color: var(--mj-text-secondary);\n flex: 1;\n}\n\n.at-detail-run-duration {\n color: var(--mj-text-muted);\n}\n\n.at-detail-run-items {\n color: var(--mj-text-muted);\n}\n\n@media (max-width: 600px) {\n .at-slide-panel {\n width: 100%;\n }\n\n .at-detail-panel {\n width: 100%;\n }\n}\n"] }]
|
|
578
2787
|
}], null, null); })();
|
|
579
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AutotaggingPipelineResourceComponent, { className: "AutotaggingPipelineResourceComponent", filePath: "src/AI/components/autotagging/autotagging-pipeline-resource.component.ts", lineNumber:
|
|
2788
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AutotaggingPipelineResourceComponent, { className: "AutotaggingPipelineResourceComponent", filePath: "src/AI/components/autotagging/autotagging-pipeline-resource.component.ts", lineNumber: 193 }); })();
|
|
580
2789
|
export function LoadAutotaggingPipelineResource() {
|
|
581
2790
|
// Prevents tree-shaking
|
|
582
2791
|
}
|