@memberjunction/ng-dashboards 6.2.0-edge.3 → 6.2.0-edge.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AI/components/analytics/realtime/realtime-transcripts-data.d.ts +4 -3
- package/dist/AI/components/analytics/realtime/realtime-transcripts-data.d.ts.map +1 -1
- package/dist/AI/components/analytics/realtime/realtime-transcripts-data.js +8 -5
- package/dist/AI/components/analytics/realtime/realtime-transcripts-data.js.map +1 -1
- package/dist/AI/components/duplicates/compare-value.component.d.ts +67 -0
- package/dist/AI/components/duplicates/compare-value.component.d.ts.map +1 -0
- package/dist/AI/components/duplicates/compare-value.component.js +168 -0
- package/dist/AI/components/duplicates/compare-value.component.js.map +1 -0
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +49 -3
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +287 -169
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts +77 -0
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts.map +1 -0
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js +116 -0
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js.map +1 -0
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +1 -0
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +16 -4
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +2 -0
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +12 -6
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/sensitive-fields.d.ts +53 -0
- package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -0
- package/dist/AI/components/vectors/sensitive-fields.js +226 -0
- package/dist/AI/components/vectors/sensitive-fields.js.map +1 -0
- package/dist/AI/components/vectors/vector-document-rules.d.ts +126 -0
- package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -0
- package/dist/AI/components/vectors/vector-document-rules.js +168 -0
- package/dist/AI/components/vectors/vector-document-rules.js.map +1 -0
- package/dist/AI/components/vectors/vector-index-auto.d.ts +29 -0
- package/dist/AI/components/vectors/vector-index-auto.d.ts.map +1 -0
- package/dist/AI/components/vectors/vector-index-auto.js +59 -0
- package/dist/AI/components/vectors/vector-index-auto.js.map +1 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +58 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +493 -250
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/Actions/components/actions-overview.component.d.ts.map +1 -1
- package/dist/Actions/components/actions-overview.component.js +7 -3
- 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 +3 -2
- package/dist/Actions/components/categories-list-view.component.js.map +1 -1
- package/dist/Communication/communication-agent-context.d.ts +11 -1
- package/dist/Communication/communication-agent-context.d.ts.map +1 -1
- package/dist/Communication/communication-agent-context.js +15 -0
- package/dist/Communication/communication-agent-context.js.map +1 -1
- package/dist/Communication/communication-dashboard.component.d.ts.map +1 -1
- package/dist/Communication/communication-dashboard.component.js +5 -0
- package/dist/Communication/communication-dashboard.component.js.map +1 -1
- package/dist/Communication/communication-providers-resource.component.d.ts +27 -1
- package/dist/Communication/communication-providers-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-providers-resource.component.js +722 -78
- package/dist/Communication/communication-providers-resource.component.js.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.d.ts.map +1 -1
- package/dist/ComponentStudio/component-studio-dashboard.component.js +1 -0
- package/dist/ComponentStudio/component-studio-dashboard.component.js.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +0 -3
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +5 -14
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js +1 -0
- package/dist/ComponentStudio/components/artifact-load-dialog.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +1 -0
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.d.ts +2 -0
- package/dist/Credentials/components/credentials-list-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +12 -10
- package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-agent-context.d.ts +14 -43
- package/dist/DashboardBrowser/dashboard-browser-agent-context.d.ts.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-agent-context.js +6 -29
- package/dist/DashboardBrowser/dashboard-browser-agent-context.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts +174 -321
- package/dist/DashboardBrowser/dashboard-browser-resource.component.d.ts.map +1 -1
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js +522 -1195
- package/dist/DashboardBrowser/dashboard-browser-resource.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboard-library-filter.d.ts +116 -0
- package/dist/DashboardBrowser/dashboard-library-filter.d.ts.map +1 -0
- package/dist/DashboardBrowser/dashboard-library-filter.js +277 -0
- package/dist/DashboardBrowser/dashboard-library-filter.js.map +1 -0
- package/dist/DashboardBrowser/dashboard-share-dialog.component.d.ts +1 -1
- package/dist/DashboardBrowser/dashboard-share-dialog.component.js.map +1 -1
- package/dist/DashboardBrowser/dashboards-agent-tools.d.ts +26 -0
- package/dist/DashboardBrowser/dashboards-agent-tools.d.ts.map +1 -0
- package/dist/DashboardBrowser/dashboards-agent-tools.js +32 -0
- package/dist/DashboardBrowser/dashboards-agent-tools.js.map +1 -0
- package/dist/DashboardBrowser/dashboards-categories-resource.component.d.ts +58 -0
- package/dist/DashboardBrowser/dashboards-categories-resource.component.d.ts.map +1 -0
- package/dist/DashboardBrowser/dashboards-categories-resource.component.js +391 -0
- package/dist/DashboardBrowser/dashboards-categories-resource.component.js.map +1 -0
- package/dist/DashboardBrowser/dashboards-categories.helpers.d.ts +37 -0
- package/dist/DashboardBrowser/dashboards-categories.helpers.d.ts.map +1 -0
- package/dist/DashboardBrowser/dashboards-categories.helpers.js +68 -0
- package/dist/DashboardBrowser/dashboards-categories.helpers.js.map +1 -0
- package/dist/DashboardEditor/dashboard-editor.component.d.ts +295 -0
- package/dist/DashboardEditor/dashboard-editor.component.d.ts.map +1 -0
- package/dist/DashboardEditor/dashboard-editor.component.js +1022 -0
- package/dist/DashboardEditor/dashboard-editor.component.js.map +1 -0
- package/dist/DashboardEditor/dashboard-editor.types.d.ts +23 -0
- package/dist/DashboardEditor/dashboard-editor.types.d.ts.map +1 -0
- package/dist/DashboardEditor/dashboard-editor.types.js +3 -0
- package/dist/DashboardEditor/dashboard-editor.types.js.map +1 -0
- package/dist/DashboardEditor/dashboard-viewer-factory.d.ts +11 -0
- package/dist/DashboardEditor/dashboard-viewer-factory.d.ts.map +1 -0
- package/dist/DashboardEditor/dashboard-viewer-factory.js +17 -0
- package/dist/DashboardEditor/dashboard-viewer-factory.js.map +1 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +51 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +375 -223
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/services/explorer-state.service.d.ts +1 -1
- package/dist/DataExplorer/services/explorer-state.service.js +2 -5
- package/dist/DataExplorer/services/explorer-state.service.js.map +1 -1
- package/dist/DevTools/app-state-inspector.component.d.ts.map +1 -1
- package/dist/DevTools/app-state-inspector.component.js +1 -0
- package/dist/DevTools/app-state-inspector.component.js.map +1 -1
- package/dist/DevTools/class-registry.component.d.ts.map +1 -1
- package/dist/DevTools/class-registry.component.js +1 -0
- package/dist/DevTools/class-registry.component.js.map +1 -1
- package/dist/DevTools/event-monitor.component.d.ts.map +1 -1
- package/dist/DevTools/event-monitor.component.js +2 -0
- package/dist/DevTools/event-monitor.component.js.map +1 -1
- package/dist/DevTools/graphql-console.component.d.ts.map +1 -1
- package/dist/DevTools/graphql-console.component.js.map +1 -1
- package/dist/DevTools/grid-width-lab.component.d.ts.map +1 -1
- package/dist/DevTools/grid-width-lab.component.js +1 -0
- package/dist/DevTools/grid-width-lab.component.js.map +1 -1
- package/dist/DevTools/layout-inspector.component.d.ts.map +1 -1
- package/dist/DevTools/layout-inspector.component.js +1 -0
- package/dist/DevTools/layout-inspector.component.js.map +1 -1
- package/dist/DevTools/lazy-module-status.component.d.ts.map +1 -1
- package/dist/DevTools/lazy-module-status.component.js +1 -0
- package/dist/DevTools/lazy-module-status.component.js.map +1 -1
- package/dist/DevTools/settings-explorer.component.d.ts.map +1 -1
- package/dist/DevTools/settings-explorer.component.js +1 -0
- package/dist/DevTools/settings-explorer.component.js.map +1 -1
- package/dist/DevTools/tab-strip-lab.component.d.ts.map +1 -1
- package/dist/DevTools/tab-strip-lab.component.js +1 -0
- package/dist/DevTools/tab-strip-lab.component.js.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts +5 -0
- package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts.map +1 -1
- package/dist/EntityAdmin/entity-admin-dashboard.component.js +8 -5
- package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts +0 -14
- package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.js +7 -29
- package/dist/FormBuilder/form-builder-resource.component.js.map +1 -1
- package/dist/Home/home-agent-context.d.ts +29 -10
- package/dist/Home/home-agent-context.d.ts.map +1 -1
- package/dist/Home/home-agent-context.js +50 -24
- package/dist/Home/home-agent-context.js.map +1 -1
- package/dist/Home/home-dashboard-switcher.component.d.ts +95 -0
- package/dist/Home/home-dashboard-switcher.component.d.ts.map +1 -0
- package/dist/Home/home-dashboard-switcher.component.js +442 -0
- package/dist/Home/home-dashboard-switcher.component.js.map +1 -0
- package/dist/Home/home-dashboard.component.d.ts +330 -17
- package/dist/Home/home-dashboard.component.d.ts.map +1 -1
- package/dist/Home/home-dashboard.component.js +1702 -1014
- package/dist/Home/home-dashboard.component.js.map +1 -1
- package/dist/Home/home-menus.d.ts +38 -0
- package/dist/Home/home-menus.d.ts.map +1 -0
- package/dist/Home/home-menus.js +53 -0
- package/dist/Home/home-menus.js.map +1 -0
- package/dist/Home/home-pinned-dashboards.d.ts +33 -0
- package/dist/Home/home-pinned-dashboards.d.ts.map +1 -0
- package/dist/Home/home-pinned-dashboards.js +76 -0
- package/dist/Home/home-pinned-dashboards.js.map +1 -0
- package/dist/Integration/components/overview/overview.component.js +2 -2
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +2 -2
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts +11 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js +24 -2
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts +16 -2
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +87 -33
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
- package/dist/LoginStudio/login-studio-inspector.component.d.ts +130 -0
- package/dist/LoginStudio/login-studio-inspector.component.d.ts.map +1 -0
- package/dist/LoginStudio/login-studio-inspector.component.js +781 -0
- package/dist/LoginStudio/login-studio-inspector.component.js.map +1 -0
- package/dist/LoginStudio/login-studio-resource.component.d.ts +153 -0
- package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -0
- package/dist/LoginStudio/login-studio-resource.component.js +857 -0
- package/dist/LoginStudio/login-studio-resource.component.js.map +1 -0
- package/dist/PredictiveStudio/components/ps-production.component.d.ts +5 -1
- package/dist/PredictiveStudio/components/ps-production.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-production.component.js +64 -41
- package/dist/PredictiveStudio/components/ps-production.component.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +3 -2
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/RealtimeRecordings/realtime-recordings-dashboard.component.js +2 -2
- package/dist/RealtimeRecordings/realtime-recordings-dashboard.component.js.map +1 -1
- package/dist/TelephonyOperations/telephony-operations-dashboard.component.d.ts +1 -0
- package/dist/TelephonyOperations/telephony-operations-dashboard.component.d.ts.map +1 -1
- package/dist/TelephonyOperations/telephony-operations-dashboard.component.js +7 -0
- package/dist/TelephonyOperations/telephony-operations-dashboard.component.js.map +1 -1
- package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
- package/dist/Testing/components/testing-explorer.component.js +7 -7
- package/dist/Testing/components/testing-explorer.component.js.map +1 -1
- package/dist/Workflows/components/workflow-runs-resource.component.js +4 -4
- package/dist/Workflows/components/workflow-runs-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +21 -20
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +4 -1
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +70 -62
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +33 -5
- package/dist/core-dashboards.module.js.map +1 -1
- package/dist/data-explorer-dashboards.module.d.ts +1 -1
- package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
- package/dist/data-explorer-dashboards.module.js +3 -1
- package/dist/data-explorer-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +4 -0
- package/dist/public-api.js.map +1 -1
- package/dist/shared/dashboard-library-changes.d.ts +23 -0
- package/dist/shared/dashboard-library-changes.d.ts.map +1 -0
- package/dist/shared/dashboard-library-changes.js +26 -0
- package/dist/shared/dashboard-library-changes.js.map +1 -0
- package/dist/shared/dashboard-owner-names.d.ts +17 -0
- package/dist/shared/dashboard-owner-names.d.ts.map +1 -0
- package/dist/shared/dashboard-owner-names.js +65 -0
- package/dist/shared/dashboard-owner-names.js.map +1 -0
- package/dist/shared/dashboard-recents.d.ts +34 -0
- package/dist/shared/dashboard-recents.d.ts.map +1 -0
- package/dist/shared/dashboard-recents.js +87 -0
- package/dist/shared/dashboard-recents.js.map +1 -0
- package/dist/shared/dashboards-app-install.d.ts +59 -0
- package/dist/shared/dashboards-app-install.d.ts.map +1 -0
- package/dist/shared/dashboards-app-install.js +97 -0
- package/dist/shared/dashboards-app-install.js.map +1 -0
- package/dist/shared/dashboards-app.helpers.d.ts +42 -0
- package/dist/shared/dashboards-app.helpers.d.ts.map +1 -0
- package/dist/shared/dashboards-app.helpers.js +143 -0
- package/dist/shared/dashboards-app.helpers.js.map +1 -0
- package/package.json +73 -69
|
@@ -748,7 +748,7 @@ function WorkflowRunsResourceComponent_Conditional_16_Conditional_22_Conditional
|
|
|
748
748
|
i0.ɵɵadvance();
|
|
749
749
|
i0.ɵɵproperty("size", ctx_r0.Layout.StepPanelOpen ? ctx_r0.Layout.StepSplitSizes[0] : 100)("minSize", 25);
|
|
750
750
|
i0.ɵɵadvance(2);
|
|
751
|
-
i0.ɵɵproperty("Provider", ctx_r0.ProviderToUse)("ParentTaskID", selected_r9.ID)("WorkflowName", selected_r9.Name)("LiveUpdates", selected_r9.Status === "Running" || selected_r9.Status === "In Progress")("ReplayAt", ctx_r0.ReplayAt)("ShowLegend", ctx_r0.Layout.ShowLegend);
|
|
751
|
+
i0.ɵɵproperty("Provider", ctx_r0.ProviderToUse)("ParentTaskID", selected_r9.ID)("WorkflowName", selected_r9.Name)("LiveUpdates", selected_r9.Status === "Running" || selected_r9.Status === "In Progress")("ReplayAt", ctx_r0.ReplayAt)("ShowLegend", ctx_r0.Layout.ShowLegend)("ShowVariables", false);
|
|
752
752
|
i0.ɵɵadvance(2);
|
|
753
753
|
i0.ɵɵconditional(ctx_r0.CanReplay ? 5 : -1);
|
|
754
754
|
i0.ɵɵadvance();
|
|
@@ -795,7 +795,7 @@ function WorkflowRunsResourceComponent_Conditional_16_Conditional_22_Template(rf
|
|
|
795
795
|
i0.ɵɵtext(18, " JSON ");
|
|
796
796
|
i0.ɵɵelementEnd()();
|
|
797
797
|
i0.ɵɵconditionalCreate(19, WorkflowRunsResourceComponent_Conditional_16_Conditional_22_Conditional_19_Template, 9, 5, "div", 46);
|
|
798
|
-
i0.ɵɵconditionalCreate(20, WorkflowRunsResourceComponent_Conditional_16_Conditional_22_Conditional_20_Template, 12,
|
|
798
|
+
i0.ɵɵconditionalCreate(20, WorkflowRunsResourceComponent_Conditional_16_Conditional_22_Conditional_20_Template, 12, 18, "as-split", 47)(21, WorkflowRunsResourceComponent_Conditional_16_Conditional_22_Conditional_21_Template, 2, 3, "div", 48);
|
|
799
799
|
i0.ɵɵelementEnd();
|
|
800
800
|
} if (rf & 2) {
|
|
801
801
|
const selected_r9 = ctx;
|
|
@@ -1796,7 +1796,7 @@ let WorkflowRunsResourceComponent = class WorkflowRunsResourceComponent extends
|
|
|
1796
1796
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.GraphDebug = _t.first);
|
|
1797
1797
|
} }, hostBindings: function WorkflowRunsResourceComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
1798
1798
|
i0.ɵɵlistener("resize", function WorkflowRunsResourceComponent_resize_HostBindingHandler() { return ctx.onViewportResized(); }, i0.ɵɵresolveWindow);
|
|
1799
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 4, consts: [["GraphDebug", ""], ["Title", "Runs", "Icon", "fa-solid fa-timeline", "Subtitle", "Every workflow that has run \u2014 however it was started."], ["meta", ""], ["Label", "runs", 3, "Count", "Total"], ["actions", ""], [3, "Clicked", "Loading"], ["toolbar", ""], ["Placeholder", "Search runs", 3, "ValueChange", "Value"], [1, "wfr-status-filters"], ["type", "button", "mjButton", "", "size", "sm", 3, "variant"], ["text", "Loading runs..."], ["Variant", "error", 3, "Message"], ["Icon", "fa-solid fa-timeline", "Title", "Nothing has run yet", "Message", "When a workflow runs \u2014 started by hand, on a schedule, or by an agent \u2014 it will appear here."], ["Icon", "fa-solid fa-filter", "Title", "No runs match", "Message", "Nothing matches the current filter. Clear it to see everything that has run."], ["direction", "horizontal", "unit", "percent", 1, "wfr-split", 3, "gutterSize", "disabled"], ["type", "button", "mjButton", "", "size", "sm", 3, "click", "variant"], ["direction", "horizontal", "unit", "percent", 1, "wfr-split", 3, "dragEnd", "gutterSize", "disabled"], [3, "size", "minSize"], [1, "wfr-list"], ["role", "row", 1, "wfr-head"], ["type", "button", 1, "wfr-head-cell", "wfr-col-name", 3, "click"], ["aria-hidden", "true", 3, "ngClass"], ["type", "button", 1, "wfr-head-cell", "wfr-col-time", 3, "click"], ["type", "button", 1, "wfr-head-cell", "wfr-col-duration", 3, "click"], ["type", "button", 1, "wfr-head-cell", "wfr-col-status", 3, "click"], ["type", "button", 1, "wfr-row", 3, "wfr-row-selected"], [3, "size", "minSize", "visible"], [1, "wfr-detail"], ["type", "button", 1, "wfr-row", 3, "click"], [1, "wfr-col-name", "wfr-row-name"], [1, "wfr-col-time"], [1, "wfr-col-duration"], [1, "wfr-col-status", "wfr-row-status"], [1, "wfr-detail-head"], [1, "wfr-detail-title"], [1, "wfr-detail-name"], [1, "wfr-row-status"], [1, "wfr-detail-actions"], ["mjButton", "", "variant", "flat", "size", "sm"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "title"], ["mjButton", "", "variant", "flat", "size", "sm", "aria-label", "Close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], ["role", "tablist", 1, "wfr-detail-tabs"], ["type", "button", 1, "wfr-tab", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-diagram-project"], ["aria-hidden", "true", 1, "fa-solid", "fa-code"], ["role", "status", 1, "wfr-stall"], ["unit", "percent", 1, "wfr-graph-split", 3, "direction", "gutterSize"], [1, "wfr-json-pane"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-up-right-from-square"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid"], [1, "wfr-stall-body"], ["aria-hidden", "true", 1, "fa-solid", "fa-triangle-exclamation"], [1, "wfr-stall-copy"], [1, "wfr-stall-reason"], [1, "wfr-stall-actions"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], ["unit", "percent", 1, "wfr-graph-split", 3, "dragEnd", "direction", "gutterSize"], [1, "wfr-graph-pane"], ["Height", "100%", 3, "NodeSelected", "ConnectionSelected", "LegendToggled", "Settled", "Frame", "PausedChange", "Provider", "ParentTaskID", "WorkflowName", "LiveUpdates", "ReplayAt", "ShowLegend"], [1, "wfr-replay"], ["aria-label", "Armed breakpoints", 1, "wfr-bp-bar"], ["aria-label", "Engine activity", 1, "wfr-engine"], [1, "wfr-steps-pane"], ["text", "Loading steps..."], ["aria-hidden", "true", 1, "fa-solid", "fa-clock-rotate-left"], ["type", "range", "min", "0", "max", "100", "step", "1", "aria-label", "Replay position", 3, "input", "value"], [1, "wfr-chip", "wfr-chip-paused"], ["type", "button", 1, "wfr-chip", "wfr-chip-break"], ["aria-hidden", "true", 1, "fa-solid", "fa-pause"], ["type", "button", 1, "wfr-chip", "wfr-chip-break", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-circle"], ["role", "button", "tabindex", "0", "aria-label", "Remove breakpoint", 1, "wfr-chip-x", 3, "click"], [1, "wfr-tick", 3, "wfr-tick-held"], [1, "wfr-tick", "wfr-tick-paused"], [1, "wfr-tick"], [1, "wfr-step-list"], ["type", "button", 1, "wfr-step", 3, "wfr-step-selected"], [1, "wfr-step-json"], ["Size", "compact", "Icon", "fa-solid fa-hand-pointer", "Title", "Select a step", "Message", "Click a step on the canvas or in the list to see everything it recorded."], ["type", "button", 1, "wfr-step", 3, "click"], [1, "wfr-step-name"], [1, "wfr-step-meta"], [1, "wfr-step-json-head"], [1, "wfr-chip", "wfr-chip-forced"], [1, "wfr-insp-card"], [1, "wfr-insp-label"], [1, "wfr-insp-actions"], [1, "wfr-insp-hint"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "disabled"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "disabled"], ["role", "status", 1, "wfr-insp-card", "wfr-insp-failure"], ["type", "button", 1, "wfr-bp", 3, "click", "disabled", "title"], ["aria-hidden", "true", 1, "fa-circle"], [1, "wfr-insp-card", 3, "wfr-insp-bad"], [1, "wfr-editor-card"], [1, "wfr-editor-card", "wfr-editor-danger"], [3, "InputPayload", "OutputPayload", "Invocation"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Declare this step not-taken; later steps proceed", 3, "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "disabled"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Declare this step not-taken; later steps proceed", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-forward"], ["aria-hidden", "true", 1, "fa-solid", "fa-pen-to-square"], ["aria-hidden", "true", 1, "fa-solid", "fa-rotate-right"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-flag-checkered"], ["rows", "8", "spellcheck", "false", 1, "mj-textarea", "wfr-json-edit", 3, "ngModelChange", "ngModel"], [1, "wfr-editor-error"], ["rows", "6", "spellcheck", "false", 1, "mj-textarea", "wfr-json-edit", 3, "ngModelChange", "ngModel"], ["type", "text", 1, "mj-input", 3, "ngModelChange", "ngModel", "placeholder"], [2, "width", "100%", 3, "ngModel", "language", "readonly"]], template: function WorkflowRunsResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1799
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 4, consts: [["GraphDebug", ""], ["Title", "Runs", "Icon", "fa-solid fa-timeline", "Subtitle", "Every workflow that has run \u2014 however it was started."], ["meta", ""], ["Label", "runs", 3, "Count", "Total"], ["actions", ""], [3, "Clicked", "Loading"], ["toolbar", ""], ["Placeholder", "Search runs", 3, "ValueChange", "Value"], [1, "wfr-status-filters"], ["type", "button", "mjButton", "", "size", "sm", 3, "variant"], ["text", "Loading runs..."], ["Variant", "error", 3, "Message"], ["Icon", "fa-solid fa-timeline", "Title", "Nothing has run yet", "Message", "When a workflow runs \u2014 started by hand, on a schedule, or by an agent \u2014 it will appear here."], ["Icon", "fa-solid fa-filter", "Title", "No runs match", "Message", "Nothing matches the current filter. Clear it to see everything that has run."], ["direction", "horizontal", "unit", "percent", 1, "wfr-split", 3, "gutterSize", "disabled"], ["type", "button", "mjButton", "", "size", "sm", 3, "click", "variant"], ["direction", "horizontal", "unit", "percent", 1, "wfr-split", 3, "dragEnd", "gutterSize", "disabled"], [3, "size", "minSize"], [1, "wfr-list"], ["role", "row", 1, "wfr-head"], ["type", "button", 1, "wfr-head-cell", "wfr-col-name", 3, "click"], ["aria-hidden", "true", 3, "ngClass"], ["type", "button", 1, "wfr-head-cell", "wfr-col-time", 3, "click"], ["type", "button", 1, "wfr-head-cell", "wfr-col-duration", 3, "click"], ["type", "button", 1, "wfr-head-cell", "wfr-col-status", 3, "click"], ["type", "button", 1, "wfr-row", 3, "wfr-row-selected"], [3, "size", "minSize", "visible"], [1, "wfr-detail"], ["type", "button", 1, "wfr-row", 3, "click"], [1, "wfr-col-name", "wfr-row-name"], [1, "wfr-col-time"], [1, "wfr-col-duration"], [1, "wfr-col-status", "wfr-row-status"], [1, "wfr-detail-head"], [1, "wfr-detail-title"], [1, "wfr-detail-name"], [1, "wfr-row-status"], [1, "wfr-detail-actions"], ["mjButton", "", "variant", "flat", "size", "sm"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "title"], ["mjButton", "", "variant", "flat", "size", "sm", "aria-label", "Close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], ["role", "tablist", 1, "wfr-detail-tabs"], ["type", "button", 1, "wfr-tab", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-diagram-project"], ["aria-hidden", "true", 1, "fa-solid", "fa-code"], ["role", "status", 1, "wfr-stall"], ["unit", "percent", 1, "wfr-graph-split", 3, "direction", "gutterSize"], [1, "wfr-json-pane"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-up-right-from-square"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "title"], ["aria-hidden", "true", 1, "fa-solid"], [1, "wfr-stall-body"], ["aria-hidden", "true", 1, "fa-solid", "fa-triangle-exclamation"], [1, "wfr-stall-copy"], [1, "wfr-stall-reason"], [1, "wfr-stall-actions"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], ["unit", "percent", 1, "wfr-graph-split", 3, "dragEnd", "direction", "gutterSize"], [1, "wfr-graph-pane"], ["Height", "100%", 3, "NodeSelected", "ConnectionSelected", "LegendToggled", "Settled", "Frame", "PausedChange", "Provider", "ParentTaskID", "WorkflowName", "LiveUpdates", "ReplayAt", "ShowLegend", "ShowVariables"], [1, "wfr-replay"], ["aria-label", "Armed breakpoints", 1, "wfr-bp-bar"], ["aria-label", "Engine activity", 1, "wfr-engine"], [1, "wfr-steps-pane"], ["text", "Loading steps..."], ["aria-hidden", "true", 1, "fa-solid", "fa-clock-rotate-left"], ["type", "range", "min", "0", "max", "100", "step", "1", "aria-label", "Replay position", 3, "input", "value"], [1, "wfr-chip", "wfr-chip-paused"], ["type", "button", 1, "wfr-chip", "wfr-chip-break"], ["aria-hidden", "true", 1, "fa-solid", "fa-pause"], ["type", "button", 1, "wfr-chip", "wfr-chip-break", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-circle"], ["role", "button", "tabindex", "0", "aria-label", "Remove breakpoint", 1, "wfr-chip-x", 3, "click"], [1, "wfr-tick", 3, "wfr-tick-held"], [1, "wfr-tick", "wfr-tick-paused"], [1, "wfr-tick"], [1, "wfr-step-list"], ["type", "button", 1, "wfr-step", 3, "wfr-step-selected"], [1, "wfr-step-json"], ["Size", "compact", "Icon", "fa-solid fa-hand-pointer", "Title", "Select a step", "Message", "Click a step on the canvas or in the list to see everything it recorded."], ["type", "button", 1, "wfr-step", 3, "click"], [1, "wfr-step-name"], [1, "wfr-step-meta"], [1, "wfr-step-json-head"], [1, "wfr-chip", "wfr-chip-forced"], [1, "wfr-insp-card"], [1, "wfr-insp-label"], [1, "wfr-insp-actions"], [1, "wfr-insp-hint"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "disabled"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click", "disabled"], ["role", "status", 1, "wfr-insp-card", "wfr-insp-failure"], ["type", "button", 1, "wfr-bp", 3, "click", "disabled", "title"], ["aria-hidden", "true", 1, "fa-circle"], [1, "wfr-insp-card", 3, "wfr-insp-bad"], [1, "wfr-editor-card"], [1, "wfr-editor-card", "wfr-editor-danger"], [3, "InputPayload", "OutputPayload", "Invocation"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Declare this step not-taken; later steps proceed", 3, "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "disabled"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "disabled"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Declare this step not-taken; later steps proceed", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-forward"], ["aria-hidden", "true", 1, "fa-solid", "fa-pen-to-square"], ["aria-hidden", "true", 1, "fa-solid", "fa-rotate-right"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-flag-checkered"], ["rows", "8", "spellcheck", "false", 1, "mj-textarea", "wfr-json-edit", 3, "ngModelChange", "ngModel"], [1, "wfr-editor-error"], ["rows", "6", "spellcheck", "false", 1, "mj-textarea", "wfr-json-edit", 3, "ngModelChange", "ngModel"], ["type", "text", 1, "mj-input", 3, "ngModelChange", "ngModel", "placeholder"], [2, "width", "100%", 3, "ngModel", "language", "readonly"]], template: function WorkflowRunsResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1800
1800
|
i0.ɵɵelementStart(0, "mj-page-layout")(1, "mj-page-header", 1)(2, "div", 2);
|
|
1801
1801
|
i0.ɵɵconditionalCreate(3, WorkflowRunsResourceComponent_Conditional_3_Template, 1, 2, "mj-stat-badge", 3);
|
|
1802
1802
|
i0.ɵɵelementEnd();
|
|
@@ -1831,7 +1831,7 @@ WorkflowRunsResourceComponent = WorkflowRunsResourceComponent_1 = __decorate([
|
|
|
1831
1831
|
export { WorkflowRunsResourceComponent };
|
|
1832
1832
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(WorkflowRunsResourceComponent, [{
|
|
1833
1833
|
type: Component,
|
|
1834
|
-
args: [{ standalone: false, selector: 'mj-workflow-runs', changeDetection: ChangeDetectionStrategy.OnPush, template: "<mj-page-layout>\n <mj-page-header\n Title=\"Runs\"\n Icon=\"fa-solid fa-timeline\"\n Subtitle=\"Every workflow that has run \u2014 however it was started.\">\n\n <div meta>\n @if (!IsLoading && Runs.length > 0) {\n <mj-stat-badge\n [Count]=\"VisibleRuns.length\"\n [Total]=\"Runs.length\"\n Label=\"runs\"></mj-stat-badge>\n }\n </div>\n\n <div actions>\n <mj-refresh-button [Loading]=\"IsLoading\" (Clicked)=\"loadData()\"></mj-refresh-button>\n </div>\n\n <div toolbar>\n <mj-page-search\n [Value]=\"SearchText\"\n Placeholder=\"Search runs\"\n (ValueChange)=\"OnSearch($event)\"></mj-page-search>\n\n <div class=\"wfr-status-filters\">\n @for (status of StatusFilters; track status) {\n <button\n type=\"button\"\n mjButton\n [variant]=\"StatusFilter === status ? 'primary' : 'flat'\"\n size=\"sm\"\n (click)=\"OnFilterByStatus(status)\">\n {{ status === 'all' ? 'All' : status }}\n </button>\n }\n </div>\n </div>\n </mj-page-header>\n\n <mj-page-body>\n @if (IsLoading) {\n <mj-loading text=\"Loading runs...\"></mj-loading>\n } @else if (LoadError) {\n <mj-alert Variant=\"error\" [Message]=\"LoadError\"></mj-alert>\n } @else if (Runs.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-timeline\"\n Title=\"Nothing has run yet\"\n Message=\"When a workflow runs \u2014 started by hand, on a schedule, or by an agent \u2014 it will appear here.\">\n </mj-empty-state>\n } @else if (VisibleRuns.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-filter\"\n Title=\"No runs match\"\n Message=\"Nothing matches the current filter. Clear it to see everything that has run.\">\n </mj-empty-state>\n } @else {\n <as-split class=\"wfr-split\" direction=\"horizontal\" unit=\"percent\"\n [gutterSize]=\"8\" [disabled]=\"!SelectedRun\" (dragEnd)=\"OnSplitDragEnd($event.sizes)\">\n <as-split-area [size]=\"SelectedRun ? Layout.SplitSizes[0] : 100\" [minSize]=\"20\">\n <div class=\"wfr-list\">\n <!-- A header row that sorts. Every column a person scans by is sortable, because \"the\n longest run\" and \"the one that failed this morning\" are the two questions this list\n exists to answer and neither is answerable by scrolling. -->\n <div class=\"wfr-head\" role=\"row\">\n <button type=\"button\" class=\"wfr-head-cell wfr-col-name\" (click)=\"OnSort('Name')\">\n Workflow <i [ngClass]=\"SortIcon('Name')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-time\" (click)=\"OnSort('StartedAt')\">\n Started <i [ngClass]=\"SortIcon('StartedAt')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-time\" (click)=\"OnSort('CompletedAt')\">\n Ended <i [ngClass]=\"SortIcon('CompletedAt')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-duration\" (click)=\"OnSort('Duration')\">\n Duration <i [ngClass]=\"SortIcon('Duration')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-status\" (click)=\"OnSort('Status')\">\n Status <i [ngClass]=\"SortIcon('Status')\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n @for (run of VisibleRuns; track run.ID) {\n <button\n type=\"button\"\n class=\"wfr-row\"\n [class.wfr-row-selected]=\"run.ID === SelectedRunID\"\n (click)=\"OnSelectRun(run)\">\n <span class=\"wfr-col-name wfr-row-name\">{{ run.Name }}</span>\n <!-- An em dash, never a fabricated time: a run that has not started has no start, and\n printing one would read as data. -->\n <span class=\"wfr-col-time\">{{ run.StartedAt ? (run.StartedAt | date:'MMM d, h:mm:ss a') : '\u2014' }}</span>\n <span class=\"wfr-col-time\">{{ run.CompletedAt ? (run.CompletedAt | date:'MMM d, h:mm:ss a') : '\u2014' }}</span>\n <span class=\"wfr-col-duration\">{{ run.Duration }}</span>\n <span class=\"wfr-col-status wfr-row-status\" [attr.data-status]=\"run.Status\">{{ run.Status }}</span>\n </button>\n }\n </div>\n </as-split-area>\n\n <as-split-area [size]=\"SelectedRun ? Layout.SplitSizes[1] : 0\" [minSize]=\"25\" [visible]=\"!!SelectedRun\">\n @if (SelectedRun; as selected) {\n <!-- The canvas lives in the RIGHT PANEL on selection, not nested inside the list row.\n A graph needs room to be read; inlining one per row turns a scannable list into a\n stack of diagrams. -->\n <aside class=\"wfr-detail\">\n <header class=\"wfr-detail-head\">\n <div class=\"wfr-detail-title\">\n <span class=\"wfr-detail-name\">{{ selected.Name }}</span>\n <span class=\"wfr-row-status\" [attr.data-status]=\"selected.Status\">{{ selected.Status }}</span>\n </div>\n <div class=\"wfr-detail-actions\">\n @if (selected.AgentRunID) {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnOpenAgentRun(selected)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n Agent run\n </button>\n }\n @if (DetailTab === 'graph') {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"ToggleStepPanel()\"\n [title]=\"Layout.StepPanelOpen ? 'Hide step details' : 'Show step details'\">\n <i class=\"fa-solid\" [class.fa-square-caret-right]=\"Layout.StepPanelOpen\"\n [class.fa-square-caret-left]=\"!Layout.StepPanelOpen\" aria-hidden=\"true\"></i>\n </button>\n }\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnSelectRun(selected)\" aria-label=\"Close\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </header>\n\n <div class=\"wfr-detail-tabs\" role=\"tablist\">\n <button type=\"button\" class=\"wfr-tab\" [class.wfr-tab-active]=\"DetailTab === 'graph'\"\n (click)=\"OnDetailTab('graph')\">\n <i class=\"fa-solid fa-diagram-project\" aria-hidden=\"true\"></i> Workflow\n </button>\n <button type=\"button\" class=\"wfr-tab\" [class.wfr-tab-active]=\"DetailTab === 'json'\"\n (click)=\"OnDetailTab('json')\">\n <i class=\"fa-solid fa-code\" aria-hidden=\"true\"></i> JSON\n </button>\n </div>\n\n @if (Stall) {\n <!-- The hardening review's signature failure \u2014 \"the run strands silently\" \u2014 made\n loud. A held path is now something the operator can answer, not just read. -->\n <div class=\"wfr-stall\" role=\"status\" [attr.data-kind]=\"Stall.kind\">\n <div class=\"wfr-stall-body\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <div class=\"wfr-stall-copy\">\n <span>{{ Stall.message }}</span>\n @if (Stall.conditionText) {\n <code>{{ Stall.conditionText }}</code>\n }\n @if (Stall.reason) {\n <span class=\"wfr-stall-reason\">{{ Stall.reason }}</span>\n }\n </div>\n </div>\n @if (Stall.kind === 'held' && Stall.edgeID) {\n <div class=\"wfr-stall-actions\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(Stall.edgeID!, 'true')\">\n Answer true\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(Stall.edgeID!, 'false')\">\n Answer false\n </button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnDismissStall()\">\n Leave held\n </button>\n </div>\n }\n </div>\n }\n\n @if (DetailTab === 'graph') {\n <!-- Canvas BESIDE the step it opened, not above it. A JSON record in a strip along the\n bottom shows about ten lines, which is not enough of a record to read. -->\n <as-split class=\"wfr-graph-split\" [direction]=\"InnerSplitDirection\" unit=\"percent\"\n [gutterSize]=\"8\" (dragEnd)=\"OnStepSplitDragEnd($event.sizes)\">\n <as-split-area [size]=\"Layout.StepPanelOpen ? Layout.StepSplitSizes[0] : 100\" [minSize]=\"25\">\n <div class=\"wfr-graph-pane\">\n <mj-task-graph-debugger\n #GraphDebug\n [Provider]=\"ProviderToUse\"\n [ParentTaskID]=\"selected.ID\"\n [WorkflowName]=\"selected.Name\"\n [LiveUpdates]=\"selected.Status === 'Running' || selected.Status === 'In Progress'\"\n [ReplayAt]=\"ReplayAt\"\n [ShowLegend]=\"Layout.ShowLegend\"\n Height=\"100%\"\n (NodeSelected)=\"OnGraphNodeSelected($event)\"\n (ConnectionSelected)=\"OnGraphConnectionSelected($event)\"\n (LegendToggled)=\"OnLegendToggled($event)\"\n (Settled)=\"OnCanvasSettled()\"\n (Frame)=\"OnFrame($event)\"\n (PausedChange)=\"DebugPaused = $event\">\n </mj-task-graph-debugger>\n\n @if (CanReplay) {\n <!-- Replay: scrub through the settled run on the same canvas, reconstructed\n from each step's own timestamps. Read-only by construction. -->\n <div class=\"wfr-replay\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n <input type=\"range\" min=\"0\" max=\"100\" step=\"1\"\n [value]=\"ReplayPercent ?? 100\"\n (input)=\"OnReplayScrub($any($event.target).value)\"\n aria-label=\"Replay position\" />\n @if (ReplayPercent !== null) {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnReplayReset()\">Now</button>\n }\n </div>\n }\n\n @if (GraphDebug.Breakpoints.length > 0 || GraphDebug.PausedAtTaskID) {\n <div class=\"wfr-bp-bar\" aria-label=\"Armed breakpoints\">\n @if (GraphDebug.PausedAtTaskID) {\n <span class=\"wfr-chip wfr-chip-paused\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n Paused at {{ StepName(GraphDebug.PausedAtTaskID) }}\n </span>\n }\n @for (id of GraphDebug.Breakpoints; track id) {\n <button type=\"button\" class=\"wfr-chip wfr-chip-break\" (click)=\"OnSelectBreakpoint(id)\">\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n {{ StepName(id) }}\n <span class=\"wfr-chip-x\" (click)=\"OnRemoveBreakpoint(id); $event.stopPropagation()\"\n role=\"button\" tabindex=\"0\" aria-label=\"Remove breakpoint\">\u00D7</span>\n </button>\n }\n </div>\n }\n\n @if (EngineTicks.length > 0) {\n <!-- The engine strip: one tick per dispatcher pass. A stuck run is a strip\n that keeps ticking with nothing moving \u2014 the honest visual of a stall. -->\n <div class=\"wfr-engine\" aria-label=\"Engine activity\">\n @for (tick of EngineTicks; track tick.passNumber) {\n <span class=\"wfr-tick\" [class.wfr-tick-held]=\"(tick.heldCount ?? 0) > 0\">\n #{{ tick.passNumber }} \u00B7 ready {{ tick.eligibleCount ?? 0 }}\n \u00B7 held {{ tick.heldCount ?? 0 }} \u00B7 took {{ tick.claimedCount ?? 0 }}\n </span>\n }\n @if (GraphDebug.Paused) {\n <span class=\"wfr-tick wfr-tick-paused\">\u23F8 paused \u2014 nothing new starts</span>\n }\n </div>\n }\n </div>\n </as-split-area>\n\n <as-split-area [size]=\"Layout.StepPanelOpen ? Layout.StepSplitSizes[1] : 0\" [minSize]=\"20\"\n [visible]=\"Layout.StepPanelOpen\">\n <div class=\"wfr-steps-pane\">\n @if (StepsLoading) {\n <mj-loading text=\"Loading steps...\"></mj-loading>\n } @else {\n <div class=\"wfr-step-list\">\n @for (step of SelectedSteps; track step.ID) {\n <button type=\"button\" class=\"wfr-step\"\n [class.wfr-step-selected]=\"step.ID === SelectedStepID\"\n [attr.data-status]=\"step.Status\"\n (click)=\"OnSelectStep(step)\">\n <span class=\"wfr-step-name\">{{ step.Name }}</span>\n <span class=\"wfr-step-meta\">{{ step.StepType || 'Step' }}</span>\n </button>\n }\n </div>\n\n @if (InspectorMode === 'edge' && SelectedEdge; as edge) {\n <div class=\"wfr-step-json\">\n <div class=\"wfr-step-json-head\">\n <span>{{ SelectedEdgeFromName }} \u2192 {{ SelectedEdgeToName }}</span>\n @if (SelectedEdgeOverride) {\n <span class=\"wfr-chip wfr-chip-forced\">forced {{ SelectedEdgeOverride }}</span>\n }\n </div>\n <div class=\"wfr-insp-card\">\n <span class=\"wfr-insp-label\">Condition</span>\n @if (edge.Condition?.trim()) {\n <code>{{ edge.Condition }}</code>\n } @else {\n <span>Unconditional \u2014 this path always runs.</span>\n }\n </div>\n @if (SelectedEdgeIsConditional) {\n <div class=\"wfr-insp-actions\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(edge.ID, 'true')\">Answer true</button>\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(edge.ID, 'false')\">Answer false</button>\n @if (SelectedEdgeOverride) {\n <button mjButton variant=\"flat\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(edge.ID, null)\">Clear override</button>\n }\n </div>\n } @else {\n <p class=\"wfr-insp-hint\">Skip the target step instead of overriding an unconditional path.</p>\n }\n </div>\n } @else if (SelectedStep; as step) {\n <div class=\"wfr-step-json\">\n <div class=\"wfr-step-json-head\">\n <span>{{ step.Name }}</span>\n <span class=\"wfr-row-status\" [attr.data-status]=\"step.Status\">{{ step.Status }}</span>\n </div>\n\n @if (SelectedStepFailureReason; as reason) {\n <div class=\"wfr-insp-card wfr-insp-failure\" role=\"status\">\n <span class=\"wfr-insp-label\">Why it failed</span>\n <span>{{ reason }}</span>\n </div>\n }\n\n <button type=\"button\" class=\"wfr-bp\"\n [class.wfr-bp-on]=\"HasBreakpoint(step.ID)\"\n [disabled]=\"ControlBusy\"\n (click)=\"OnBreakpointToggled({ TaskID: step.ID, Enabled: !HasBreakpoint(step.ID) })\"\n [attr.aria-pressed]=\"HasBreakpoint(step.ID)\"\n [title]=\"HasBreakpoint(step.ID) ? 'Remove breakpoint' : 'Break before this step'\">\n <i class=\"fa-circle\"\n [class.fa-solid]=\"HasBreakpoint(step.ID)\"\n [class.fa-regular]=\"!HasBreakpoint(step.ID)\"\n aria-hidden=\"true\"></i>\n </button>\n\n <!-- The inspector: live engine facts about this step, from the frame\n stream \u2014 claim, path verdicts, runner progress, what-if. -->\n @if (SelectedStepProgress; as progress) {\n <div class=\"wfr-insp-card\">\n <span class=\"wfr-insp-label\">Doing now</span>\n <span>{{ progress.progressMessage }}\n @if (progress.progressPercent != null) { ({{ progress.progressPercent }}%) }\n </span>\n </div>\n }\n @if (SelectedStepClaim; as claim) {\n <div class=\"wfr-insp-card\" [class.wfr-insp-bad]=\"claim.claimEvent === 'heartbeat-lost'\">\n <span class=\"wfr-insp-label\">Worker</span>\n <span>\n @switch (claim.claimEvent) {\n @case ('claimed') { {{ claim.claimedBy }} \u2014 working }\n @case ('heartbeat-lost') { {{ claim.claimedBy }} \u2014 lost, will be requeued }\n @case ('reclaimed') { requeued by the engine }\n }\n </span>\n </div>\n }\n @for (verdict of SelectedStepVerdicts; track verdict.edgeId) {\n <div class=\"wfr-insp-card\" [attr.data-verdict]=\"verdict.verdict\">\n <span class=\"wfr-insp-label\">\n @switch (verdict.verdict) {\n @case ('satisfied') { Path taken }\n @case ('notTaken') { Path not taken }\n @case ('held') { Path can't be answered }\n }\n </span>\n <span>\n @if (verdict.conditionText) { <code>{{ verdict.conditionText }}</code> }\n @if (verdict.reason) { \u2014 {{ verdict.reason }} }\n </span>\n </div>\n }\n @if (SelectedStepWhatIf; as whatIf) {\n <div class=\"wfr-insp-card\">\n <span class=\"wfr-insp-label\">If this step fails</span>\n <span>{{ whatIf.BlockedCount }} step{{ whatIf.BlockedCount === 1 ? '' : 's' }} can no longer run</span>\n </div>\n }\n @if (step.Status === 'Pending' || step.Status === 'Failed' || CanForceComplete(step)) {\n <div class=\"wfr-insp-actions\">\n @if (step.Status === 'Pending') {\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnSkipStep(step)\"\n title=\"Declare this step not-taken; later steps proceed\">\n <i class=\"fa-solid fa-forward\" aria-hidden=\"true\"></i> Skip step\n </button>\n }\n @if (CanEditInput(step)) {\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OpenEditInput(step)\">\n <i class=\"fa-solid fa-pen-to-square\" aria-hidden=\"true\"></i>\n {{ step.Status === 'Failed' ? 'Edit input & retry' : 'Edit input' }}\n </button>\n }\n @if (step.Status === 'Failed') {\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnRetryStep(step)\">\n <i class=\"fa-solid fa-rotate-right\" aria-hidden=\"true\"></i> Retry\n </button>\n }\n @if (CanForceComplete(step)) {\n <button mjButton variant=\"danger\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OpenForceComplete(step)\">\n <i class=\"fa-solid fa-flag-checkered\" aria-hidden=\"true\"></i> Force complete\n </button>\n }\n </div>\n }\n\n @if (EditInputOpen) {\n <div class=\"wfr-editor-card\">\n <span class=\"wfr-insp-label\">{{ step.Status === 'Failed' ? 'Edit input and retry' : 'Edit input' }}</span>\n <p class=\"wfr-insp-hint\">Applies to this run only. Invalid JSON is refused here.</p>\n <textarea class=\"mj-textarea wfr-json-edit\" [(ngModel)]=\"EditInputJson\"\n rows=\"8\" spellcheck=\"false\"></textarea>\n @if (EditInputError) {\n <span class=\"wfr-editor-error\">{{ EditInputError }}</span>\n }\n <div class=\"wfr-insp-actions\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"SubmitEditInput(step)\">\n {{ step.Status === 'Failed' ? 'Apply & retry' : 'Apply' }}\n </button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"EditInputOpen = false\">Cancel</button>\n </div>\n </div>\n }\n\n @if (ForceCompleteOpen) {\n <div class=\"wfr-editor-card wfr-editor-danger\">\n <span class=\"wfr-insp-label\">Force complete</span>\n <p class=\"wfr-insp-hint\">Downstream conditions will evaluate against this output as if the step had produced it. Type the step name to confirm.</p>\n <textarea class=\"mj-textarea wfr-json-edit\" [(ngModel)]=\"ForceCompleteJson\"\n rows=\"6\" spellcheck=\"false\"></textarea>\n <input class=\"mj-input\" type=\"text\" [(ngModel)]=\"ForceCompleteName\"\n [placeholder]=\"'Type \u201C' + step.Name + '\u201D to confirm'\" />\n @if (ForceCompleteError) {\n <span class=\"wfr-editor-error\">{{ ForceCompleteError }}</span>\n }\n <div class=\"wfr-insp-actions\">\n <button mjButton variant=\"danger\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"SubmitForceComplete(step)\">Force complete</button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"ForceCompleteOpen = false\">Cancel</button>\n </div>\n </div>\n }\n\n <mj-task-graph-variables\n [InputPayload]=\"StepPayload(step, 'InputPayload')\"\n [OutputPayload]=\"StepPayload(step, 'OutputPayload')\"\n [Invocation]=\"Invocation\">\n </mj-task-graph-variables>\n </div>\n } @else {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-hand-pointer\"\n Title=\"Select a step\"\n Message=\"Click a step on the canvas or in the list to see everything it recorded.\">\n </mj-empty-state>\n }\n }\n </div>\n </as-split-area>\n </as-split>\n } @else {\n <div class=\"wfr-json-pane\">\n <mj-code-editor\n [ngModel]=\"SelectedRunJson\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"width: 100%;\">\n </mj-code-editor>\n </div>\n }\n </aside>\n }\n </as-split-area>\n </as-split>\n }\n </mj-page-body>\n</mj-page-layout>\n", styles: [":host {\n display: block;\n height: 100%;\n}\n\n.wfr-status-filters {\n display: flex;\n gap: var(--mj-space-1);\n align-items: center;\n}\n\n/* List alone until something is selected; two resizable panes after. The size is the user's \u2014 see\n the LAYOUT_KEYS note on the component for why it is persisted server-side rather than locally. */\n.wfr-split {\n height: 100%;\n min-height: 0;\n}\n\n/* A gutter you can find. The default is a hairline, which is discoverable only by accident. */\n:host ::ng-deep .wfr-split > .as-split-gutter,\n:host ::ng-deep .wfr-graph-split > .as-split-gutter {\n background: transparent !important;\n position: relative;\n}\n\n:host ::ng-deep .wfr-split > .as-split-gutter::after,\n:host ::ng-deep .wfr-graph-split > .as-split-gutter::after {\n content: '';\n position: absolute;\n inset: 0;\n margin: auto;\n background: var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n}\n\n:host ::ng-deep .wfr-split.as-horizontal > .as-split-gutter::after,\n:host ::ng-deep .wfr-graph-split.as-horizontal > .as-split-gutter::after {\n width: 2px;\n}\n\n:host ::ng-deep .wfr-graph-split.as-vertical > .as-split-gutter::after {\n height: 2px;\n}\n\n:host ::ng-deep .wfr-split > .as-split-gutter:hover::after,\n:host ::ng-deep .wfr-graph-split > .as-split-gutter:hover::after {\n background: var(--mj-brand-primary);\n}\n\n/* The canvas and the step record sit SIDE BY SIDE \u2014 a JSON record in a strip along the bottom shows\n about ten lines. Stacks below the breakpoint, where three columns would leave each too narrow to\n use. */\n.wfr-graph-split {\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.wfr-list {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-1);\n overflow-y: auto;\n min-height: 0;\n}\n\n.wfr-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n width: 100%;\n padding: var(--mj-space-2) var(--mj-space-3);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n text-align: left;\n cursor: pointer;\n color: var(--mj-text-primary);\n}\n\n.wfr-row:hover {\n border-color: var(--mj-border-strong);\n}\n\n.wfr-row:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.wfr-row-selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.wfr-row-main {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.wfr-row-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wfr-row-when {\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n}\n\n.wfr-row-status {\n flex: none;\n font-size: var(--mj-font-size-xs);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n padding: 2px var(--mj-space-2);\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n/* Status carries meaning, so it is encoded in colour as well as text \u2014 a failed run should be\n findable without reading every row. Skipped stays grey on purpose: a branch that was not taken\n is a normal outcome, not a warning. */\n.wfr-row-status[data-status='Complete'] {\n color: var(--mj-status-success);\n border-color: color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n.wfr-row-status[data-status='Failed'] {\n color: var(--mj-status-error);\n border-color: color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n\n.wfr-row-status[data-status='Running'] {\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.wfr-detail {\n display: flex;\n flex-direction: column;\n /* Fills its split area. Without it the column sizes to its CONTENT, so the canvas below \u2014\n `flex: 1 1 auto` of an auto-height parent \u2014 got its intrinsic height and left dead space. */\n height: 100%;\n min-height: 0;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n}\n\n.wfr-detail-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.wfr-detail-title {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n min-width: 0;\n}\n\n.wfr-detail-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wfr-detail-actions {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1);\n flex: none;\n}\n\n/* ============================================================\n The run list as a sortable table\n ============================================================\n A run list is scanned for two things \u2014 the slowest run and the one that failed \u2014 and neither is\n answerable by scrolling. Columns line up so a reader compares down a column rather than reading\n each row; `tabular-nums` keeps the timestamps from jittering as digits change. */\n.wfr-head,\n.wfr-row {\n display: grid;\n grid-template-columns: minmax(0, 2fr) minmax(0, 1.3fr) minmax(0, 1.3fr) minmax(0, 0.7fr) minmax(0, 0.9fr);\n gap: var(--mj-space-2);\n align-items: center;\n}\n\n.wfr-head {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: 0 var(--mj-space-3) var(--mj-space-1);\n background: var(--mj-bg-page);\n}\n\n.wfr-head-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n background: none;\n border: none;\n padding: var(--mj-space-1) 0;\n font-size: var(--mj-font-size-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-secondary);\n cursor: pointer;\n text-align: left;\n}\n\n.wfr-head-cell:hover {\n color: var(--mj-text-primary);\n}\n\n.wfr-head-cell i {\n opacity: 0.65;\n font-size: 0.85em;\n}\n\n.wfr-col-time,\n.wfr-col-duration {\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.wfr-col-status {\n justify-self: start;\n}\n\n/* ============================================================\n Detail panel: canvas + step JSON, or the whole run as JSON\n ============================================================ */\n.wfr-detail-tabs {\n display: flex;\n gap: var(--mj-space-1);\n padding: 0 var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.wfr-tab {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n padding: var(--mj-space-2) var(--mj-space-2);\n font-size: var(--mj-font-size-sm);\n font-weight: 600;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.wfr-tab-active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.wfr-graph-pane {\n height: 100%;\n min-height: 12rem;\n}\n\n.wfr-steps-pane {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n border-left: 1px solid var(--mj-border-default);\n overflow: hidden;\n}\n\n/* Stacked layout puts the divider back on top, where the eye expects it. */\n:host ::ng-deep .as-vertical .wfr-steps-pane {\n border-left: none;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.wfr-step-list {\n display: flex;\n flex-wrap: wrap;\n gap: var(--mj-space-1);\n padding: var(--mj-space-2);\n border-bottom: 1px solid var(--mj-border-default);\n max-height: 8rem;\n overflow-y: auto;\n flex: none;\n}\n\n.wfr-step {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-1) var(--mj-space-2);\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-primary);\n font-size: var(--mj-font-size-sm);\n cursor: pointer;\n text-align: left;\n}\n\n.wfr-step:hover {\n border-color: var(--mj-border-strong);\n}\n\n.wfr-step-selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n/* Work that never ran must not read like work that did \u2014 the same rule the run timeline follows. */\n.wfr-step[data-status='Skipped'] .wfr-step-name {\n text-decoration: line-through;\n color: var(--mj-text-secondary);\n}\n\n.wfr-step-name {\n font-weight: 600;\n}\n\n.wfr-step-meta {\n font-size: var(--mj-font-size-xs);\n color: var(--mj-text-secondary);\n}\n\n.wfr-step-json,\n.wfr-json-pane {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\n.wfr-step-json-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n padding: var(--mj-space-1) var(--mj-space-3);\n font-weight: 600;\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-secondary);\n flex: none;\n}\n\n/* \u2500\u2500 live console \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\u2500\u2500\u2500\u2500 */\n\n.wfr-stall {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 12px;\n margin: 0 12px 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 45%, var(--mj-border-default));\n border-left: 4px solid var(--mj-status-warning);\n border-radius: var(--mj-radius-md);\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n font-size: var(--mj-font-size-sm);\n}\n.wfr-stall-body {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n.wfr-stall i { color: var(--mj-status-warning); }\n.wfr-stall-copy {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n.wfr-stall-copy code {\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n}\n.wfr-stall-reason { color: var(--mj-text-secondary); }\n.wfr-stall-actions { display: flex; flex-wrap: wrap; gap: 6px; }\n\n.wfr-replay {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 12px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n.wfr-replay i { color: var(--mj-text-secondary); }\n.wfr-replay input[type='range'] { flex: 1; accent-color: var(--mj-brand-primary); }\n\n.wfr-engine {\n display: flex;\n gap: 8px;\n overflow-x: auto;\n padding: 6px 12px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n}\n.wfr-tick {\n flex: none;\n padding: 3px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n white-space: nowrap;\n}\n.wfr-tick-held {\n border-color: color-mix(in srgb, var(--mj-status-warning, #d97706) 45%, var(--mj-border-default));\n background: color-mix(in srgb, var(--mj-status-warning, #d97706) 8%, var(--mj-bg-surface));\n}\n.wfr-tick-paused { color: var(--mj-brand-primary); border-color: var(--mj-border-strong); }\n\n.wfr-insp-card {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 7px 10px;\n margin: 0 0 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-primary);\n}\n.wfr-insp-card code {\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n}\n.wfr-insp-label {\n font-size: var(--mj-font-size-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-secondary);\n}\n.wfr-insp-card[data-verdict='held'],\n.wfr-insp-bad {\n border-color: color-mix(in srgb, var(--mj-status-warning, #d97706) 45%, var(--mj-border-default));\n background: color-mix(in srgb, var(--mj-status-warning, #d97706) 8%, var(--mj-bg-surface));\n}\n.wfr-insp-card[data-verdict='satisfied'] .wfr-insp-label { color: var(--mj-status-success); }\n.wfr-insp-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 8px; }\n.wfr-insp-hint {\n margin: 0 0 8px;\n font-size: var(--mj-font-size-xs);\n color: var(--mj-text-muted);\n}\n\n.wfr-bp-bar {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 6px 12px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n.wfr-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: var(--mj-font-size-xs);\n cursor: pointer;\n}\n.wfr-chip-break { color: var(--mj-status-error); border-color: color-mix(in srgb, var(--mj-status-error) 40%, transparent); }\n.wfr-chip-break i { font-size: 7px; }\n.wfr-chip-paused {\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n cursor: default;\n}\n.wfr-chip-forced {\n color: var(--mj-status-warning);\n border-color: color-mix(in srgb, var(--mj-status-warning) 40%, transparent);\n cursor: default;\n}\n.wfr-chip-x {\n font-size: 14px;\n line-height: 1;\n padding: 0 2px;\n}\n.wfr-chip-x:hover { color: var(--mj-text-primary); }\n\n.wfr-bp {\n width: 22px;\n height: 22px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin: 0 0 8px;\n padding: 0;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n.wfr-bp:hover { color: var(--mj-status-error); }\n.wfr-bp-on,\n.wfr-bp-on:hover { color: var(--mj-status-error); }\n.wfr-bp i { font-size: 10px; }\n.wfr-bp:disabled { opacity: 0.45; cursor: default; }\n\n.wfr-editor-card {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n margin: 0 0 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n}\n.wfr-editor-danger {\n border-color: color-mix(in srgb, var(--mj-status-error) 40%, var(--mj-border-default));\n}\n.wfr-json-edit {\n width: 100%;\n min-height: 120px;\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n resize: vertical;\n}\n.wfr-editor-error { color: var(--mj-status-error); font-size: var(--mj-font-size-xs); }\n.wfr-insp-failure { border-color: var(--mj-status-error); color: var(--mj-status-error); }\n"] }]
|
|
1834
|
+
args: [{ standalone: false, selector: 'mj-workflow-runs', changeDetection: ChangeDetectionStrategy.OnPush, template: "<mj-page-layout>\n <mj-page-header\n Title=\"Runs\"\n Icon=\"fa-solid fa-timeline\"\n Subtitle=\"Every workflow that has run \u2014 however it was started.\">\n\n <div meta>\n @if (!IsLoading && Runs.length > 0) {\n <mj-stat-badge\n [Count]=\"VisibleRuns.length\"\n [Total]=\"Runs.length\"\n Label=\"runs\"></mj-stat-badge>\n }\n </div>\n\n <div actions>\n <mj-refresh-button [Loading]=\"IsLoading\" (Clicked)=\"loadData()\"></mj-refresh-button>\n </div>\n\n <div toolbar>\n <mj-page-search\n [Value]=\"SearchText\"\n Placeholder=\"Search runs\"\n (ValueChange)=\"OnSearch($event)\"></mj-page-search>\n\n <div class=\"wfr-status-filters\">\n @for (status of StatusFilters; track status) {\n <button\n type=\"button\"\n mjButton\n [variant]=\"StatusFilter === status ? 'primary' : 'flat'\"\n size=\"sm\"\n (click)=\"OnFilterByStatus(status)\">\n {{ status === 'all' ? 'All' : status }}\n </button>\n }\n </div>\n </div>\n </mj-page-header>\n\n <mj-page-body>\n @if (IsLoading) {\n <mj-loading text=\"Loading runs...\"></mj-loading>\n } @else if (LoadError) {\n <mj-alert Variant=\"error\" [Message]=\"LoadError\"></mj-alert>\n } @else if (Runs.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-timeline\"\n Title=\"Nothing has run yet\"\n Message=\"When a workflow runs \u2014 started by hand, on a schedule, or by an agent \u2014 it will appear here.\">\n </mj-empty-state>\n } @else if (VisibleRuns.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-filter\"\n Title=\"No runs match\"\n Message=\"Nothing matches the current filter. Clear it to see everything that has run.\">\n </mj-empty-state>\n } @else {\n <as-split class=\"wfr-split\" direction=\"horizontal\" unit=\"percent\"\n [gutterSize]=\"8\" [disabled]=\"!SelectedRun\" (dragEnd)=\"OnSplitDragEnd($event.sizes)\">\n <as-split-area [size]=\"SelectedRun ? Layout.SplitSizes[0] : 100\" [minSize]=\"20\">\n <div class=\"wfr-list\">\n <!-- A header row that sorts. Every column a person scans by is sortable, because \"the\n longest run\" and \"the one that failed this morning\" are the two questions this list\n exists to answer and neither is answerable by scrolling. -->\n <div class=\"wfr-head\" role=\"row\">\n <button type=\"button\" class=\"wfr-head-cell wfr-col-name\" (click)=\"OnSort('Name')\">\n Workflow <i [ngClass]=\"SortIcon('Name')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-time\" (click)=\"OnSort('StartedAt')\">\n Started <i [ngClass]=\"SortIcon('StartedAt')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-time\" (click)=\"OnSort('CompletedAt')\">\n Ended <i [ngClass]=\"SortIcon('CompletedAt')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-duration\" (click)=\"OnSort('Duration')\">\n Duration <i [ngClass]=\"SortIcon('Duration')\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"wfr-head-cell wfr-col-status\" (click)=\"OnSort('Status')\">\n Status <i [ngClass]=\"SortIcon('Status')\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n @for (run of VisibleRuns; track run.ID) {\n <button\n type=\"button\"\n class=\"wfr-row\"\n [class.wfr-row-selected]=\"run.ID === SelectedRunID\"\n (click)=\"OnSelectRun(run)\">\n <span class=\"wfr-col-name wfr-row-name\">{{ run.Name }}</span>\n <!-- An em dash, never a fabricated time: a run that has not started has no start, and\n printing one would read as data. -->\n <span class=\"wfr-col-time\">{{ run.StartedAt ? (run.StartedAt | date:'MMM d, h:mm:ss a') : '\u2014' }}</span>\n <span class=\"wfr-col-time\">{{ run.CompletedAt ? (run.CompletedAt | date:'MMM d, h:mm:ss a') : '\u2014' }}</span>\n <span class=\"wfr-col-duration\">{{ run.Duration }}</span>\n <span class=\"wfr-col-status wfr-row-status\" [attr.data-status]=\"run.Status\">{{ run.Status }}</span>\n </button>\n }\n </div>\n </as-split-area>\n\n <as-split-area [size]=\"SelectedRun ? Layout.SplitSizes[1] : 0\" [minSize]=\"25\" [visible]=\"!!SelectedRun\">\n @if (SelectedRun; as selected) {\n <!-- The canvas lives in the RIGHT PANEL on selection, not nested inside the list row.\n A graph needs room to be read; inlining one per row turns a scannable list into a\n stack of diagrams. -->\n <aside class=\"wfr-detail\">\n <header class=\"wfr-detail-head\">\n <div class=\"wfr-detail-title\">\n <span class=\"wfr-detail-name\">{{ selected.Name }}</span>\n <span class=\"wfr-row-status\" [attr.data-status]=\"selected.Status\">{{ selected.Status }}</span>\n </div>\n <div class=\"wfr-detail-actions\">\n @if (selected.AgentRunID) {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnOpenAgentRun(selected)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n Agent run\n </button>\n }\n @if (DetailTab === 'graph') {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"ToggleStepPanel()\"\n [title]=\"Layout.StepPanelOpen ? 'Hide step details' : 'Show step details'\">\n <i class=\"fa-solid\" [class.fa-square-caret-right]=\"Layout.StepPanelOpen\"\n [class.fa-square-caret-left]=\"!Layout.StepPanelOpen\" aria-hidden=\"true\"></i>\n </button>\n }\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnSelectRun(selected)\" aria-label=\"Close\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </header>\n\n <div class=\"wfr-detail-tabs\" role=\"tablist\">\n <button type=\"button\" class=\"wfr-tab\" [class.wfr-tab-active]=\"DetailTab === 'graph'\"\n (click)=\"OnDetailTab('graph')\">\n <i class=\"fa-solid fa-diagram-project\" aria-hidden=\"true\"></i> Workflow\n </button>\n <button type=\"button\" class=\"wfr-tab\" [class.wfr-tab-active]=\"DetailTab === 'json'\"\n (click)=\"OnDetailTab('json')\">\n <i class=\"fa-solid fa-code\" aria-hidden=\"true\"></i> JSON\n </button>\n </div>\n\n @if (Stall) {\n <!-- The hardening review's signature failure \u2014 \"the run strands silently\" \u2014 made\n loud. A held path is now something the operator can answer, not just read. -->\n <div class=\"wfr-stall\" role=\"status\" [attr.data-kind]=\"Stall.kind\">\n <div class=\"wfr-stall-body\">\n <i class=\"fa-solid fa-triangle-exclamation\" aria-hidden=\"true\"></i>\n <div class=\"wfr-stall-copy\">\n <span>{{ Stall.message }}</span>\n @if (Stall.conditionText) {\n <code>{{ Stall.conditionText }}</code>\n }\n @if (Stall.reason) {\n <span class=\"wfr-stall-reason\">{{ Stall.reason }}</span>\n }\n </div>\n </div>\n @if (Stall.kind === 'held' && Stall.edgeID) {\n <div class=\"wfr-stall-actions\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(Stall.edgeID!, 'true')\">\n Answer true\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(Stall.edgeID!, 'false')\">\n Answer false\n </button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnDismissStall()\">\n Leave held\n </button>\n </div>\n }\n </div>\n }\n\n @if (DetailTab === 'graph') {\n <!-- Canvas BESIDE the step it opened, not above it. A JSON record in a strip along the\n bottom shows about ten lines, which is not enough of a record to read. -->\n <as-split class=\"wfr-graph-split\" [direction]=\"InnerSplitDirection\" unit=\"percent\"\n [gutterSize]=\"8\" (dragEnd)=\"OnStepSplitDragEnd($event.sizes)\">\n <as-split-area [size]=\"Layout.StepPanelOpen ? Layout.StepSplitSizes[0] : 100\" [minSize]=\"25\">\n <div class=\"wfr-graph-pane\">\n <mj-task-graph-debugger\n #GraphDebug\n [Provider]=\"ProviderToUse\"\n [ParentTaskID]=\"selected.ID\"\n [WorkflowName]=\"selected.Name\"\n [LiveUpdates]=\"selected.Status === 'Running' || selected.Status === 'In Progress'\"\n [ReplayAt]=\"ReplayAt\"\n [ShowLegend]=\"Layout.ShowLegend\"\n [ShowVariables]=\"false\"\n Height=\"100%\"\n (NodeSelected)=\"OnGraphNodeSelected($event)\"\n (ConnectionSelected)=\"OnGraphConnectionSelected($event)\"\n (LegendToggled)=\"OnLegendToggled($event)\"\n (Settled)=\"OnCanvasSettled()\"\n (Frame)=\"OnFrame($event)\"\n (PausedChange)=\"DebugPaused = $event\">\n </mj-task-graph-debugger>\n\n @if (CanReplay) {\n <!-- Replay: scrub through the settled run on the same canvas, reconstructed\n from each step's own timestamps. Read-only by construction. -->\n <div class=\"wfr-replay\">\n <i class=\"fa-solid fa-clock-rotate-left\" aria-hidden=\"true\"></i>\n <input type=\"range\" min=\"0\" max=\"100\" step=\"1\"\n [value]=\"ReplayPercent ?? 100\"\n (input)=\"OnReplayScrub($any($event.target).value)\"\n aria-label=\"Replay position\" />\n @if (ReplayPercent !== null) {\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"OnReplayReset()\">Now</button>\n }\n </div>\n }\n\n @if (GraphDebug.Breakpoints.length > 0 || GraphDebug.PausedAtTaskID) {\n <div class=\"wfr-bp-bar\" aria-label=\"Armed breakpoints\">\n @if (GraphDebug.PausedAtTaskID) {\n <span class=\"wfr-chip wfr-chip-paused\">\n <i class=\"fa-solid fa-pause\" aria-hidden=\"true\"></i>\n Paused at {{ StepName(GraphDebug.PausedAtTaskID) }}\n </span>\n }\n @for (id of GraphDebug.Breakpoints; track id) {\n <button type=\"button\" class=\"wfr-chip wfr-chip-break\" (click)=\"OnSelectBreakpoint(id)\">\n <i class=\"fa-solid fa-circle\" aria-hidden=\"true\"></i>\n {{ StepName(id) }}\n <span class=\"wfr-chip-x\" (click)=\"OnRemoveBreakpoint(id); $event.stopPropagation()\"\n role=\"button\" tabindex=\"0\" aria-label=\"Remove breakpoint\">\u00D7</span>\n </button>\n }\n </div>\n }\n\n @if (EngineTicks.length > 0) {\n <!-- The engine strip: one tick per dispatcher pass. A stuck run is a strip\n that keeps ticking with nothing moving \u2014 the honest visual of a stall. -->\n <div class=\"wfr-engine\" aria-label=\"Engine activity\">\n @for (tick of EngineTicks; track tick.passNumber) {\n <span class=\"wfr-tick\" [class.wfr-tick-held]=\"(tick.heldCount ?? 0) > 0\">\n #{{ tick.passNumber }} \u00B7 ready {{ tick.eligibleCount ?? 0 }}\n \u00B7 held {{ tick.heldCount ?? 0 }} \u00B7 took {{ tick.claimedCount ?? 0 }}\n </span>\n }\n @if (GraphDebug.Paused) {\n <span class=\"wfr-tick wfr-tick-paused\">\u23F8 paused \u2014 nothing new starts</span>\n }\n </div>\n }\n </div>\n </as-split-area>\n\n <as-split-area [size]=\"Layout.StepPanelOpen ? Layout.StepSplitSizes[1] : 0\" [minSize]=\"20\"\n [visible]=\"Layout.StepPanelOpen\">\n <div class=\"wfr-steps-pane\">\n @if (StepsLoading) {\n <mj-loading text=\"Loading steps...\"></mj-loading>\n } @else {\n <div class=\"wfr-step-list\">\n @for (step of SelectedSteps; track step.ID) {\n <button type=\"button\" class=\"wfr-step\"\n [class.wfr-step-selected]=\"step.ID === SelectedStepID\"\n [attr.data-status]=\"step.Status\"\n (click)=\"OnSelectStep(step)\">\n <span class=\"wfr-step-name\">{{ step.Name }}</span>\n <span class=\"wfr-step-meta\">{{ step.StepType || 'Step' }}</span>\n </button>\n }\n </div>\n\n @if (InspectorMode === 'edge' && SelectedEdge; as edge) {\n <div class=\"wfr-step-json\">\n <div class=\"wfr-step-json-head\">\n <span>{{ SelectedEdgeFromName }} \u2192 {{ SelectedEdgeToName }}</span>\n @if (SelectedEdgeOverride) {\n <span class=\"wfr-chip wfr-chip-forced\">forced {{ SelectedEdgeOverride }}</span>\n }\n </div>\n <div class=\"wfr-insp-card\">\n <span class=\"wfr-insp-label\">Condition</span>\n @if (edge.Condition?.trim()) {\n <code>{{ edge.Condition }}</code>\n } @else {\n <span>Unconditional \u2014 this path always runs.</span>\n }\n </div>\n @if (SelectedEdgeIsConditional) {\n <div class=\"wfr-insp-actions\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(edge.ID, 'true')\">Answer true</button>\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(edge.ID, 'false')\">Answer false</button>\n @if (SelectedEdgeOverride) {\n <button mjButton variant=\"flat\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnOverrideEdge(edge.ID, null)\">Clear override</button>\n }\n </div>\n } @else {\n <p class=\"wfr-insp-hint\">Skip the target step instead of overriding an unconditional path.</p>\n }\n </div>\n } @else if (SelectedStep; as step) {\n <div class=\"wfr-step-json\">\n <div class=\"wfr-step-json-head\">\n <span>{{ step.Name }}</span>\n <span class=\"wfr-row-status\" [attr.data-status]=\"step.Status\">{{ step.Status }}</span>\n </div>\n\n @if (SelectedStepFailureReason; as reason) {\n <div class=\"wfr-insp-card wfr-insp-failure\" role=\"status\">\n <span class=\"wfr-insp-label\">Why it failed</span>\n <span>{{ reason }}</span>\n </div>\n }\n\n <button type=\"button\" class=\"wfr-bp\"\n [class.wfr-bp-on]=\"HasBreakpoint(step.ID)\"\n [disabled]=\"ControlBusy\"\n (click)=\"OnBreakpointToggled({ TaskID: step.ID, Enabled: !HasBreakpoint(step.ID) })\"\n [attr.aria-pressed]=\"HasBreakpoint(step.ID)\"\n [title]=\"HasBreakpoint(step.ID) ? 'Remove breakpoint' : 'Break before this step'\">\n <i class=\"fa-circle\"\n [class.fa-solid]=\"HasBreakpoint(step.ID)\"\n [class.fa-regular]=\"!HasBreakpoint(step.ID)\"\n aria-hidden=\"true\"></i>\n </button>\n\n <!-- The inspector: live engine facts about this step, from the frame\n stream \u2014 claim, path verdicts, runner progress, what-if. -->\n @if (SelectedStepProgress; as progress) {\n <div class=\"wfr-insp-card\">\n <span class=\"wfr-insp-label\">Doing now</span>\n <span>{{ progress.progressMessage }}\n @if (progress.progressPercent != null) { ({{ progress.progressPercent }}%) }\n </span>\n </div>\n }\n @if (SelectedStepClaim; as claim) {\n <div class=\"wfr-insp-card\" [class.wfr-insp-bad]=\"claim.claimEvent === 'heartbeat-lost'\">\n <span class=\"wfr-insp-label\">Worker</span>\n <span>\n @switch (claim.claimEvent) {\n @case ('claimed') { {{ claim.claimedBy }} \u2014 working }\n @case ('heartbeat-lost') { {{ claim.claimedBy }} \u2014 lost, will be requeued }\n @case ('reclaimed') { requeued by the engine }\n }\n </span>\n </div>\n }\n @for (verdict of SelectedStepVerdicts; track verdict.edgeId) {\n <div class=\"wfr-insp-card\" [attr.data-verdict]=\"verdict.verdict\">\n <span class=\"wfr-insp-label\">\n @switch (verdict.verdict) {\n @case ('satisfied') { Path taken }\n @case ('notTaken') { Path not taken }\n @case ('held') { Path can't be answered }\n }\n </span>\n <span>\n @if (verdict.conditionText) { <code>{{ verdict.conditionText }}</code> }\n @if (verdict.reason) { \u2014 {{ verdict.reason }} }\n </span>\n </div>\n }\n @if (SelectedStepWhatIf; as whatIf) {\n <div class=\"wfr-insp-card\">\n <span class=\"wfr-insp-label\">If this step fails</span>\n <span>{{ whatIf.BlockedCount }} step{{ whatIf.BlockedCount === 1 ? '' : 's' }} can no longer run</span>\n </div>\n }\n @if (step.Status === 'Pending' || step.Status === 'Failed' || CanForceComplete(step)) {\n <div class=\"wfr-insp-actions\">\n @if (step.Status === 'Pending') {\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnSkipStep(step)\"\n title=\"Declare this step not-taken; later steps proceed\">\n <i class=\"fa-solid fa-forward\" aria-hidden=\"true\"></i> Skip step\n </button>\n }\n @if (CanEditInput(step)) {\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OpenEditInput(step)\">\n <i class=\"fa-solid fa-pen-to-square\" aria-hidden=\"true\"></i>\n {{ step.Status === 'Failed' ? 'Edit input & retry' : 'Edit input' }}\n </button>\n }\n @if (step.Status === 'Failed') {\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OnRetryStep(step)\">\n <i class=\"fa-solid fa-rotate-right\" aria-hidden=\"true\"></i> Retry\n </button>\n }\n @if (CanForceComplete(step)) {\n <button mjButton variant=\"danger\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"OpenForceComplete(step)\">\n <i class=\"fa-solid fa-flag-checkered\" aria-hidden=\"true\"></i> Force complete\n </button>\n }\n </div>\n }\n\n @if (EditInputOpen) {\n <div class=\"wfr-editor-card\">\n <span class=\"wfr-insp-label\">{{ step.Status === 'Failed' ? 'Edit input and retry' : 'Edit input' }}</span>\n <p class=\"wfr-insp-hint\">Applies to this run only. Invalid JSON is refused here.</p>\n <textarea class=\"mj-textarea wfr-json-edit\" [(ngModel)]=\"EditInputJson\"\n rows=\"8\" spellcheck=\"false\"></textarea>\n @if (EditInputError) {\n <span class=\"wfr-editor-error\">{{ EditInputError }}</span>\n }\n <div class=\"wfr-insp-actions\">\n <button mjButton variant=\"primary\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"SubmitEditInput(step)\">\n {{ step.Status === 'Failed' ? 'Apply & retry' : 'Apply' }}\n </button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"EditInputOpen = false\">Cancel</button>\n </div>\n </div>\n }\n\n @if (ForceCompleteOpen) {\n <div class=\"wfr-editor-card wfr-editor-danger\">\n <span class=\"wfr-insp-label\">Force complete</span>\n <p class=\"wfr-insp-hint\">Downstream conditions will evaluate against this output as if the step had produced it. Type the step name to confirm.</p>\n <textarea class=\"mj-textarea wfr-json-edit\" [(ngModel)]=\"ForceCompleteJson\"\n rows=\"6\" spellcheck=\"false\"></textarea>\n <input class=\"mj-input\" type=\"text\" [(ngModel)]=\"ForceCompleteName\"\n [placeholder]=\"'Type \u201C' + step.Name + '\u201D to confirm'\" />\n @if (ForceCompleteError) {\n <span class=\"wfr-editor-error\">{{ ForceCompleteError }}</span>\n }\n <div class=\"wfr-insp-actions\">\n <button mjButton variant=\"danger\" size=\"sm\" [disabled]=\"ControlBusy\"\n (click)=\"SubmitForceComplete(step)\">Force complete</button>\n <button mjButton variant=\"flat\" size=\"sm\" (click)=\"ForceCompleteOpen = false\">Cancel</button>\n </div>\n </div>\n }\n\n <mj-task-graph-variables\n [InputPayload]=\"StepPayload(step, 'InputPayload')\"\n [OutputPayload]=\"StepPayload(step, 'OutputPayload')\"\n [Invocation]=\"Invocation\">\n </mj-task-graph-variables>\n </div>\n } @else {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-hand-pointer\"\n Title=\"Select a step\"\n Message=\"Click a step on the canvas or in the list to see everything it recorded.\">\n </mj-empty-state>\n }\n }\n </div>\n </as-split-area>\n </as-split>\n } @else {\n <div class=\"wfr-json-pane\">\n <mj-code-editor\n [ngModel]=\"SelectedRunJson\"\n [language]=\"'json'\"\n [readonly]=\"true\"\n style=\"width: 100%;\">\n </mj-code-editor>\n </div>\n }\n </aside>\n }\n </as-split-area>\n </as-split>\n }\n </mj-page-body>\n</mj-page-layout>\n", styles: [":host {\n display: block;\n height: 100%;\n}\n\n.wfr-status-filters {\n display: flex;\n gap: var(--mj-space-1);\n align-items: center;\n}\n\n/* List alone until something is selected; two resizable panes after. The size is the user's \u2014 see\n the LAYOUT_KEYS note on the component for why it is persisted server-side rather than locally. */\n.wfr-split {\n height: 100%;\n min-height: 0;\n}\n\n/* A gutter you can find. The default is a hairline, which is discoverable only by accident. */\n:host ::ng-deep .wfr-split > .as-split-gutter,\n:host ::ng-deep .wfr-graph-split > .as-split-gutter {\n background: transparent !important;\n position: relative;\n}\n\n:host ::ng-deep .wfr-split > .as-split-gutter::after,\n:host ::ng-deep .wfr-graph-split > .as-split-gutter::after {\n content: '';\n position: absolute;\n inset: 0;\n margin: auto;\n background: var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n}\n\n:host ::ng-deep .wfr-split.as-horizontal > .as-split-gutter::after,\n:host ::ng-deep .wfr-graph-split.as-horizontal > .as-split-gutter::after {\n width: 2px;\n}\n\n:host ::ng-deep .wfr-graph-split.as-vertical > .as-split-gutter::after {\n height: 2px;\n}\n\n:host ::ng-deep .wfr-split > .as-split-gutter:hover::after,\n:host ::ng-deep .wfr-graph-split > .as-split-gutter:hover::after {\n background: var(--mj-brand-primary);\n}\n\n/* The canvas and the step record sit SIDE BY SIDE \u2014 a JSON record in a strip along the bottom shows\n about ten lines. Stacks below the breakpoint, where three columns would leave each too narrow to\n use. */\n.wfr-graph-split {\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.wfr-list {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-1);\n overflow-y: auto;\n min-height: 0;\n}\n\n.wfr-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n width: 100%;\n padding: var(--mj-space-2) var(--mj-space-3);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n text-align: left;\n cursor: pointer;\n color: var(--mj-text-primary);\n}\n\n.wfr-row:hover {\n border-color: var(--mj-border-strong);\n}\n\n.wfr-row:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.wfr-row-selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.wfr-row-main {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.wfr-row-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wfr-row-when {\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n}\n\n.wfr-row-status {\n flex: none;\n font-size: var(--mj-font-size-xs);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n padding: 2px var(--mj-space-2);\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-page);\n color: var(--mj-text-secondary);\n border: 1px solid var(--mj-border-default);\n}\n\n/* Status carries meaning, so it is encoded in colour as well as text \u2014 a failed run should be\n findable without reading every row. Skipped stays grey on purpose: a branch that was not taken\n is a normal outcome, not a warning. */\n.wfr-row-status[data-status='Complete'] {\n color: var(--mj-status-success);\n border-color: color-mix(in srgb, var(--mj-status-success) 40%, transparent);\n}\n\n.wfr-row-status[data-status='Failed'] {\n color: var(--mj-status-error);\n border-color: color-mix(in srgb, var(--mj-status-error) 40%, transparent);\n}\n\n.wfr-row-status[data-status='Running'] {\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n}\n\n.wfr-detail {\n display: flex;\n flex-direction: column;\n /* Fills its split area. Without it the column sizes to its CONTENT, so the canvas below \u2014\n `flex: 1 1 auto` of an auto-height parent \u2014 got its intrinsic height and left dead space. */\n height: 100%;\n min-height: 0;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n}\n\n.wfr-detail-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.wfr-detail-title {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n min-width: 0;\n}\n\n.wfr-detail-name {\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.wfr-detail-actions {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1);\n flex: none;\n}\n\n/* ============================================================\n The run list as a sortable table\n ============================================================\n A run list is scanned for two things \u2014 the slowest run and the one that failed \u2014 and neither is\n answerable by scrolling. Columns line up so a reader compares down a column rather than reading\n each row; `tabular-nums` keeps the timestamps from jittering as digits change. */\n.wfr-head,\n.wfr-row {\n display: grid;\n grid-template-columns: minmax(0, 2fr) minmax(0, 1.3fr) minmax(0, 1.3fr) minmax(0, 0.7fr) minmax(0, 0.9fr);\n gap: var(--mj-space-2);\n align-items: center;\n}\n\n.wfr-head {\n position: sticky;\n top: 0;\n z-index: 1;\n padding: 0 var(--mj-space-3) var(--mj-space-1);\n background: var(--mj-bg-page);\n}\n\n.wfr-head-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n background: none;\n border: none;\n padding: var(--mj-space-1) 0;\n font-size: var(--mj-font-size-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-secondary);\n cursor: pointer;\n text-align: left;\n}\n\n.wfr-head-cell:hover {\n color: var(--mj-text-primary);\n}\n\n.wfr-head-cell i {\n opacity: 0.65;\n font-size: 0.85em;\n}\n\n.wfr-col-time,\n.wfr-col-duration {\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.wfr-col-status {\n justify-self: start;\n}\n\n/* ============================================================\n Detail panel: canvas + step JSON, or the whole run as JSON\n ============================================================ */\n.wfr-detail-tabs {\n display: flex;\n gap: var(--mj-space-1);\n padding: 0 var(--mj-space-3);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.wfr-tab {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: none;\n border: none;\n border-bottom: 2px solid transparent;\n padding: var(--mj-space-2) var(--mj-space-2);\n font-size: var(--mj-font-size-sm);\n font-weight: 600;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\n.wfr-tab-active {\n color: var(--mj-brand-primary);\n border-bottom-color: var(--mj-brand-primary);\n}\n\n.wfr-graph-pane {\n height: 100%;\n min-height: 12rem;\n}\n\n.wfr-steps-pane {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n border-left: 1px solid var(--mj-border-default);\n overflow: hidden;\n}\n\n/* Stacked layout puts the divider back on top, where the eye expects it. */\n:host ::ng-deep .as-vertical .wfr-steps-pane {\n border-left: none;\n border-top: 1px solid var(--mj-border-default);\n}\n\n.wfr-step-list {\n display: flex;\n flex-wrap: wrap;\n gap: var(--mj-space-1);\n padding: var(--mj-space-2);\n border-bottom: 1px solid var(--mj-border-default);\n max-height: 8rem;\n overflow-y: auto;\n flex: none;\n}\n\n.wfr-step {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-1) var(--mj-space-2);\n background: var(--mj-bg-page);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-primary);\n font-size: var(--mj-font-size-sm);\n cursor: pointer;\n text-align: left;\n}\n\n.wfr-step:hover {\n border-color: var(--mj-border-strong);\n}\n\n.wfr-step-selected {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n/* Work that never ran must not read like work that did \u2014 the same rule the run timeline follows. */\n.wfr-step[data-status='Skipped'] .wfr-step-name {\n text-decoration: line-through;\n color: var(--mj-text-secondary);\n}\n\n.wfr-step-name {\n font-weight: 600;\n}\n\n.wfr-step-meta {\n font-size: var(--mj-font-size-xs);\n color: var(--mj-text-secondary);\n}\n\n.wfr-step-json,\n.wfr-json-pane {\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: auto;\n}\n\n.wfr-step-json-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n padding: var(--mj-space-1) var(--mj-space-3);\n font-weight: 600;\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-secondary);\n flex: none;\n}\n\n/* \u2500\u2500 live console \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\u2500\u2500\u2500\u2500 */\n\n.wfr-stall {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 12px;\n margin: 0 12px 8px;\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 45%, var(--mj-border-default));\n border-left: 4px solid var(--mj-status-warning);\n border-radius: var(--mj-radius-md);\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n color: var(--mj-text-primary);\n font-size: var(--mj-font-size-sm);\n}\n.wfr-stall-body {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n.wfr-stall i { color: var(--mj-status-warning); }\n.wfr-stall-copy {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n.wfr-stall-copy code {\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n}\n.wfr-stall-reason { color: var(--mj-text-secondary); }\n.wfr-stall-actions { display: flex; flex-wrap: wrap; gap: 6px; }\n\n.wfr-replay {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 6px 12px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n.wfr-replay i { color: var(--mj-text-secondary); }\n.wfr-replay input[type='range'] { flex: 1; accent-color: var(--mj-brand-primary); }\n\n.wfr-engine {\n display: flex;\n gap: 8px;\n overflow-x: auto;\n padding: 6px 12px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n color: var(--mj-text-secondary);\n font-variant-numeric: tabular-nums;\n}\n.wfr-tick {\n flex: none;\n padding: 3px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n white-space: nowrap;\n}\n.wfr-tick-held {\n border-color: color-mix(in srgb, var(--mj-status-warning, #d97706) 45%, var(--mj-border-default));\n background: color-mix(in srgb, var(--mj-status-warning, #d97706) 8%, var(--mj-bg-surface));\n}\n.wfr-tick-paused { color: var(--mj-brand-primary); border-color: var(--mj-border-strong); }\n\n.wfr-insp-card {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 7px 10px;\n margin: 0 0 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface);\n font-size: var(--mj-font-size-sm);\n color: var(--mj-text-primary);\n}\n.wfr-insp-card code {\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n}\n.wfr-insp-label {\n font-size: var(--mj-font-size-xs);\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--mj-text-secondary);\n}\n.wfr-insp-card[data-verdict='held'],\n.wfr-insp-bad {\n border-color: color-mix(in srgb, var(--mj-status-warning, #d97706) 45%, var(--mj-border-default));\n background: color-mix(in srgb, var(--mj-status-warning, #d97706) 8%, var(--mj-bg-surface));\n}\n.wfr-insp-card[data-verdict='satisfied'] .wfr-insp-label { color: var(--mj-status-success); }\n.wfr-insp-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 8px; }\n.wfr-insp-hint {\n margin: 0 0 8px;\n font-size: var(--mj-font-size-xs);\n color: var(--mj-text-muted);\n}\n\n.wfr-bp-bar {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 6px 12px;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n}\n.wfr-chip {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: var(--mj-font-size-xs);\n cursor: pointer;\n}\n.wfr-chip-break { color: var(--mj-status-error); border-color: color-mix(in srgb, var(--mj-status-error) 40%, transparent); }\n.wfr-chip-break i { font-size: 7px; }\n.wfr-chip-paused {\n color: var(--mj-brand-primary);\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, transparent);\n cursor: default;\n}\n.wfr-chip-forced {\n color: var(--mj-status-warning);\n border-color: color-mix(in srgb, var(--mj-status-warning) 40%, transparent);\n cursor: default;\n}\n.wfr-chip-x {\n font-size: 14px;\n line-height: 1;\n padding: 0 2px;\n}\n.wfr-chip-x:hover { color: var(--mj-text-primary); }\n\n.wfr-bp {\n width: 22px;\n height: 22px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin: 0 0 8px;\n padding: 0;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n.wfr-bp:hover { color: var(--mj-status-error); }\n.wfr-bp-on,\n.wfr-bp-on:hover { color: var(--mj-status-error); }\n.wfr-bp i { font-size: 10px; }\n.wfr-bp:disabled { opacity: 0.45; cursor: default; }\n\n.wfr-editor-card {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n margin: 0 0 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n}\n.wfr-editor-danger {\n border-color: color-mix(in srgb, var(--mj-status-error) 40%, var(--mj-border-default));\n}\n.wfr-json-edit {\n width: 100%;\n min-height: 120px;\n font-family: var(--mj-font-mono, ui-monospace, monospace);\n font-size: var(--mj-font-size-xs);\n resize: vertical;\n}\n.wfr-editor-error { color: var(--mj-status-error); font-size: var(--mj-font-size-xs); }\n.wfr-insp-failure { border-color: var(--mj-status-error); color: var(--mj-status-error); }\n"] }]
|
|
1835
1835
|
}], () => [{ type: i0.ChangeDetectorRef }], { onViewportResized: [{
|
|
1836
1836
|
type: HostListener,
|
|
1837
1837
|
args: ['window:resize']
|