@memberjunction/ng-dashboards 5.22.0 → 5.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +947 -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 +7645 -430
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +285 -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 +2454 -277
- 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 +20 -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 +419 -232
- 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/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +17 -17
- package/dist/DataExplorer/data-explorer-dashboard.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/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +1 -0
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +5 -4
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +247 -259
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +1 -0
- package/dist/Integration/components/overview/overview.component.js.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.js +1 -0
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.js +1 -0
- package/dist/Integration/components/schedules/schedules.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/analytics/analytics-resource.component.d.ts +411 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +4266 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +140 -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 +780 -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 +8 -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 +246 -195
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts +75 -0
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +601 -0
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts +93 -12
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js +637 -107
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/index.d.ts +3 -0
- package/dist/KnowledgeHub/index.d.ts.map +1 -1
- package/dist/KnowledgeHub/index.js +3 -0
- package/dist/KnowledgeHub/index.js.map +1 -1
- package/dist/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/__tests__/analytics-resource.test.d.ts +2 -0
- package/dist/__tests__/analytics-resource.test.d.ts.map +1 -0
- package/dist/__tests__/analytics-resource.test.js +181 -0
- package/dist/__tests__/analytics-resource.test.js.map +1 -0
- package/dist/__tests__/scheduling.test.d.ts +2 -0
- package/dist/__tests__/scheduling.test.d.ts.map +1 -0
- package/dist/__tests__/scheduling.test.js +205 -0
- package/dist/__tests__/scheduling.test.js.map +1 -0
- 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 +20 -20
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +43 -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 +2 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +2 -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/shared/entity-field-display.d.ts +44 -0
- package/dist/shared/entity-field-display.d.ts.map +1 -0
- package/dist/shared/entity-field-display.js +118 -0
- package/dist/shared/entity-field-display.js.map +1 -0
- 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 +48 -55
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Knowledge Hub Scheduled Pipelines Dashboard Tab
|
|
9
|
+
*
|
|
10
|
+
* Full-page resource component for managing scheduled pipelines within the
|
|
11
|
+
* Knowledge Hub application. Displays job cards in a compact grid, recent
|
|
12
|
+
* activity table, and provides create/edit via the reusable
|
|
13
|
+
* ScheduledJobDialogComponent from @memberjunction/ng-scheduling.
|
|
14
|
+
*
|
|
15
|
+
* Registered as BaseResourceComponent for the Knowledge Hub application.
|
|
16
|
+
*/
|
|
17
|
+
import { Component, ChangeDetectorRef, inject } from '@angular/core';
|
|
18
|
+
import { Subject } from 'rxjs';
|
|
19
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
20
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
21
|
+
import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';
|
|
22
|
+
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
23
|
+
import { ScheduledJobService } from '@memberjunction/ng-scheduling';
|
|
24
|
+
import * as i0 from "@angular/core";
|
|
25
|
+
import * as i1 from "@angular/forms";
|
|
26
|
+
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
27
|
+
import * as i3 from "@memberjunction/ng-scheduling";
|
|
28
|
+
const _forTrack0 = ($index, $item) => $item.ID;
|
|
29
|
+
function SchedulingResourceComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
30
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
31
|
+
i0.ɵɵelement(1, "mj-loading", 1);
|
|
32
|
+
i0.ɵɵelementEnd();
|
|
33
|
+
} }
|
|
34
|
+
function SchedulingResourceComponent_Conditional_1_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
35
|
+
i0.ɵɵelementStart(0, "strong");
|
|
36
|
+
i0.ɵɵtext(1);
|
|
37
|
+
i0.ɵɵelementEnd();
|
|
38
|
+
i0.ɵɵtext(2, " active ");
|
|
39
|
+
} if (rf & 2) {
|
|
40
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
41
|
+
i0.ɵɵadvance();
|
|
42
|
+
i0.ɵɵtextInterpolate(ctx_r1.ActiveCount);
|
|
43
|
+
} }
|
|
44
|
+
function SchedulingResourceComponent_Conditional_1_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
45
|
+
i0.ɵɵtext(0, " \u00B7 ");
|
|
46
|
+
i0.ɵɵelementStart(1, "strong");
|
|
47
|
+
i0.ɵɵtext(2);
|
|
48
|
+
i0.ɵɵelementEnd();
|
|
49
|
+
i0.ɵɵtext(3, " paused ");
|
|
50
|
+
} if (rf & 2) {
|
|
51
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
52
|
+
i0.ɵɵadvance(2);
|
|
53
|
+
i0.ɵɵtextInterpolate(ctx_r1.PausedCount);
|
|
54
|
+
} }
|
|
55
|
+
function SchedulingResourceComponent_Conditional_1_Conditional_20_For_2_For_11_Template(rf, ctx) { if (rf & 1) {
|
|
56
|
+
i0.ɵɵelement(0, "span", 36);
|
|
57
|
+
} if (rf & 2) {
|
|
58
|
+
const dotClass_r5 = ctx.$implicit;
|
|
59
|
+
i0.ɵɵclassMap(dotClass_r5);
|
|
60
|
+
} }
|
|
61
|
+
function SchedulingResourceComponent_Conditional_1_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
62
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
63
|
+
i0.ɵɵelementStart(0, "div", 22);
|
|
64
|
+
i0.ɵɵlistener("click", function SchedulingResourceComponent_Conditional_1_Conditional_20_For_2_Template_div_click_0_listener() { const job_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.OnEditJob(job_r4)); });
|
|
65
|
+
i0.ɵɵelementStart(1, "div", 23);
|
|
66
|
+
i0.ɵɵelement(2, "span", 24);
|
|
67
|
+
i0.ɵɵelementStart(3, "div", 25)(4, "div", 26);
|
|
68
|
+
i0.ɵɵtext(5);
|
|
69
|
+
i0.ɵɵelementEnd();
|
|
70
|
+
i0.ɵɵelementStart(6, "div", 27);
|
|
71
|
+
i0.ɵɵelement(7, "i", 28);
|
|
72
|
+
i0.ɵɵtext(8);
|
|
73
|
+
i0.ɵɵelementEnd()()();
|
|
74
|
+
i0.ɵɵelementStart(9, "div", 29);
|
|
75
|
+
i0.ɵɵrepeaterCreate(10, SchedulingResourceComponent_Conditional_1_Conditional_20_For_2_For_11_Template, 1, 2, "span", 30, i0.ɵɵrepeaterTrackByIndex);
|
|
76
|
+
i0.ɵɵelementStart(12, "span", 31);
|
|
77
|
+
i0.ɵɵtext(13, "last 7 runs");
|
|
78
|
+
i0.ɵɵelementEnd()();
|
|
79
|
+
i0.ɵɵelementStart(14, "div", 32)(15, "span", 33);
|
|
80
|
+
i0.ɵɵelement(16, "i", 28);
|
|
81
|
+
i0.ɵɵtext(17, " Last: ");
|
|
82
|
+
i0.ɵɵelementStart(18, "strong");
|
|
83
|
+
i0.ɵɵtext(19);
|
|
84
|
+
i0.ɵɵelementEnd()();
|
|
85
|
+
i0.ɵɵelementStart(20, "span", 33);
|
|
86
|
+
i0.ɵɵelement(21, "i", 34);
|
|
87
|
+
i0.ɵɵelementStart(22, "strong");
|
|
88
|
+
i0.ɵɵtext(23);
|
|
89
|
+
i0.ɵɵelementEnd()();
|
|
90
|
+
i0.ɵɵelementStart(24, "span", 33);
|
|
91
|
+
i0.ɵɵelement(25, "i", 35);
|
|
92
|
+
i0.ɵɵtext(26, " Next: ");
|
|
93
|
+
i0.ɵɵelementStart(27, "strong");
|
|
94
|
+
i0.ɵɵtext(28);
|
|
95
|
+
i0.ɵɵelementEnd()()()();
|
|
96
|
+
} if (rf & 2) {
|
|
97
|
+
const job_r4 = ctx.$implicit;
|
|
98
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
99
|
+
i0.ɵɵclassProp("paused", job_r4.Status === "Paused")("disabled", job_r4.Status === "Disabled");
|
|
100
|
+
i0.ɵɵadvance(2);
|
|
101
|
+
i0.ɵɵclassProp("dot-active", job_r4.Status === "Active")("dot-paused", job_r4.Status === "Paused")("dot-disabled", job_r4.Status === "Disabled");
|
|
102
|
+
i0.ɵɵadvance(3);
|
|
103
|
+
i0.ɵɵtextInterpolate(job_r4.Name);
|
|
104
|
+
i0.ɵɵadvance(3);
|
|
105
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.GetCronDescription(job_r4.CronExpression), " ");
|
|
106
|
+
i0.ɵɵadvance(2);
|
|
107
|
+
i0.ɵɵrepeater(ctx_r1.GetSparkline(job_r4.ID));
|
|
108
|
+
i0.ɵɵadvance(9);
|
|
109
|
+
i0.ɵɵtextInterpolate(ctx_r1.GetTimeAgo(job_r4.LastRunAt));
|
|
110
|
+
i0.ɵɵadvance(4);
|
|
111
|
+
i0.ɵɵtextInterpolate(ctx_r1.GetSuccessRate(job_r4));
|
|
112
|
+
i0.ɵɵadvance(5);
|
|
113
|
+
i0.ɵɵtextInterpolate(ctx_r1.GetTimeUntil(job_r4.NextRunAt));
|
|
114
|
+
} }
|
|
115
|
+
function SchedulingResourceComponent_Conditional_1_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
116
|
+
i0.ɵɵelementStart(0, "div", 14);
|
|
117
|
+
i0.ɵɵrepeaterCreate(1, SchedulingResourceComponent_Conditional_1_Conditional_20_For_2_Template, 29, 15, "div", 21, _forTrack0);
|
|
118
|
+
i0.ɵɵelementEnd();
|
|
119
|
+
} if (rf & 2) {
|
|
120
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
121
|
+
i0.ɵɵadvance();
|
|
122
|
+
i0.ɵɵrepeater(ctx_r1.FilteredJobs);
|
|
123
|
+
} }
|
|
124
|
+
function SchedulingResourceComponent_Conditional_1_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
125
|
+
i0.ɵɵelementStart(0, "div", 15);
|
|
126
|
+
i0.ɵɵelement(1, "i", 37);
|
|
127
|
+
i0.ɵɵelementStart(2, "p");
|
|
128
|
+
i0.ɵɵtext(3, "No Knowledge Hub schedules found");
|
|
129
|
+
i0.ɵɵelementEnd();
|
|
130
|
+
i0.ɵɵelementStart(4, "span");
|
|
131
|
+
i0.ɵɵtext(5, "Create a new schedule to automate classification and vector sync");
|
|
132
|
+
i0.ɵɵelementEnd()();
|
|
133
|
+
} }
|
|
134
|
+
function SchedulingResourceComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
135
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
136
|
+
i0.ɵɵelementStart(0, "div", 2)(1, "button", 3);
|
|
137
|
+
i0.ɵɵlistener("click", function SchedulingResourceComponent_Conditional_1_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnNewSchedule()); });
|
|
138
|
+
i0.ɵɵelement(2, "i", 4);
|
|
139
|
+
i0.ɵɵtext(3, " New Schedule ");
|
|
140
|
+
i0.ɵɵelementEnd();
|
|
141
|
+
i0.ɵɵelementStart(4, "select", 5);
|
|
142
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_select_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.StatusFilter, $event) || (ctx_r1.StatusFilter = $event); return i0.ɵɵresetView($event); });
|
|
143
|
+
i0.ɵɵlistener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_select_ngModelChange_4_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFilterChanged()); });
|
|
144
|
+
i0.ɵɵelementStart(5, "option", 6);
|
|
145
|
+
i0.ɵɵtext(6, "All Statuses");
|
|
146
|
+
i0.ɵɵelementEnd();
|
|
147
|
+
i0.ɵɵelementStart(7, "option", 7);
|
|
148
|
+
i0.ɵɵtext(8, "Active");
|
|
149
|
+
i0.ɵɵelementEnd();
|
|
150
|
+
i0.ɵɵelementStart(9, "option", 8);
|
|
151
|
+
i0.ɵɵtext(10, "Paused");
|
|
152
|
+
i0.ɵɵelementEnd();
|
|
153
|
+
i0.ɵɵelementStart(11, "option", 9);
|
|
154
|
+
i0.ɵɵtext(12, "Disabled");
|
|
155
|
+
i0.ɵɵelementEnd();
|
|
156
|
+
i0.ɵɵelementStart(13, "option", 10);
|
|
157
|
+
i0.ɵɵtext(14, "Pending");
|
|
158
|
+
i0.ɵɵelementEnd()();
|
|
159
|
+
i0.ɵɵelementStart(15, "input", 11);
|
|
160
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_input_ngModelChange_15_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.SearchQuery, $event) || (ctx_r1.SearchQuery = $event); return i0.ɵɵresetView($event); });
|
|
161
|
+
i0.ɵɵlistener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_input_ngModelChange_15_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnSearchChanged()); });
|
|
162
|
+
i0.ɵɵelementEnd();
|
|
163
|
+
i0.ɵɵelement(16, "div", 12);
|
|
164
|
+
i0.ɵɵelementStart(17, "span", 13);
|
|
165
|
+
i0.ɵɵconditionalCreate(18, SchedulingResourceComponent_Conditional_1_Conditional_18_Template, 3, 1);
|
|
166
|
+
i0.ɵɵconditionalCreate(19, SchedulingResourceComponent_Conditional_1_Conditional_19_Template, 4, 1);
|
|
167
|
+
i0.ɵɵelementEnd()();
|
|
168
|
+
i0.ɵɵconditionalCreate(20, SchedulingResourceComponent_Conditional_1_Conditional_20_Template, 3, 0, "div", 14)(21, SchedulingResourceComponent_Conditional_1_Conditional_21_Template, 6, 0, "div", 15);
|
|
169
|
+
i0.ɵɵelementStart(22, "div", 16)(23, "button", 17);
|
|
170
|
+
i0.ɵɵlistener("click", function SchedulingResourceComponent_Conditional_1_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.GoToSchedulingApp()); });
|
|
171
|
+
i0.ɵɵelement(24, "i", 18);
|
|
172
|
+
i0.ɵɵtext(25, " Open Scheduling App ");
|
|
173
|
+
i0.ɵɵelementEnd();
|
|
174
|
+
i0.ɵɵelementStart(26, "span", 19);
|
|
175
|
+
i0.ɵɵtext(27, "Manage all scheduled jobs across the system");
|
|
176
|
+
i0.ɵɵelementEnd()();
|
|
177
|
+
i0.ɵɵelementStart(28, "mj-scheduled-job-dialog", 20);
|
|
178
|
+
i0.ɵɵlistener("Close", function SchedulingResourceComponent_Conditional_1_Template_mj_scheduled_job_dialog_Close_28_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDialogClosed($event)); });
|
|
179
|
+
i0.ɵɵelementEnd();
|
|
180
|
+
} if (rf & 2) {
|
|
181
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
182
|
+
i0.ɵɵadvance(4);
|
|
183
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.StatusFilter);
|
|
184
|
+
i0.ɵɵadvance(11);
|
|
185
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.SearchQuery);
|
|
186
|
+
i0.ɵɵadvance(3);
|
|
187
|
+
i0.ɵɵconditional(ctx_r1.ActiveCount > 0 ? 18 : -1);
|
|
188
|
+
i0.ɵɵadvance();
|
|
189
|
+
i0.ɵɵconditional(ctx_r1.PausedCount > 0 ? 19 : -1);
|
|
190
|
+
i0.ɵɵadvance();
|
|
191
|
+
i0.ɵɵconditional(ctx_r1.FilteredJobs.length > 0 ? 20 : 21);
|
|
192
|
+
i0.ɵɵadvance(8);
|
|
193
|
+
i0.ɵɵproperty("Visible", ctx_r1.ShowEditDialog)("ScheduledJobID", ctx_r1.EditingJobID);
|
|
194
|
+
} }
|
|
195
|
+
let SchedulingResourceComponent = class SchedulingResourceComponent extends BaseResourceComponent {
|
|
196
|
+
cdr = inject(ChangeDetectorRef);
|
|
197
|
+
navigationService = inject(NavigationService);
|
|
198
|
+
scheduledJobService = inject(ScheduledJobService);
|
|
199
|
+
destroy$ = new Subject();
|
|
200
|
+
// ================================================================
|
|
201
|
+
// Resource overrides
|
|
202
|
+
// ================================================================
|
|
203
|
+
async GetResourceDisplayName(_data) {
|
|
204
|
+
return 'Schedules';
|
|
205
|
+
}
|
|
206
|
+
async GetResourceIconClass(_data) {
|
|
207
|
+
return 'fa-solid fa-clock';
|
|
208
|
+
}
|
|
209
|
+
// ================================================================
|
|
210
|
+
// State
|
|
211
|
+
// ================================================================
|
|
212
|
+
IsLoading = true;
|
|
213
|
+
AllJobs = [];
|
|
214
|
+
FilteredJobs = [];
|
|
215
|
+
RecentRuns = [];
|
|
216
|
+
StatusFilter = '';
|
|
217
|
+
SearchQuery = '';
|
|
218
|
+
/** Map of jobID -> last 7 run statuses for sparkline display */
|
|
219
|
+
sparklineCache = new Map();
|
|
220
|
+
// Edit dialog
|
|
221
|
+
ShowEditDialog = false;
|
|
222
|
+
EditingJobID = null;
|
|
223
|
+
// ================================================================
|
|
224
|
+
// Computed
|
|
225
|
+
// ================================================================
|
|
226
|
+
get ActiveCount() {
|
|
227
|
+
return this.AllJobs.filter(j => j.Status === 'Active').length;
|
|
228
|
+
}
|
|
229
|
+
get PausedCount() {
|
|
230
|
+
return this.AllJobs.filter(j => j.Status === 'Paused').length;
|
|
231
|
+
}
|
|
232
|
+
get DisabledCount() {
|
|
233
|
+
return this.AllJobs.filter(j => j.Status === 'Disabled').length;
|
|
234
|
+
}
|
|
235
|
+
// ================================================================
|
|
236
|
+
// Lifecycle
|
|
237
|
+
// ================================================================
|
|
238
|
+
async ngAfterViewInit() {
|
|
239
|
+
await this.loadData();
|
|
240
|
+
this.NotifyLoadComplete();
|
|
241
|
+
}
|
|
242
|
+
ngOnDestroy() {
|
|
243
|
+
this.destroy$.next();
|
|
244
|
+
this.destroy$.complete();
|
|
245
|
+
}
|
|
246
|
+
// ================================================================
|
|
247
|
+
// Public Methods — Toolbar
|
|
248
|
+
// ================================================================
|
|
249
|
+
OnNewSchedule() {
|
|
250
|
+
this.EditingJobID = null;
|
|
251
|
+
this.ShowEditDialog = true;
|
|
252
|
+
this.cdr.detectChanges();
|
|
253
|
+
}
|
|
254
|
+
OnFilterChanged() {
|
|
255
|
+
this.applyFilters();
|
|
256
|
+
this.cdr.detectChanges();
|
|
257
|
+
}
|
|
258
|
+
OnSearchChanged() {
|
|
259
|
+
this.applyFilters();
|
|
260
|
+
this.cdr.detectChanges();
|
|
261
|
+
}
|
|
262
|
+
// ================================================================
|
|
263
|
+
// Public Methods — Card Actions
|
|
264
|
+
// ================================================================
|
|
265
|
+
OnEditJob(job) {
|
|
266
|
+
this.EditingJobID = job.ID;
|
|
267
|
+
this.ShowEditDialog = true;
|
|
268
|
+
this.cdr.detectChanges();
|
|
269
|
+
}
|
|
270
|
+
async OnRunNow(job) {
|
|
271
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Triggering "${job.Name}" — this feature requires server-side support.`, 'info', 4000);
|
|
272
|
+
}
|
|
273
|
+
// ================================================================
|
|
274
|
+
// Public Methods — Dialog
|
|
275
|
+
// ================================================================
|
|
276
|
+
async OnDialogClosed(result) {
|
|
277
|
+
this.ShowEditDialog = false;
|
|
278
|
+
this.EditingJobID = null;
|
|
279
|
+
if (result.Saved || result.Deleted) {
|
|
280
|
+
await this.loadData();
|
|
281
|
+
}
|
|
282
|
+
this.cdr.detectChanges();
|
|
283
|
+
}
|
|
284
|
+
/** Navigate to the full Scheduling application */
|
|
285
|
+
GoToSchedulingApp() {
|
|
286
|
+
const md = new Metadata();
|
|
287
|
+
const schedulingApp = md.Applications.find(a => a.Name === 'Scheduling');
|
|
288
|
+
if (schedulingApp) {
|
|
289
|
+
this.navigationService.SwitchToApp(schedulingApp.ID);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
MJNotificationService.Instance.CreateSimpleNotification('Scheduling app not found. Check application configuration.', 'warning', 3000);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// ================================================================
|
|
296
|
+
// Public Methods — Card Display Helpers
|
|
297
|
+
// ================================================================
|
|
298
|
+
GetStatusDotClass(job) {
|
|
299
|
+
return (job.Status ?? 'pending').toLowerCase();
|
|
300
|
+
}
|
|
301
|
+
GetCronDescription(cron) {
|
|
302
|
+
if (!cron)
|
|
303
|
+
return 'No schedule';
|
|
304
|
+
const parts = this.parseCron(cron);
|
|
305
|
+
if (!parts)
|
|
306
|
+
return cron;
|
|
307
|
+
return this.cronToHuman(parts);
|
|
308
|
+
}
|
|
309
|
+
GetSparkline(jobID) {
|
|
310
|
+
return this.sparklineCache.get(jobID) ?? [];
|
|
311
|
+
}
|
|
312
|
+
GetTimeAgo(date) {
|
|
313
|
+
if (!date)
|
|
314
|
+
return 'Never';
|
|
315
|
+
const now = new Date();
|
|
316
|
+
const d = new Date(date);
|
|
317
|
+
const diffMs = now.getTime() - d.getTime();
|
|
318
|
+
return this.formatDuration(diffMs);
|
|
319
|
+
}
|
|
320
|
+
GetTimeUntil(date) {
|
|
321
|
+
if (!date)
|
|
322
|
+
return '--';
|
|
323
|
+
const now = new Date();
|
|
324
|
+
const d = new Date(date);
|
|
325
|
+
const diffMs = d.getTime() - now.getTime();
|
|
326
|
+
if (diffMs <= 0)
|
|
327
|
+
return 'Due';
|
|
328
|
+
return this.formatDuration(diffMs);
|
|
329
|
+
}
|
|
330
|
+
GetSuccessRate(job) {
|
|
331
|
+
if (job.RunCount === 0)
|
|
332
|
+
return 'N/A';
|
|
333
|
+
return Math.round((job.SuccessCount / job.RunCount) * 100) + '%';
|
|
334
|
+
}
|
|
335
|
+
GetSuccessRateClass(job) {
|
|
336
|
+
if (job.RunCount === 0)
|
|
337
|
+
return '';
|
|
338
|
+
const rate = job.SuccessCount / job.RunCount;
|
|
339
|
+
if (rate >= 0.95)
|
|
340
|
+
return 'high';
|
|
341
|
+
if (rate >= 0.80)
|
|
342
|
+
return 'mid';
|
|
343
|
+
return '';
|
|
344
|
+
}
|
|
345
|
+
GetDuration(run) {
|
|
346
|
+
if (!run.StartedAt || !run.CompletedAt)
|
|
347
|
+
return '--';
|
|
348
|
+
const start = new Date(run.StartedAt).getTime();
|
|
349
|
+
const end = new Date(run.CompletedAt).getTime();
|
|
350
|
+
const diffMs = end - start;
|
|
351
|
+
return this.formatDurationShort(diffMs);
|
|
352
|
+
}
|
|
353
|
+
GetItemsProcessed(run) {
|
|
354
|
+
if (!run.Details)
|
|
355
|
+
return '--';
|
|
356
|
+
try {
|
|
357
|
+
const details = JSON.parse(run.Details);
|
|
358
|
+
if (details['ItemsProcessed'] != null) {
|
|
359
|
+
const total = details['TotalItems'];
|
|
360
|
+
const processed = details['ItemsProcessed'];
|
|
361
|
+
if (run.Status === 'Failed' && total != null) {
|
|
362
|
+
return `${this.formatNumber(processed)} / ${this.formatNumber(total)}`;
|
|
363
|
+
}
|
|
364
|
+
return this.formatNumber(processed);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
// details not parseable
|
|
369
|
+
}
|
|
370
|
+
return '--';
|
|
371
|
+
}
|
|
372
|
+
// ================================================================
|
|
373
|
+
// Private Methods
|
|
374
|
+
// ================================================================
|
|
375
|
+
async loadData() {
|
|
376
|
+
this.IsLoading = true;
|
|
377
|
+
this.cdr.detectChanges();
|
|
378
|
+
try {
|
|
379
|
+
const rv = new RunView();
|
|
380
|
+
const [jobsResult, runsResult] = await rv.RunViews([
|
|
381
|
+
{
|
|
382
|
+
EntityName: 'MJ: Scheduled Jobs',
|
|
383
|
+
ExtraFilter: `Name LIKE '%Autotag%' OR Name LIKE '%Vector%' OR Name LIKE '%Content%' OR Name LIKE '%Knowledge%' OR Name LIKE '%Tag%'`,
|
|
384
|
+
OrderBy: 'Name',
|
|
385
|
+
ResultType: 'entity_object',
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
EntityName: 'MJ: Scheduled Job Runs',
|
|
389
|
+
ExtraFilter: '',
|
|
390
|
+
OrderBy: 'StartedAt DESC',
|
|
391
|
+
MaxRows: 100,
|
|
392
|
+
ResultType: 'entity_object',
|
|
393
|
+
},
|
|
394
|
+
]);
|
|
395
|
+
if (jobsResult.Success) {
|
|
396
|
+
this.AllJobs = jobsResult.Results;
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
this.AllJobs = [];
|
|
400
|
+
}
|
|
401
|
+
const allRuns = runsResult.Success
|
|
402
|
+
? runsResult.Results
|
|
403
|
+
: [];
|
|
404
|
+
this.RecentRuns = allRuns.slice(0, 10);
|
|
405
|
+
this.buildSparklineCache(allRuns);
|
|
406
|
+
this.applyFilters();
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
console.error('[SchedulingResource] Error loading data:', error);
|
|
410
|
+
this.AllJobs = [];
|
|
411
|
+
this.FilteredJobs = [];
|
|
412
|
+
this.RecentRuns = [];
|
|
413
|
+
}
|
|
414
|
+
finally {
|
|
415
|
+
this.IsLoading = false;
|
|
416
|
+
this.cdr.detectChanges();
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
applyFilters() {
|
|
420
|
+
let jobs = this.AllJobs;
|
|
421
|
+
if (this.StatusFilter) {
|
|
422
|
+
jobs = jobs.filter(j => j.Status === this.StatusFilter);
|
|
423
|
+
}
|
|
424
|
+
if (this.SearchQuery.trim()) {
|
|
425
|
+
const query = this.SearchQuery.trim().toLowerCase();
|
|
426
|
+
jobs = jobs.filter(j => j.Name.toLowerCase().includes(query) ||
|
|
427
|
+
(j.Description ?? '').toLowerCase().includes(query));
|
|
428
|
+
}
|
|
429
|
+
this.FilteredJobs = jobs;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Build sparkline data for each job from the last 7 runs.
|
|
433
|
+
* Each dot is 'ok', 'fail', or 'skip'.
|
|
434
|
+
*/
|
|
435
|
+
buildSparklineCache(allRuns) {
|
|
436
|
+
this.sparklineCache.clear();
|
|
437
|
+
// Group runs by job ID
|
|
438
|
+
const runsByJob = new Map();
|
|
439
|
+
for (const run of allRuns) {
|
|
440
|
+
const jobID = run.ScheduledJobID;
|
|
441
|
+
if (!runsByJob.has(jobID)) {
|
|
442
|
+
runsByJob.set(jobID, []);
|
|
443
|
+
}
|
|
444
|
+
runsByJob.get(jobID).push(run);
|
|
445
|
+
}
|
|
446
|
+
// Build sparkline for each job (up to 7 most recent runs)
|
|
447
|
+
for (const job of this.AllJobs) {
|
|
448
|
+
const runs = runsByJob.get(job.ID) ?? [];
|
|
449
|
+
const last7 = runs.slice(0, 7);
|
|
450
|
+
const dots = last7.map(r => this.runStatusToDot(r));
|
|
451
|
+
// Pad to 7 with 'skip' dots if fewer runs
|
|
452
|
+
while (dots.length < 7) {
|
|
453
|
+
dots.push('skip');
|
|
454
|
+
}
|
|
455
|
+
this.sparklineCache.set(job.ID, dots);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
runStatusToDot(run) {
|
|
459
|
+
if (run.Status === 'Completed' && run.Success)
|
|
460
|
+
return 'ok';
|
|
461
|
+
if (run.Status === 'Failed' || (run.Status === 'Completed' && !run.Success))
|
|
462
|
+
return 'fail';
|
|
463
|
+
if (run.Status === 'Running')
|
|
464
|
+
return 'ok'; // treat in-progress as OK
|
|
465
|
+
return 'skip';
|
|
466
|
+
}
|
|
467
|
+
// ================================================================
|
|
468
|
+
// Cron Parsing
|
|
469
|
+
// ================================================================
|
|
470
|
+
parseCron(cron) {
|
|
471
|
+
const parts = cron.trim().split(/\s+/);
|
|
472
|
+
// Support 5-part (no seconds) and 6-part (with seconds) cron
|
|
473
|
+
if (parts.length === 5) {
|
|
474
|
+
return {
|
|
475
|
+
Second: '0',
|
|
476
|
+
Minute: parts[0],
|
|
477
|
+
Hour: parts[1],
|
|
478
|
+
DayOfMonth: parts[2],
|
|
479
|
+
Month: parts[3],
|
|
480
|
+
DayOfWeek: parts[4],
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
if (parts.length === 6) {
|
|
484
|
+
return {
|
|
485
|
+
Second: parts[0],
|
|
486
|
+
Minute: parts[1],
|
|
487
|
+
Hour: parts[2],
|
|
488
|
+
DayOfMonth: parts[3],
|
|
489
|
+
Month: parts[4],
|
|
490
|
+
DayOfWeek: parts[5],
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
return null;
|
|
494
|
+
}
|
|
495
|
+
cronToHuman(p) {
|
|
496
|
+
// Every N minutes: */N * * * *
|
|
497
|
+
if (p.Minute.startsWith('*/') && p.Hour === '*' && p.DayOfMonth === '*' && p.Month === '*' && p.DayOfWeek === '*') {
|
|
498
|
+
const interval = parseInt(p.Minute.slice(2), 10);
|
|
499
|
+
if (interval === 1)
|
|
500
|
+
return 'Every minute';
|
|
501
|
+
return `Every ${interval} minutes`;
|
|
502
|
+
}
|
|
503
|
+
// Every N hours: 0 */N * * *
|
|
504
|
+
if (p.Minute !== '*' && !p.Minute.includes('/') && p.Hour.startsWith('*/') && p.DayOfMonth === '*') {
|
|
505
|
+
const interval = parseInt(p.Hour.slice(2), 10);
|
|
506
|
+
if (interval === 1)
|
|
507
|
+
return 'Every hour';
|
|
508
|
+
return `Every ${interval} hours`;
|
|
509
|
+
}
|
|
510
|
+
// Specific hour with specific or wildcard day fields
|
|
511
|
+
if (!p.Minute.includes('*') && !p.Minute.includes('/') &&
|
|
512
|
+
!p.Hour.includes('*') && !p.Hour.includes('/') &&
|
|
513
|
+
p.Month === '*') {
|
|
514
|
+
const hour = parseInt(p.Hour, 10);
|
|
515
|
+
const minute = parseInt(p.Minute, 10);
|
|
516
|
+
const timeStr = this.formatTime(hour, minute);
|
|
517
|
+
// Weekly: specific day of week
|
|
518
|
+
if (p.DayOfWeek !== '*' && p.DayOfMonth === '*') {
|
|
519
|
+
const dayName = this.dayOfWeekName(p.DayOfWeek);
|
|
520
|
+
return `Weekly on ${dayName} at ${timeStr}`;
|
|
521
|
+
}
|
|
522
|
+
// Monthly: specific day of month
|
|
523
|
+
if (p.DayOfMonth !== '*' && p.DayOfWeek === '*') {
|
|
524
|
+
return `Monthly on day ${p.DayOfMonth} at ${timeStr}`;
|
|
525
|
+
}
|
|
526
|
+
// Daily
|
|
527
|
+
if (p.DayOfMonth === '*' && p.DayOfWeek === '*') {
|
|
528
|
+
return `Daily at ${timeStr}`;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
// Fallback: return the raw cron expression
|
|
532
|
+
return `${p.Minute} ${p.Hour} ${p.DayOfMonth} ${p.Month} ${p.DayOfWeek}`;
|
|
533
|
+
}
|
|
534
|
+
formatTime(hour, minute) {
|
|
535
|
+
const ampm = hour >= 12 ? 'PM' : 'AM';
|
|
536
|
+
const h = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
|
|
537
|
+
const m = minute.toString().padStart(2, '0');
|
|
538
|
+
return `${h}:${m} ${ampm}`;
|
|
539
|
+
}
|
|
540
|
+
dayOfWeekName(dow) {
|
|
541
|
+
const names = {
|
|
542
|
+
'0': 'Sunday', '1': 'Monday', '2': 'Tuesday',
|
|
543
|
+
'3': 'Wednesday', '4': 'Thursday', '5': 'Friday',
|
|
544
|
+
'6': 'Saturday', '7': 'Sunday',
|
|
545
|
+
'SUN': 'Sunday', 'MON': 'Monday', 'TUE': 'Tuesday',
|
|
546
|
+
'WED': 'Wednesday', 'THU': 'Thursday', 'FRI': 'Friday',
|
|
547
|
+
'SAT': 'Saturday',
|
|
548
|
+
};
|
|
549
|
+
return names[dow.toUpperCase()] ?? dow;
|
|
550
|
+
}
|
|
551
|
+
// ================================================================
|
|
552
|
+
// Formatting Helpers
|
|
553
|
+
// ================================================================
|
|
554
|
+
formatDuration(ms) {
|
|
555
|
+
const seconds = Math.floor(ms / 1000);
|
|
556
|
+
const minutes = Math.floor(seconds / 60);
|
|
557
|
+
const hours = Math.floor(minutes / 60);
|
|
558
|
+
const days = Math.floor(hours / 24);
|
|
559
|
+
if (days > 0)
|
|
560
|
+
return `${days}d ago`;
|
|
561
|
+
if (hours > 0)
|
|
562
|
+
return `${hours}h ago`;
|
|
563
|
+
if (minutes > 0)
|
|
564
|
+
return `${minutes}m ago`;
|
|
565
|
+
return 'Just now';
|
|
566
|
+
}
|
|
567
|
+
formatDurationShort(ms) {
|
|
568
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
569
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
570
|
+
const seconds = totalSeconds % 60;
|
|
571
|
+
if (minutes >= 60) {
|
|
572
|
+
const hours = Math.floor(minutes / 60);
|
|
573
|
+
const remainMinutes = minutes % 60;
|
|
574
|
+
return `${hours}h ${remainMinutes}m`;
|
|
575
|
+
}
|
|
576
|
+
return `${minutes}m ${seconds.toString().padStart(2, '0')}s`;
|
|
577
|
+
}
|
|
578
|
+
formatNumber(n) {
|
|
579
|
+
return n.toLocaleString();
|
|
580
|
+
}
|
|
581
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵSchedulingResourceComponent_BaseFactory; return function SchedulingResourceComponent_Factory(__ngFactoryType__) { return (ɵSchedulingResourceComponent_BaseFactory || (ɵSchedulingResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(SchedulingResourceComponent)))(__ngFactoryType__ || SchedulingResourceComponent); }; })();
|
|
582
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SchedulingResourceComponent, selectors: [["app-scheduling-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 1, consts: [[1, "loading-container"], ["text", "Loading scheduled pipelines..."], [1, "toolbar"], [1, "btn-primary", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "filter-select", 3, "ngModelChange", "ngModel"], ["value", ""], ["value", "Active"], ["value", "Paused"], ["value", "Disabled"], ["value", "Pending"], ["type", "text", "placeholder", "Search pipelines...", 1, "search-input", 3, "ngModelChange", "ngModel"], [1, "toolbar-spacer"], [1, "toolbar-stat"], [1, "cards-grid"], [1, "empty-state"], [1, "scheduling-app-link"], [1, "btn-secondary", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], [1, "link-hint"], [3, "Close", "Visible", "ScheduledJobID"], [1, "job-card", 3, "paused", "disabled"], [1, "job-card", 3, "click"], [1, "card-top"], [1, "status-dot"], [1, "card-title-area"], [1, "card-name"], [1, "card-cron"], [1, "fa-regular", "fa-clock"], [1, "sparkline"], [1, "spark-dot", 3, "class"], [1, "sparkline-label"], [1, "card-stats"], [1, "stat"], [1, "fa-solid", "fa-chart-simple"], [1, "fa-regular", "fa-calendar"], [1, "spark-dot"], [1, "fa-regular", "fa-calendar-xmark"]], template: function SchedulingResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
583
|
+
i0.ɵɵconditionalCreate(0, SchedulingResourceComponent_Conditional_0_Template, 2, 0, "div", 0)(1, SchedulingResourceComponent_Conditional_1_Template, 29, 7);
|
|
584
|
+
} if (rf & 2) {
|
|
585
|
+
i0.ɵɵconditional(ctx.IsLoading ? 0 : 1);
|
|
586
|
+
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.NgModel, i2.LoadingComponent, i3.ScheduledJobDialogComponent], styles: ["\n\n[_nghost-%COMP%] {\n display: block;\n padding: 28px 32px 40px;\n max-width: 1200px;\n min-width: 0;\n}\n\n\n\n.page-header[_ngcontent-%COMP%] {\n margin-bottom: 24px;\n}\n.page-header[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n.page-header[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n\n\n.toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 20px;\n flex-wrap: wrap;\n}\n.btn-primary[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: var(--mj-radius-sm, 6px);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n white-space: nowrap;\n}\n.btn-primary[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n.filter-select[_ngcontent-%COMP%] {\n padding: 7px 32px 7px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm, 6px);\n font-size: 13px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2394a3b8'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 10px center;\n cursor: pointer;\n}\n.search-input[_ngcontent-%COMP%] {\n padding: 7px 12px 7px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm, 6px);\n font-size: 13px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n width: 220px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='%2394a3b8'%3E%3Cpath d='M10 6.5a3.5 3.5 0 11-7 0 3.5 3.5 0 017 0zm-.3 3.9a5.5 5.5 0 111.1-1.1l3.1 3.1a.75.75 0 01-1.1 1.1L9.7 10.4z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: 10px center;\n}\n.search-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n.toolbar-spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n.toolbar-stat[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n.toolbar-stat[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n\n\n.card-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 14px;\n margin-bottom: 32px;\n}\n@media (max-width: 1024px) {\n .card-grid[_ngcontent-%COMP%] { grid-template-columns: repeat(2, 1fr); }\n}\n@media (max-width: 640px) {\n .card-grid[_ngcontent-%COMP%] { grid-template-columns: 1fr; }\n}\n\n\n\n.job-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n padding: 14px 16px;\n box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n position: relative;\n cursor: pointer;\n transition: box-shadow 0.2s, border-color 0.2s;\n height: 132px;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n}\n.job-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--mj-shadow-card-hover, 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04));\n border-color: var(--mj-border-strong);\n}\n.job-card[_ngcontent-%COMP%]:hover .card-actions[_ngcontent-%COMP%] {\n opacity: 1;\n}\n.job-card.disabled-card[_ngcontent-%COMP%] {\n opacity: 0.65;\n}\n\n.card-top[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n.status-dot[_ngcontent-%COMP%] {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 4px;\n}\n.status-dot.active[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent);\n}\n.status-dot.paused[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 18%, transparent);\n}\n.status-dot.disabled[_ngcontent-%COMP%], \n.status-dot.pending[_ngcontent-%COMP%], \n.status-dot.expired[_ngcontent-%COMP%] {\n background: var(--mj-border-strong);\n}\n\n.card-title-area[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n.card-title[_ngcontent-%COMP%] {\n font-size: 13.5px;\n font-weight: 650;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n.card-cron[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 1px;\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.card-cron[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n\n\n.card-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n.card-stat[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.card-stat[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n.card-stat[_ngcontent-%COMP%] .value[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n.success-rate[_ngcontent-%COMP%] {\n font-weight: 700;\n}\n.success-rate.high[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n.success-rate.mid[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n\n\n\n.sparkline[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 3px;\n margin-top: 8px;\n}\n.spark-dot[_ngcontent-%COMP%] {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n}\n.spark-dot.ok[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 65%, transparent);\n}\n.spark-dot.fail[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-error) 65%, transparent);\n}\n.spark-dot.skip[_ngcontent-%COMP%] {\n background: var(--mj-border-default);\n}\n.sparkline-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-left: 4px;\n}\n\n\n\n.card-actions[_ngcontent-%COMP%] {\n position: absolute;\n top: 10px;\n right: 10px;\n display: flex;\n gap: 6px;\n opacity: 0;\n transition: opacity 0.15s;\n}\n.card-action-btn[_ngcontent-%COMP%] {\n padding: 4px 10px;\n font-size: 11px;\n font-weight: 600;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.12s;\n box-shadow: 0 1px 2px rgba(0,0,0,0.06);\n}\n.card-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n.card-action-btn.run-now[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-border-default));\n}\n.card-action-btn.run-now[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n}\n\n\n\n.card-status-label[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 11.5px;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.card-status-label.paused[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n}\n.card-status-label.disabled[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n.section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 14px;\n}\n.section-header[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 650;\n color: var(--mj-text-primary);\n}\n.section-header[_ngcontent-%COMP%] .badge[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n\n\n.activity-table[_ngcontent-%COMP%] {\n width: 100%;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n overflow: hidden;\n}\n.activity-table[_ngcontent-%COMP%] table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n}\n.activity-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 10px 14px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 11.5px;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 9px 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n.activity-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:last-child td[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n.activity-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.activity-table[_ngcontent-%COMP%] .job-name-cell[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.activity-table[_ngcontent-%COMP%] .time-cell[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12.5px;\n}\n.items-cell[_ngcontent-%COMP%] {\n text-align: right;\n font-weight: 600;\n}\n.items-cell.failed[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 11.5px;\n font-weight: 600;\n}\n.status-badge.success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n.status-badge.failed[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n.status-badge.running[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info);\n}\n.status-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 9px;\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 60px;\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 padding: 60px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 40px;\n margin-bottom: 12px;\n}\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin-bottom: 4px;\n}\n.empty-state[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n\n\n.scheduling-app-link[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 20px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 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 font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.link-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}"] });
|
|
587
|
+
};
|
|
588
|
+
SchedulingResourceComponent = __decorate([
|
|
589
|
+
RegisterClass(BaseResourceComponent, 'SchedulingResource')
|
|
590
|
+
], SchedulingResourceComponent);
|
|
591
|
+
export { SchedulingResourceComponent };
|
|
592
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SchedulingResourceComponent, [{
|
|
593
|
+
type: Component,
|
|
594
|
+
args: [{ standalone: false, selector: 'app-scheduling-resource', template: "@if (IsLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading scheduled pipelines...\"></mj-loading>\n </div>\n} @else {\n <!-- Toolbar -->\n <div class=\"toolbar\">\n <button class=\"btn-primary\" (click)=\"OnNewSchedule()\">\n <i class=\"fa-solid fa-plus\"></i> New Schedule\n </button>\n <select class=\"filter-select\" [(ngModel)]=\"StatusFilter\" (ngModelChange)=\"OnFilterChanged()\">\n <option value=\"\">All Statuses</option>\n <option value=\"Active\">Active</option>\n <option value=\"Paused\">Paused</option>\n <option value=\"Disabled\">Disabled</option>\n <option value=\"Pending\">Pending</option>\n </select>\n <input type=\"text\"\n class=\"search-input\"\n placeholder=\"Search pipelines...\"\n [(ngModel)]=\"SearchQuery\"\n (ngModelChange)=\"OnSearchChanged()\" />\n <div class=\"toolbar-spacer\"></div>\n <span class=\"toolbar-stat\">\n @if (ActiveCount > 0) { <strong>{{ ActiveCount }}</strong> active }\n @if (PausedCount > 0) { · <strong>{{ PausedCount }}</strong> paused }\n </span>\n </div>\n\n <!-- Job Cards Grid -->\n @if (FilteredJobs.length > 0) {\n <div class=\"cards-grid\">\n @for (job of FilteredJobs; track job.ID) {\n <div class=\"job-card\"\n [class.paused]=\"job.Status === 'Paused'\"\n [class.disabled]=\"job.Status === 'Disabled'\"\n (click)=\"OnEditJob(job)\">\n <div class=\"card-top\">\n <span class=\"status-dot\"\n [class.dot-active]=\"job.Status === 'Active'\"\n [class.dot-paused]=\"job.Status === 'Paused'\"\n [class.dot-disabled]=\"job.Status === 'Disabled'\"></span>\n <div class=\"card-title-area\">\n <div class=\"card-name\">{{ job.Name }}</div>\n <div class=\"card-cron\">\n <i class=\"fa-regular fa-clock\"></i>\n {{ GetCronDescription(job.CronExpression) }}\n </div>\n </div>\n </div>\n <div class=\"sparkline\">\n @for (dotClass of GetSparkline(job.ID); track $index) {\n <span class=\"spark-dot\" [class]=\"dotClass\"></span>\n }\n <span class=\"sparkline-label\">last 7 runs</span>\n </div>\n <div class=\"card-stats\">\n <span class=\"stat\">\n <i class=\"fa-regular fa-clock\"></i>\n Last: <strong>{{ GetTimeAgo(job.LastRunAt) }}</strong>\n </span>\n <span class=\"stat\">\n <i class=\"fa-solid fa-chart-simple\"></i>\n <strong>{{ GetSuccessRate(job) }}</strong>\n </span>\n <span class=\"stat\">\n <i class=\"fa-regular fa-calendar\"></i>\n Next: <strong>{{ GetTimeUntil(job.NextRunAt) }}</strong>\n </span>\n </div>\n </div>\n }\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-regular fa-calendar-xmark\"></i>\n <p>No Knowledge Hub schedules found</p>\n <span>Create a new schedule to automate classification and vector sync</span>\n </div>\n }\n\n <!-- Link to full Scheduling App -->\n <div class=\"scheduling-app-link\">\n <button class=\"btn-secondary\" (click)=\"GoToSchedulingApp()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open Scheduling App\n </button>\n <span class=\"link-hint\">Manage all scheduled jobs across the system</span>\n </div>\n\n <!-- Edit Dialog -->\n <mj-scheduled-job-dialog\n [Visible]=\"ShowEditDialog\"\n [ScheduledJobID]=\"EditingJobID\"\n (Close)=\"OnDialogClosed($event)\">\n </mj-scheduled-job-dialog>\n}\n", styles: ["/* \u2500\u2500 Host \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host {\n display: block;\n padding: 28px 32px 40px;\n max-width: 1200px;\n min-width: 0;\n}\n\n/* \u2500\u2500 Page Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.page-header {\n margin-bottom: 24px;\n}\n.page-header h1 {\n font-size: 22px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n.page-header p {\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n/* \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.toolbar {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 20px;\n flex-wrap: wrap;\n}\n.btn-primary {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border: none;\n border-radius: var(--mj-radius-sm, 6px);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s;\n white-space: nowrap;\n}\n.btn-primary:hover {\n background: var(--mj-brand-primary-hover);\n}\n.filter-select {\n padding: 7px 32px 7px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm, 6px);\n font-size: 13px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n appearance: none;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2394a3b8'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 10px center;\n cursor: pointer;\n}\n.search-input {\n padding: 7px 12px 7px 32px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm, 6px);\n font-size: 13px;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n width: 220px;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='%2394a3b8'%3E%3Cpath d='M10 6.5a3.5 3.5 0 11-7 0 3.5 3.5 0 017 0zm-.3 3.9a5.5 5.5 0 111.1-1.1l3.1 3.1a.75.75 0 01-1.1 1.1L9.7 10.4z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: 10px center;\n}\n.search-input::placeholder {\n color: var(--mj-text-muted);\n}\n.toolbar-spacer {\n flex: 1;\n}\n.toolbar-stat {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n.toolbar-stat strong {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n/* \u2500\u2500 Card Grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.card-grid {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 14px;\n margin-bottom: 32px;\n}\n@media (max-width: 1024px) {\n .card-grid { grid-template-columns: repeat(2, 1fr); }\n}\n@media (max-width: 640px) {\n .card-grid { grid-template-columns: 1fr; }\n}\n\n/* \u2500\u2500 Job Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.job-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n padding: 14px 16px;\n box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n position: relative;\n cursor: pointer;\n transition: box-shadow 0.2s, border-color 0.2s;\n height: 132px;\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n}\n.job-card:hover {\n box-shadow: var(--mj-shadow-card-hover, 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04));\n border-color: var(--mj-border-strong);\n}\n.job-card:hover .card-actions {\n opacity: 1;\n}\n.job-card.disabled-card {\n opacity: 0.65;\n}\n\n.card-top {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n.status-dot {\n width: 9px;\n height: 9px;\n border-radius: 50%;\n flex-shrink: 0;\n margin-top: 4px;\n}\n.status-dot.active {\n background: var(--mj-status-success);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent);\n}\n.status-dot.paused {\n background: var(--mj-status-warning);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 18%, transparent);\n}\n.status-dot.disabled,\n.status-dot.pending,\n.status-dot.expired {\n background: var(--mj-border-strong);\n}\n\n.card-title-area {\n flex: 1;\n min-width: 0;\n}\n.card-title {\n font-size: 13.5px;\n font-weight: 650;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n.card-cron {\n font-size: 12px;\n color: var(--mj-text-secondary);\n margin-top: 1px;\n display: flex;\n align-items: center;\n gap: 5px;\n}\n.card-cron i {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n/* Stats row */\n.card-stats {\n display: flex;\n align-items: center;\n gap: 16px;\n font-size: 11.5px;\n color: var(--mj-text-muted);\n}\n.card-stat {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.card-stat i {\n font-size: 10px;\n}\n.card-stat .value {\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n.success-rate {\n font-weight: 700;\n}\n.success-rate.high {\n color: var(--mj-status-success);\n}\n.success-rate.mid {\n color: var(--mj-status-warning);\n}\n\n/* Sparkline */\n.sparkline {\n display: flex;\n align-items: center;\n gap: 3px;\n margin-top: 8px;\n}\n.spark-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n}\n.spark-dot.ok {\n background: color-mix(in srgb, var(--mj-status-success) 65%, transparent);\n}\n.spark-dot.fail {\n background: color-mix(in srgb, var(--mj-status-error) 65%, transparent);\n}\n.spark-dot.skip {\n background: var(--mj-border-default);\n}\n.sparkline-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n margin-left: 4px;\n}\n\n/* Hover actions */\n.card-actions {\n position: absolute;\n top: 10px;\n right: 10px;\n display: flex;\n gap: 6px;\n opacity: 0;\n transition: opacity 0.15s;\n}\n.card-action-btn {\n padding: 4px 10px;\n font-size: 11px;\n font-weight: 600;\n border-radius: 4px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.12s;\n box-shadow: 0 1px 2px rgba(0,0,0,0.06);\n}\n.card-action-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-strong);\n}\n.card-action-btn.run-now {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-border-default));\n}\n.card-action-btn.run-now:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n}\n\n/* Paused/disabled status on card */\n.card-status-label {\n font-weight: 600;\n font-size: 11.5px;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.card-status-label.paused {\n color: var(--mj-status-warning);\n}\n.card-status-label.disabled {\n color: var(--mj-text-muted);\n}\n\n/* \u2500\u2500 Section Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.section-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 14px;\n}\n.section-header h2 {\n font-size: 15px;\n font-weight: 650;\n color: var(--mj-text-primary);\n}\n.section-header .badge {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-sunken);\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n/* \u2500\u2500 Activity Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.activity-table {\n width: 100%;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n overflow: hidden;\n}\n.activity-table table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n}\n.activity-table thead th {\n background: var(--mj-bg-surface-card);\n padding: 10px 14px;\n text-align: left;\n font-weight: 600;\n color: var(--mj-text-secondary);\n font-size: 11.5px;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-table tbody td {\n padding: 9px 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-primary);\n}\n.activity-table tbody tr:last-child td {\n border-bottom: none;\n}\n.activity-table tbody tr:hover {\n background: var(--mj-bg-surface-hover);\n}\n.activity-table .job-name-cell {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.activity-table .time-cell {\n color: var(--mj-text-secondary);\n font-size: 12.5px;\n}\n.items-cell {\n text-align: right;\n font-weight: 600;\n}\n.items-cell.failed {\n color: var(--mj-status-error);\n}\n\n/* Status badges */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 10px;\n border-radius: 10px;\n font-size: 11.5px;\n font-weight: 600;\n}\n.status-badge.success {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n.status-badge.failed {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n.status-badge.running {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info);\n}\n.status-badge i {\n font-size: 9px;\n}\n\n/* \u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.loading-container {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 60px;\n}\n\n/* \u2500\u2500 Empty state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\n.empty-state i {\n font-size: 40px;\n margin-bottom: 12px;\n}\n.empty-state p {\n font-size: 14px;\n margin-bottom: 4px;\n}\n.empty-state span {\n font-size: 12px;\n}\n\n/* Scheduling App Link */\n.scheduling-app-link {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-top: 20px;\n padding-top: 16px;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.btn-secondary {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 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 font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.btn-secondary:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.link-hint {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n"] }]
|
|
595
|
+
}], null, null); })();
|
|
596
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SchedulingResourceComponent, { className: "SchedulingResourceComponent", filePath: "src/KnowledgeHub/components/scheduling/scheduling-resource.component.ts", lineNumber: 38 }); })();
|
|
597
|
+
/** Tree-shaking prevention */
|
|
598
|
+
export function LoadSchedulingResource() {
|
|
599
|
+
// Prevents tree-shaking of the component
|
|
600
|
+
}
|
|
601
|
+
//# sourceMappingURL=scheduling-resource.component.js.map
|