@memberjunction/ng-dashboards 6.2.0-edge.4 → 6.2.0-edge.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +15 -7
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +7 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +209 -57
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts +12 -11
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js +15 -15
- package/dist/AI/components/duplicates/duplicate-detection-run-scope.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.d.ts.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +28 -16
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- 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 +30 -6
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +15 -7
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/sensitive-fields.d.ts +58 -0
- package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -0
- package/dist/AI/components/vectors/sensitive-fields.js +251 -0
- package/dist/AI/components/vectors/sensitive-fields.js.map +1 -0
- package/dist/AI/components/vectors/vector-document-rules.d.ts +139 -0
- package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -0
- package/dist/AI/components/vectors/vector-document-rules.js +182 -0
- package/dist/AI/components/vectors/vector-document-rules.js.map +1 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +83 -14
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +546 -271
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-store-selection.d.ts +32 -0
- package/dist/AI/components/vectors/vector-store-selection.d.ts.map +1 -0
- package/dist/AI/components/vectors/vector-store-selection.js +57 -0
- package/dist/AI/components/vectors/vector-store-selection.js.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts +236 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.d.ts.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.js +374 -0
- package/dist/ChiefOfStaff/chief-of-staff-agent-context.js.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts +195 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.d.ts.map +1 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js +2910 -0
- package/dist/ChiefOfStaff/chief-of-staff-dashboard.component.js.map +1 -0
- package/dist/ChiefOfStaff/index.d.ts +3 -0
- package/dist/ChiefOfStaff/index.d.ts.map +1 -0
- package/dist/ChiefOfStaff/index.js +3 -0
- package/dist/ChiefOfStaff/index.js.map +1 -0
- 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-logs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-logs-resource.component.js +2 -1
- package/dist/Communication/communication-logs-resource.component.js.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-monitor-resource.component.js +23 -18
- package/dist/Communication/communication-monitor-resource.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/Communication/communication-runs-resource.component.d.ts.map +1 -1
- package/dist/Communication/communication-runs-resource.component.js +11 -10
- package/dist/Communication/communication-runs-resource.component.js.map +1 -1
- package/dist/DashboardEditor/dashboard-editor.component.d.ts +17 -2
- package/dist/DashboardEditor/dashboard-editor.component.d.ts.map +1 -1
- package/dist/DashboardEditor/dashboard-editor.component.js +94 -43
- package/dist/DashboardEditor/dashboard-editor.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +49 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +220 -55
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.d.ts +2 -0
- package/dist/DataExplorer/models/explorer-state.interface.d.ts.map +1 -1
- package/dist/DataExplorer/models/explorer-state.interface.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/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 +161 -0
- package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -0
- package/dist/LoginStudio/login-studio-resource.component.js +890 -0
- package/dist/LoginStudio/login-studio-resource.component.js.map +1 -0
- package/dist/MCP/mcp-dashboard.component.d.ts +24 -4
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +118 -65
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.d.ts +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.d.ts.map +1 -1
- package/dist/PredictiveStudio/business-predictions.view-models.js +3 -3
- package/dist/PredictiveStudio/business-predictions.view-models.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts +6 -63
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.js +256 -521
- package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts +0 -18
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js +122 -249
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +5 -9
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipelines.component.js +98 -130
- package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts +53 -4
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js +335 -326
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts +19 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.d.ts.map +1 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.js +85 -0
- package/dist/PredictiveStudio/components/ps-row-drivers.component.js.map +1 -0
- package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts +19 -1
- package/dist/PredictiveStudio/engine/predictive-studio.engine.d.ts.map +1 -1
- package/dist/PredictiveStudio/engine/predictive-studio.engine.js +51 -2
- package/dist/PredictiveStudio/engine/predictive-studio.engine.js.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts +3 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.d.ts.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-agent-context.js +3 -0
- package/dist/PredictiveStudio/predictive-studio-agent-context.js.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts +27 -4
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts.map +1 -1
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js +94 -61
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +29 -5
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +185 -103
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.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 +22 -21
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +8 -2
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +2 -1
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +11 -3
- package/dist/core-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/package.json +72 -69
- package/dist/PredictiveStudio/at-risk.view-models.d.ts +0 -120
- package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +0 -1
- package/dist/PredictiveStudio/at-risk.view-models.js +0 -261
- package/dist/PredictiveStudio/at-risk.view-models.js.map +0 -1
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts +0 -109
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.d.ts.map +0 -1
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.js +0 -323
- package/dist/PredictiveStudio/components/ps-confirm-modal.component.js.map +0 -1
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts +0 -137
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts.map +0 -1
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js +0 -826
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ps-studio-resource.component.js","sourceRoot":"","sources":["../../../src/PredictiveStudio/resources/ps-studio-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewChild, inject } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { LogError, UserInfo } from '@memberjunction/core';\nimport { MJConversationEntity, MJEnvironmentEntityExtended, MJMLAlgorithmEntity, UserInfoEngine } from '@memberjunction/core-entities';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { PSResourceBase } from './ps-resource-base';\nimport { PSPanelKey } from '../predictive-studio.types';\nimport { PSPipelinesComponent } from '../components/ps-pipelines.component';\nimport {\n STUDIO_SECTIONS,\n PSSection,\n sectionGroups,\n sectionsInGroup,\n sectionLabel,\n hasSection,\n routeHomeNavigate,\n} from '../predictive-studio.nav';\nimport {\n buildStudioAgentContext,\n resolvePSRecord,\n buildPSNotFoundError,\n} from '../predictive-studio-agent-context';\nimport { validateStringParam } from '../../shared/agent-tool-validation';\nimport type { NavigationRequest } from '@memberjunction/ng-artifacts';\n\n/** Predictive Studio application ID (from `metadata/applications/.predictive-studio-application.json`). */\nconst PREDICTIVE_STUDIO_APP_ID = '299C9272-8D38-40CA-85D4-0980F2C9FAD1';\nconst MODEL_DEV_AGENT_NAME = 'Model Development Agent';\n\n/**\n * **Studio** — the analyst workbench door (one of Predictive Studio's three consolidated nav items,\n * alongside `Predictions` and `Models`). Hosts the build/run section panels (`ps-home`, `ps-pipelines`,\n * `ps-catalog`, `ps-experiments`, `ps-compare`) behind an internal left-nav grouped by lifecycle\n * (Overview · Build · Run), so the outer app nav stays quiet while analysts get all the depth one click\n * in. The active section round-trips through the `section` query param (deep links + back/forward). A\n * single docked **Model Development Agent** copilot is shared by every section's \"Ask the agent\" CTA —\n * wired with the full conversation lifecycle (`isNewConversation` → `conversationCreated`) so the first\n * message actually creates + sends. Cross-door navigation (to a Models section) routes via the nav\n * service; see {@link routeHomeNavigate}.\n */\n@RegisterClass(BaseResourceComponent, 'PredictiveStudioStudioResource')\n@Component({\n standalone: false,\n selector: 'mj-ps-studio-resource',\n template: `\n <mj-page-header-interior [Title]=\"activeLabel\" [Subtitle]=\"activeSubtitle\">\n </mj-page-header-interior>\n <mj-page-body-interior [Flex]=\"true\" [Padding]=\"false\">\n @if (isLoading) {\n <mj-loading text=\"Loading Studio…\" size=\"medium\"></mj-loading>\n } @else if (loadError) {\n <div class=\"ps-load-error\" data-testid=\"ps-load-error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <div class=\"ps-load-error-text\">\n <strong>Couldn't load {{ sectionTitle }}</strong>\n <span class=\"ps-load-error-detail\">{{ loadError }}</span>\n </div>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"retryLoad()\"><i class=\"fa-solid fa-rotate-right\"></i> Try again</button>\n </div>\n } @else {\n <div class=\"ps-studio-host\" [class.nav-collapsed]=\"isNavCollapsed\" [class.chat-open]=\"chatOpen\" data-testid=\"ps-studio-shell\">\n @if (isNavCollapsed) {\n <div class=\"ps-nav-collapsed-strip\" role=\"region\" aria-label=\"Studio navigation (collapsed)\">\n <button class=\"ps-nav-rail-collapse\" type=\"button\" (click)=\"toggleNav()\" aria-label=\"Expand studio navigation\" title=\"Expand navigation\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n <div class=\"ps-nav-collapsed-strip-label\"><i class=\"fa-solid fa-flask-vial\"></i> Studio</div>\n </div>\n }\n\n <as-split direction=\"horizontal\" class=\"studio-outer-splitter\" unit=\"percent\" [gutterSize]=\"isNavCollapsed ? 0 : 6\" (dragEnd)=\"onNavSplitDragEnd($event.sizes)\">\n @if (!isNavCollapsed) {\n <as-split-area [size]=\"navSizePct\" [minSize]=\"10\" [maxSize]=\"30\">\n <aside class=\"ps-leftnav\">\n <div class=\"ps-leftnav-header\">\n <span class=\"ps-leftnav-title\">Studio</span>\n <button class=\"ps-leftnav-collapse-btn\" type=\"button\" (click)=\"toggleNav()\" title=\"Collapse navigation\" aria-label=\"Collapse navigation\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n </div>\n @for (group of groups; track group) {\n @if (group) { <div class=\"ps-nav-group\">{{ group }}</div> }\n @for (item of itemsForGroup(group); track item.key) {\n <button class=\"ps-nav-item\" [class.active]=\"activeSection === item.key\"\n [attr.data-testid]=\"'ps-nav-' + item.key\" (click)=\"selectSection(item.key)\">\n <i [class]=\"item.icon\"></i> <span>{{ item.label }}</span>\n </button>\n }\n }\n </aside>\n </as-split-area>\n }\n\n <as-split-area [size]=\"isNavCollapsed ? 100 : (100 - navSizePct)\" [minSize]=\"60\">\n <div class=\"ps-studio-workspace\">\n <as-split direction=\"horizontal\" class=\"studio-copilot-splitter\" unit=\"percent\" [gutterSize]=\"chatOpen ? 6 : 0\" (dragEnd)=\"onCopilotSplitDragEnd($event.sizes)\">\n <as-split-area [size]=\"chatOpen ? (copilotExpanded ? 40 : mainSizePct) : 100\" [minSize]=\"30\">\n <section class=\"ps-content\" [class.fill]=\"activeSection === 'pipelines'\" [attr.data-testid]=\"'ps-panel-' + activeSection\">\n @switch (activeSection) {\n @case ('home') { <ps-home [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (navigate)=\"mapNavigate($event)\" (askAgent)=\"onAskAgent($event)\"></ps-home> }\n @case ('pipelines') { <ps-pipelines #pipelinesComp [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (askAgent)=\"onAskAgent($event)\" (navigate)=\"mapNavigate($event)\"></ps-pipelines> }\n @case ('catalog') { <ps-catalog [engine]=\"engine\" (askAgent)=\"onAskAgent($event)\" (createPipeline)=\"onCreatePipelineFromCatalog($event)\"></ps-catalog> }\n @case ('experiments') { <ps-experiments [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\"></ps-experiments> }\n @case ('compare') { <ps-compare [engine]=\"engine\"></ps-compare> }\n }\n </section>\n </as-split-area>\n\n @if (chatOpen) {\n <as-split-area [size]=\"copilotExpanded ? 60 : copilotSizePct\" [minSize]=\"20\" [maxSize]=\"70\">\n <aside class=\"ps-copilot\" [class.expanded]=\"copilotExpanded\" data-testid=\"ps-studio-copilot\">\n <div class=\"ps-copilot-head\">\n <div class=\"ps-copilot-title\"><i class=\"fa-solid fa-robot\"></i> Model Dev Agent</div>\n <div class=\"ps-copilot-actions\">\n <button class=\"ps-copilot-btn\" (click)=\"toggleCopilotExpanded()\" [title]=\"copilotExpanded ? 'Collapse panel' : 'Expand panel'\"><i class=\"fa-solid\" [class.fa-up-right-and-down-left-from-center]=\"!copilotExpanded\" [class.fa-down-left-and-up-right-to-center]=\"copilotExpanded\"></i></button>\n <button class=\"ps-copilot-close\" (click)=\"closeChat()\" aria-label=\"Close agent chat\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n </div>\n <div class=\"ps-copilot-body\">\n @if (currentUser) {\n <mj-conversation-chat-area\n [Provider]=\"Provider\" [environmentId]=\"chatEnvironmentId\" [currentUser]=\"currentUser\"\n [conversation]=\"chatConversation\" [conversationId]=\"chatConversationId\" [isNewConversation]=\"chatIsNewConversation\"\n [suppressNewConversationEmptyState]=\"true\" [allowMentions]=\"false\" [overlayMode]=\"false\"\n [showExportButton]=\"false\" [showShareButton]=\"false\" [showArtifactIndicator]=\"true\"\n [showAgentPicker]=\"false\" [showAgentModePicker]=\"false\"\n [defaultAgentId]=\"modelDevAgentId\" [pendingMessage]=\"pendingPrompt\"\n [applicationScope]=\"'Application'\" [applicationId]=\"applicationId\" [appContext]=\"chatAppContext\"\n (conversationCreated)=\"onChatConversationCreated($event)\"\n (pendingMessageConsumed)=\"onChatPendingMessageConsumed()\"\n (navigationRequest)=\"onNavigationRequest($event)\">\n </mj-conversation-chat-area>\n } @else { <div class=\"ps-copilot-empty\"><mj-loading text=\"Connecting…\" size=\"small\"></mj-loading></div> }\n </div>\n </aside>\n </as-split-area>\n }\n </as-split>\n </div>\n </as-split-area>\n </as-split>\n </div>\n }\n </mj-page-body-interior>\n `,\n styles: [\n `\n :host { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host { display: flex; flex: 1; min-height: 0; overflow: hidden; width: 100%; height: 100%; }\n .studio-outer-splitter { flex: 1; width: 100%; height: 100%; min-height: 0; min-width: 0; background: transparent; }\n .studio-outer-splitter .as-split-gutter { background: transparent; transition: background-color 0.15s ease; position: relative; }\n .studio-outer-splitter .as-split-gutter:hover { background-color: var(--mj-brand-primary, #6366f1); }\n .studio-outer-splitter .as-split-gutter::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 2px; height: 24px; border-radius: 1px; background: var(--mj-border-strong, #cbd5e1); }\n .studio-outer-splitter .as-split-gutter:hover::after { background: #ffffff; }\n\n .ps-nav-collapsed-strip { width: 44px; min-width: 44px; max-width: 44px; flex: none; background: var(--mj-bg-surface); border-right: 1px solid var(--mj-border-default); display: flex; flex-direction: column; align-items: center; padding: 10px 0; gap: 14px; z-index: 2; }\n .ps-nav-rail-collapse { background: var(--mj-bg-surface-subtle); border: 1px solid var(--mj-border-default); border-radius: 6px; color: var(--mj-text-secondary); cursor: pointer; display: grid; place-items: center; width: 28px; height: 28px; padding: 0; font-size: 11px; transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; }\n .ps-nav-rail-collapse:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); border-color: var(--mj-border-strong); }\n .ps-nav-collapsed-strip-label { writing-mode: vertical-rl; transform: rotate(180deg); font-size: 11px; font-weight: 600; letter-spacing: 0.04em; color: var(--mj-text-muted); display: flex; align-items: center; gap: 8px; text-transform: uppercase; }\n\n .ps-leftnav { width: 100%; height: 100%; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 2px; box-sizing: border-box; }\n .ps-leftnav-header { display: flex; align-items: center; justify-content: space-between; padding: 4px 6px 8px; border-bottom: 1px solid var(--mj-border-subtle); margin-bottom: 4px; }\n .ps-leftnav-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--mj-text-muted); }\n .ps-leftnav-collapse-btn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 6px; border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); color: var(--mj-text-muted); cursor: pointer; transition: all 0.15s ease; padding: 0; }\n .ps-leftnav-collapse-btn:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); border-color: var(--mj-border-strong); }\n\n .ps-nav-group { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 10px 8px 4px; }\n .ps-nav-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item i { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active i { color: var(--mj-brand-primary); }\n\n .ps-studio-workspace { display: flex; flex: 1; width: 100%; height: 100%; min-height: 0; min-width: 0; overflow: hidden; }\n .studio-copilot-splitter { flex: 1; width: 100%; height: 100%; min-height: 0; min-width: 0; }\n .studio-copilot-splitter .as-split-gutter { background: transparent; transition: background-color 0.15s ease; position: relative; }\n .studio-copilot-splitter .as-split-gutter:hover { background-color: var(--mj-brand-primary, #6366f1); }\n .studio-copilot-splitter .as-split-gutter::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 2px; height: 24px; border-radius: 1px; background: var(--mj-border-strong, #cbd5e1); }\n .ps-content { width: 100%; height: 100%; flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n /* Fill mode (pipelines): the section stops page-scrolling so the panel's inner\n columns (canvas / inspector) can each own their scrollbar. */\n .ps-content.fill { overflow: hidden; display: flex; flex-direction: column; padding-bottom: 14px; }\n .ps-content.fill > * { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .ps-copilot { width: 100%; height: 100%; max-width: none; flex: 1; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title i { color: var(--mj-brand-primary); }\n .ps-copilot-actions { display: flex; align-items: center; gap: 4px; }\n .ps-copilot-btn { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-btn:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-close { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body mj-conversation-chat-area { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty { display: flex; align-items: center; justify-content: center; flex: 1; }\n .ps-load-error { display: flex; align-items: center; gap: 14px; max-width: 620px; margin: 32px auto; padding: 18px 20px; border: 1px solid var(--mj-status-error-border); background: var(--mj-status-error-bg); border-radius: var(--mj-radius-lg); }\n .ps-load-error > i { font-size: 24px; color: var(--mj-status-error); }\n .ps-load-error-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }\n .ps-load-error-text strong { color: var(--mj-text-primary); }\n .ps-load-error-detail { color: var(--mj-text-secondary); font-size: var(--mj-text-sm); word-break: break-word; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open .ps-content, .ps-studio-host.chat-open .ps-leftnav { display: none; } .ps-copilot { width: 100%; max-width: none; border-left: none; } }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PSStudioResourceComponent extends PSResourceBase {\n protected readonly SectionKey = 'studio';\n protected readonly SectionLabel = 'Studio';\n protected readonly SectionIcon = 'fa-solid fa-flask-vial';\n\n private readonly cdrLocal = inject(ChangeDetectorRef);\n\n /** The active workbench section (which panel renders). Round-trips through the `section` query param. */\n public ActiveSection: PSPanelKey = 'home';\n\n /** @deprecated Use {@link ActiveSection}. */\n public get activeSection(): PSPanelKey {\n return this.ActiveSection;\n }\n /** @deprecated Use {@link ActiveSection}. */\n public set activeSection(value: PSPanelKey) {\n this.ActiveSection = value;\n }\n public readonly sections: readonly PSSection[] = STUDIO_SECTIONS;\n\n @ViewChild('pipelinesComp') PipelinesComponent?: PSPipelinesComponent;\n\n /** @deprecated Use {@link PipelinesComponent}. */\n get pipelinesComponent(): PSPipelinesComponent | undefined {\n return this.PipelinesComponent;\n }\n /** @deprecated Use {@link PipelinesComponent}. */\n set pipelinesComponent(value: PSPipelinesComponent | undefined) {\n this.PipelinesComponent = value;\n }\n\n public OnCreatePipelineFromCatalog(algo: MJMLAlgorithmEntity): void {\n this.selectSection('pipelines');\n setTimeout(() => {\n this.PipelinesComponent?.openWizard(algo.ID);\n }, 50);\n }\n\n /** @deprecated Use {@link OnCreatePipelineFromCatalog}. */\n public onCreatePipelineFromCatalog(algo: MJMLAlgorithmEntity): void {\n return this.OnCreatePipelineFromCatalog(algo);\n }\n\n // ── docked Model Dev Agent copilot ───────────────────────────────\n public ChatOpen = false;\n\n /** @deprecated Use {@link ChatOpen}. */\n public get chatOpen() {\n return this.ChatOpen;\n }\n /** @deprecated Use {@link ChatOpen}. */\n public set chatOpen(value) {\n this.ChatOpen = value;\n }\n public PendingPrompt: string | null = null;\n\n /** @deprecated Use {@link PendingPrompt}. */\n public get pendingPrompt(): string | null {\n return this.PendingPrompt;\n }\n /** @deprecated Use {@link PendingPrompt}. */\n public set pendingPrompt(value: string | null) {\n this.PendingPrompt = value;\n }\n private _modelDevAgentId: string | null = null;\n /** Conversation lifecycle (see {@link onChatConversationCreated}) — without it the first send no-ops. */\n public ChatConversation: MJConversationEntity | null = null;\n\n /** @deprecated Use {@link ChatConversation}. */\n public get chatConversation(): MJConversationEntity | null {\n return this.ChatConversation;\n }\n /** @deprecated Use {@link ChatConversation}. */\n public set chatConversation(value: MJConversationEntity | null) {\n this.ChatConversation = value;\n }\n public ChatConversationId: string | null = null;\n\n /** @deprecated Use {@link ChatConversationId}. */\n public get chatConversationId(): string | null {\n return this.ChatConversationId;\n }\n /** @deprecated Use {@link ChatConversationId}. */\n public set chatConversationId(value: string | null) {\n this.ChatConversationId = value;\n }\n public ChatIsNewConversation = true;\n\n /** @deprecated Use {@link ChatIsNewConversation}. */\n public get chatIsNewConversation() {\n return this.ChatIsNewConversation;\n }\n /** @deprecated Use {@link ChatIsNewConversation}. */\n public set chatIsNewConversation(value) {\n this.ChatIsNewConversation = value;\n }\n public IsNavCollapsed = false;\n\n /** @deprecated Use {@link IsNavCollapsed}. */\n public get isNavCollapsed() {\n return this.IsNavCollapsed;\n }\n /** @deprecated Use {@link IsNavCollapsed}. */\n public set isNavCollapsed(value) {\n this.IsNavCollapsed = value;\n }\n public NavSizePct = 14;\n\n /** @deprecated Use {@link NavSizePct}. */\n public get navSizePct() {\n return this.NavSizePct;\n }\n /** @deprecated Use {@link NavSizePct}. */\n public set navSizePct(value) {\n this.NavSizePct = value;\n }\n public MainSizePct = 68;\n\n /** @deprecated Use {@link MainSizePct}. */\n public get mainSizePct() {\n return this.MainSizePct;\n }\n /** @deprecated Use {@link MainSizePct}. */\n public set mainSizePct(value) {\n this.MainSizePct = value;\n }\n public CopilotSizePct = 32;\n\n /** @deprecated Use {@link CopilotSizePct}. */\n public get copilotSizePct() {\n return this.CopilotSizePct;\n }\n /** @deprecated Use {@link CopilotSizePct}. */\n public set copilotSizePct(value) {\n this.CopilotSizePct = value;\n }\n\n override ngOnInit(): void {\n super.ngOnInit();\n const initial = this.GetQueryParams()['section'] as PSPanelKey | undefined;\n if (initial && hasSection(this.sections, initial)) this.ActiveSection = initial;\n this.loadLayoutPrefs();\n }\n\n public ToggleNav(): void {\n this.IsNavCollapsed = !this.IsNavCollapsed;\n this.saveLayoutPrefs();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link ToggleNav}. */\n public toggleNav(): void {\n return this.ToggleNav();\n }\n\n public OnNavSplitDragEnd(sizes: readonly (number | '*')[]): void {\n if (Array.isArray(sizes) && sizes.length === 2 && typeof sizes[0] === 'number') {\n this.NavSizePct = Math.round(sizes[0]);\n this.saveLayoutPrefs();\n }\n }\n\n /** @deprecated Use {@link OnNavSplitDragEnd}. */\n public onNavSplitDragEnd(sizes: readonly (number | '*')[]): void {\n return this.OnNavSplitDragEnd(sizes);\n }\n\n public OnCopilotSplitDragEnd(sizes: readonly (number | '*')[]): void {\n if (Array.isArray(sizes) && sizes.length === 2 && typeof sizes[0] === 'number' && typeof sizes[1] === 'number') {\n this.MainSizePct = Math.round(sizes[0]);\n this.CopilotSizePct = Math.round(sizes[1]);\n this.saveLayoutPrefs();\n }\n }\n\n /** @deprecated Use {@link OnCopilotSplitDragEnd}. */\n public onCopilotSplitDragEnd(sizes: readonly (number | '*')[]): void {\n return this.OnCopilotSplitDragEnd(sizes);\n }\n\n private loadLayoutPrefs(): void {\n const saved = UserInfoEngine.Instance.GetSetting('mj.predictiveStudio.studio.layout');\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n if (typeof parsed.navSizePct === 'number' && parsed.navSizePct >= 10 && parsed.navSizePct <= 35) {\n this.NavSizePct = parsed.navSizePct;\n }\n if (typeof parsed.isNavCollapsed === 'boolean') {\n this.IsNavCollapsed = parsed.isNavCollapsed;\n }\n if (typeof parsed.copilotSizePct === 'number' && parsed.copilotSizePct >= 20 && parsed.copilotSizePct <= 60) {\n this.CopilotSizePct = parsed.copilotSizePct;\n this.MainSizePct = 100 - this.CopilotSizePct;\n }\n } catch {}\n }\n }\n\n private saveLayoutPrefs(): void {\n const prefs = {\n navSizePct: this.NavSizePct,\n isNavCollapsed: this.IsNavCollapsed,\n copilotSizePct: this.CopilotSizePct,\n mainSizePct: this.MainSizePct,\n };\n UserInfoEngine.Instance.SetSettingDebounced('mj.predictiveStudio.studio.layout', JSON.stringify(prefs));\n }\n\n /** React to deep-link / back-forward `section` changes after the initial mount. */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n const next = params['section'] as PSPanelKey | undefined;\n if (next && next !== this.ActiveSection && hasSection(this.sections, next)) {\n this.ActiveSection = next;\n this.cdrLocal.detectChanges();\n }\n }\n\n /** Deep agent context for the Studio door (build/run workbench counts + active section). */\n protected override extraAgentContext(): Record<string, unknown> {\n return buildStudioAgentContext({\n ActiveSection: this.ActiveSection,\n ActiveSectionLabel: this.ActiveLabel,\n SectionLabels: this.sections.map((s) => s.label),\n PublishedModelCount: this.engine.PublishedModels.length,\n RunningSessionCount: this.engine.RunningSessions.length,\n PipelineCount: this.engine.Pipelines.length,\n AlgorithmCount: this.engine.Algorithms.length,\n ExperimentCount: this.engine.Experiments.length,\n TrainingRunCount: this.engine.TrainingRuns.length,\n ChatOpen: this.ChatOpen,\n });\n }\n\n /**\n * 🔒 Read/navigate-only agent tools for the Studio door: switch the active section, or open the docked\n * Model Dev Agent co-pilot. NO build/train/publish tool is exposed — model creation runs through the\n * co-pilot conversation (the approve-gated builder), never a fire-and-forget agent tool.\n */\n protected override registerAgentTools(): void {\n this.navigationService.SetAgentClientTools(this, [\n {\n Name: 'SwitchStudioSection',\n Description:\n 'Switch the Studio workbench to a section. Pass the section key or label (see SectionLabels): Overview, Training Pipelines, Algorithm Catalog, Experiments, or Compare Runs.',\n ParameterSchema: { type: 'object', properties: { section: { type: 'string', description: 'The section key or label to switch to' } } },\n Handler: async (params: Record<string, unknown>) => {\n const check = validateStringParam(params['section'], 'section');\n if (!check.ok) return check.result;\n const candidates = this.sections.map((s) => ({ ID: s.key, Name: s.label }));\n const match = resolvePSRecord(check.value, candidates);\n if (!match) return { Success: false, ErrorMessage: buildPSNotFoundError(check.value, candidates, 'section') };\n this.selectSection(match.ID as PSPanelKey);\n return { Success: true, Data: { activeSection: match.Name } };\n },\n },\n {\n Name: 'OpenModelDevAgentCopilot',\n Description:\n 'Open the docked Model Development Agent co-pilot in the Studio (does not send a message — the user drives the conversation). Use when the user wants to design/build a new prediction.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n this.OpenCopilot();\n return { Success: true, Data: { chatOpen: true } };\n },\n },\n ]);\n }\n\n // ── left-nav ─────────────────────────────────────────────────────\n public get Groups(): string[] { return sectionGroups(this.sections); }\n\n /** @deprecated Use {@link Groups}. */\n public get groups(): string[] {\n return this.Groups;\n }\n public ItemsForGroup(group: string): PSSection[] { return sectionsInGroup(this.sections, group); }\n\n /** @deprecated Use {@link ItemsForGroup}. */\n public itemsForGroup(group: string): PSSection[] {\n return this.ItemsForGroup(group);\n }\n public get ActiveLabel(): string { return sectionLabel(this.sections, this.ActiveSection); }\n\n /** @deprecated Use {@link ActiveLabel}. */\n public get activeLabel(): string {\n return this.ActiveLabel;\n }\n\n /** Section-specific subtitle for the interior header (so every section doesn't repeat one generic line). */\n public get ActiveSubtitle(): string {\n const map: Record<string, string> = {\n home: 'Start a new prediction from your data, a template, or the agent.',\n pipelines: 'Assemble features and train from the algorithm catalog.',\n catalog: 'Browse algorithms with a fit guide for your use case.',\n experiments: 'Run and track model experiments.',\n compare: 'Compare runs on the honest holdout score.',\n };\n return map[this.ActiveSection] ?? '';\n }\n\n /** @deprecated Use {@link ActiveSubtitle}. */\n public get activeSubtitle(): string {\n return this.ActiveSubtitle;\n }\n\n public selectSection(key: PSPanelKey): void {\n if (this.ActiveSection === key) return;\n this.ActiveSection = key;\n this.UpdateQueryParams({ section: key });\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** The Overview panel's in-app navigation: switch section in-place, or cross to the Models door. */\n public MapNavigate(key: PSPanelKey): void {\n const target = routeHomeNavigate(key);\n if (target.Kind === 'section') {\n this.selectSection(target.Key);\n } else if (target.Kind === 'app') {\n void this.navigationService.SwitchToApp(PREDICTIVE_STUDIO_APP_ID, target.NavLabel, { section: target.Section });\n }\n }\n\n /** @deprecated Use {@link MapNavigate}. */\n public mapNavigate(key: PSPanelKey): void {\n return this.MapNavigate(key);\n }\n\n // ── copilot ──────────────────────────────────────────────────────\n public get CurrentUser(): UserInfo | null { return this.ProviderToUse.CurrentUser ?? null; }\n\n /** @deprecated Use {@link CurrentUser}. */\n public get currentUser(): UserInfo | null {\n return this.CurrentUser;\n }\n\n public get ChatEnvironmentId(): string {\n return (this.Data?.Configuration?.['environmentId'] as string | undefined) || MJEnvironmentEntityExtended.DefaultEnvironmentID;\n }\n\n /** @deprecated Use {@link ChatEnvironmentId}. */\n public get chatEnvironmentId(): string {\n return this.ChatEnvironmentId;\n }\n public get applicationId(): string | null { return (this.Data?.Configuration?.['applicationId'] as string | undefined) ?? null; }\n public get ModelDevAgentId(): string | null { return this._modelDevAgentId; }\n\n /** @deprecated Use {@link ModelDevAgentId}. */\n public get modelDevAgentId(): string | null {\n return this.ModelDevAgentId;\n }\n public get ChatAppContext(): Record<string, unknown> {\n return { app: 'Predictive Studio', section: this.ActiveSection, publishedModels: this.engine.Models.filter((m) => m.Status === 'Published').length };\n }\n\n /** @deprecated Use {@link ChatAppContext}. */\n public get chatAppContext(): Record<string, unknown> {\n return this.ChatAppContext;\n }\n\n public OnAskAgent(starterPrompt: string): void {\n this.PendingPrompt = starterPrompt;\n this.ChatOpen = true;\n void this.ensureModelDevAgentResolved();\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OnAskAgent}. */\n public onAskAgent(starterPrompt: string): void {\n return this.OnAskAgent(starterPrompt);\n }\n\n /** Open the docked co-pilot (clean chat) — used by the read-only `OpenModelDevAgentCopilot` agent tool. */\n public OpenCopilot(): void {\n this.PendingPrompt = null;\n this.ChatOpen = true;\n void this.ensureModelDevAgentResolved();\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OpenCopilot}. */\n public openCopilot(): void {\n return this.OpenCopilot();\n }\n\n public CloseChat(): void {\n this.ChatOpen = false;\n this.PendingPrompt = null;\n this.CopilotExpanded = false;\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link CloseChat}. */\n public closeChat(): void {\n return this.CloseChat();\n }\n\n public CopilotExpanded = false;\n\n /** @deprecated Use {@link CopilotExpanded}. */\n public get copilotExpanded() {\n return this.CopilotExpanded;\n }\n /** @deprecated Use {@link CopilotExpanded}. */\n public set copilotExpanded(value) {\n this.CopilotExpanded = value;\n }\n\n public ToggleCopilotExpanded(): void {\n this.CopilotExpanded = !this.CopilotExpanded;\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link ToggleCopilotExpanded}. */\n public toggleCopilotExpanded(): void {\n return this.ToggleCopilotExpanded();\n }\n\n public OnNavigationRequest(req: NavigationRequest): void {\n if (req.navItemName === 'Models' || req.queryParams?.['modelId']) {\n void this.navigationService.SwitchToApp(PREDICTIVE_STUDIO_APP_ID, 'Models', req.queryParams);\n } else if (req.appName) {\n void this.navigationService.SwitchToApp(req.appName, req.navItemName, req.queryParams);\n }\n }\n\n /** @deprecated Use {@link OnNavigationRequest}. */\n public onNavigationRequest(req: NavigationRequest): void {\n return this.OnNavigationRequest(req);\n }\n\n /** Chat-area created its backing conversation on the first send — capture it + leave new-mode so the thread renders. */\n public OnChatConversationCreated(event: { conversation: MJConversationEntity; pendingMessage?: string }): void {\n this.PendingPrompt = event.pendingMessage ?? null;\n this.ChatConversation = event.conversation;\n this.ChatConversationId = event.conversation.ID;\n this.ChatIsNewConversation = false;\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OnChatConversationCreated}. */\n public onChatConversationCreated(event: { conversation: MJConversationEntity; pendingMessage?: string }): void {\n return this.OnChatConversationCreated(event);\n }\n\n /** Chat-area delivered the seeded prompt — clear the buffer so a re-render doesn't resend it. */\n public OnChatPendingMessageConsumed(): void {\n this.PendingPrompt = null;\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OnChatPendingMessageConsumed}. */\n public onChatPendingMessageConsumed(): void {\n return this.OnChatPendingMessageConsumed();\n }\n\n private async ensureModelDevAgentResolved(): Promise<void> {\n if (this._modelDevAgentId) return;\n try {\n await AIEngineBase.Instance.Config(false, this.ProviderToUse.CurrentUser ?? undefined);\n this._modelDevAgentId =\n AIEngineBase.Instance.Agents?.find((a) => a.Name?.trim().toLowerCase() === MODEL_DEV_AGENT_NAME.toLowerCase())?.ID ?? null;\n if (!this._modelDevAgentId) LogError(`PSStudioResource: '${MODEL_DEV_AGENT_NAME}' not found — chat uses default-agent routing.`);\n this.cdrLocal.detectChanges();\n } catch (err) {\n LogError(`PSStudioResource.ensureModelDevAgentResolved: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n\n/** Tree-shaking prevention — called from the subpath module so the @RegisterClass survives bundling. */\nexport function LoadPSStudioResource(): void {\n // intentionally empty\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ps-studio-resource.component.js","sourceRoot":"","sources":["../../../src/PredictiveStudio/resources/ps-studio-resource.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAY,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAwB,2BAA2B,EAAuB,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACvI,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,OAAO,EACL,eAAe,EAEf,aAAa,EACb,eAAe,EACf,YAAY,EACZ,UAAU,EACV,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,oBAAoB,GACrB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;;;;;;;;;;;;;;IA2BjE,gCAA8D;;;;IAE9D,8BAAoE;IAClE,uBAAgD;IAE9C,AADF,8BAAgC,aACtB;IAAA,YAAgC;IAAA,iBAAS;IACjD,+BAAmC;IAAA,YAAe;IACpD,AADoD,iBAAO,EACrD;IACN,iCAAqE;IAAtB,6LAAS,kBAAW,KAAC;IAAC,wBAAwC;IAAC,0BAAS;IACzH,AADyH,iBAAS,EAC5H;;;IAJM,eAAgC;IAAhC,4DAAgC;IACL,eAAe;IAAf,sCAAe;;;;IAQhD,AADF,+BAA6F,iBAC8C;IAAtF,4MAAS,kBAAW,KAAC;IACtE,wBAAyC;IAC3C,iBAAS;IACT,+BAA0C;IAAA,wBAAsC;IAAC,uBAAM;IACzF,AADyF,iBAAM,EACzF;;;IAcgB,+BAA0B;IAAA,YAAW;IAAA,iBAAM;;;IAAjB,cAAW;IAAX,8BAAW;;;;IAEjD,kCAC8E;IAAlC,kPAAS,iCAAuB,KAAC;IAC3E,oBAA2B;IAAC,4BAAM;IAAA,YAAgB;IACpD,AADoD,iBAAO,EAClD;;;;IAHmB,8DAA2C;;IAElE,cAAmB;IAAnB,2BAAmB;IAAY,eAAgB;IAAhB,mCAAgB;;;IAJtD,8HAAa;IACb,kIAKC;;;;IAND,mCAA2D;IAC3D,cAKC;IALD,cAAA,8BAAoB,CAKnB;;;;IAZD,AADF,AADF,AADF,yCAAiE,gBACrC,cACO,eACE;IAAA,sBAAM;IAAA,iBAAO;IAC5C,kCAAyI;IAAnF,4MAAS,kBAAW,KAAC;IACzE,wBAAwC;IAE5C,AADE,iBAAS,EACL;IACN,4IAQC;IAEL,AADE,iBAAQ,EACM;;;IAlBkC,AAAf,AAApB,wCAAmB,eAAe,eAAe;IAQ5D,eAQC;IARD,4BAQC;;;;IAWsB,mCAAiK;IAAhC,AAAjC,kNAAY,0BAAmB,KAAC,qMAAa,yBAAkB,KAAC;IAAC,iBAAU;;;IAArH,AAA3B,AAAlB,sCAAiB,kCAA2B,iDAA0C;;;;IAC1F,2CAAqL;IAAjC,AAAhC,yNAAY,yBAAkB,KAAC,4MAAa,0BAAmB,KAAC;IAAC,iBAAe;;;IAA1H,AAA3B,AAAlB,sCAAiB,kCAA2B,iDAA0C;;;;IACrH,sCAAqH;IAAvD,AAAhC,uNAAY,yBAAkB,KAAC,sNAAmB,0CAAmC,KAAC;IAAC,iBAAa;;;IAAtH,sCAAiB;;;IACzB,qCAAwH;;;IAA3D,AAA3B,AAAlB,sCAAiB,kCAA2B,iDAA0C;;;IAC1G,iCAA2C;;;IAA/B,sCAAiB;;;;IAiB7C,qDAUoD;IAAlD,AADA,AADA,kRAAuB,wCAAiC,KAAC,qQAC/B,qCAA8B,KAAC,iQACpC,kCAA2B,KAAC;IACnD,iBAA4B;;;IAJyC,AAAhC,AAAnC,AADmC,AAAnC,AAD0B,AAA1B,AADqD,AAA1B,AAA3B,AADmE,AAAxB,AAA3C,AADwE,AAAtC,AAAlC,AAD0D,AAApC,AAAtB,0CAAqB,2CAAoC,mCAA4B,yCACpD,6CAAsC,mDAA4C,2CACzE,wBAAwB,sBAAsB,2BAC9D,0BAA0B,+BAA+B,0BAC1D,8BAA8B,0CACrB,wCAAiC,mCACjC,uCAAgC,qCAA8B;;;IAK1F,+BAA8B;IAAA,iCAAyD;IAAA,iBAAM;;;;IApBvG,AADF,AADF,AADF,yCAA4F,gBACG,cAC9D,cACG;IAAA,wBAAiC;IAAC,gCAAe;IAAA,iBAAM;IAEnF,AADF,+BAAgC,iBACiG;IAAhG,8MAAS,8BAAuB,KAAC;IAA+D,wBAAuJ;IAAA,iBAAS;IAC/R,kCAAqF;IAApD,8MAAS,kBAAW,KAAC;IAA+B,yBAAiC;IAE1H,AADE,AADwH,iBAAS,EAC3H,EACF;IACN,gCAA6B;IAczB,AAbF,kJAAmB,qGAaV;IAGf,AADE,AADE,iBAAM,EACA,EACM;;;IA1B6D,AAAf,AAA/C,0EAA8C,eAAe,eAAe;IAC/D,cAAkC;IAAlC,kDAAkC;IAIW,eAA6D;IAA7D,kFAA6D;IAAqB,cAAgE;IAAC,AAAjE,gFAAgE,+DAA8D;IAKnR,eAayG;IAbzG,8CAayG;;;;IAxE3H,+BAA8H;IAC5H,0GAAsB;IAStB,oCAAgK;IAA5C,yMAAW,sCAA+B,KAAC;IAC7J,oHAAuB;IAwBnB,AADF,AADF,yCAAiF,cAC9C,mBACiI;IAAhD,yMAAW,0CAAmC,KAAC;IAE3J,AADF,yCAA6F,kBAC+B;IAMtH,AADA,AADA,AADA,AADA,uGAAgB,wFACK,sFACF,0FACI,sFACJ;IAGzB,AADE,iBAAU,EACI;IAEhB,wHAAgB;IAiC1B,AADE,AADE,AADE,AADE,iBAAW,EACP,EACQ,EACP,EACP;;;;IAjF6D,AAAvC,sDAAsC,8BAA6B;IAC7F,cAOC;IAPD,gDAOC;IAE6E,cAAqC;IAArC,0DAAqC;IACjH,cAoBC;IApBD,iDAoBC;IAEc,cAAkD;IAAC,AAAnD,4EAAkD,eAAe;IAEI,eAA+B;IAA/B,oDAA+B;IAC9F,cAA8D;IAAC,AAA/D,+FAA8D,eAAe;IAC9D,cAA4C;IAA5C,4DAA4C;;IACtE,cAMC;IAND,uDAAA,MAAM,oBAAN,WAAW,qBAAX,SAAS,qBAAT,aAAa,qBAAb,SAAS,WAMR;IAIL,eA4BC;IA5BD,2CA4BC;;AA/GnB,2GAA2G;AAC3G,MAAM,wBAAwB,GAAG,sCAAsC,CAAC;AACxE,MAAM,oBAAoB,GAAG,yBAAyB,CAAC;AAEvD;;;;;;;;;;GAUG;AAsKI,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,cAAc;IACxC,UAAU,GAAG,QAAQ,CAAC;IACtB,YAAY,GAAG,QAAQ,CAAC;IACxB,WAAW,GAAG,wBAAwB,CAAC;IAEzC,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAEtD,yGAAyG;IAClG,aAAa,GAAe,MAAM,CAAC;IAE1C,6CAA6C;IAC7C,IAAW,aAAa;QACtB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IACD,6CAA6C;IAC7C,IAAW,aAAa,CAAC,KAAiB;QACxC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IAC7B,CAAC;IACe,QAAQ,GAAyB,eAAe,CAAC;IAErC,kBAAkB,CAAwB;IAEtE,kDAAkD;IAClD,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IACD,kDAAkD;IAClD,IAAI,kBAAkB,CAAC,KAAuC;QAC5D,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;IAClC,CAAC;IAEM,2BAA2B,CAAC,IAAyB;QAC1D,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAChC,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC,EAAE,EAAE,CAAC,CAAC;IACT,CAAC;IAED,2DAA2D;IACpD,2BAA2B,CAAC,IAAyB;QAC1D,OAAO,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC;IAED,oEAAoE;IAC7D,QAAQ,GAAG,KAAK,CAAC;IAExB,wCAAwC;IACxC,IAAW,QAAQ;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IACD,wCAAwC;IACxC,IAAW,QAAQ,CAAC,KAAK;QACvB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACxB,CAAC;IACM,aAAa,GAAkB,IAAI,CAAC;IAE3C,6CAA6C;IAC7C,IAAW,aAAa;QACtB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IACD,6CAA6C;IAC7C,IAAW,aAAa,CAAC,KAAoB;QAC3C,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IAC7B,CAAC;IACO,gBAAgB,GAAkB,IAAI,CAAC;IAC/C,yGAAyG;IAClG,gBAAgB,GAAgC,IAAI,CAAC;IAE5D,gDAAgD;IAChD,IAAW,gBAAgB;QACzB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IACD,gDAAgD;IAChD,IAAW,gBAAgB,CAAC,KAAkC;QAC5D,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IACM,kBAAkB,GAAkB,IAAI,CAAC;IAEhD,kDAAkD;IAClD,IAAW,kBAAkB;QAC3B,OAAO,IAAI,CAAC,kBAAkB,CAAC;IACjC,CAAC;IACD,kDAAkD;IAClD,IAAW,kBAAkB,CAAC,KAAoB;QAChD,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;IAClC,CAAC;IACM,qBAAqB,GAAG,IAAI,CAAC;IAEpC,qDAAqD;IACrD,IAAW,qBAAqB;QAC9B,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;IACD,qDAAqD;IACrD,IAAW,qBAAqB,CAAC,KAAK;QACpC,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;IACrC,CAAC;IACM,cAAc,GAAG,KAAK,CAAC;IAE9B,8CAA8C;IAC9C,IAAW,cAAc;QACvB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IACD,8CAA8C;IAC9C,IAAW,cAAc,CAAC,KAAK;QAC7B,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAC9B,CAAC;IACM,UAAU,GAAG,EAAE,CAAC;IAEvB,0CAA0C;IAC1C,IAAW,UAAU;QACnB,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IACD,0CAA0C;IAC1C,IAAW,UAAU,CAAC,KAAK;QACzB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC1B,CAAC;IACM,WAAW,GAAG,EAAE,CAAC;IAExB,2CAA2C;IAC3C,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IACD,2CAA2C;IAC3C,IAAW,WAAW,CAAC,KAAK;QAC1B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IACM,cAAc,GAAG,EAAE,CAAC;IAE3B,8CAA8C;IAC9C,IAAW,cAAc;QACvB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IACD,8CAA8C;IAC9C,IAAW,cAAc,CAAC,KAAK;QAC7B,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAC9B,CAAC;IAEQ,QAAQ;QACf,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,SAAS,CAA2B,CAAC;QAC3E,IAAI,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC;YAAE,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;QAChF,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC;IAEM,SAAS;QACd,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC;QAC3C,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,yCAAyC;IAClC,SAAS;QACd,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;IAC1B,CAAC;IAEM,iBAAiB,CAAC,KAAgC;QACvD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC/E,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,iDAAiD;IAC1C,iBAAiB,CAAC,KAAgC;QACvD,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAEM,qBAAqB,CAAC,KAAgC;QAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC/G,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACxC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,qDAAqD;IAC9C,qBAAqB,CAAC,KAAgC;QAC3D,OAAO,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IAEO,eAAe;QACrB,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,mCAAmC,CAAC,CAAC;QACtF,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACjC,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,UAAU,IAAI,EAAE,IAAI,MAAM,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;oBAChG,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;gBACtC,CAAC;gBACD,IAAI,OAAO,MAAM,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;oBAC/C,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;gBAC9C,CAAC;gBACD,IAAI,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ,IAAI,MAAM,CAAC,cAAc,IAAI,EAAE,IAAI,MAAM,CAAC,cAAc,IAAI,EAAE,EAAE,CAAC;oBAC5G,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;oBAC5C,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC;gBAC/C,CAAC;YACH,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,eAAe;QACrB,MAAM,KAAK,GAAG;YACZ,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC;QACF,cAAc,CAAC,QAAQ,CAAC,mBAAmB,CAAC,mCAAmC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1G,CAAC;IAED,mFAAmF;IAChE,oBAAoB,CAAC,MAA8B,EAAE,OAAgC;QACtG,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAA2B,CAAC;QACzD,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,aAAa,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;YAC3E,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;YAC1B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;IAED,4FAA4F;IACzE,iBAAiB;QAClC,OAAO,uBAAuB,CAAC;YAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,kBAAkB,EAAE,IAAI,CAAC,WAAW;YACpC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;YAChD,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM;YACvD,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM;YACvD,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM;YAC3C,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM;YAC7C,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM;YAC/C,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM;YACjD,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACgB,kBAAkB;QACnC,IAAI,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,IAAI,EAAE;YAC/C;gBACE,IAAI,EAAE,qBAAqB;gBAC3B,WAAW,EACT,6KAA6K;gBAC/K,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uCAAuC,EAAE,EAAE,EAAE;gBACtI,OAAO,EAAE,KAAK,EAAE,MAA+B,EAAE,EAAE;oBACjD,MAAM,KAAK,GAAG,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;oBAChE,IAAI,CAAC,KAAK,CAAC,EAAE;wBAAE,OAAO,KAAK,CAAC,MAAM,CAAC;oBACnC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;oBAC5E,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;oBACvD,IAAI,CAAC,KAAK;wBAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,CAAC;oBAC9G,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAgB,CAAC,CAAC;oBAC3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;gBAChE,CAAC;aACF;YACD;gBACE,IAAI,EAAE,0BAA0B;gBAChC,WAAW,EACT,wLAAwL;gBAC1L,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;gBACnD,OAAO,EAAE,KAAK,IAAI,EAAE;oBAClB,IAAI,CAAC,WAAW,EAAE,CAAC;oBACnB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;gBACrD,CAAC;aACF;SACF,CAAC,CAAC;IACL,CAAC;IAED,oEAAoE;IACpE,IAAW,MAAM,KAAe,OAAO,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtE,sCAAsC;IACtC,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IACM,aAAa,CAAC,KAAa,IAAiB,OAAO,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAElG,6CAA6C;IACtC,aAAa,CAAC,KAAa;QAChC,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;IACD,IAAW,WAAW,KAAa,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAE5F,2CAA2C;IAC3C,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,4GAA4G;IAC5G,IAAW,cAAc;QACvB,MAAM,GAAG,GAA2B;YAClC,IAAI,EAAE,kEAAkE;YACxE,SAAS,EAAE,yDAAyD;YACpE,OAAO,EAAE,uDAAuD;YAChE,WAAW,EAAE,2CAA2C;YACxD,OAAO,EAAE,2CAA2C;SACrD,CAAC;QACF,OAAO,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IACvC,CAAC;IAED,8CAA8C;IAC9C,IAAW,cAAc;QACvB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEM,aAAa,CAAC,GAAe;QAClC,IAAI,IAAI,CAAC,aAAa,KAAK,GAAG;YAAE,OAAO;QACvC,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC;QACzB,IAAI,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,oGAAoG;IAC7F,WAAW,CAAC,GAAe;QAChC,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACjC,KAAK,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,wBAAwB,EAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAClH,CAAC;IACH,CAAC;IAED,2CAA2C;IACpC,WAAW,CAAC,GAAe;QAChC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,oEAAoE;IACpE,IAAW,WAAW,KAAsB,OAAO,IAAI,CAAC,aAAa,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC;IAE5F,2CAA2C;IAC3C,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,IAAW,iBAAiB;QAC1B,OAAQ,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,eAAe,CAAwB,IAAI,2BAA2B,CAAC,oBAAoB,CAAC;IACjI,CAAC;IAED,iDAAiD;IACjD,IAAW,iBAAiB;QAC1B,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IACD,IAAW,aAAa,KAAoB,OAAQ,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,eAAe,CAAwB,IAAI,IAAI,CAAC,CAAC,CAAC;IACjI,IAAW,eAAe,KAAoB,OAAO,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAE7E,+CAA+C;IAC/C,IAAW,eAAe;QACxB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IACD,IAAW,cAAc;QACvB,OAAO,EAAE,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,EAAE,CAAC;IACvJ,CAAC;IAED,8CAA8C;IAC9C,IAAW,cAAc;QACvB,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAEM,UAAU,CAAC,aAAqB;QACrC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,KAAK,IAAI,CAAC,2BAA2B,EAAE,CAAC;QACxC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,0CAA0C;IACnC,UAAU,CAAC,aAAqB;QACrC,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC;IAED,2GAA2G;IACpG,WAAW;QAChB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,KAAK,IAAI,CAAC,2BAA2B,EAAE,CAAC;QACxC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,2CAA2C;IACpC,WAAW;QAChB,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;IAC5B,CAAC;IAEM,SAAS;QACd,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,yCAAyC;IAClC,SAAS;QACd,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;IAC1B,CAAC;IAEM,eAAe,GAAG,KAAK,CAAC;IAE/B,+CAA+C;IAC/C,IAAW,eAAe;QACxB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IACD,+CAA+C;IAC/C,IAAW,eAAe,CAAC,KAAK;QAC9B,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,CAAC;IAEM,qBAAqB;QAC1B,IAAI,CAAC,eAAe,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,qDAAqD;IAC9C,qBAAqB;QAC1B,OAAO,IAAI,CAAC,qBAAqB,EAAE,CAAC;IACtC,CAAC;IAEM,mBAAmB,CAAC,GAAsB;QAC/C,IAAI,GAAG,CAAC,WAAW,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC;YACjE,KAAK,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,wBAAwB,EAAE,QAAQ,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/F,CAAC;aAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YACvB,KAAK,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAED,mDAAmD;IAC5C,mBAAmB,CAAC,GAAsB;QAC/C,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,wHAAwH;IACjH,yBAAyB,CAAC,KAAsE;QACrG,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC;QAClD,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAAC;QAC3C,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC,qBAAqB,GAAG,KAAK,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,yDAAyD;IAClD,yBAAyB,CAAC,KAAsE;QACrG,OAAO,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED,iGAAiG;IAC1F,4BAA4B;QACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC;IAED,4DAA4D;IACrD,4BAA4B;QACjC,OAAO,IAAI,CAAC,4BAA4B,EAAE,CAAC;IAC7C,CAAC;IAEO,KAAK,CAAC,2BAA2B;QACvC,IAAI,IAAI,CAAC,gBAAgB;YAAE,OAAO;QAClC,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,WAAW,IAAI,SAAS,CAAC,CAAC;YACvF,IAAI,CAAC,gBAAgB;gBACnB,YAAY,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,oBAAoB,CAAC,WAAW,EAAE,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC;YAC7H,IAAI,CAAC,IAAI,CAAC,gBAAgB;gBAAE,QAAQ,CAAC,sBAAsB,oBAAoB,gDAAgD,CAAC,CAAC;YACjI,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,iDAAiD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChH,CAAC;IACH,CAAC;iRAvdU,yBAAyB,yBAAzB,yBAAyB;6DAAzB,yBAAyB;;;;;;YAhKlC,6CAC0B;YAC1B,gDAAuD;YAYnD,AATA,AAFF,kGAAiB,sEAEO,uEASf;YAoFX,iBAAwB;;YAlGuB,AAAtB,uCAAqB,gCAA4B;YAEnD,cAAa;YAAC,AAAd,2BAAa,kBAAkB;YACpD,cA8FC;YA9FD,2DA8FC;;;AA+DM,yBAAyB;IArKrC,aAAa,CAAC,qBAAqB,EAAE,gCAAgC,CAAC;GAqK1D,yBAAyB,CAwdrC;;iFAxdY,yBAAyB;cApKrC,SAAS;6BACI,KAAK,YACP,uBAAuB,YACvB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoGT,mBA2DgB,uBAAuB,CAAC,MAAM;;kBAsB9C,SAAS;mBAAC,eAAe;;kFApBf,yBAAyB;AA0dtC,wGAAwG;AACxG,MAAM,UAAU,oBAAoB;IAClC,sBAAsB;AACxB,CAAC","sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewChild, inject } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { LogError, UserInfo } from '@memberjunction/core';\nimport { MJConversationEntity, MJEnvironmentEntityExtended, MJMLAlgorithmEntity, UserInfoEngine } from '@memberjunction/core-entities';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { PSResourceBase } from './ps-resource-base';\nimport { PSPanelKey } from '../predictive-studio.types';\nimport { PSPipelinesComponent } from '../components/ps-pipelines.component';\nimport {\n STUDIO_SECTIONS,\n PSSection,\n sectionGroups,\n sectionsInGroup,\n sectionLabel,\n hasSection,\n routeHomeNavigate,\n} from '../predictive-studio.nav';\nimport {\n buildStudioAgentContext,\n resolvePSRecord,\n buildPSNotFoundError,\n} from '../predictive-studio-agent-context';\nimport { validateStringParam } from '../../shared/agent-tool-validation';\nimport type { NavigationRequest } from '@memberjunction/ng-artifacts';\n\n/** Predictive Studio application ID (from `metadata/applications/.predictive-studio-application.json`). */\nconst PREDICTIVE_STUDIO_APP_ID = '299C9272-8D38-40CA-85D4-0980F2C9FAD1';\nconst MODEL_DEV_AGENT_NAME = 'Model Development Agent';\n\n/**\n * **Studio** — the analyst workbench door (one of Predictive Studio's three consolidated nav items,\n * alongside `Predictions` and `Models`). Hosts the build/run section panels (`ps-home`, `ps-pipelines`,\n * `ps-catalog`, `ps-experiments`, `ps-compare`) behind an internal left-nav grouped by lifecycle\n * (Overview · Build · Run), so the outer app nav stays quiet while analysts get all the depth one click\n * in. The active section round-trips through the `section` query param (deep links + back/forward). A\n * single docked **Model Development Agent** copilot is shared by every section's \"Ask the agent\" CTA —\n * wired with the full conversation lifecycle (`isNewConversation` → `conversationCreated`) so the first\n * message actually creates + sends. Cross-door navigation (to a Models section) routes via the nav\n * service; see {@link routeHomeNavigate}.\n */\n@RegisterClass(BaseResourceComponent, 'PredictiveStudioStudioResource')\n@Component({\n standalone: false,\n selector: 'mj-ps-studio-resource',\n template: `\n <mj-page-header-interior [Title]=\"activeLabel\" [Subtitle]=\"activeSubtitle\">\n </mj-page-header-interior>\n <mj-page-body-interior [Flex]=\"true\" [Padding]=\"false\">\n @if (isLoading) {\n <mj-loading text=\"Loading Studio…\" size=\"medium\"></mj-loading>\n } @else if (loadError) {\n <div class=\"ps-load-error\" data-testid=\"ps-load-error\" role=\"alert\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n <div class=\"ps-load-error-text\">\n <strong>Couldn't load {{ sectionTitle }}</strong>\n <span class=\"ps-load-error-detail\">{{ loadError }}</span>\n </div>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"retryLoad()\"><i class=\"fa-solid fa-rotate-right\"></i> Try again</button>\n </div>\n } @else {\n <div class=\"ps-studio-host\" [class.nav-collapsed]=\"isNavCollapsed\" [class.chat-open]=\"chatOpen\" data-testid=\"ps-studio-shell\">\n @if (isNavCollapsed) {\n <div class=\"ps-nav-collapsed-strip\" role=\"region\" aria-label=\"Studio navigation (collapsed)\">\n <button class=\"ps-nav-rail-collapse\" type=\"button\" (click)=\"toggleNav()\" aria-label=\"Expand studio navigation\" title=\"Expand navigation\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </button>\n <div class=\"ps-nav-collapsed-strip-label\"><i class=\"fa-solid fa-flask-vial\"></i> Studio</div>\n </div>\n }\n\n <as-split direction=\"horizontal\" class=\"studio-outer-splitter\" unit=\"percent\" [gutterSize]=\"isNavCollapsed ? 0 : 6\" (dragEnd)=\"onNavSplitDragEnd($event.sizes)\">\n @if (!isNavCollapsed) {\n <as-split-area [size]=\"navSizePct\" [minSize]=\"10\" [maxSize]=\"30\">\n <aside class=\"ps-leftnav\">\n <div class=\"ps-leftnav-header\">\n <span class=\"ps-leftnav-title\">Studio</span>\n <button class=\"ps-leftnav-collapse-btn\" type=\"button\" (click)=\"toggleNav()\" title=\"Collapse navigation\" aria-label=\"Collapse navigation\">\n <i class=\"fa-solid fa-chevron-left\"></i>\n </button>\n </div>\n @for (group of groups; track group) {\n @if (group) { <div class=\"ps-nav-group\">{{ group }}</div> }\n @for (item of itemsForGroup(group); track item.key) {\n <button class=\"ps-nav-item\" [class.active]=\"activeSection === item.key\"\n [attr.data-testid]=\"'ps-nav-' + item.key\" (click)=\"selectSection(item.key)\">\n <i [class]=\"item.icon\"></i> <span>{{ item.label }}</span>\n </button>\n }\n }\n </aside>\n </as-split-area>\n }\n\n <as-split-area [size]=\"isNavCollapsed ? 100 : (100 - navSizePct)\" [minSize]=\"60\">\n <div class=\"ps-studio-workspace\">\n <as-split direction=\"horizontal\" class=\"studio-copilot-splitter\" unit=\"percent\" [gutterSize]=\"chatOpen ? 6 : 0\" (dragEnd)=\"onCopilotSplitDragEnd($event.sizes)\">\n <as-split-area [size]=\"chatOpen ? (copilotExpanded ? 40 : mainSizePct) : 100\" [minSize]=\"30\">\n <section class=\"ps-content\" [class.fill]=\"activeSection === 'pipelines'\" [attr.data-testid]=\"'ps-panel-' + activeSection\">\n @switch (activeSection) {\n @case ('home') { <ps-home [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (navigate)=\"mapNavigate($event)\" (askAgent)=\"onAskAgent($event)\"></ps-home> }\n @case ('pipelines') { <ps-pipelines #pipelinesComp [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\" (askAgent)=\"onAskAgent($event)\" (navigate)=\"mapNavigate($event)\"></ps-pipelines> }\n @case ('catalog') { <ps-catalog [engine]=\"engine\" (askAgent)=\"onAskAgent($event)\" (createPipeline)=\"onCreatePipelineFromCatalog($event)\"></ps-catalog> }\n @case ('experiments') { <ps-experiments [engine]=\"engine\" [provider]=\"ProviderToUse\" [currentUser]=\"ProviderToUse.CurrentUser\"></ps-experiments> }\n @case ('compare') { <ps-compare [engine]=\"engine\"></ps-compare> }\n }\n </section>\n </as-split-area>\n\n @if (chatOpen) {\n <as-split-area [size]=\"copilotExpanded ? 60 : copilotSizePct\" [minSize]=\"20\" [maxSize]=\"70\">\n <aside class=\"ps-copilot\" [class.expanded]=\"copilotExpanded\" data-testid=\"ps-studio-copilot\">\n <div class=\"ps-copilot-head\">\n <div class=\"ps-copilot-title\"><i class=\"fa-solid fa-robot\"></i> Model Dev Agent</div>\n <div class=\"ps-copilot-actions\">\n <button class=\"ps-copilot-btn\" (click)=\"toggleCopilotExpanded()\" [title]=\"copilotExpanded ? 'Collapse panel' : 'Expand panel'\"><i class=\"fa-solid\" [class.fa-up-right-and-down-left-from-center]=\"!copilotExpanded\" [class.fa-down-left-and-up-right-to-center]=\"copilotExpanded\"></i></button>\n <button class=\"ps-copilot-close\" (click)=\"closeChat()\" aria-label=\"Close agent chat\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n </div>\n <div class=\"ps-copilot-body\">\n @if (currentUser) {\n <mj-conversation-chat-area\n [Provider]=\"Provider\" [environmentId]=\"chatEnvironmentId\" [currentUser]=\"currentUser\"\n [conversation]=\"chatConversation\" [conversationId]=\"chatConversationId\" [isNewConversation]=\"chatIsNewConversation\"\n [suppressNewConversationEmptyState]=\"true\" [allowMentions]=\"false\" [overlayMode]=\"false\"\n [showExportButton]=\"false\" [showShareButton]=\"false\" [showArtifactIndicator]=\"true\"\n [showAgentPicker]=\"false\" [showAgentModePicker]=\"false\"\n [defaultAgentId]=\"modelDevAgentId\" [pendingMessage]=\"pendingPrompt\"\n [applicationScope]=\"'Application'\" [applicationId]=\"applicationId\" [appContext]=\"chatAppContext\"\n (conversationCreated)=\"onChatConversationCreated($event)\"\n (pendingMessageConsumed)=\"onChatPendingMessageConsumed()\"\n (navigationRequest)=\"onNavigationRequest($event)\">\n </mj-conversation-chat-area>\n } @else { <div class=\"ps-copilot-empty\"><mj-loading text=\"Connecting…\" size=\"small\"></mj-loading></div> }\n </div>\n </aside>\n </as-split-area>\n }\n </as-split>\n </div>\n </as-split-area>\n </as-split>\n </div>\n }\n </mj-page-body-interior>\n `,\n styles: [\n `\n :host { display: flex; flex-direction: column; width: 100%; height: 100%; min-height: 0; }\n .ps-studio-host { display: flex; flex: 1; min-height: 0; overflow: hidden; width: 100%; height: 100%; }\n .studio-outer-splitter { flex: 1; width: 100%; height: 100%; min-height: 0; min-width: 0; background: transparent; }\n .studio-outer-splitter .as-split-gutter { background: transparent; transition: background-color 0.15s ease; position: relative; }\n .studio-outer-splitter .as-split-gutter:hover { background-color: var(--mj-brand-primary, #6366f1); }\n .studio-outer-splitter .as-split-gutter::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 2px; height: 24px; border-radius: 1px; background: var(--mj-border-strong, #cbd5e1); }\n .studio-outer-splitter .as-split-gutter:hover::after { background: #ffffff; }\n\n .ps-nav-collapsed-strip { width: 44px; min-width: 44px; max-width: 44px; flex: none; background: var(--mj-bg-surface); border-right: 1px solid var(--mj-border-default); display: flex; flex-direction: column; align-items: center; padding: 10px 0; gap: 14px; z-index: 2; }\n .ps-nav-rail-collapse { background: var(--mj-bg-surface-subtle); border: 1px solid var(--mj-border-default); border-radius: 6px; color: var(--mj-text-secondary); cursor: pointer; display: grid; place-items: center; width: 28px; height: 28px; padding: 0; font-size: 11px; transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease; }\n .ps-nav-rail-collapse:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); border-color: var(--mj-border-strong); }\n .ps-nav-collapsed-strip-label { writing-mode: vertical-rl; transform: rotate(180deg); font-size: 11px; font-weight: 600; letter-spacing: 0.04em; color: var(--mj-text-muted); display: flex; align-items: center; gap: 8px; text-transform: uppercase; }\n\n .ps-leftnav { width: 100%; height: 100%; border-right: 1px solid var(--mj-border-default); background: var(--mj-bg-surface-card); overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 2px; box-sizing: border-box; }\n .ps-leftnav-header { display: flex; align-items: center; justify-content: space-between; padding: 4px 6px 8px; border-bottom: 1px solid var(--mj-border-subtle); margin-bottom: 4px; }\n .ps-leftnav-title { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--mj-text-muted); }\n .ps-leftnav-collapse-btn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 6px; border: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); color: var(--mj-text-muted); cursor: pointer; transition: all 0.15s ease; padding: 0; }\n .ps-leftnav-collapse-btn:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); border-color: var(--mj-border-strong); }\n\n .ps-nav-group { font-size: var(--mj-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--mj-text-muted); padding: 10px 8px 4px; }\n .ps-nav-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; border-radius: var(--mj-radius-md); cursor: pointer; color: var(--mj-text-secondary); font-size: var(--mj-text-sm); font-weight: 500; transition: background .12s, color .12s; }\n .ps-nav-item i { width: 18px; text-align: center; color: var(--mj-text-muted); }\n .ps-nav-item:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-primary); }\n .ps-nav-item.active { background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); color: var(--mj-brand-primary); font-weight: 600; }\n .ps-nav-item.active i { color: var(--mj-brand-primary); }\n\n .ps-studio-workspace { display: flex; flex: 1; width: 100%; height: 100%; min-height: 0; min-width: 0; overflow: hidden; }\n .studio-copilot-splitter { flex: 1; width: 100%; height: 100%; min-height: 0; min-width: 0; }\n .studio-copilot-splitter .as-split-gutter { background: transparent; transition: background-color 0.15s ease; position: relative; }\n .studio-copilot-splitter .as-split-gutter:hover { background-color: var(--mj-brand-primary, #6366f1); }\n .studio-copilot-splitter .as-split-gutter::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 2px; height: 24px; border-radius: 1px; background: var(--mj-border-strong, #cbd5e1); }\n .ps-content { width: 100%; height: 100%; flex: 1; min-width: 0; overflow-y: auto; padding: 8px 14px 24px; }\n /* Fill mode (pipelines): the section stops page-scrolling so the panel's inner\n columns (canvas / inspector) can each own their scrollbar. */\n .ps-content.fill { overflow: hidden; display: flex; flex-direction: column; padding-bottom: 14px; }\n .ps-content.fill > * { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .ps-copilot { width: 100%; height: 100%; max-width: none; flex: 1; border-left: 1px solid var(--mj-border-default); background: var(--mj-bg-surface); display: flex; flex-direction: column; min-height: 0; }\n .ps-copilot-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--mj-border-default); }\n .ps-copilot-title { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--mj-text-primary); }\n .ps-copilot-title i { color: var(--mj-brand-primary); }\n .ps-copilot-actions { display: flex; align-items: center; gap: 4px; }\n .ps-copilot-btn { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-btn:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-close { background: transparent; border: none; cursor: pointer; padding: 6px 8px; border-radius: 6px; color: var(--mj-text-muted); }\n .ps-copilot-close:hover { background: var(--mj-bg-surface-hover); color: var(--mj-text-secondary); }\n .ps-copilot-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }\n .ps-copilot-body mj-conversation-chat-area { flex: 1; min-height: 0; display: block; }\n .ps-copilot-empty { display: flex; align-items: center; justify-content: center; flex: 1; }\n .ps-load-error { display: flex; align-items: center; gap: 14px; max-width: 620px; margin: 32px auto; padding: 18px 20px; border: 1px solid var(--mj-status-error-border); background: var(--mj-status-error-bg); border-radius: var(--mj-radius-lg); }\n .ps-load-error > i { font-size: 24px; color: var(--mj-status-error); }\n .ps-load-error-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }\n .ps-load-error-text strong { color: var(--mj-text-primary); }\n .ps-load-error-detail { color: var(--mj-text-secondary); font-size: var(--mj-text-sm); word-break: break-word; }\n @media (max-width: 1100px) { .ps-studio-host.chat-open .ps-content, .ps-studio-host.chat-open .ps-leftnav { display: none; } .ps-copilot { width: 100%; max-width: none; border-left: none; } }\n `,\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PSStudioResourceComponent extends PSResourceBase {\n protected readonly SectionKey = 'studio';\n protected readonly SectionLabel = 'Studio';\n protected readonly SectionIcon = 'fa-solid fa-flask-vial';\n\n private readonly cdrLocal = inject(ChangeDetectorRef);\n\n /** The active workbench section (which panel renders). Round-trips through the `section` query param. */\n public ActiveSection: PSPanelKey = 'home';\n\n /** @deprecated Use {@link ActiveSection}. */\n public get activeSection(): PSPanelKey {\n return this.ActiveSection;\n }\n /** @deprecated Use {@link ActiveSection}. */\n public set activeSection(value: PSPanelKey) {\n this.ActiveSection = value;\n }\n public readonly sections: readonly PSSection[] = STUDIO_SECTIONS;\n\n @ViewChild('pipelinesComp') PipelinesComponent?: PSPipelinesComponent;\n\n /** @deprecated Use {@link PipelinesComponent}. */\n get pipelinesComponent(): PSPipelinesComponent | undefined {\n return this.PipelinesComponent;\n }\n /** @deprecated Use {@link PipelinesComponent}. */\n set pipelinesComponent(value: PSPipelinesComponent | undefined) {\n this.PipelinesComponent = value;\n }\n\n public OnCreatePipelineFromCatalog(algo: MJMLAlgorithmEntity): void {\n this.selectSection('pipelines');\n setTimeout(() => {\n this.PipelinesComponent?.openWizard(algo.ID);\n }, 50);\n }\n\n /** @deprecated Use {@link OnCreatePipelineFromCatalog}. */\n public onCreatePipelineFromCatalog(algo: MJMLAlgorithmEntity): void {\n return this.OnCreatePipelineFromCatalog(algo);\n }\n\n // ── docked Model Dev Agent copilot ───────────────────────────────\n public ChatOpen = false;\n\n /** @deprecated Use {@link ChatOpen}. */\n public get chatOpen() {\n return this.ChatOpen;\n }\n /** @deprecated Use {@link ChatOpen}. */\n public set chatOpen(value) {\n this.ChatOpen = value;\n }\n public PendingPrompt: string | null = null;\n\n /** @deprecated Use {@link PendingPrompt}. */\n public get pendingPrompt(): string | null {\n return this.PendingPrompt;\n }\n /** @deprecated Use {@link PendingPrompt}. */\n public set pendingPrompt(value: string | null) {\n this.PendingPrompt = value;\n }\n private _modelDevAgentId: string | null = null;\n /** Conversation lifecycle (see {@link onChatConversationCreated}) — without it the first send no-ops. */\n public ChatConversation: MJConversationEntity | null = null;\n\n /** @deprecated Use {@link ChatConversation}. */\n public get chatConversation(): MJConversationEntity | null {\n return this.ChatConversation;\n }\n /** @deprecated Use {@link ChatConversation}. */\n public set chatConversation(value: MJConversationEntity | null) {\n this.ChatConversation = value;\n }\n public ChatConversationId: string | null = null;\n\n /** @deprecated Use {@link ChatConversationId}. */\n public get chatConversationId(): string | null {\n return this.ChatConversationId;\n }\n /** @deprecated Use {@link ChatConversationId}. */\n public set chatConversationId(value: string | null) {\n this.ChatConversationId = value;\n }\n public ChatIsNewConversation = true;\n\n /** @deprecated Use {@link ChatIsNewConversation}. */\n public get chatIsNewConversation() {\n return this.ChatIsNewConversation;\n }\n /** @deprecated Use {@link ChatIsNewConversation}. */\n public set chatIsNewConversation(value) {\n this.ChatIsNewConversation = value;\n }\n public IsNavCollapsed = false;\n\n /** @deprecated Use {@link IsNavCollapsed}. */\n public get isNavCollapsed() {\n return this.IsNavCollapsed;\n }\n /** @deprecated Use {@link IsNavCollapsed}. */\n public set isNavCollapsed(value) {\n this.IsNavCollapsed = value;\n }\n public NavSizePct = 14;\n\n /** @deprecated Use {@link NavSizePct}. */\n public get navSizePct() {\n return this.NavSizePct;\n }\n /** @deprecated Use {@link NavSizePct}. */\n public set navSizePct(value) {\n this.NavSizePct = value;\n }\n public MainSizePct = 68;\n\n /** @deprecated Use {@link MainSizePct}. */\n public get mainSizePct() {\n return this.MainSizePct;\n }\n /** @deprecated Use {@link MainSizePct}. */\n public set mainSizePct(value) {\n this.MainSizePct = value;\n }\n public CopilotSizePct = 32;\n\n /** @deprecated Use {@link CopilotSizePct}. */\n public get copilotSizePct() {\n return this.CopilotSizePct;\n }\n /** @deprecated Use {@link CopilotSizePct}. */\n public set copilotSizePct(value) {\n this.CopilotSizePct = value;\n }\n\n override ngOnInit(): void {\n super.ngOnInit();\n const initial = this.GetQueryParams()['section'] as PSPanelKey | undefined;\n if (initial && hasSection(this.sections, initial)) this.ActiveSection = initial;\n this.loadLayoutPrefs();\n }\n\n public ToggleNav(): void {\n this.IsNavCollapsed = !this.IsNavCollapsed;\n this.saveLayoutPrefs();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link ToggleNav}. */\n public toggleNav(): void {\n return this.ToggleNav();\n }\n\n public OnNavSplitDragEnd(sizes: readonly (number | '*')[]): void {\n if (Array.isArray(sizes) && sizes.length === 2 && typeof sizes[0] === 'number') {\n this.NavSizePct = Math.round(sizes[0]);\n this.saveLayoutPrefs();\n }\n }\n\n /** @deprecated Use {@link OnNavSplitDragEnd}. */\n public onNavSplitDragEnd(sizes: readonly (number | '*')[]): void {\n return this.OnNavSplitDragEnd(sizes);\n }\n\n public OnCopilotSplitDragEnd(sizes: readonly (number | '*')[]): void {\n if (Array.isArray(sizes) && sizes.length === 2 && typeof sizes[0] === 'number' && typeof sizes[1] === 'number') {\n this.MainSizePct = Math.round(sizes[0]);\n this.CopilotSizePct = Math.round(sizes[1]);\n this.saveLayoutPrefs();\n }\n }\n\n /** @deprecated Use {@link OnCopilotSplitDragEnd}. */\n public onCopilotSplitDragEnd(sizes: readonly (number | '*')[]): void {\n return this.OnCopilotSplitDragEnd(sizes);\n }\n\n private loadLayoutPrefs(): void {\n const saved = UserInfoEngine.Instance.GetSetting('mj.predictiveStudio.studio.layout');\n if (saved) {\n try {\n const parsed = JSON.parse(saved);\n if (typeof parsed.navSizePct === 'number' && parsed.navSizePct >= 10 && parsed.navSizePct <= 35) {\n this.NavSizePct = parsed.navSizePct;\n }\n if (typeof parsed.isNavCollapsed === 'boolean') {\n this.IsNavCollapsed = parsed.isNavCollapsed;\n }\n if (typeof parsed.copilotSizePct === 'number' && parsed.copilotSizePct >= 20 && parsed.copilotSizePct <= 60) {\n this.CopilotSizePct = parsed.copilotSizePct;\n this.MainSizePct = 100 - this.CopilotSizePct;\n }\n } catch {}\n }\n }\n\n private saveLayoutPrefs(): void {\n const prefs = {\n navSizePct: this.NavSizePct,\n isNavCollapsed: this.IsNavCollapsed,\n copilotSizePct: this.CopilotSizePct,\n mainSizePct: this.MainSizePct,\n };\n UserInfoEngine.Instance.SetSettingDebounced('mj.predictiveStudio.studio.layout', JSON.stringify(prefs));\n }\n\n /** React to deep-link / back-forward `section` changes after the initial mount. */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n const next = params['section'] as PSPanelKey | undefined;\n if (next && next !== this.ActiveSection && hasSection(this.sections, next)) {\n this.ActiveSection = next;\n this.cdrLocal.detectChanges();\n }\n }\n\n /** Deep agent context for the Studio door (build/run workbench counts + active section). */\n protected override extraAgentContext(): Record<string, unknown> {\n return buildStudioAgentContext({\n ActiveSection: this.ActiveSection,\n ActiveSectionLabel: this.ActiveLabel,\n SectionLabels: this.sections.map((s) => s.label),\n PublishedModelCount: this.engine.PublishedModels.length,\n RunningSessionCount: this.engine.RunningSessions.length,\n PipelineCount: this.engine.Pipelines.length,\n AlgorithmCount: this.engine.Algorithms.length,\n ExperimentCount: this.engine.Experiments.length,\n TrainingRunCount: this.engine.TrainingRuns.length,\n ChatOpen: this.ChatOpen,\n });\n }\n\n /**\n * 🔒 Read/navigate-only agent tools for the Studio door: switch the active section, or open the docked\n * Model Dev Agent co-pilot. NO build/train/publish tool is exposed — model creation runs through the\n * co-pilot conversation (the approve-gated builder), never a fire-and-forget agent tool.\n */\n protected override registerAgentTools(): void {\n this.navigationService.SetAgentClientTools(this, [\n {\n Name: 'SwitchStudioSection',\n Description:\n 'Switch the Studio workbench to a section. Pass the section key or label (see SectionLabels): Overview, Training Pipelines, Algorithm Catalog, Experiments, or Compare Runs.',\n ParameterSchema: { type: 'object', properties: { section: { type: 'string', description: 'The section key or label to switch to' } } },\n Handler: async (params: Record<string, unknown>) => {\n const check = validateStringParam(params['section'], 'section');\n if (!check.ok) return check.result;\n const candidates = this.sections.map((s) => ({ ID: s.key, Name: s.label }));\n const match = resolvePSRecord(check.value, candidates);\n if (!match) return { Success: false, ErrorMessage: buildPSNotFoundError(check.value, candidates, 'section') };\n this.selectSection(match.ID as PSPanelKey);\n return { Success: true, Data: { activeSection: match.Name } };\n },\n },\n {\n Name: 'OpenModelDevAgentCopilot',\n Description:\n 'Open the docked Model Development Agent co-pilot in the Studio (does not send a message — the user drives the conversation). Use when the user wants to design/build a new prediction.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n this.OpenCopilot();\n return { Success: true, Data: { chatOpen: true } };\n },\n },\n ]);\n }\n\n // ── left-nav ─────────────────────────────────────────────────────\n public get Groups(): string[] { return sectionGroups(this.sections); }\n\n /** @deprecated Use {@link Groups}. */\n public get groups(): string[] {\n return this.Groups;\n }\n public ItemsForGroup(group: string): PSSection[] { return sectionsInGroup(this.sections, group); }\n\n /** @deprecated Use {@link ItemsForGroup}. */\n public itemsForGroup(group: string): PSSection[] {\n return this.ItemsForGroup(group);\n }\n public get ActiveLabel(): string { return sectionLabel(this.sections, this.ActiveSection); }\n\n /** @deprecated Use {@link ActiveLabel}. */\n public get activeLabel(): string {\n return this.ActiveLabel;\n }\n\n /** Section-specific subtitle for the interior header (so every section doesn't repeat one generic line). */\n public get ActiveSubtitle(): string {\n const map: Record<string, string> = {\n home: 'Start a new prediction from your data, a template, or the agent.',\n pipelines: 'Assemble features and train from the algorithm catalog.',\n catalog: 'Browse algorithms with a fit guide for your use case.',\n experiments: 'Review earlier model experiment sessions.',\n compare: 'Compare runs on the honest holdout score.',\n };\n return map[this.ActiveSection] ?? '';\n }\n\n /** @deprecated Use {@link ActiveSubtitle}. */\n public get activeSubtitle(): string {\n return this.ActiveSubtitle;\n }\n\n public selectSection(key: PSPanelKey): void {\n if (this.ActiveSection === key) return;\n this.ActiveSection = key;\n this.UpdateQueryParams({ section: key });\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** The Overview panel's in-app navigation: switch section in-place, or cross to the Models door. */\n public MapNavigate(key: PSPanelKey): void {\n const target = routeHomeNavigate(key);\n if (target.Kind === 'section') {\n this.selectSection(target.Key);\n } else if (target.Kind === 'app') {\n void this.navigationService.SwitchToApp(PREDICTIVE_STUDIO_APP_ID, target.NavLabel, { section: target.Section });\n }\n }\n\n /** @deprecated Use {@link MapNavigate}. */\n public mapNavigate(key: PSPanelKey): void {\n return this.MapNavigate(key);\n }\n\n // ── copilot ──────────────────────────────────────────────────────\n public get CurrentUser(): UserInfo | null { return this.ProviderToUse.CurrentUser ?? null; }\n\n /** @deprecated Use {@link CurrentUser}. */\n public get currentUser(): UserInfo | null {\n return this.CurrentUser;\n }\n\n public get ChatEnvironmentId(): string {\n return (this.Data?.Configuration?.['environmentId'] as string | undefined) || MJEnvironmentEntityExtended.DefaultEnvironmentID;\n }\n\n /** @deprecated Use {@link ChatEnvironmentId}. */\n public get chatEnvironmentId(): string {\n return this.ChatEnvironmentId;\n }\n public get applicationId(): string | null { return (this.Data?.Configuration?.['applicationId'] as string | undefined) ?? null; }\n public get ModelDevAgentId(): string | null { return this._modelDevAgentId; }\n\n /** @deprecated Use {@link ModelDevAgentId}. */\n public get modelDevAgentId(): string | null {\n return this.ModelDevAgentId;\n }\n public get ChatAppContext(): Record<string, unknown> {\n return { app: 'Predictive Studio', section: this.ActiveSection, publishedModels: this.engine.Models.filter((m) => m.Status === 'Published').length };\n }\n\n /** @deprecated Use {@link ChatAppContext}. */\n public get chatAppContext(): Record<string, unknown> {\n return this.ChatAppContext;\n }\n\n public OnAskAgent(starterPrompt: string): void {\n this.PendingPrompt = starterPrompt;\n this.ChatOpen = true;\n void this.ensureModelDevAgentResolved();\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OnAskAgent}. */\n public onAskAgent(starterPrompt: string): void {\n return this.OnAskAgent(starterPrompt);\n }\n\n /** Open the docked co-pilot (clean chat) — used by the read-only `OpenModelDevAgentCopilot` agent tool. */\n public OpenCopilot(): void {\n this.PendingPrompt = null;\n this.ChatOpen = true;\n void this.ensureModelDevAgentResolved();\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OpenCopilot}. */\n public openCopilot(): void {\n return this.OpenCopilot();\n }\n\n public CloseChat(): void {\n this.ChatOpen = false;\n this.PendingPrompt = null;\n this.CopilotExpanded = false;\n this.publishAgentContext();\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link CloseChat}. */\n public closeChat(): void {\n return this.CloseChat();\n }\n\n public CopilotExpanded = false;\n\n /** @deprecated Use {@link CopilotExpanded}. */\n public get copilotExpanded() {\n return this.CopilotExpanded;\n }\n /** @deprecated Use {@link CopilotExpanded}. */\n public set copilotExpanded(value) {\n this.CopilotExpanded = value;\n }\n\n public ToggleCopilotExpanded(): void {\n this.CopilotExpanded = !this.CopilotExpanded;\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link ToggleCopilotExpanded}. */\n public toggleCopilotExpanded(): void {\n return this.ToggleCopilotExpanded();\n }\n\n public OnNavigationRequest(req: NavigationRequest): void {\n if (req.navItemName === 'Models' || req.queryParams?.['modelId']) {\n void this.navigationService.SwitchToApp(PREDICTIVE_STUDIO_APP_ID, 'Models', req.queryParams);\n } else if (req.appName) {\n void this.navigationService.SwitchToApp(req.appName, req.navItemName, req.queryParams);\n }\n }\n\n /** @deprecated Use {@link OnNavigationRequest}. */\n public onNavigationRequest(req: NavigationRequest): void {\n return this.OnNavigationRequest(req);\n }\n\n /** Chat-area created its backing conversation on the first send — capture it + leave new-mode so the thread renders. */\n public OnChatConversationCreated(event: { conversation: MJConversationEntity; pendingMessage?: string }): void {\n this.PendingPrompt = event.pendingMessage ?? null;\n this.ChatConversation = event.conversation;\n this.ChatConversationId = event.conversation.ID;\n this.ChatIsNewConversation = false;\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OnChatConversationCreated}. */\n public onChatConversationCreated(event: { conversation: MJConversationEntity; pendingMessage?: string }): void {\n return this.OnChatConversationCreated(event);\n }\n\n /** Chat-area delivered the seeded prompt — clear the buffer so a re-render doesn't resend it. */\n public OnChatPendingMessageConsumed(): void {\n this.PendingPrompt = null;\n this.cdrLocal.detectChanges();\n }\n\n /** @deprecated Use {@link OnChatPendingMessageConsumed}. */\n public onChatPendingMessageConsumed(): void {\n return this.OnChatPendingMessageConsumed();\n }\n\n private async ensureModelDevAgentResolved(): Promise<void> {\n if (this._modelDevAgentId) return;\n try {\n await AIEngineBase.Instance.Config(false, this.ProviderToUse.CurrentUser ?? undefined);\n this._modelDevAgentId =\n AIEngineBase.Instance.Agents?.find((a) => a.Name?.trim().toLowerCase() === MODEL_DEV_AGENT_NAME.toLowerCase())?.ID ?? null;\n if (!this._modelDevAgentId) LogError(`PSStudioResource: '${MODEL_DEV_AGENT_NAME}' not found — chat uses default-agent routing.`);\n this.cdrLocal.detectChanges();\n } catch (err) {\n LogError(`PSStudioResource.ensureModelDevAgentResolved: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n\n/** Tree-shaking prevention — called from the subpath module so the @RegisterClass survives bundling. */\nexport function LoadPSStudioResource(): void {\n // intentionally empty\n}\n"]}
|
|
@@ -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']
|