@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,4 +1,4 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, inject, } from '@angular/core';
|
|
1
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject, } from '@angular/core';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import { FormsModule } from '@angular/forms';
|
|
4
4
|
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
@@ -6,14 +6,14 @@ import { NavigationService } from '@memberjunction/ng-shared';
|
|
|
6
6
|
import { MJButtonDirective, MJViewToggleComponent, MjSlidePanelComponent, } from '@memberjunction/ng-ui-components';
|
|
7
7
|
import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
|
|
8
8
|
import { CompositeKey, LogError, RunView } from '@memberjunction/core';
|
|
9
|
-
import { NormalizeUUID, UUIDsEqual } from '@memberjunction/global';
|
|
9
|
+
import { EscapeSQLString, NormalizeUUID, UUIDsEqual } from '@memberjunction/global';
|
|
10
10
|
import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
11
11
|
import { AgGridModule } from 'ag-grid-angular';
|
|
12
12
|
import { AllCommunityModule, ModuleRegistry, themeAlpine, } from 'ag-grid-community';
|
|
13
|
-
import {
|
|
14
|
-
import { resolveOutcomeConfig, resolveScoreBand, resolveOutcomeStyle, formatPredictionScore, } from '@memberjunction/predictive-studio-core';
|
|
13
|
+
import { AtRiskRules, ProblemTypes, resolveOutcomeConfig, ResolveScoreBand, resolveOutcomeStyle, formatPredictionScore, } from '@memberjunction/predictive-studio-core';
|
|
15
14
|
import { PredictiveStudioScoreHistoryService, } from '../predictive-studio-score-history.service';
|
|
16
15
|
import { PredictiveStudioEngine } from '../engine/predictive-studio.engine';
|
|
16
|
+
import { PSRowDriversComponent } from './ps-row-drivers.component';
|
|
17
17
|
import * as i0 from "@angular/core";
|
|
18
18
|
import * as i1 from "@memberjunction/ng-shared-generic";
|
|
19
19
|
import * as i2 from "ag-grid-angular";
|
|
@@ -104,7 +104,16 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_7_T
|
|
|
104
104
|
} if (rf & 2) {
|
|
105
105
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
106
106
|
i0.ɵɵadvance();
|
|
107
|
-
i0.ɵɵtextInterpolate2("Filtered by ", ctx_r1.
|
|
107
|
+
i0.ɵɵtextInterpolate2("Filtered by ", ctx_r1.SelectedTierLabel, "", ctx_r1.searchText ? " query \"" + ctx_r1.searchText + "\"" : "");
|
|
108
|
+
} }
|
|
109
|
+
function PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
110
|
+
i0.ɵɵelementStart(0, "span", 36);
|
|
111
|
+
i0.ɵɵtext(1);
|
|
112
|
+
i0.ɵɵelementEnd();
|
|
113
|
+
} if (rf & 2) {
|
|
114
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
115
|
+
i0.ɵɵadvance();
|
|
116
|
+
i0.ɵɵtextInterpolate1("Showing the first ", ctx_r1.MaxRunDetailRowsLabel, " predictions");
|
|
108
117
|
} }
|
|
109
118
|
function PSPredictionsGridComponent_Conditional_25_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
110
119
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
@@ -119,8 +128,9 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_0_Template(rf, ct
|
|
|
119
128
|
i0.ɵɵtext(6);
|
|
120
129
|
i0.ɵɵelementEnd();
|
|
121
130
|
i0.ɵɵconditionalCreate(7, PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_7_Template, 2, 2, "span", 35);
|
|
122
|
-
i0.ɵɵ
|
|
123
|
-
i0.ɵɵ
|
|
131
|
+
i0.ɵɵconditionalCreate(8, PSPredictionsGridComponent_Conditional_25_Conditional_0_Conditional_8_Template, 2, 1, "span", 36);
|
|
132
|
+
i0.ɵɵelementStart(9, "span", 35);
|
|
133
|
+
i0.ɵɵtext(10, "Click any row to inspect details & score history");
|
|
124
134
|
i0.ɵɵelementEnd()();
|
|
125
135
|
} if (rf & 2) {
|
|
126
136
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -131,6 +141,8 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_0_Template(rf, ct
|
|
|
131
141
|
i0.ɵɵtextInterpolate1(" of ", ctx_r1.allRows.length, " predictions");
|
|
132
142
|
i0.ɵɵadvance();
|
|
133
143
|
i0.ɵɵconditional(ctx_r1.selectedTier !== "all" || ctx_r1.searchText ? 7 : -1);
|
|
144
|
+
i0.ɵɵadvance();
|
|
145
|
+
i0.ɵɵconditional(ctx_r1.DetailRowsCapped ? 8 : -1);
|
|
134
146
|
} }
|
|
135
147
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
136
148
|
i0.ɵɵelement(0, "i");
|
|
@@ -142,17 +154,17 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditio
|
|
|
142
154
|
} }
|
|
143
155
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template(rf, ctx) { if (rf & 1) {
|
|
144
156
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
145
|
-
i0.ɵɵelementStart(0, "div",
|
|
157
|
+
i0.ɵɵelementStart(0, "div", 55);
|
|
146
158
|
i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template_div_click_0_listener() { const b_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.setTierAndGrid(b_r9.key)); });
|
|
147
|
-
i0.ɵɵelementStart(1, "span",
|
|
148
|
-
i0.ɵɵconditionalCreate(2, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditional_2_Template, 1, 5, "i",
|
|
159
|
+
i0.ɵɵelementStart(1, "span", 39);
|
|
160
|
+
i0.ɵɵconditionalCreate(2, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Conditional_2_Template, 1, 5, "i", 56);
|
|
149
161
|
i0.ɵɵtext(3);
|
|
150
162
|
i0.ɵɵelementEnd();
|
|
151
|
-
i0.ɵɵelementStart(4, "span",
|
|
163
|
+
i0.ɵɵelementStart(4, "span", 41);
|
|
152
164
|
i0.ɵɵtext(5);
|
|
153
165
|
i0.ɵɵpipe(6, "number");
|
|
154
166
|
i0.ɵɵelementEnd();
|
|
155
|
-
i0.ɵɵelementStart(7, "span",
|
|
167
|
+
i0.ɵɵelementStart(7, "span", 42);
|
|
156
168
|
i0.ɵɵtext(8);
|
|
157
169
|
i0.ɵɵelementEnd()();
|
|
158
170
|
} if (rf & 2) {
|
|
@@ -172,7 +184,7 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template
|
|
|
172
184
|
} }
|
|
173
185
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template(rf, ctx) { if (rf & 1) {
|
|
174
186
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
175
|
-
i0.ɵɵelementStart(0, "button",
|
|
187
|
+
i0.ɵɵelementStart(0, "button", 57);
|
|
176
188
|
i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.clearDecileFilter()); });
|
|
177
189
|
i0.ɵɵelement(1, "i", 22);
|
|
178
190
|
i0.ɵɵtext(2, " Clear Decile Filter ");
|
|
@@ -180,35 +192,35 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_
|
|
|
180
192
|
} }
|
|
181
193
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template(rf, ctx) { if (rf & 1) {
|
|
182
194
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
183
|
-
i0.ɵɵelementStart(0, "div",
|
|
195
|
+
i0.ɵɵelementStart(0, "div", 58);
|
|
184
196
|
i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template_div_click_0_listener() { const b_r12 = i0.ɵɵrestoreView(_r11).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectDecile(b_r12.idx)); });
|
|
185
|
-
i0.ɵɵelementStart(1, "span",
|
|
197
|
+
i0.ɵɵelementStart(1, "span", 59);
|
|
186
198
|
i0.ɵɵtext(2);
|
|
187
199
|
i0.ɵɵpipe(3, "number");
|
|
188
200
|
i0.ɵɵelementEnd();
|
|
189
|
-
i0.ɵɵelementStart(4, "div",
|
|
190
|
-
i0.ɵɵelement(5, "div",
|
|
201
|
+
i0.ɵɵelementStart(4, "div", 60);
|
|
202
|
+
i0.ɵɵelement(5, "div", 61);
|
|
191
203
|
i0.ɵɵelementEnd();
|
|
192
|
-
i0.ɵɵelementStart(6, "div",
|
|
204
|
+
i0.ɵɵelementStart(6, "div", 62)(7, "span", 63);
|
|
193
205
|
i0.ɵɵtext(8);
|
|
194
206
|
i0.ɵɵelementEnd();
|
|
195
|
-
i0.ɵɵelementStart(9, "span",
|
|
207
|
+
i0.ɵɵelementStart(9, "span", 64);
|
|
196
208
|
i0.ɵɵtext(10);
|
|
197
209
|
i0.ɵɵelementEnd()();
|
|
198
|
-
i0.ɵɵelementStart(11, "div",
|
|
210
|
+
i0.ɵɵelementStart(11, "div", 65)(12, "div", 66);
|
|
199
211
|
i0.ɵɵtext(13);
|
|
200
212
|
i0.ɵɵelementEnd();
|
|
201
|
-
i0.ɵɵelementStart(14, "div",
|
|
213
|
+
i0.ɵɵelementStart(14, "div", 67)(15, "span", 68);
|
|
202
214
|
i0.ɵɵtext(16);
|
|
203
215
|
i0.ɵɵpipe(17, "number");
|
|
204
216
|
i0.ɵɵelementEnd();
|
|
205
|
-
i0.ɵɵelementStart(18, "span",
|
|
217
|
+
i0.ɵɵelementStart(18, "span", 69);
|
|
206
218
|
i0.ɵɵtext(19);
|
|
207
219
|
i0.ɵɵelementEnd()();
|
|
208
|
-
i0.ɵɵelementStart(20, "div",
|
|
220
|
+
i0.ɵɵelementStart(20, "div", 70);
|
|
209
221
|
i0.ɵɵtext(21);
|
|
210
222
|
i0.ɵɵelementEnd();
|
|
211
|
-
i0.ɵɵelementStart(22, "div",
|
|
223
|
+
i0.ɵɵelementStart(22, "div", 71);
|
|
212
224
|
i0.ɵɵtext(23);
|
|
213
225
|
i0.ɵɵelementEnd()()();
|
|
214
226
|
} if (rf & 2) {
|
|
@@ -239,15 +251,15 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template
|
|
|
239
251
|
i0.ɵɵtextInterpolate(ctx_r1.selectedDecileIndex === b_r12.idx ? "Click to clear filter" : "Click to filter grid");
|
|
240
252
|
} }
|
|
241
253
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_7_Template(rf, ctx) { if (rf & 1) {
|
|
242
|
-
i0.ɵɵelement(0, "div",
|
|
254
|
+
i0.ɵɵelement(0, "div", 77);
|
|
243
255
|
} if (rf & 2) {
|
|
244
256
|
const c_r13 = ctx.$implicit;
|
|
245
257
|
i0.ɵɵstyleProp("width", c_r13.pct, "%")("background", c_r13.color);
|
|
246
258
|
i0.ɵɵproperty("title", c_r13.name + ": " + c_r13.count + " (" + c_r13.pct + "%)");
|
|
247
259
|
} }
|
|
248
260
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_10_Template(rf, ctx) { if (rf & 1) {
|
|
249
|
-
i0.ɵɵelementStart(0, "div",
|
|
250
|
-
i0.ɵɵelement(1, "span",
|
|
261
|
+
i0.ɵɵelementStart(0, "div", 76);
|
|
262
|
+
i0.ɵɵelement(1, "span", 78);
|
|
251
263
|
i0.ɵɵelementStart(2, "strong");
|
|
252
264
|
i0.ɵɵtext(3);
|
|
253
265
|
i0.ɵɵelementEnd();
|
|
@@ -264,15 +276,15 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_
|
|
|
264
276
|
i0.ɵɵtextInterpolate2("", c_r14.count, " (", c_r14.pct, "%)");
|
|
265
277
|
} }
|
|
266
278
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_Template(rf, ctx) { if (rf & 1) {
|
|
267
|
-
i0.ɵɵelementStart(0, "div",
|
|
268
|
-
i0.ɵɵelement(3, "i",
|
|
279
|
+
i0.ɵɵelementStart(0, "div", 44)(1, "div", 45)(2, "span");
|
|
280
|
+
i0.ɵɵelement(3, "i", 72);
|
|
269
281
|
i0.ɵɵtext(4, " Predicted Outcome Classes");
|
|
270
282
|
i0.ɵɵelementEnd()();
|
|
271
|
-
i0.ɵɵelementStart(5, "div",
|
|
272
|
-
i0.ɵɵrepeaterCreate(6, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_7_Template, 1, 5, "div",
|
|
283
|
+
i0.ɵɵelementStart(5, "div", 73);
|
|
284
|
+
i0.ɵɵrepeaterCreate(6, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_7_Template, 1, 5, "div", 74, _forTrack2);
|
|
273
285
|
i0.ɵɵelementEnd();
|
|
274
|
-
i0.ɵɵelementStart(8, "div",
|
|
275
|
-
i0.ɵɵrepeaterCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_10_Template, 6, 5, "div",
|
|
286
|
+
i0.ɵɵelementStart(8, "div", 75);
|
|
287
|
+
i0.ɵɵrepeaterCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_For_10_Template, 6, 5, "div", 76, _forTrack2);
|
|
276
288
|
i0.ɵɵelementEnd()();
|
|
277
289
|
} if (rf & 2) {
|
|
278
290
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
@@ -282,7 +294,7 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_
|
|
|
282
294
|
i0.ɵɵrepeater(ctx_r1.classBreakdown);
|
|
283
295
|
} }
|
|
284
296
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
285
|
-
i0.ɵɵelementStart(0, "span",
|
|
297
|
+
i0.ɵɵelementStart(0, "span", 85);
|
|
286
298
|
i0.ɵɵtext(1);
|
|
287
299
|
i0.ɵɵelementEnd();
|
|
288
300
|
} if (rf & 2) {
|
|
@@ -293,17 +305,17 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_
|
|
|
293
305
|
} }
|
|
294
306
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template(rf, ctx) { if (rf & 1) {
|
|
295
307
|
const _r15 = i0.ɵɵgetCurrentView();
|
|
296
|
-
i0.ɵɵelementStart(0, "div",
|
|
297
|
-
i0.ɵɵelement(3, "i",
|
|
308
|
+
i0.ɵɵelementStart(0, "div", 54)(1, "div", 45)(2, "div", 46);
|
|
309
|
+
i0.ɵɵelement(3, "i", 79);
|
|
298
310
|
i0.ɵɵelementStart(4, "span");
|
|
299
311
|
i0.ɵɵtext(5, " Decile Drill-Down: ");
|
|
300
|
-
i0.ɵɵelementStart(6, "strong",
|
|
312
|
+
i0.ɵɵelementStart(6, "strong", 80);
|
|
301
313
|
i0.ɵɵtext(7);
|
|
302
314
|
i0.ɵɵelementEnd();
|
|
303
315
|
i0.ɵɵtext(8);
|
|
304
|
-
i0.ɵɵconditionalCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Conditional_9_Template, 2, 3, "span",
|
|
316
|
+
i0.ɵɵconditionalCreate(9, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Conditional_9_Template, 2, 3, "span", 81);
|
|
305
317
|
i0.ɵɵelementEnd()();
|
|
306
|
-
i0.ɵɵelementStart(10, "div",
|
|
318
|
+
i0.ɵɵelementStart(10, "div", 48)(11, "span", 49);
|
|
307
319
|
i0.ɵɵtext(12, " Showing ");
|
|
308
320
|
i0.ɵɵelementStart(13, "strong");
|
|
309
321
|
i0.ɵɵtext(14);
|
|
@@ -312,15 +324,15 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_
|
|
|
312
324
|
i0.ɵɵtext(16);
|
|
313
325
|
i0.ɵɵpipe(17, "number");
|
|
314
326
|
i0.ɵɵelementEnd();
|
|
315
|
-
i0.ɵɵelementStart(18, "button",
|
|
327
|
+
i0.ɵɵelementStart(18, "button", 57);
|
|
316
328
|
i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.clearDecileFilter()); });
|
|
317
329
|
i0.ɵɵelement(19, "i", 22);
|
|
318
330
|
i0.ɵɵtext(20, " Show All Deciles ");
|
|
319
331
|
i0.ɵɵelementEnd()()();
|
|
320
|
-
i0.ɵɵelementStart(21, "div",
|
|
332
|
+
i0.ɵɵelementStart(21, "div", 82)(22, "ag-grid-angular", 83);
|
|
321
333
|
i0.ɵɵlistener("gridReady", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_ag_grid_angular_gridReady_22_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onChartGridReady($event)); })("rowClicked", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_ag_grid_angular_rowClicked_22_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onRowClicked($event)); })("cellClicked", function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template_ag_grid_angular_cellClicked_22_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onCellClicked($event)); });
|
|
322
334
|
i0.ɵɵelementEnd()();
|
|
323
|
-
i0.ɵɵelementStart(23, "div",
|
|
335
|
+
i0.ɵɵelementStart(23, "div", 84)(24, "span", 35);
|
|
324
336
|
i0.ɵɵtext(25, "Click any row to inspect explainability drivers and score history in the slide-in drawer");
|
|
325
337
|
i0.ɵɵelementEnd()()();
|
|
326
338
|
} if (rf & 2) {
|
|
@@ -339,36 +351,36 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_
|
|
|
339
351
|
i0.ɵɵproperty("theme", ctx_r1.Theme)("columnDefs", ctx_r1.columnDefs)("defaultColDef", ctx_r1.defaultColDef)("gridOptions", ctx_r1.chartGridOptions)("rowData", ctx_r1.filteredRows);
|
|
340
352
|
} }
|
|
341
353
|
function PSPredictionsGridComponent_Conditional_25_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
342
|
-
i0.ɵɵelementStart(0, "div", 32)(1, "div",
|
|
343
|
-
i0.ɵɵelement(4, "i",
|
|
354
|
+
i0.ɵɵelementStart(0, "div", 32)(1, "div", 37)(2, "div", 38)(3, "span", 39);
|
|
355
|
+
i0.ɵɵelement(4, "i", 40);
|
|
344
356
|
i0.ɵɵtext(5, " Scored Cohort");
|
|
345
357
|
i0.ɵɵelementEnd();
|
|
346
|
-
i0.ɵɵelementStart(6, "span",
|
|
358
|
+
i0.ɵɵelementStart(6, "span", 41);
|
|
347
359
|
i0.ɵɵtext(7);
|
|
348
360
|
i0.ɵɵpipe(8, "number");
|
|
349
361
|
i0.ɵɵelementEnd();
|
|
350
|
-
i0.ɵɵelementStart(9, "span",
|
|
362
|
+
i0.ɵɵelementStart(9, "span", 42);
|
|
351
363
|
i0.ɵɵtext(10, "Total records");
|
|
352
364
|
i0.ɵɵelementEnd()();
|
|
353
|
-
i0.ɵɵrepeaterCreate(11, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template, 9, 12, "div",
|
|
365
|
+
i0.ɵɵrepeaterCreate(11, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_12_Template, 9, 12, "div", 43, _forTrack0);
|
|
354
366
|
i0.ɵɵelementEnd();
|
|
355
|
-
i0.ɵɵelementStart(13, "div",
|
|
356
|
-
i0.ɵɵelement(16, "i",
|
|
367
|
+
i0.ɵɵelementStart(13, "div", 44)(14, "div", 45)(15, "div", 46);
|
|
368
|
+
i0.ɵɵelement(16, "i", 47);
|
|
357
369
|
i0.ɵɵelementStart(17, "span");
|
|
358
370
|
i0.ɵɵtext(18);
|
|
359
371
|
i0.ɵɵelementEnd()();
|
|
360
|
-
i0.ɵɵelementStart(19, "div",
|
|
372
|
+
i0.ɵɵelementStart(19, "div", 48)(20, "span", 49);
|
|
361
373
|
i0.ɵɵtext(21, "Cohort Mean: ");
|
|
362
374
|
i0.ɵɵelementStart(22, "strong");
|
|
363
375
|
i0.ɵɵtext(23);
|
|
364
376
|
i0.ɵɵelementEnd()();
|
|
365
|
-
i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template, 3, 0, "button",
|
|
377
|
+
i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_24_Template, 3, 0, "button", 50);
|
|
366
378
|
i0.ɵɵelementEnd()();
|
|
367
|
-
i0.ɵɵelementStart(25, "div",
|
|
368
|
-
i0.ɵɵrepeaterCreate(27, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template, 24, 24, "div",
|
|
379
|
+
i0.ɵɵelementStart(25, "div", 51)(26, "div", 52);
|
|
380
|
+
i0.ɵɵrepeaterCreate(27, PSPredictionsGridComponent_Conditional_25_Conditional_1_For_28_Template, 24, 24, "div", 53, _forTrack1);
|
|
369
381
|
i0.ɵɵelementEnd()()();
|
|
370
|
-
i0.ɵɵconditionalCreate(29, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_Template, 11, 0, "div",
|
|
371
|
-
i0.ɵɵconditionalCreate(30, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template, 26, 14, "div",
|
|
382
|
+
i0.ɵɵconditionalCreate(29, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_29_Template, 11, 0, "div", 44);
|
|
383
|
+
i0.ɵɵconditionalCreate(30, PSPredictionsGridComponent_Conditional_25_Conditional_1_Conditional_30_Template, 26, 14, "div", 54);
|
|
372
384
|
i0.ɵɵelementEnd();
|
|
373
385
|
} if (rf & 2) {
|
|
374
386
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -390,7 +402,7 @@ function PSPredictionsGridComponent_Conditional_25_Conditional_1_Template(rf, ct
|
|
|
390
402
|
i0.ɵɵconditional(ctx_r1.selectedDecileIndex !== null ? 30 : -1);
|
|
391
403
|
} }
|
|
392
404
|
function PSPredictionsGridComponent_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
393
|
-
i0.ɵɵconditionalCreate(0, PSPredictionsGridComponent_Conditional_25_Conditional_0_Template,
|
|
405
|
+
i0.ɵɵconditionalCreate(0, PSPredictionsGridComponent_Conditional_25_Conditional_0_Template, 11, 9);
|
|
394
406
|
i0.ɵɵconditionalCreate(1, PSPredictionsGridComponent_Conditional_25_Conditional_1_Template, 31, 8, "div", 32);
|
|
395
407
|
} if (rf & 2) {
|
|
396
408
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -400,9 +412,9 @@ function PSPredictionsGridComponent_Conditional_25_Template(rf, ctx) { if (rf &
|
|
|
400
412
|
} }
|
|
401
413
|
function PSPredictionsGridComponent_Conditional_26_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
402
414
|
const _r17 = i0.ɵɵgetCurrentView();
|
|
403
|
-
i0.ɵɵelementStart(0, "button",
|
|
415
|
+
i0.ɵɵelementStart(0, "button", 111);
|
|
404
416
|
i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_26_Conditional_15_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.openSubjectRecord()); });
|
|
405
|
-
i0.ɵɵelement(1, "i",
|
|
417
|
+
i0.ɵɵelement(1, "i", 112);
|
|
406
418
|
i0.ɵɵtext(2);
|
|
407
419
|
i0.ɵɵelementEnd();
|
|
408
420
|
} if (rf & 2) {
|
|
@@ -417,10 +429,10 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_24_Template(rf, c
|
|
|
417
429
|
i0.ɵɵclassMap(i0.ɵɵinterpolate1("fa-solid ", ctx_r1.selectedRow.icon));
|
|
418
430
|
} }
|
|
419
431
|
function PSPredictionsGridComponent_Conditional_26_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
420
|
-
i0.ɵɵelementStart(0, "div",
|
|
432
|
+
i0.ɵɵelementStart(0, "div", 99)(1, "strong");
|
|
421
433
|
i0.ɵɵtext(2, "Predicted Outcome:");
|
|
422
434
|
i0.ɵɵelementEnd();
|
|
423
|
-
i0.ɵɵelementStart(3, "span",
|
|
435
|
+
i0.ɵɵelementStart(3, "span", 113);
|
|
424
436
|
i0.ɵɵtext(4);
|
|
425
437
|
i0.ɵɵelementEnd()();
|
|
426
438
|
} if (rf & 2) {
|
|
@@ -430,141 +442,107 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_26_Template(rf, c
|
|
|
430
442
|
i0.ɵɵadvance();
|
|
431
443
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.selectedRow.class, " ");
|
|
432
444
|
} }
|
|
433
|
-
function
|
|
434
|
-
i0.ɵɵ
|
|
435
|
-
i0.ɵɵtext(1, "No individual driver breakdown was recorded for this row.");
|
|
436
|
-
i0.ɵɵelementEnd();
|
|
437
|
-
} }
|
|
438
|
-
function PSPredictionsGridComponent_Conditional_26_Conditional_40_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
439
|
-
i0.ɵɵelementStart(0, "div", 113)(1, "div", 114);
|
|
440
|
-
i0.ɵɵelement(2, "i", 115);
|
|
441
|
-
i0.ɵɵtext(3);
|
|
442
|
-
i0.ɵɵelementEnd();
|
|
443
|
-
i0.ɵɵelementStart(4, "span", 112);
|
|
444
|
-
i0.ɵɵtext(5);
|
|
445
|
-
i0.ɵɵelementEnd()();
|
|
446
|
-
} if (rf & 2) {
|
|
447
|
-
const d_r18 = ctx.$implicit;
|
|
448
|
-
i0.ɵɵadvance(2);
|
|
449
|
-
i0.ɵɵstyleProp("color", d_r18.up ? "var(--mj-status-error)" : "var(--mj-status-success)");
|
|
450
|
-
i0.ɵɵclassProp("fa-arrow-up", d_r18.up)("fa-arrow-down", !d_r18.up);
|
|
451
|
-
i0.ɵɵadvance();
|
|
452
|
-
i0.ɵɵtextInterpolate1(" ", d_r18.label, " ");
|
|
453
|
-
i0.ɵɵadvance();
|
|
454
|
-
i0.ɵɵclassMap(d_r18.up ? "red" : "green");
|
|
455
|
-
i0.ɵɵadvance();
|
|
456
|
-
i0.ɵɵtextInterpolate1(" ", d_r18.up ? "Increases Risk" : "Lowers Risk", " ");
|
|
445
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_47_Template(rf, ctx) { if (rf & 1) {
|
|
446
|
+
i0.ɵɵelement(0, "mj-loading", 110);
|
|
457
447
|
} }
|
|
458
|
-
function
|
|
459
|
-
i0.ɵɵelementStart(0, "div", 105);
|
|
460
|
-
i0.ɵɵrepeaterCreate(1, PSPredictionsGridComponent_Conditional_26_Conditional_40_For_2_Template, 6, 10, "div", 113, _forTrack1);
|
|
461
|
-
i0.ɵɵelementEnd();
|
|
462
|
-
} if (rf & 2) {
|
|
463
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
464
|
-
i0.ɵɵadvance();
|
|
465
|
-
i0.ɵɵrepeater(ctx_r1.selectedRow.drivers);
|
|
466
|
-
} }
|
|
467
|
-
function PSPredictionsGridComponent_Conditional_26_Conditional_48_Template(rf, ctx) { if (rf & 1) {
|
|
468
|
-
i0.ɵɵelement(0, "mj-loading", 109);
|
|
469
|
-
} }
|
|
470
|
-
function PSPredictionsGridComponent_Conditional_26_Conditional_49_For_13_Template(rf, ctx) { if (rf & 1) {
|
|
448
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_13_Template(rf, ctx) { if (rf & 1) {
|
|
471
449
|
i0.ɵɵnamespaceSVG();
|
|
472
|
-
i0.ɵɵelementStart(0, "circle",
|
|
450
|
+
i0.ɵɵelementStart(0, "circle", 124)(1, "title");
|
|
473
451
|
i0.ɵɵtext(2);
|
|
474
452
|
i0.ɵɵelementEnd()();
|
|
475
|
-
i0.ɵɵelementStart(3, "text",
|
|
453
|
+
i0.ɵɵelementStart(3, "text", 125);
|
|
476
454
|
i0.ɵɵtext(4);
|
|
477
455
|
i0.ɵɵelementEnd();
|
|
478
456
|
} if (rf & 2) {
|
|
479
|
-
const
|
|
480
|
-
i0.ɵɵattribute("cx",
|
|
457
|
+
const p_r18 = ctx.$implicit;
|
|
458
|
+
i0.ɵɵattribute("cx", p_r18.x)("cy", p_r18.y)("fill", p_r18.color);
|
|
481
459
|
i0.ɵɵadvance(2);
|
|
482
|
-
i0.ɵɵtextInterpolate3("",
|
|
460
|
+
i0.ɵɵtextInterpolate3("", p_r18.dateStr, ": ", p_r18.scoreFormatted, " (", p_r18.class || "No class", ")");
|
|
483
461
|
i0.ɵɵadvance();
|
|
484
|
-
i0.ɵɵattribute("cx",
|
|
462
|
+
i0.ɵɵattribute("cx", p_r18.x)("cy", p_r18.y - 9);
|
|
485
463
|
i0.ɵɵadvance();
|
|
486
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
464
|
+
i0.ɵɵtextInterpolate1(" ", p_r18.scoreFormatted, " ");
|
|
487
465
|
} }
|
|
488
|
-
function
|
|
489
|
-
i0.ɵɵelementStart(0, "span",
|
|
466
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
467
|
+
i0.ɵɵelementStart(0, "span", 127);
|
|
490
468
|
i0.ɵɵtext(1, "Baseline");
|
|
491
469
|
i0.ɵɵelementEnd();
|
|
492
470
|
} }
|
|
493
|
-
function
|
|
494
|
-
i0.ɵɵelementStart(0, "span",
|
|
495
|
-
i0.ɵɵelement(1, "i",
|
|
471
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
472
|
+
i0.ɵɵelementStart(0, "span", 128);
|
|
473
|
+
i0.ɵɵelement(1, "i", 130);
|
|
496
474
|
i0.ɵɵtext(2);
|
|
497
475
|
i0.ɵɵelementEnd();
|
|
498
476
|
} if (rf & 2) {
|
|
499
|
-
const
|
|
477
|
+
const pt_r19 = i0.ɵɵnextContext().$implicit;
|
|
500
478
|
i0.ɵɵadvance(2);
|
|
501
|
-
i0.ɵɵtextInterpolate1(" +", (
|
|
479
|
+
i0.ɵɵtextInterpolate1(" +", (pt_r19.Delta * 100).toFixed(1), "%");
|
|
502
480
|
} }
|
|
503
|
-
function
|
|
504
|
-
i0.ɵɵelementStart(0, "span",
|
|
505
|
-
i0.ɵɵelement(1, "i",
|
|
481
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
482
|
+
i0.ɵɵelementStart(0, "span", 129);
|
|
483
|
+
i0.ɵɵelement(1, "i", 131);
|
|
506
484
|
i0.ɵɵtext(2);
|
|
507
485
|
i0.ɵɵelementEnd();
|
|
508
486
|
} if (rf & 2) {
|
|
509
|
-
const
|
|
487
|
+
const pt_r19 = i0.ɵɵnextContext().$implicit;
|
|
510
488
|
i0.ɵɵadvance(2);
|
|
511
|
-
i0.ɵɵtextInterpolate1(" ", (
|
|
489
|
+
i0.ɵɵtextInterpolate1(" ", (pt_r19.Delta * 100).toFixed(1), "%");
|
|
512
490
|
} }
|
|
513
|
-
function
|
|
514
|
-
i0.ɵɵelementStart(0, "span",
|
|
491
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
492
|
+
i0.ɵɵelementStart(0, "span", 127);
|
|
515
493
|
i0.ɵɵtext(1, "0%");
|
|
516
494
|
i0.ɵɵelementEnd();
|
|
517
495
|
} }
|
|
518
|
-
function
|
|
496
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Template(rf, ctx) { if (rf & 1) {
|
|
519
497
|
i0.ɵɵelementStart(0, "tr")(1, "td");
|
|
520
498
|
i0.ɵɵtext(2);
|
|
521
499
|
i0.ɵɵpipe(3, "date");
|
|
522
500
|
i0.ɵɵelementEnd();
|
|
523
|
-
i0.ɵɵelementStart(4, "td")(5, "span",
|
|
501
|
+
i0.ɵɵelementStart(4, "td")(5, "span", 113);
|
|
524
502
|
i0.ɵɵtext(6);
|
|
525
503
|
i0.ɵɵelementEnd()();
|
|
526
|
-
i0.ɵɵelementStart(7, "td")(8, "strong",
|
|
504
|
+
i0.ɵɵelementStart(7, "td")(8, "strong", 126);
|
|
527
505
|
i0.ɵɵtext(9);
|
|
528
506
|
i0.ɵɵelementEnd()();
|
|
529
507
|
i0.ɵɵelementStart(10, "td");
|
|
530
|
-
i0.ɵɵconditionalCreate(11,
|
|
508
|
+
i0.ɵɵconditionalCreate(11, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_11_Template, 2, 0, "span", 127)(12, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_12_Template, 3, 1, "span", 128)(13, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_13_Template, 3, 1, "span", 129)(14, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Conditional_14_Template, 2, 0, "span", 127);
|
|
531
509
|
i0.ɵɵelementEnd();
|
|
532
510
|
i0.ɵɵelementStart(15, "td");
|
|
533
511
|
i0.ɵɵtext(16);
|
|
534
512
|
i0.ɵɵelementEnd()();
|
|
535
513
|
} if (rf & 2) {
|
|
536
|
-
const
|
|
514
|
+
const pt_r19 = ctx.$implicit;
|
|
537
515
|
i0.ɵɵadvance(2);
|
|
538
|
-
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 7,
|
|
516
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 7, pt_r19.RunDate, "short"));
|
|
539
517
|
i0.ɵɵadvance(3);
|
|
540
|
-
i0.ɵɵclassMap(
|
|
518
|
+
i0.ɵɵclassMap(pt_r19.status === "Succeeded" ? "green" : "gray");
|
|
541
519
|
i0.ɵɵadvance();
|
|
542
|
-
i0.ɵɵtextInterpolate(
|
|
520
|
+
i0.ɵɵtextInterpolate(pt_r19.status);
|
|
543
521
|
i0.ɵɵadvance(3);
|
|
544
|
-
i0.ɵɵtextInterpolate(
|
|
522
|
+
i0.ɵɵtextInterpolate(pt_r19.ScoreFormatted);
|
|
545
523
|
i0.ɵɵadvance(2);
|
|
546
|
-
i0.ɵɵconditional(
|
|
524
|
+
i0.ɵɵconditional(pt_r19.Delta == null ? 11 : pt_r19.Delta > 0.005 ? 12 : pt_r19.Delta < -0.005 ? 13 : 14);
|
|
547
525
|
i0.ɵɵadvance(5);
|
|
548
|
-
i0.ɵɵtextInterpolate(
|
|
526
|
+
i0.ɵɵtextInterpolate(pt_r19.class || "\u2014");
|
|
549
527
|
} }
|
|
550
|
-
function
|
|
528
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_48_Template(rf, ctx) { if (rf & 1) {
|
|
551
529
|
i0.ɵɵnamespaceSVG();
|
|
552
|
-
i0.ɵɵelementStart(0, "svg",
|
|
553
|
-
i0.ɵɵelement(1, "line",
|
|
554
|
-
i0.ɵɵelementStart(4, "text",
|
|
530
|
+
i0.ɵɵelementStart(0, "svg", 114);
|
|
531
|
+
i0.ɵɵelement(1, "line", 115)(2, "line", 116)(3, "line", 117);
|
|
532
|
+
i0.ɵɵelementStart(4, "text", 118);
|
|
555
533
|
i0.ɵɵtext(5, "100%");
|
|
556
534
|
i0.ɵɵelementEnd();
|
|
557
|
-
i0.ɵɵelementStart(6, "text",
|
|
535
|
+
i0.ɵɵelementStart(6, "text", 119);
|
|
558
536
|
i0.ɵɵtext(7, "50%");
|
|
559
537
|
i0.ɵɵelementEnd();
|
|
560
|
-
i0.ɵɵelementStart(8, "text",
|
|
538
|
+
i0.ɵɵelementStart(8, "text", 120);
|
|
561
539
|
i0.ɵɵtext(9, "0%");
|
|
562
540
|
i0.ɵɵelementEnd();
|
|
563
|
-
i0.ɵɵelement(10, "polygon",
|
|
564
|
-
i0.ɵɵrepeaterCreate(12,
|
|
541
|
+
i0.ɵɵelement(10, "polygon", 121)(11, "polyline", 122);
|
|
542
|
+
i0.ɵɵrepeaterCreate(12, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_13_Template, 5, 9, null, null, _forTrack3);
|
|
565
543
|
i0.ɵɵelementEnd();
|
|
566
544
|
i0.ɵɵnamespaceHTML();
|
|
567
|
-
i0.ɵɵelementStart(14, "table",
|
|
545
|
+
i0.ɵɵelementStart(14, "table", 123)(15, "thead")(16, "tr")(17, "th");
|
|
568
546
|
i0.ɵɵtext(18, "When");
|
|
569
547
|
i0.ɵɵelementEnd();
|
|
570
548
|
i0.ɵɵelementStart(19, "th");
|
|
@@ -580,7 +558,7 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_49_Template(rf, c
|
|
|
580
558
|
i0.ɵɵtext(26, "Class");
|
|
581
559
|
i0.ɵɵelementEnd()()();
|
|
582
560
|
i0.ɵɵelementStart(27, "tbody");
|
|
583
|
-
i0.ɵɵrepeaterCreate(28,
|
|
561
|
+
i0.ɵɵrepeaterCreate(28, PSPredictionsGridComponent_Conditional_26_Conditional_48_For_29_Template, 17, 10, "tr", null, _forTrack3);
|
|
584
562
|
i0.ɵɵelementEnd()();
|
|
585
563
|
} if (rf & 2) {
|
|
586
564
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -593,8 +571,8 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_49_Template(rf, c
|
|
|
593
571
|
i0.ɵɵadvance(16);
|
|
594
572
|
i0.ɵɵrepeater(ctx_r1.historyPoints);
|
|
595
573
|
} }
|
|
596
|
-
function
|
|
597
|
-
i0.ɵɵelementStart(0, "div",
|
|
574
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_49_Template(rf, ctx) { if (rf & 1) {
|
|
575
|
+
i0.ɵɵelementStart(0, "div", 49);
|
|
598
576
|
i0.ɵɵtext(1);
|
|
599
577
|
i0.ɵɵpipe(2, "date");
|
|
600
578
|
i0.ɵɵelementEnd();
|
|
@@ -603,66 +581,66 @@ function PSPredictionsGridComponent_Conditional_26_Conditional_50_Template(rf, c
|
|
|
603
581
|
i0.ɵɵadvance();
|
|
604
582
|
i0.ɵɵtextInterpolate1(" This record has been scored once so far (", i0.ɵɵpipeBind2(2, 1, ctx_r1.historyPoints[0].RunDate, "medium"), "). As more runs occur over time, the score trendline will track changes here. ");
|
|
605
583
|
} }
|
|
606
|
-
function
|
|
607
|
-
i0.ɵɵelementStart(0, "div",
|
|
584
|
+
function PSPredictionsGridComponent_Conditional_26_Conditional_50_Template(rf, ctx) { if (rf & 1) {
|
|
585
|
+
i0.ɵɵelementStart(0, "div", 49);
|
|
608
586
|
i0.ɵɵtext(1, "No historical runs found for this record.");
|
|
609
587
|
i0.ɵɵelementEnd();
|
|
610
588
|
} }
|
|
611
589
|
function PSPredictionsGridComponent_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
612
590
|
const _r16 = i0.ɵɵgetCurrentView();
|
|
613
|
-
i0.ɵɵelementStart(0, "mj-slide-panel",
|
|
591
|
+
i0.ɵɵelementStart(0, "mj-slide-panel", 86);
|
|
614
592
|
i0.ɵɵlistener("WidthChanged", function PSPredictionsGridComponent_Conditional_26_Template_mj_slide_panel_WidthChanged_0_listener($event) { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDrawerWidthChanged($event)); })("Closed", function PSPredictionsGridComponent_Conditional_26_Template_mj_slide_panel_Closed_0_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.closeDetail()); });
|
|
615
|
-
i0.ɵɵelementStart(1, "div",
|
|
593
|
+
i0.ɵɵelementStart(1, "div", 87)(2, "div", 88)(3, "div", 89)(4, "h3");
|
|
616
594
|
i0.ɵɵtext(5);
|
|
617
595
|
i0.ɵɵelementEnd();
|
|
618
|
-
i0.ɵɵelementStart(6, "div",
|
|
596
|
+
i0.ɵɵelementStart(6, "div", 46)(7, "span", 90);
|
|
619
597
|
i0.ɵɵtext(8);
|
|
620
598
|
i0.ɵɵelementEnd();
|
|
621
|
-
i0.ɵɵelementStart(9, "span",
|
|
599
|
+
i0.ɵɵelementStart(9, "span", 91);
|
|
622
600
|
i0.ɵɵtext(10);
|
|
623
601
|
i0.ɵɵelementEnd()()();
|
|
624
|
-
i0.ɵɵelementStart(11, "div",
|
|
602
|
+
i0.ɵɵelementStart(11, "div", 92)(12, "button", 93);
|
|
625
603
|
i0.ɵɵlistener("click", function PSPredictionsGridComponent_Conditional_26_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.drillThrough(ctx_r1.selectedRow)); });
|
|
626
|
-
i0.ɵɵelement(13, "i",
|
|
604
|
+
i0.ɵɵelement(13, "i", 94);
|
|
627
605
|
i0.ɵɵtext(14);
|
|
628
606
|
i0.ɵɵelementEnd();
|
|
629
|
-
i0.ɵɵconditionalCreate(15, PSPredictionsGridComponent_Conditional_26_Conditional_15_Template, 3, 2, "button",
|
|
607
|
+
i0.ɵɵconditionalCreate(15, PSPredictionsGridComponent_Conditional_26_Conditional_15_Template, 3, 2, "button", 95);
|
|
630
608
|
i0.ɵɵelementEnd()();
|
|
631
|
-
i0.ɵɵelementStart(16, "div",
|
|
609
|
+
i0.ɵɵelementStart(16, "div", 96)(17, "div", 97);
|
|
632
610
|
i0.ɵɵtext(18);
|
|
633
611
|
i0.ɵɵelementEnd();
|
|
634
|
-
i0.ɵɵelementStart(19, "div",
|
|
612
|
+
i0.ɵɵelementStart(19, "div", 98)(20, "div", 99)(21, "strong");
|
|
635
613
|
i0.ɵɵtext(22);
|
|
636
614
|
i0.ɵɵelementEnd();
|
|
637
|
-
i0.ɵɵelementStart(23, "span",
|
|
638
|
-
i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_26_Conditional_24_Template, 1, 3, "i",
|
|
615
|
+
i0.ɵɵelementStart(23, "span", 85);
|
|
616
|
+
i0.ɵɵconditionalCreate(24, PSPredictionsGridComponent_Conditional_26_Conditional_24_Template, 1, 3, "i", 100);
|
|
639
617
|
i0.ɵɵtext(25);
|
|
640
618
|
i0.ɵɵelementEnd()();
|
|
641
|
-
i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Conditional_26_Template, 5, 3, "div",
|
|
642
|
-
i0.ɵɵelementStart(27, "div",
|
|
619
|
+
i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Conditional_26_Template, 5, 3, "div", 99);
|
|
620
|
+
i0.ɵɵelementStart(27, "div", 99)(28, "strong");
|
|
643
621
|
i0.ɵɵtext(29);
|
|
644
622
|
i0.ɵɵelementEnd();
|
|
645
|
-
i0.ɵɵelementStart(30, "span",
|
|
623
|
+
i0.ɵɵelementStart(30, "span", 101);
|
|
646
624
|
i0.ɵɵtext(31);
|
|
647
625
|
i0.ɵɵelementEnd()();
|
|
648
|
-
i0.ɵɵelementStart(32, "div",
|
|
626
|
+
i0.ɵɵelementStart(32, "div", 102);
|
|
649
627
|
i0.ɵɵtext(33);
|
|
650
628
|
i0.ɵɵpipe(34, "date");
|
|
651
629
|
i0.ɵɵelementEnd()()();
|
|
652
|
-
i0.ɵɵelementStart(35, "div",
|
|
653
|
-
i0.ɵɵelement(37, "i",
|
|
654
|
-
i0.ɵɵtext(38, "
|
|
630
|
+
i0.ɵɵelementStart(35, "div", 103)(36, "div", 104);
|
|
631
|
+
i0.ɵɵelement(37, "i", 105);
|
|
632
|
+
i0.ɵɵtext(38, " Factors behind this score (associations, not causes) ");
|
|
655
633
|
i0.ɵɵelementEnd();
|
|
656
|
-
i0.ɵɵ
|
|
634
|
+
i0.ɵɵelement(39, "ps-row-drivers", 106);
|
|
657
635
|
i0.ɵɵelementEnd();
|
|
658
|
-
i0.ɵɵelementStart(
|
|
659
|
-
i0.ɵɵelement(
|
|
660
|
-
i0.ɵɵtext(
|
|
636
|
+
i0.ɵɵelementStart(40, "div", 107)(41, "div", 108)(42, "span");
|
|
637
|
+
i0.ɵɵelement(43, "i", 109);
|
|
638
|
+
i0.ɵɵtext(44, " Historical Score Trendline");
|
|
661
639
|
i0.ɵɵelementEnd();
|
|
662
|
-
i0.ɵɵelementStart(
|
|
663
|
-
i0.ɵɵtext(
|
|
640
|
+
i0.ɵɵelementStart(45, "span", 49);
|
|
641
|
+
i0.ɵɵtext(46);
|
|
664
642
|
i0.ɵɵelementEnd()();
|
|
665
|
-
i0.ɵɵconditionalCreate(
|
|
643
|
+
i0.ɵɵconditionalCreate(47, PSPredictionsGridComponent_Conditional_26_Conditional_47_Template, 1, 0, "mj-loading", 110)(48, PSPredictionsGridComponent_Conditional_26_Conditional_48_Template, 30, 2)(49, PSPredictionsGridComponent_Conditional_26_Conditional_49_Template, 3, 4, "div", 49)(50, PSPredictionsGridComponent_Conditional_26_Conditional_50_Template, 2, 0, "div", 49);
|
|
666
644
|
i0.ɵɵelementEnd()()();
|
|
667
645
|
} if (rf & 2) {
|
|
668
646
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -698,11 +676,11 @@ function PSPredictionsGridComponent_Conditional_26_Template(rf, ctx) { if (rf &
|
|
|
698
676
|
i0.ɵɵadvance(2);
|
|
699
677
|
i0.ɵɵtextInterpolate1(" Scored: ", ctx_r1.selectedRow.scoredAtDate ? i0.ɵɵpipeBind2(34, 23, ctx_r1.selectedRow.scoredAtDate, "medium") : "\u2014", " ");
|
|
700
678
|
i0.ɵɵadvance(6);
|
|
701
|
-
i0.ɵɵ
|
|
702
|
-
i0.ɵɵadvance(
|
|
679
|
+
i0.ɵɵproperty("Drivers", ctx_r1.selectedRow.drivers);
|
|
680
|
+
i0.ɵɵadvance(7);
|
|
703
681
|
i0.ɵɵtextInterpolate2("", ctx_r1.historyPoints.length, " run", ctx_r1.historyPoints.length === 1 ? "" : "s", " recorded");
|
|
704
682
|
i0.ɵɵadvance();
|
|
705
|
-
i0.ɵɵconditional(ctx_r1.historyLoading ?
|
|
683
|
+
i0.ɵɵconditional(ctx_r1.historyLoading ? 47 : ctx_r1.historyPoints.length > 1 ? 48 : ctx_r1.historyPoints.length === 1 ? 49 : 50);
|
|
706
684
|
} }
|
|
707
685
|
ModuleRegistry.registerModules([AllCommunityModule]);
|
|
708
686
|
/**
|
|
@@ -750,12 +728,25 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
750
728
|
get readOnly() {
|
|
751
729
|
return this.ReadOnly;
|
|
752
730
|
}
|
|
731
|
+
/**
|
|
732
|
+
* Emitted after the grid parses a run, with the run's at-risk rows. A host that needs the rows (counts, export, a list)
|
|
733
|
+
* takes them from here rather than reading the run a second time. Also emitted, empty, when the model has no run.
|
|
734
|
+
*/
|
|
735
|
+
RowsLoaded = new EventEmitter();
|
|
736
|
+
/** Emitted with the error message when the run's predictions fail to load. */
|
|
737
|
+
RowsLoadFailed = new EventEmitter();
|
|
753
738
|
cdr = inject(ChangeDetectorRef);
|
|
754
739
|
navigationService = inject(NavigationService);
|
|
755
740
|
scoreHistoryService = inject(PredictiveStudioScoreHistoryService);
|
|
756
741
|
Math = Math;
|
|
742
|
+
/** The run-detail cap, formatted for the footer notice. */
|
|
743
|
+
MaxRunDetailRowsLabel = PredictiveStudioEngine.MaxRunDetailRowsLabel;
|
|
744
|
+
/** The tier of a regression row whose value falls in none of the outcome bands. */
|
|
745
|
+
static unbandedTier = { Key: 'unbanded', Label: 'No band', BadgeColor: 'gray' };
|
|
757
746
|
isLoading = false;
|
|
758
747
|
loadError = null;
|
|
748
|
+
/** True when the run has more predictions than {@link PredictiveStudioEngine.MaxRunDetailRows}; only the first are shown. */
|
|
749
|
+
DetailRowsCapped = false;
|
|
759
750
|
AllRows = [];
|
|
760
751
|
/** @deprecated Use {@link AllRows}. */
|
|
761
752
|
get allRows() {
|
|
@@ -994,6 +985,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
994
985
|
set defaultColDef(value) {
|
|
995
986
|
this.DefaultColDef = value;
|
|
996
987
|
}
|
|
988
|
+
/** True when the model's score is the probability of the good outcome, so risk is `1 - score` (e.g. a renewal model). */
|
|
997
989
|
IsRenewalModel = false;
|
|
998
990
|
/** @deprecated Use {@link IsRenewalModel}. */
|
|
999
991
|
get isRenewalModel() {
|
|
@@ -1012,10 +1004,12 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1012
1004
|
set selectedDecileIndex(value) {
|
|
1013
1005
|
this.SelectedDecileIndex = value;
|
|
1014
1006
|
}
|
|
1007
|
+
/**
|
|
1008
|
+
* True for a regression model. Risk bands are classification rules, so a regression model's tiers, row band, status and
|
|
1009
|
+
* badge come from its outcome bands on the raw value, and the risk column is hidden.
|
|
1010
|
+
*/
|
|
1015
1011
|
get IsRegression() {
|
|
1016
|
-
return (
|
|
1017
|
-
this.OutcomeConfig?.Format === 'currency' ||
|
|
1018
|
-
this.OutcomeConfig?.Format === 'number');
|
|
1012
|
+
return ProblemTypes.IsRegression(this.ProblemType);
|
|
1019
1013
|
}
|
|
1020
1014
|
/** @deprecated Use {@link IsRegression}. */
|
|
1021
1015
|
get isRegression() {
|
|
@@ -1087,22 +1081,30 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1087
1081
|
},
|
|
1088
1082
|
},
|
|
1089
1083
|
{
|
|
1090
|
-
field: '
|
|
1084
|
+
field: 'status',
|
|
1091
1085
|
headerName: statusLabel,
|
|
1092
1086
|
width: 155,
|
|
1087
|
+
// The tier order: by risk for classification (the tiers are risk bands), by value for regression.
|
|
1088
|
+
comparator: (_a, _b, nodeA, nodeB) => this.IsRegression
|
|
1089
|
+
? (nodeA.data?.score ?? 0) - (nodeB.data?.score ?? 0)
|
|
1090
|
+
: (nodeA.data?.riskPct ?? 0) - (nodeB.data?.riskPct ?? 0),
|
|
1093
1091
|
cellRenderer: (params) => {
|
|
1094
1092
|
if (!params.data)
|
|
1095
1093
|
return '';
|
|
1096
1094
|
const badgeColor = params.data.badgeColor || 'gray';
|
|
1097
1095
|
const icon = params.data.icon ? `<i class="fa-solid ${this.escapeHtml(params.data.icon)}"></i> ` : '';
|
|
1098
1096
|
const label = this.escapeHtml(params.data.status || params.data.band);
|
|
1099
|
-
|
|
1100
|
-
return `<span class="ps-badge ${badgeColor}" title="${scoreLabel}: ${this.escapeHtml(params.data.scoreFormatted)}">${icon}${label}</span>`;
|
|
1101
|
-
}
|
|
1102
|
-
const pct = Math.round(params.data.score * 100);
|
|
1103
|
-
return `<span class="ps-badge ${badgeColor}" title="${pct}% ${scoreLabel}">${icon}${label} (${pct}%)</span>`;
|
|
1097
|
+
return `<span class="ps-badge ${badgeColor}" title="${this.escapeHtml(scoreLabel)}: ${this.escapeHtml(params.data.scoreFormatted)}">${icon}${label}</span>`;
|
|
1104
1098
|
},
|
|
1105
1099
|
},
|
|
1100
|
+
{
|
|
1101
|
+
field: 'riskPct',
|
|
1102
|
+
headerName: 'Risk',
|
|
1103
|
+
width: 95,
|
|
1104
|
+
// Risk is a classification measure (1 - score for a good-outcome model); a regression value has none.
|
|
1105
|
+
hide: this.IsRegression,
|
|
1106
|
+
cellRenderer: (params) => params.data ? `<span class="ps-mono" data-testid="ps-risk-cell">${params.data.riskPct}%</span>` : '',
|
|
1107
|
+
},
|
|
1106
1108
|
{
|
|
1107
1109
|
field: 'class',
|
|
1108
1110
|
headerName: 'Predicted Outcome',
|
|
@@ -1128,11 +1130,13 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1128
1130
|
return '<span class="ps-muted">—</span>';
|
|
1129
1131
|
}
|
|
1130
1132
|
const chips = params.data.drivers.slice(0, 2).map((d) => {
|
|
1131
|
-
const cls = d.
|
|
1132
|
-
const icon = d.
|
|
1133
|
-
const label = this.escapeHtml(d.
|
|
1134
|
-
|
|
1135
|
-
|
|
1133
|
+
const cls = d.Up ? 'up' : 'down';
|
|
1134
|
+
const icon = d.Up ? 'fa-arrow-up' : 'fa-arrow-down';
|
|
1135
|
+
const label = this.escapeHtml(d.Label);
|
|
1136
|
+
// The arrow is the direction of RISK, not of the score column, so the tooltip says so.
|
|
1137
|
+
const title = `${label}: ${d.Up ? 'raises' : 'lowers'} risk`;
|
|
1138
|
+
return `<span class="ps-why-chip ${cls}" title="${title}"><i class="fa-solid ${icon}"></i> ${label}</span>`;
|
|
1139
|
+
}).join(' ');
|
|
1136
1140
|
return `<div class="pg-drivers-cell">${chips}</div>`;
|
|
1137
1141
|
},
|
|
1138
1142
|
},
|
|
@@ -1206,125 +1210,122 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1206
1210
|
return this.Reload();
|
|
1207
1211
|
}
|
|
1208
1212
|
async loadPredictions() {
|
|
1213
|
+
this.resetRunState();
|
|
1209
1214
|
if (!this.modelId && !this.RunId) {
|
|
1210
|
-
this.AllRows = [];
|
|
1211
1215
|
this.applyFilter();
|
|
1212
1216
|
return;
|
|
1213
1217
|
}
|
|
1214
1218
|
this.isLoading = true;
|
|
1215
|
-
this.loadError = null;
|
|
1216
1219
|
this.cdr.markForCheck();
|
|
1217
1220
|
try {
|
|
1218
1221
|
const provider = this.ProviderToUse;
|
|
1219
1222
|
const user = provider.CurrentUser ?? undefined;
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
let model = null;
|
|
1223
|
-
if (this.modelId) {
|
|
1224
|
-
const modelsRes = await RunView.FromMetadataProvider(provider).RunView({
|
|
1225
|
-
EntityName: 'MJ: ML Models',
|
|
1226
|
-
ExtraFilter: `ID = '${this.modelId.replace(/'/g, "''")}'`,
|
|
1227
|
-
MaxRows: 1,
|
|
1228
|
-
ResultType: 'entity_object',
|
|
1229
|
-
}, user);
|
|
1230
|
-
model = modelsRes.Success && modelsRes.Results ? modelsRes.Results[0] : null;
|
|
1231
|
-
}
|
|
1232
|
-
if (!effectiveRunId && this.modelId) {
|
|
1233
|
-
// Query latest process run for this model using engine
|
|
1234
|
-
try {
|
|
1235
|
-
const engine = PredictiveStudioEngine.Instance;
|
|
1236
|
-
const runs = await engine.LoadRecentRunsForModel(this.modelId, provider, user, { maxRows: 1 });
|
|
1237
|
-
if (runs && runs.length > 0) {
|
|
1238
|
-
effectiveRunId = runs[0].ID;
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
catch {
|
|
1242
|
-
// Fallback if engine is not yet primed
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1223
|
+
const model = await this.loadModel();
|
|
1224
|
+
const effectiveRunId = this.RunId ?? (await this.resolveLatestRunId());
|
|
1245
1225
|
if (!effectiveRunId) {
|
|
1246
|
-
this.AllRows = [];
|
|
1247
1226
|
this.applyFilter();
|
|
1248
|
-
this.
|
|
1249
|
-
this.cdr.markForCheck();
|
|
1227
|
+
this.RowsLoaded.emit({ Rows: [], Capped: false });
|
|
1250
1228
|
return;
|
|
1251
1229
|
}
|
|
1252
|
-
// 2. Resolve target entity
|
|
1253
1230
|
await this.resolveTargetEntity(model);
|
|
1254
|
-
//
|
|
1255
|
-
const
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
OrderBy: '__mj_CreatedAt ASC',
|
|
1259
|
-
MaxRows: 10000,
|
|
1260
|
-
ResultType: 'entity_object',
|
|
1261
|
-
}, user);
|
|
1262
|
-
if (!detailsRes.Success || !detailsRes.Results) {
|
|
1263
|
-
this.AllRows = [];
|
|
1264
|
-
this.applyFilter();
|
|
1265
|
-
this.isLoading = false;
|
|
1266
|
-
this.cdr.markForCheck();
|
|
1267
|
-
return;
|
|
1268
|
-
}
|
|
1269
|
-
// 4. Resolve OutcomeConfig and determine polarity
|
|
1270
|
-
if (model?.ProblemType) {
|
|
1271
|
-
this.ProblemType = model.ProblemType.toLowerCase();
|
|
1272
|
-
}
|
|
1273
|
-
this.OutcomeConfig = resolveOutcomeConfig(model ?? undefined);
|
|
1274
|
-
this.IsRenewalModel = this.OutcomeConfig.Polarity === 'positive' && !this.IsRegression;
|
|
1275
|
-
this.SetupColumnDefs();
|
|
1276
|
-
const polarity = ResolveRenewalPolarity(detailsRes.Results.map((d) => d.ResultPayload), model?.TargetVariable);
|
|
1277
|
-
// When the model outputs P(Renewed) (scoreIsLapseRisk = false), adverse risk is inverted (1 - score).
|
|
1278
|
-
// When the model outputs P(Lapse) (scoreIsLapseRisk = true), adverse risk is ALREADY score (invertedRisk = false).
|
|
1279
|
-
const shouldInvertRisk = polarity.IsRenewalModel ? !polarity.ScoreIsLapseRisk : false;
|
|
1280
|
-
const parsedAtRisk = ParseAtRiskRows(detailsRes.Results.map((d) => ({ recordId: d.RecordID, ResultPayload: d.ResultPayload })), { InvertedRisk: shouldInvertRisk, OutcomeConfig: this.OutcomeConfig });
|
|
1281
|
-
// Map details into indexed lookup for scoredAt timestamp
|
|
1231
|
+
// The run's process run details by keyset paging, read-only and only the columns the grid uses; throws on failure.
|
|
1232
|
+
const read = await PredictiveStudioEngine.Instance.LoadRunDetails(effectiveRunId, provider, user);
|
|
1233
|
+
this.applyModelOptions(model);
|
|
1234
|
+
const parsedAtRisk = AtRiskRules.ParseAtRiskRows(read.Rows.map((d) => ({ RecordID: d.RecordID, ResultPayload: d.ResultPayload })), { InvertedRisk: this.IsRenewalModel });
|
|
1282
1235
|
const detailByRecord = new Map();
|
|
1283
|
-
for (const d of
|
|
1236
|
+
for (const d of read.Rows) {
|
|
1284
1237
|
detailByRecord.set(NormalizeUUID(d.RecordID), d);
|
|
1285
1238
|
}
|
|
1286
|
-
this.AllRows = parsedAtRisk.map((r) =>
|
|
1287
|
-
|
|
1288
|
-
const dt = detail?.CompletedAt ?? detail?.__mj_CreatedAt ?? null;
|
|
1289
|
-
// For renewal models, the primary displayed score is Renewal Probability (0–1).
|
|
1290
|
-
// If the raw score was lapse risk, renewal probability is 1 - r.score.
|
|
1291
|
-
// Otherwise, raw score is already renewal probability.
|
|
1292
|
-
const displayScore = polarity.IsRenewalModel
|
|
1293
|
-
? (polarity.ScoreIsLapseRisk ? Math.max(0, Math.min(1, 1 - r.score)) : r.score)
|
|
1294
|
-
: r.score;
|
|
1295
|
-
const resolved = this.OutcomeConfig
|
|
1296
|
-
? resolveScoreBand(displayScore, this.OutcomeConfig)
|
|
1297
|
-
: null;
|
|
1298
|
-
const formatted = formatPredictionScore(displayScore, this.OutcomeConfig, this.ProblemType);
|
|
1299
|
-
return {
|
|
1300
|
-
recordId: r.recordId,
|
|
1301
|
-
recordName: r.label ?? r.recordId,
|
|
1302
|
-
score: displayScore,
|
|
1303
|
-
scoreFormatted: formatted,
|
|
1304
|
-
riskPct: r.riskPct,
|
|
1305
|
-
band: resolved?.Key ?? r.band,
|
|
1306
|
-
badgeColor: resolved?.BadgeColor ?? r.badgeColor,
|
|
1307
|
-
icon: resolved?.Icon ?? r.icon,
|
|
1308
|
-
class: r.class,
|
|
1309
|
-
drivers: r.drivers ?? [],
|
|
1310
|
-
status: resolved?.Label ?? r.status ?? detail?.Status ?? 'Succeeded',
|
|
1311
|
-
scoredAtDate: dt instanceof Date ? dt : dt ? new Date(dt) : null,
|
|
1312
|
-
};
|
|
1313
|
-
});
|
|
1239
|
+
this.AllRows = parsedAtRisk.map((r) => this.toGridRow(r, detailByRecord.get(NormalizeUUID(r.RecordID))));
|
|
1240
|
+
this.DetailRowsCapped = read.Capped;
|
|
1314
1241
|
this.computeVisibleBands();
|
|
1315
1242
|
this.applyFilter();
|
|
1316
|
-
|
|
1243
|
+
this.RowsLoaded.emit({ Rows: parsedAtRisk, Capped: read.Capped });
|
|
1244
|
+
// Lazy lookup of record names for visible rows
|
|
1317
1245
|
this.ScheduleVisibleRowsLookup(0);
|
|
1318
1246
|
}
|
|
1319
1247
|
catch (err) {
|
|
1320
1248
|
this.loadError = err instanceof Error ? err.message : String(err);
|
|
1321
1249
|
LogError(`PSPredictionsGridComponent.loadPredictions: ${this.loadError}`);
|
|
1250
|
+
this.RowsLoadFailed.emit(this.loadError);
|
|
1322
1251
|
}
|
|
1323
1252
|
finally {
|
|
1324
1253
|
this.isLoading = false;
|
|
1325
1254
|
this.cdr.markForCheck();
|
|
1326
1255
|
}
|
|
1327
1256
|
}
|
|
1257
|
+
/** Clears everything derived from the previous run, so a model or run switch never shows the old run's rows or notices. */
|
|
1258
|
+
resetRunState() {
|
|
1259
|
+
this.AllRows = [];
|
|
1260
|
+
this.FilteredRows = [];
|
|
1261
|
+
this.VisibleBands = [];
|
|
1262
|
+
this.DetailRowsCapped = false;
|
|
1263
|
+
this.loadError = null;
|
|
1264
|
+
this.SelectedTier = 'all';
|
|
1265
|
+
this.SelectedDecileIndex = null;
|
|
1266
|
+
}
|
|
1267
|
+
/** The grid's model, or null when no model id is bound. */
|
|
1268
|
+
async loadModel() {
|
|
1269
|
+
if (!this.modelId)
|
|
1270
|
+
return null;
|
|
1271
|
+
const provider = this.ProviderToUse;
|
|
1272
|
+
const modelsRes = await RunView.FromMetadataProvider(provider).RunView({
|
|
1273
|
+
EntityName: 'MJ: ML Models',
|
|
1274
|
+
ExtraFilter: `ID = '${EscapeSQLString(this.modelId)}'`,
|
|
1275
|
+
MaxRows: 1,
|
|
1276
|
+
ResultType: 'entity_object',
|
|
1277
|
+
}, provider.CurrentUser ?? undefined);
|
|
1278
|
+
return modelsRes.Success && modelsRes.Results ? modelsRes.Results[0] ?? null : null;
|
|
1279
|
+
}
|
|
1280
|
+
/** The model's latest run when no run id is bound, or null when it has none. */
|
|
1281
|
+
async resolveLatestRunId() {
|
|
1282
|
+
if (!this.modelId)
|
|
1283
|
+
return null;
|
|
1284
|
+
const provider = this.ProviderToUse;
|
|
1285
|
+
const runs = await PredictiveStudioEngine.Instance.LoadRecentRunsForModel(this.modelId, provider, provider.CurrentUser ?? undefined, { maxRows: 1 });
|
|
1286
|
+
return runs[0]?.ID ?? null;
|
|
1287
|
+
}
|
|
1288
|
+
/** The model's problem type, outcome config and polarity: one rule (`BuildAtRiskOptions`), shared with the resource and the gate probe. */
|
|
1289
|
+
applyModelOptions(model) {
|
|
1290
|
+
if (model?.ProblemType) {
|
|
1291
|
+
this.ProblemType = model.ProblemType.toLowerCase();
|
|
1292
|
+
}
|
|
1293
|
+
const atRiskOptions = AtRiskRules.BuildAtRiskOptions(model ?? undefined);
|
|
1294
|
+
this.OutcomeConfig = atRiskOptions.OutcomeConfig;
|
|
1295
|
+
// A positive-polarity score is P(good outcome): risk is 1 - score, while the displayed score stays the model's own.
|
|
1296
|
+
this.IsRenewalModel = atRiskOptions.InvertedRisk === true;
|
|
1297
|
+
this.SetupColumnDefs();
|
|
1298
|
+
}
|
|
1299
|
+
/** One displayed row: the model's own score, its risk, and its tier (risk band, or outcome band for regression). */
|
|
1300
|
+
toGridRow(r, detail) {
|
|
1301
|
+
const dt = detail?.CompletedAt ?? detail?.__mj_CreatedAt ?? null;
|
|
1302
|
+
const tier = this.tierFor(r);
|
|
1303
|
+
return {
|
|
1304
|
+
recordId: r.RecordID,
|
|
1305
|
+
recordName: r.Label || r.RecordID,
|
|
1306
|
+
score: r.Score,
|
|
1307
|
+
scoreFormatted: formatPredictionScore(r.Score, this.OutcomeConfig, this.ProblemType),
|
|
1308
|
+
riskPct: r.RiskPct,
|
|
1309
|
+
band: tier.Key,
|
|
1310
|
+
badgeColor: tier.BadgeColor,
|
|
1311
|
+
icon: tier.Icon,
|
|
1312
|
+
class: r.Class,
|
|
1313
|
+
drivers: r.Drivers || [],
|
|
1314
|
+
status: tier.Label,
|
|
1315
|
+
scoredAtDate: dt instanceof Date ? dt : dt ? new Date(dt) : null,
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* A row's tier. Classification: the risk band Core put on the row, so "High" is the riskiest records whatever the
|
|
1320
|
+
* polarity. Regression: the outcome band of the raw value (risk bands do not apply to a value such as an LTV).
|
|
1321
|
+
*/
|
|
1322
|
+
tierFor(r) {
|
|
1323
|
+
if (!this.IsRegression) {
|
|
1324
|
+
return { Key: r.Band, Label: r.Status, BadgeColor: r.BadgeColor, Icon: r.Icon };
|
|
1325
|
+
}
|
|
1326
|
+
const band = ResolveScoreBand(r.Score, this.OutcomeConfig);
|
|
1327
|
+
return band ? { Key: band.Key, Label: band.Label, BadgeColor: band.BadgeColor, Icon: band.Icon } : PSPredictionsGridComponent.unbandedTier;
|
|
1328
|
+
}
|
|
1328
1329
|
async resolveTargetEntity(model) {
|
|
1329
1330
|
const provider = this.ProviderToUse;
|
|
1330
1331
|
if (this.entityName) {
|
|
@@ -1338,7 +1339,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1338
1339
|
if (model?.PipelineID) {
|
|
1339
1340
|
const pRes = await RunView.FromMetadataProvider(provider).RunView({
|
|
1340
1341
|
EntityName: 'MJ: ML Training Pipelines',
|
|
1341
|
-
ExtraFilter: `ID = '${model.PipelineID
|
|
1342
|
+
ExtraFilter: `ID = '${EscapeSQLString(model.PipelineID)}'`,
|
|
1342
1343
|
MaxRows: 1,
|
|
1343
1344
|
ResultType: 'simple',
|
|
1344
1345
|
Fields: ['TargetEntityID'],
|
|
@@ -1595,47 +1596,42 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1595
1596
|
getBadgeColorVar(color) {
|
|
1596
1597
|
return this.GetBadgeColorVar(color);
|
|
1597
1598
|
}
|
|
1599
|
+
/**
|
|
1600
|
+
* The tier chips and KPI cards, each with its tier's average model score. Classification: one per risk band (the
|
|
1601
|
+
* at-risk list's tiers). Regression: one per configured outcome band, plus any tier a row landed in outside them.
|
|
1602
|
+
*/
|
|
1598
1603
|
computeVisibleBands() {
|
|
1599
|
-
const
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
count,
|
|
1612
|
-
pct,
|
|
1613
|
-
avgScore,
|
|
1614
|
-
avgScoreFormatted,
|
|
1615
|
-
badgeColor: b.BadgeColor,
|
|
1616
|
-
icon: b.Icon,
|
|
1617
|
-
description: b.Description,
|
|
1618
|
-
};
|
|
1619
|
-
});
|
|
1620
|
-
const knownKeys = new Set(bands.map((b) => b.Key));
|
|
1621
|
-
const extraKeys = new Set(this.AllRows.map((r) => r.band).filter((k) => !knownKeys.has(k)));
|
|
1622
|
-
for (const k of extraKeys) {
|
|
1623
|
-
const matching = this.AllRows.filter((r) => r.band === k);
|
|
1624
|
-
const count = matching.length;
|
|
1625
|
-
const pct = total > 0 ? Math.round((count / total) * 100) : 0;
|
|
1626
|
-
const rawAvg = count > 0 ? matching.reduce((sum, r) => sum + r.score, 0) / count : 0;
|
|
1627
|
-
const avgScore = Math.round(rawAvg * 100);
|
|
1628
|
-
const avgScoreFormatted = formatPredictionScore(rawAvg, this.OutcomeConfig, this.ProblemType);
|
|
1629
|
-
this.VisibleBands.push({
|
|
1630
|
-
key: k,
|
|
1631
|
-
label: k.charAt(0).toUpperCase() + k.slice(1),
|
|
1632
|
-
count,
|
|
1633
|
-
pct,
|
|
1634
|
-
avgScore,
|
|
1635
|
-
avgScoreFormatted,
|
|
1636
|
-
badgeColor: 'gray',
|
|
1637
|
-
});
|
|
1604
|
+
const tiers = this.IsRegression ? this.regressionTiers() : AtRiskRules.RiskBands.map((b) => ({ Key: b.Key, Label: b.Label, BadgeColor: b.BadgeColor, Icon: b.Icon }));
|
|
1605
|
+
this.VisibleBands = tiers.map((t) => this.summarizeTier(t));
|
|
1606
|
+
}
|
|
1607
|
+
/** The configured outcome bands, then each other tier the rows carry (e.g. values outside every band), in row order. */
|
|
1608
|
+
regressionTiers() {
|
|
1609
|
+
const tiers = (this.OutcomeConfig.Bands ?? []).map((b) => ({ Key: b.Key, Label: b.Label, BadgeColor: b.BadgeColor, Icon: b.Icon }));
|
|
1610
|
+
const known = new Set(tiers.map((t) => t.Key));
|
|
1611
|
+
for (const r of this.AllRows) {
|
|
1612
|
+
if (!known.has(r.band)) {
|
|
1613
|
+
known.add(r.band);
|
|
1614
|
+
tiers.push({ Key: r.band, Label: r.status, BadgeColor: r.badgeColor || 'gray', Icon: r.icon });
|
|
1615
|
+
}
|
|
1638
1616
|
}
|
|
1617
|
+
return tiers;
|
|
1618
|
+
}
|
|
1619
|
+
/** A tier's chip / KPI card: its row count, share and average model score. */
|
|
1620
|
+
summarizeTier(t) {
|
|
1621
|
+
const total = this.AllRows.length;
|
|
1622
|
+
const matching = this.AllRows.filter((r) => r.band === t.Key);
|
|
1623
|
+
const count = matching.length;
|
|
1624
|
+
const rawAvg = count > 0 ? matching.reduce((sum, r) => sum + r.score, 0) / count : 0;
|
|
1625
|
+
return {
|
|
1626
|
+
key: t.Key,
|
|
1627
|
+
label: t.Label,
|
|
1628
|
+
count,
|
|
1629
|
+
pct: total > 0 ? Math.round((count / total) * 100) : 0,
|
|
1630
|
+
avgScore: Math.round(rawAvg * 100),
|
|
1631
|
+
avgScoreFormatted: formatPredictionScore(rawAvg, this.OutcomeConfig, this.ProblemType),
|
|
1632
|
+
badgeColor: t.BadgeColor,
|
|
1633
|
+
icon: t.Icon,
|
|
1634
|
+
};
|
|
1639
1635
|
}
|
|
1640
1636
|
OnViewToggle(key) {
|
|
1641
1637
|
this.ActiveView = key === 'chart' ? 'chart' : 'grid';
|
|
@@ -1682,6 +1678,12 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1682
1678
|
clearDecileFilter() {
|
|
1683
1679
|
return this.ClearDecileFilter();
|
|
1684
1680
|
}
|
|
1681
|
+
/** The selected tier's label for the footer ("High risk", or an outcome band's label), empty when all tiers show. */
|
|
1682
|
+
get SelectedTierLabel() {
|
|
1683
|
+
if (this.SelectedTier === 'all')
|
|
1684
|
+
return '';
|
|
1685
|
+
return this.VisibleBands.find((b) => b.key === this.SelectedTier)?.label ?? this.SelectedTier;
|
|
1686
|
+
}
|
|
1685
1687
|
get SelectedDecileLabel() {
|
|
1686
1688
|
if (this.SelectedDecileIndex === null)
|
|
1687
1689
|
return '';
|
|
@@ -1706,7 +1708,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1706
1708
|
rows = rows.filter((r) => r.recordName.toLowerCase().includes(q) ||
|
|
1707
1709
|
r.recordId.toLowerCase().includes(q) ||
|
|
1708
1710
|
(r.class && r.class.toLowerCase().includes(q)) ||
|
|
1709
|
-
r.drivers.some((d) => d.
|
|
1711
|
+
r.drivers.some((d) => d.Label.toLowerCase().includes(q)));
|
|
1710
1712
|
}
|
|
1711
1713
|
this.FilteredRows = rows;
|
|
1712
1714
|
this.cdr.markForCheck();
|
|
@@ -1823,7 +1825,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1823
1825
|
return;
|
|
1824
1826
|
const recRes = await RunView.FromMetadataProvider(provider).RunView({
|
|
1825
1827
|
EntityName: entity.Name,
|
|
1826
|
-
ExtraFilter: `${entity.FirstPrimaryKey.Name} = '${recordId
|
|
1828
|
+
ExtraFilter: `${entity.FirstPrimaryKey.Name} = '${EscapeSQLString(recordId)}'`, // first-pk-ok: Single-key entity lookup by recordId
|
|
1827
1829
|
MaxRows: 1,
|
|
1828
1830
|
ResultType: 'simple',
|
|
1829
1831
|
Fields: [matchedField],
|
|
@@ -1864,6 +1866,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
1864
1866
|
modelId: this.modelId,
|
|
1865
1867
|
OutcomeConfig: this.OutcomeConfig,
|
|
1866
1868
|
ProblemType: this.ProblemType,
|
|
1869
|
+
InvertedRisk: this.IsRenewalModel,
|
|
1867
1870
|
});
|
|
1868
1871
|
}
|
|
1869
1872
|
finally {
|
|
@@ -2019,7 +2022,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2019
2022
|
// Power scale height so smaller decile bins (e.g. 2, 21, 35) are visible alongside 5,390
|
|
2020
2023
|
const height = count === 0 ? 0 : Math.round(14 + Math.pow(count / maxCount, 0.45) * 116);
|
|
2021
2024
|
const centerScore = (binMin + binMax) / 2;
|
|
2022
|
-
const band =
|
|
2025
|
+
const band = ResolveScoreBand(centerScore, this.OutcomeConfig);
|
|
2023
2026
|
const color = band ? this.GetBadgeColorVar(band.BadgeColor) : 'var(--mj-brand-primary)';
|
|
2024
2027
|
let label;
|
|
2025
2028
|
let shortLabel;
|
|
@@ -2113,7 +2116,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2113
2116
|
? Math.max(0, Math.min(1, (pt.score - minScore) / range))
|
|
2114
2117
|
: Math.max(0, Math.min(1, pt.score));
|
|
2115
2118
|
const y = Math.round(yBottom - clampedScore * ySpan);
|
|
2116
|
-
const band =
|
|
2119
|
+
const band = ResolveScoreBand(pt.score, this.OutcomeConfig);
|
|
2117
2120
|
const color = band ? this.GetBadgeColorVar(band.BadgeColor) : 'var(--mj-brand-primary)';
|
|
2118
2121
|
return {
|
|
2119
2122
|
runId: pt.runId,
|
|
@@ -2155,10 +2158,11 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2155
2158
|
return;
|
|
2156
2159
|
const scoreHeader = this.OutcomeConfig.ScoreLabel || 'Prediction Score';
|
|
2157
2160
|
const statusHeader = this.OutcomeConfig.StatusLabel || 'Risk Level';
|
|
2158
|
-
const headers = ['Record ID', 'Record Name', scoreHeader, statusHeader, 'Predicted Class', 'Top Drivers', 'Scored At'];
|
|
2159
|
-
|
|
2161
|
+
const headers = ['Record ID', 'Record Name', scoreHeader, statusHeader, 'Predicted Class', 'Top Drivers (+ raises risk, − lowers risk)', 'Scored At'];
|
|
2162
|
+
// Quoted: the drivers header carries a comma.
|
|
2163
|
+
const lines = [headers.map((h) => `"${h.replace(/"/g, '""')}"`).join(',')];
|
|
2160
2164
|
for (const r of this.FilteredRows) {
|
|
2161
|
-
const driversStr = r.drivers.map((d) => `${d.
|
|
2165
|
+
const driversStr = r.drivers.map((d) => `${d.Up ? '+' : '−'}${d.Label}`).join('; ');
|
|
2162
2166
|
const statusStr = `${r.status || r.band} (${r.scoreFormatted})`;
|
|
2163
2167
|
const rowData = [
|
|
2164
2168
|
`"${r.recordId.replace(/"/g, '""')}"`,
|
|
@@ -2192,7 +2196,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2192
2196
|
.replace(/'/g, ''');
|
|
2193
2197
|
}
|
|
2194
2198
|
static ɵfac = /*@__PURE__*/ (() => { let ɵPSPredictionsGridComponent_BaseFactory; return function PSPredictionsGridComponent_Factory(__ngFactoryType__) { return (ɵPSPredictionsGridComponent_BaseFactory || (ɵPSPredictionsGridComponent_BaseFactory = i0.ɵɵgetInheritedFactory(PSPredictionsGridComponent)))(__ngFactoryType__ || PSPredictionsGridComponent); }; })();
|
|
2195
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSPredictionsGridComponent, selectors: [["ps-predictions-grid"]], inputs: { modelId: "modelId", RunId: "RunId", runId: "runId", entityName: "entityName", ProblemType: "ProblemType", problemType: "problemType", title: "title", height: "height", ReadOnly: "ReadOnly", readOnly: "readOnly" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 27, vars: 15, consts: [[1, "ps-pred-grid-host"], [1, "pg-toolbar"], [1, "pg-toolbar-left"], [1, "pg-search-box"], [1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "placeholder", "Filter records, outcome, factors...", 1, "pg-search-input", 3, "input", "value"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear"], [1, "pg-tier-filters"], ["type", "button", 1, "pg-tier-btn", 3, "click"], [1, "pg-count-pill"], ["type", "button", 1, "pg-tier-btn", 3, "active"], [1, "pg-decile-pill"], [1, "pg-toolbar-right"], [3, "KeyChange", "Options", "ActiveKey"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-file-export"], [1, "pg-view-container"], ["text", "Loading predictions...", "size", "medium"], ["role", "alert", 1, "ps-load-error"], [1, "ps-empty", 2, "padding", "32px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "Resizable", "WidthPx"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "fa-solid", "fa-filter"], ["type", "button", "title", "Clear decile filter", 3, "click"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "ps-load-error-text"], [1, "ps-load-error-detail"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "ps-empty-ico"], [1, "fa-solid", "fa-chart-line"], [1, "pg-chart-container"], [1, "pg-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-footer"], [1, "ps-muted"], [1, "pg-chart-cards"], [1, "pg-chart-card", "total"], [1, "pg-chart-card-lbl"], [1, "fa-solid", "fa-users", "ps-muted"], [1, "pg-chart-card-val"], [1, "pg-chart-card-sub"], [1, "pg-chart-card", 3, "class"], [1, "pg-chart-section"], [1, "pg-chart-section-title"], [2, "display", "flex", "align-items", "center", "gap", "8px"], [1, "fa-solid", "fa-chart-simple", "ps-muted"], [1, "pg-chart-meta"], [1, "ps-small", "ps-muted"], ["type", "button", 1, "pg-clear-decile-btn"], [1, "pg-histogram"], [1, "pg-h-columns"], [1, "pg-h-col", 3, "active", "empty"], ["id", "pg-drilldown-anchor", 1, "pg-chart-section", "pg-chart-drilldown-section"], [1, "pg-chart-card", 3, "click"], [3, "class", "color"], ["type", "button", 1, "pg-clear-decile-btn", 3, "click"], [1, "pg-h-col", 3, "click"], [1, "pg-h-count", 3, "title"], [1, "pg-h-bar-track"], [1, "pg-h-bar"], [1, "pg-h-footer"], [1, "pg-h-range"], [1, "pg-h-pct"], [1, "pg-h-tooltip"], [1, "pg-h-tt-head"], [1, "pg-h-tt-row"], [1, "pg-h-tt-val"], [1, "pg-h-tt-pct"], [1, "pg-h-tt-badge"], [1, "pg-h-tt-hint"], [1, "fa-solid", "fa-layer-group", "ps-muted"], [2, "display", "flex", "height", "24px", "border-radius", "var(--mj-radius-full)", "overflow", "hidden", "background", "var(--mj-bg-surface-sunken)", "margin-bottom", "8px"], [3, "width", "background", "title"], [2, "display", "flex", "gap", "16px", "flex-wrap", "wrap"], [2, "display", "flex", "align-items", "center", "gap", "6px", "font-size", "var(--mj-text-xs)"], [3, "title"], [2, "width", "10px", "height", "10px", "border-radius", "2px", "display", "inline-block"], [1, "fa-solid", "fa-table-list", "ps-muted"], [2, "color", "var(--mj-brand-primary)"], [1, "ps-badge", 2, "margin-left", "6px", 3, "color"], [1, "pg-chart-grid-host"], [1, "pg-grid", "pg-chart-ag-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-drilldown-footer"], [1, "ps-badge", 2, "margin-left", "6px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "WidthChanged", "Closed", "Resizable", "WidthPx"], [1, "pg-detail-body"], [1, "pg-detail-record-head"], [1, "pg-detail-record-info"], [1, "ps-badge", "blue"], [1, "ps-mono", "ps-small", "ps-muted"], [1, "pg-detail-record-actions", 2, "display", "flex", "gap", "8px", "align-items", "center", "flex-wrap", "wrap"], ["mjButton", "", "variant", "primary", "size", "sm", "title", "Open record in Explorer", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Open subject record (e.g. Person, Account) in Explorer"], [1, "pg-detail-pred-card"], [1, "pg-detail-score-circle"], [1, "pg-detail-meta"], [1, "pg-detail-meta-line"], [3, "class"], [2, "font-weight", "700", "color", "var(--mj-text-primary)"], [1, "pg-detail-meta-sub"], [1, "pg-detail-drivers-wrap"], [1, "ps-section-title"], [1, "fa-solid", "fa-lightbulb", 2, "color", "var(--mj-status-warning)"], [
|
|
2199
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSPredictionsGridComponent, selectors: [["ps-predictions-grid"]], inputs: { modelId: "modelId", RunId: "RunId", runId: "runId", entityName: "entityName", ProblemType: "ProblemType", problemType: "problemType", title: "title", height: "height", ReadOnly: "ReadOnly", readOnly: "readOnly" }, outputs: { RowsLoaded: "RowsLoaded", RowsLoadFailed: "RowsLoadFailed" }, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 27, vars: 15, consts: [[1, "ps-pred-grid-host"], [1, "pg-toolbar"], [1, "pg-toolbar-left"], [1, "pg-search-box"], [1, "fa-solid", "fa-magnifying-glass"], ["type", "text", "placeholder", "Filter records, outcome, factors...", 1, "pg-search-input", 3, "input", "value"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear"], [1, "pg-tier-filters"], ["type", "button", 1, "pg-tier-btn", 3, "click"], [1, "pg-count-pill"], ["type", "button", 1, "pg-tier-btn", 3, "active"], [1, "pg-decile-pill"], [1, "pg-toolbar-right"], [3, "KeyChange", "Options", "ActiveKey"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], [1, "fa-solid", "fa-file-export"], [1, "pg-view-container"], ["text", "Loading predictions...", "size", "medium"], ["role", "alert", 1, "ps-load-error"], [1, "ps-empty", 2, "padding", "32px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "Resizable", "WidthPx"], ["type", "button", "title", "Clear filter", 1, "pg-search-clear", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "fa-solid", "fa-filter"], ["type", "button", "title", "Clear decile filter", 3, "click"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "ps-load-error-text"], [1, "ps-load-error-detail"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-rotate-right"], [1, "ps-empty-ico"], [1, "fa-solid", "fa-chart-line"], [1, "pg-chart-container"], [1, "pg-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-footer"], [1, "ps-muted"], ["data-testid", "ps-predictions-capped", 1, "ps-muted"], [1, "pg-chart-cards"], [1, "pg-chart-card", "total"], [1, "pg-chart-card-lbl"], [1, "fa-solid", "fa-users", "ps-muted"], [1, "pg-chart-card-val"], [1, "pg-chart-card-sub"], [1, "pg-chart-card", 3, "class"], [1, "pg-chart-section"], [1, "pg-chart-section-title"], [2, "display", "flex", "align-items", "center", "gap", "8px"], [1, "fa-solid", "fa-chart-simple", "ps-muted"], [1, "pg-chart-meta"], [1, "ps-small", "ps-muted"], ["type", "button", 1, "pg-clear-decile-btn"], [1, "pg-histogram"], [1, "pg-h-columns"], [1, "pg-h-col", 3, "active", "empty"], ["id", "pg-drilldown-anchor", 1, "pg-chart-section", "pg-chart-drilldown-section"], [1, "pg-chart-card", 3, "click"], [3, "class", "color"], ["type", "button", 1, "pg-clear-decile-btn", 3, "click"], [1, "pg-h-col", 3, "click"], [1, "pg-h-count", 3, "title"], [1, "pg-h-bar-track"], [1, "pg-h-bar"], [1, "pg-h-footer"], [1, "pg-h-range"], [1, "pg-h-pct"], [1, "pg-h-tooltip"], [1, "pg-h-tt-head"], [1, "pg-h-tt-row"], [1, "pg-h-tt-val"], [1, "pg-h-tt-pct"], [1, "pg-h-tt-badge"], [1, "pg-h-tt-hint"], [1, "fa-solid", "fa-layer-group", "ps-muted"], [2, "display", "flex", "height", "24px", "border-radius", "var(--mj-radius-full)", "overflow", "hidden", "background", "var(--mj-bg-surface-sunken)", "margin-bottom", "8px"], [3, "width", "background", "title"], [2, "display", "flex", "gap", "16px", "flex-wrap", "wrap"], [2, "display", "flex", "align-items", "center", "gap", "6px", "font-size", "var(--mj-text-xs)"], [3, "title"], [2, "width", "10px", "height", "10px", "border-radius", "2px", "display", "inline-block"], [1, "fa-solid", "fa-table-list", "ps-muted"], [2, "color", "var(--mj-brand-primary)"], [1, "ps-badge", 2, "margin-left", "6px", 3, "color"], [1, "pg-chart-grid-host"], [1, "pg-grid", "pg-chart-ag-grid", 3, "gridReady", "rowClicked", "cellClicked", "theme", "columnDefs", "defaultColDef", "gridOptions", "rowData"], [1, "pg-drilldown-footer"], [1, "ps-badge", 2, "margin-left", "6px"], ["Mode", "slide", "Title", "Record Prediction & Score History", 3, "WidthChanged", "Closed", "Resizable", "WidthPx"], [1, "pg-detail-body"], [1, "pg-detail-record-head"], [1, "pg-detail-record-info"], [1, "ps-badge", "blue"], [1, "ps-mono", "ps-small", "ps-muted"], [1, "pg-detail-record-actions", 2, "display", "flex", "gap", "8px", "align-items", "center", "flex-wrap", "wrap"], ["mjButton", "", "variant", "primary", "size", "sm", "title", "Open record in Explorer", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Open subject record (e.g. Person, Account) in Explorer"], [1, "pg-detail-pred-card"], [1, "pg-detail-score-circle"], [1, "pg-detail-meta"], [1, "pg-detail-meta-line"], [3, "class"], [2, "font-weight", "700", "color", "var(--mj-text-primary)"], [1, "pg-detail-meta-sub"], [1, "pg-detail-drivers-wrap"], [1, "ps-section-title"], [1, "fa-solid", "fa-lightbulb", 2, "color", "var(--mj-status-warning)"], [3, "Drivers"], [1, "pg-trendline-wrap"], [1, "ps-section-title", 2, "display", "flex", "align-items", "center", "justify-content", "space-between"], [1, "fa-solid", "fa-clock-rotate-left", "ps-muted"], ["text", "Loading score history...", "size", "small"], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Open subject record (e.g. Person, Account) in Explorer", 3, "click"], [1, "fa-solid", "fa-user"], [1, "ps-badge"], ["viewBox", "0 0 540 160", "preserveAspectRatio", "none", 1, "pg-trendline-svg"], ["x1", "40", "y1", "20", "x2", "520", "y2", "20", "stroke", "var(--mj-border-subtle)", "stroke-dasharray", "3,3"], ["x1", "40", "y1", "75", "x2", "520", "y2", "75", "stroke", "var(--mj-border-subtle)", "stroke-dasharray", "3,3"], ["x1", "40", "y1", "130", "x2", "520", "y2", "130", "stroke", "var(--mj-border-default)"], ["x", "32", "y", "24", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["x", "32", "y", "79", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["x", "32", "y", "134", "font-size", "10", "text-anchor", "end", "fill", "var(--mj-text-muted)"], ["fill", "color-mix(in srgb, var(--mj-brand-primary) 12%, transparent)"], ["fill", "none", "stroke", "var(--mj-brand-primary)", "stroke-width", "2.5"], [1, "pg-history-table"], ["r", "5", "stroke", "var(--mj-bg-surface)", "stroke-width", "2"], ["font-size", "10", "font-weight", "700", "text-anchor", "middle", "fill", "var(--mj-text-primary)"], [1, "ps-mono"], [1, "pg-delta-pill", "neutral"], [1, "pg-delta-pill", "up"], [1, "pg-delta-pill", "down"], [1, "fa-solid", "fa-arrow-up"], [1, "fa-solid", "fa-arrow-down"]], template: function PSPredictionsGridComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2196
2200
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3);
|
|
2197
2201
|
i0.ɵɵelement(4, "i", 4);
|
|
2198
2202
|
i0.ɵɵelementStart(5, "input", 5);
|
|
@@ -2221,7 +2225,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2221
2225
|
i0.ɵɵelementStart(21, "div", 16);
|
|
2222
2226
|
i0.ɵɵconditionalCreate(22, PSPredictionsGridComponent_Conditional_22_Template, 1, 0, "mj-loading", 17)(23, PSPredictionsGridComponent_Conditional_23_Template, 10, 1, "div", 18)(24, PSPredictionsGridComponent_Conditional_24_Template, 7, 0, "div", 19)(25, PSPredictionsGridComponent_Conditional_25_Template, 2, 2);
|
|
2223
2227
|
i0.ɵɵelementEnd();
|
|
2224
|
-
i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Template,
|
|
2228
|
+
i0.ɵɵconditionalCreate(26, PSPredictionsGridComponent_Conditional_26_Template, 51, 26, "mj-slide-panel", 20);
|
|
2225
2229
|
i0.ɵɵelementEnd();
|
|
2226
2230
|
} if (rf & 2) {
|
|
2227
2231
|
i0.ɵɵstyleProp("height", ctx.height);
|
|
@@ -2250,7 +2254,7 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2250
2254
|
SharedGenericModule, i1.LoadingComponent, MJButtonDirective,
|
|
2251
2255
|
MJViewToggleComponent,
|
|
2252
2256
|
MjSlidePanelComponent,
|
|
2253
|
-
AgGridModule, i2.AgGridAngular, i3.DecimalPipe, i3.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n\n.ps-panel[_ngcontent-%COMP%] {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n \n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n}\n\n\n.ps-row[_ngcontent-%COMP%] { display: flex; gap: 16px; }\n.ps-col[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap[_ngcontent-%COMP%] { flex-wrap: wrap; }\n.ps-spacer[_ngcontent-%COMP%] { flex: 1; }\n.ps-muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-small[_ngcontent-%COMP%] { font-size: 12.5px; }\n.ps-mono[_ngcontent-%COMP%] { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title[_ngcontent-%COMP%] {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n\n.ps-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body[_ngcontent-%COMP%] { padding: 16px; }\n\n\n.ps-kpi[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi[_ngcontent-%COMP%] .val[_ngcontent-%COMP%] { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n\n.ps-badge[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot[_ngcontent-%COMP%] { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n\n.ps-lvl[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-lvl-Strong[_ngcontent-%COMP%] { background: var(--mj-status-info); }\n.ps-lvl-Viable[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-lvl-Weak[_ngcontent-%COMP%] { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.ps-tag[_ngcontent-%COMP%] {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted[_ngcontent-%COMP%] { opacity: .6; }\n.ps-divider[_ngcontent-%COMP%] { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n\n.ps-table[_ngcontent-%COMP%] { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover td[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); }\n.ps-table[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n\n.ps-bar[_ngcontent-%COMP%] { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-bar.run[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n\n.ps-fbar[_ngcontent-%COMP%] { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar[_ngcontent-%COMP%] + .ps-fbar[_ngcontent-%COMP%] { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-fbar[_ngcontent-%COMP%] .name[_ngcontent-%COMP%] { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar[_ngcontent-%COMP%] > .ps-mono[_ngcontent-%COMP%] { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n\n.ps-gauge[_ngcontent-%COMP%] {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge[_ngcontent-%COMP%]::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge[_ngcontent-%COMP%] .g-val[_ngcontent-%COMP%] { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n\n.ps-callout[_ngcontent-%COMP%] { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 16px; margin-top: 1px; }\n\n\n.ps-stepper[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done[_ngcontent-%COMP%] { color: var(--mj-status-success-text); }\n.ps-step.done[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.ps-step.curr[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step[_ngcontent-%COMP%] .ln[_ngcontent-%COMP%] { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n\n.ps-flow[_ngcontent-%COMP%] {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node[_ngcontent-%COMP%] {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] .ps-tag[_ngcontent-%COMP%] { margin-left: auto; }\n.ps-node[_ngcontent-%COMP%] .nb[_ngcontent-%COMP%] { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] .k[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-node.src[_ngcontent-%COMP%] { border-left-color: var(--ps-node-source); }\n.ps-node.src[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-node.feat[_ngcontent-%COMP%] { border-left-color: var(--ps-node-feature); }\n.ps-node.feat[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-node.emb[_ngcontent-%COMP%] { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-node.target[_ngcontent-%COMP%] { border-left-color: var(--ps-node-target); }\n.ps-node.target[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-node.algo[_ngcontent-%COMP%] { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n.ps-node.output[_ngcontent-%COMP%] { border-left-color: var(--mj-status-success); }\n.ps-node.output[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-node.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node[_ngcontent-%COMP%] .port[_ngcontent-%COMP%] {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node[_ngcontent-%COMP%] .port.in[_ngcontent-%COMP%] { left: -6px; }\n.ps-node[_ngcontent-%COMP%] .port.out[_ngcontent-%COMP%] { right: -6px; }\nsvg.ps-edges[_ngcontent-%COMP%] { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges[_ngcontent-%COMP%] path[_ngcontent-%COMP%] { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n\n.ps-pchip[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-pchip.f[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-pchip.e[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-pchip.t[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-pchip.a[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n\n\n.ps-seg[_ngcontent-%COMP%] { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:last-child { border-right: none; }\n.ps-seg[_ngcontent-%COMP%] button.on[_ngcontent-%COMP%] { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n\n.ps-field[_ngcontent-%COMP%] { margin-bottom: 14px; }\n.ps-field[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input[_ngcontent-%COMP%] {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input[_ngcontent-%COMP%]:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n\n.ps-loading[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n\n.ps-empty[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty[_ngcontent-%COMP%] .ps-empty-ico[_ngcontent-%COMP%] {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n\n.ps-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal[_ngcontent-%COMP%] {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body[_ngcontent-%COMP%] { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body[_ngcontent-%COMP%] .ps-field[_ngcontent-%COMP%] { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot[_ngcontent-%COMP%] .ps-spacer[_ngcontent-%COMP%] { flex: 1; }", "\n\n\n\n\n.ps-pred-grid-host[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n\n.pg-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%] {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n\n.pg-view-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid[_ngcontent-%COMP%] {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n\n.pg-record-cell[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-name[_ngcontent-%COMP%] {\n text-decoration: underline;\n}\n\n.pg-record-open-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-open-icon[_ngcontent-%COMP%] {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar[_ngcontent-%COMP%] {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high[_ngcontent-%COMP%], \n.pg-score-fill.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium[_ngcontent-%COMP%], \n.pg-score-fill.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low[_ngcontent-%COMP%], \n.pg-score-fill.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-score-val[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high[_ngcontent-%COMP%], \n.pg-score-val.badge-red[_ngcontent-%COMP%] { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium[_ngcontent-%COMP%], \n.pg-score-val.badge-amber[_ngcontent-%COMP%] { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low[_ngcontent-%COMP%], \n.pg-score-val.badge-green[_ngcontent-%COMP%] { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.pg-drivers-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n\n.pg-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n\n.pg-chart-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n\n.pg-histogram[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar[_ngcontent-%COMP%] {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-bar[_ngcontent-%COMP%] {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active[_ngcontent-%COMP%] .pg-h-bar[_ngcontent-%COMP%] {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n\n.pg-h-tooltip[_ngcontent-%COMP%] {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-tooltip[_ngcontent-%COMP%] {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n\n.pg-detail-body[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle[_ngcontent-%COMP%] {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-detail-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.pg-detail-drivers-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.pg-detail-driver-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-sm);\n}\n\n.pg-detail-driver-label[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n\n.pg-trendline-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:last-child td[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n.pg-delta-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.pg-chart-drilldown-section[_ngcontent-%COMP%] {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host[_ngcontent-%COMP%] {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}"], changeDetection: 0 });
|
|
2257
|
+
AgGridModule, i2.AgGridAngular, PSRowDriversComponent, i3.DecimalPipe, i3.DatePipe], styles: ["\n\n\n\n\n\n\n\n\n\n\n\n\n.ps-panel[_ngcontent-%COMP%] {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n \n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n}\n\n\n.ps-row[_ngcontent-%COMP%] { display: flex; gap: 16px; }\n.ps-col[_ngcontent-%COMP%] { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap[_ngcontent-%COMP%] { flex-wrap: wrap; }\n.ps-spacer[_ngcontent-%COMP%] { flex: 1; }\n.ps-muted[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-small[_ngcontent-%COMP%] { font-size: 12.5px; }\n.ps-mono[_ngcontent-%COMP%] { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title[_ngcontent-%COMP%] {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n\n.ps-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body[_ngcontent-%COMP%] { padding: 16px; }\n\n\n.ps-kpi[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi[_ngcontent-%COMP%] .val[_ngcontent-%COMP%] { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n\n.ps-badge[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot[_ngcontent-%COMP%] { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n\n.ps-lvl[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-lvl-Strong[_ngcontent-%COMP%] { background: var(--mj-status-info); }\n.ps-lvl-Viable[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-lvl-Weak[_ngcontent-%COMP%] { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.ps-tag[_ngcontent-%COMP%] {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted[_ngcontent-%COMP%] { opacity: .6; }\n.ps-divider[_ngcontent-%COMP%] { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n\n.ps-table[_ngcontent-%COMP%] { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover td[_ngcontent-%COMP%] { background: var(--mj-bg-surface-hover); }\n.ps-table[_ngcontent-%COMP%] .num[_ngcontent-%COMP%] { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n\n.ps-bar[_ngcontent-%COMP%] { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-bar.run[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n\n.ps-fbar[_ngcontent-%COMP%] { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar[_ngcontent-%COMP%] + .ps-fbar[_ngcontent-%COMP%] { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span[_ngcontent-%COMP%] { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar[_ngcontent-%COMP%] .track[_ngcontent-%COMP%] > span.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.ps-fbar[_ngcontent-%COMP%] .name[_ngcontent-%COMP%] { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar[_ngcontent-%COMP%] > .ps-mono[_ngcontent-%COMP%] { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n\n.ps-gauge[_ngcontent-%COMP%] {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge[_ngcontent-%COMP%]::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge[_ngcontent-%COMP%] .g-val[_ngcontent-%COMP%] { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n\n.ps-callout[_ngcontent-%COMP%] { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info[_ngcontent-%COMP%] { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 16px; margin-top: 1px; }\n\n\n.ps-stepper[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done[_ngcontent-%COMP%] { color: var(--mj-status-success-text); }\n.ps-step.done[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.ps-step.curr[_ngcontent-%COMP%] .pip[_ngcontent-%COMP%] { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step[_ngcontent-%COMP%] .ln[_ngcontent-%COMP%] { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n\n.ps-flow[_ngcontent-%COMP%] {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node[_ngcontent-%COMP%] {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] .ps-tag[_ngcontent-%COMP%] { margin-left: auto; }\n.ps-node[_ngcontent-%COMP%] .nb[_ngcontent-%COMP%] { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node[_ngcontent-%COMP%] .nb-row[_ngcontent-%COMP%] .k[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n.ps-node.src[_ngcontent-%COMP%] { border-left-color: var(--ps-node-source); }\n.ps-node.src[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-node.feat[_ngcontent-%COMP%] { border-left-color: var(--ps-node-feature); }\n.ps-node.feat[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-node.emb[_ngcontent-%COMP%] { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-node.target[_ngcontent-%COMP%] { border-left-color: var(--ps-node-target); }\n.ps-node.target[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-node.algo[_ngcontent-%COMP%] { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n.ps-node.output[_ngcontent-%COMP%] { border-left-color: var(--mj-status-success); }\n.ps-node.output[_ngcontent-%COMP%] .nh[_ngcontent-%COMP%] i.tile[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.ps-node.selected[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node[_ngcontent-%COMP%] .port[_ngcontent-%COMP%] {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node[_ngcontent-%COMP%] .port.in[_ngcontent-%COMP%] { left: -6px; }\n.ps-node[_ngcontent-%COMP%] .port.out[_ngcontent-%COMP%] { right: -6px; }\nsvg.ps-edges[_ngcontent-%COMP%] { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges[_ngcontent-%COMP%] path[_ngcontent-%COMP%] { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n\n.ps-pchip[_ngcontent-%COMP%] {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-source); }\n.ps-pchip.f[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-feature); }\n.ps-pchip.e[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-embedding); }\n.ps-pchip.t[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-target); }\n.ps-pchip.a[_ngcontent-%COMP%] i[_ngcontent-%COMP%] { background: var(--ps-node-algorithm); }\n\n\n.ps-seg[_ngcontent-%COMP%] { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg[_ngcontent-%COMP%] button[_ngcontent-%COMP%]:last-child { border-right: none; }\n.ps-seg[_ngcontent-%COMP%] button.on[_ngcontent-%COMP%] { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n\n.ps-field[_ngcontent-%COMP%] { margin-bottom: 14px; }\n.ps-field[_ngcontent-%COMP%] > label[_ngcontent-%COMP%] {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input[_ngcontent-%COMP%] {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input[_ngcontent-%COMP%]:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n\n.ps-loading[_ngcontent-%COMP%] { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n\n.ps-empty[_ngcontent-%COMP%] {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty[_ngcontent-%COMP%] .ps-empty-ico[_ngcontent-%COMP%] {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty[_ngcontent-%COMP%] p[_ngcontent-%COMP%] { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n\n.ps-modal-backdrop[_ngcontent-%COMP%] {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal[_ngcontent-%COMP%] {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger[_ngcontent-%COMP%] .ico[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body[_ngcontent-%COMP%] { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body[_ngcontent-%COMP%] .ps-field[_ngcontent-%COMP%] { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot[_ngcontent-%COMP%] {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot[_ngcontent-%COMP%] .ps-spacer[_ngcontent-%COMP%] { flex: 1; }", "\n\n\n\n\n.ps-pred-grid-host[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n\n.pg-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%] {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n\n.pg-view-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid[_ngcontent-%COMP%] {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n\n.pg-record-cell[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-name[_ngcontent-%COMP%] {\n text-decoration: underline;\n}\n\n.pg-record-open-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link[_ngcontent-%COMP%]:hover .pg-record-open-icon[_ngcontent-%COMP%] {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar[_ngcontent-%COMP%] {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high[_ngcontent-%COMP%], \n.pg-score-fill.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium[_ngcontent-%COMP%], \n.pg-score-fill.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low[_ngcontent-%COMP%], \n.pg-score-fill.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-score-val[_ngcontent-%COMP%] {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high[_ngcontent-%COMP%], \n.pg-score-val.badge-red[_ngcontent-%COMP%] { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium[_ngcontent-%COMP%], \n.pg-score-val.badge-amber[_ngcontent-%COMP%] { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low[_ngcontent-%COMP%], \n.pg-score-val.badge-green[_ngcontent-%COMP%] { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray[_ngcontent-%COMP%] { color: var(--mj-text-muted); }\n\n.pg-drivers-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn[_ngcontent-%COMP%] {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n\n.pg-footer[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n\n.pg-chart-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low[_ngcontent-%COMP%] { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n\n.pg-histogram[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track[_ngcontent-%COMP%] {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar[_ngcontent-%COMP%] {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-bar[_ngcontent-%COMP%] {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active[_ngcontent-%COMP%] .pg-h-bar[_ngcontent-%COMP%] {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n\n.pg-h-tooltip[_ngcontent-%COMP%] {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col[_ngcontent-%COMP%]:hover .pg-h-tooltip[_ngcontent-%COMP%] {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint[_ngcontent-%COMP%] {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n\n.pg-detail-body[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle[_ngcontent-%COMP%] {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-red[_ngcontent-%COMP%] { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-amber[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low[_ngcontent-%COMP%], \n.pg-detail-score-circle.badge-green[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue[_ngcontent-%COMP%] { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray[_ngcontent-%COMP%] { background: var(--mj-text-muted); }\n\n.pg-detail-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n\n.pg-trendline-wrap[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg[_ngcontent-%COMP%] {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:last-child td[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n.pg-delta-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up[_ngcontent-%COMP%] { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down[_ngcontent-%COMP%] { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral[_ngcontent-%COMP%] { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n\n.pg-chart-drilldown-section[_ngcontent-%COMP%] {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host[_ngcontent-%COMP%] {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}"], changeDetection: 0 });
|
|
2254
2258
|
}
|
|
2255
2259
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PSPredictionsGridComponent, [{
|
|
2256
2260
|
type: Component,
|
|
@@ -2262,7 +2266,8 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2262
2266
|
MJViewToggleComponent,
|
|
2263
2267
|
MjSlidePanelComponent,
|
|
2264
2268
|
AgGridModule,
|
|
2265
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ps-pred-grid-host\" [style.height]=\"height\">\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-toolbar\">\n <div class=\"pg-toolbar-left\">\n <div class=\"pg-search-box\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <input\n type=\"text\"\n class=\"pg-search-input\"\n placeholder=\"Filter records, outcome, factors...\"\n [value]=\"searchText\"\n (input)=\"onSearchInput($event)\" />\n @if (searchText) {\n <button type=\"button\" class=\"pg-search-clear\" (click)=\"clearSearch()\" title=\"Clear filter\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n }\n </div>\n\n <div class=\"pg-tier-filters\">\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === 'all'\"\n (click)=\"setTier('all')\">\n All <span class=\"pg-count-pill\">({{ allRows.length | number }})</span>\n </button>\n @for (b of visibleBands; track b.key) {\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === b.key\"\n (click)=\"setTier(b.key)\">\n {{ b.label }} <span class=\"pg-count-pill\">({{ b.count | number }})</span>\n </button>\n }\n\n @if (selectedDecileIndex !== null) {\n <div class=\"pg-decile-pill\">\n <i class=\"fa-solid fa-filter\"></i>\n <span>Decile {{ selectedDecileLabel }}</span>\n <button type=\"button\" (click)=\"clearDecileFilter()\" title=\"Clear decile filter\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"pg-toolbar-right\">\n <mj-view-toggle\n [Options]=\"viewOptions\"\n [ActiveKey]=\"activeView\"\n (KeyChange)=\"onViewToggle($event)\">\n </mj-view-toggle>\n\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"allRows.length === 0\"\n (click)=\"exportCSV()\">\n <i class=\"fa-solid fa-file-export\"></i> Export\n </button>\n </div>\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MAIN VIEW CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-view-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading predictions...\" size=\"medium\"></mj-loading>\n } @else if (loadError) {\n <div class=\"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 predictions</strong>\n <span class=\"ps-load-error-detail\">{{ loadError }}</span>\n </div>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"reload()\"><i class=\"fa-solid fa-rotate-right\"></i> Try again</button>\n </div>\n } @else if (allRows.length === 0) {\n <div class=\"ps-empty\" style=\"padding: 32px\">\n <span class=\"ps-empty-ico\"><i class=\"fa-solid fa-chart-line\"></i></span>\n <h3>No predictions available</h3>\n <p>Run this model from Models in Production or wait for the scheduled job to produce predictions.</p>\n </div>\n } @else {\n <!-- GRID VIEW -->\n @if (activeView === 'grid') {\n <ag-grid-angular\n class=\"pg-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"GridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n\n <div class=\"pg-footer\">\n <span>Showing <strong>{{ filteredRows.length }}</strong> of {{ allRows.length }} predictions</span>\n @if (selectedTier !== 'all' || searchText) {\n <span class=\"ps-muted\">Filtered by {{ selectedTier !== 'all' ? selectedTier + ' risk' : '' }}{{ searchText ? ' query \"' + searchText + '\"' : '' }}</span>\n }\n <span class=\"ps-muted\">Click any row to inspect details & score history</span>\n </div>\n }\n\n <!-- CHART VIEW -->\n @if (activeView === 'chart') {\n <div class=\"pg-chart-container\">\n <!-- KPI Summary Cards -->\n <div class=\"pg-chart-cards\">\n <div class=\"pg-chart-card total\">\n <span class=\"pg-chart-card-lbl\"><i class=\"fa-solid fa-users ps-muted\"></i> Scored Cohort</span>\n <span class=\"pg-chart-card-val\">{{ allRows.length | number }}</span>\n <span class=\"pg-chart-card-sub\">Total records</span>\n </div>\n @for (b of visibleBands; track b.key) {\n <div class=\"pg-chart-card\" [class]=\"'tier-' + b.key\" (click)=\"setTierAndGrid(b.key)\">\n <span class=\"pg-chart-card-lbl\">\n @if (b.icon) {\n <i class=\"fa-solid {{ b.icon }}\" [style.color]=\"getBadgeColorVar(b.badgeColor)\"></i>\n }\n {{ b.label }}\n </span>\n <span class=\"pg-chart-card-val\" [style.color]=\"getBadgeColorVar(b.badgeColor)\">\n {{ b.count | number }}\n </span>\n <span class=\"pg-chart-card-sub\">{{ b.pct }}% of cohort (avg {{ b.avgScoreFormatted }} {{ outcomeConfig.ScoreLabel }})</span>\n </div>\n }\n </div>\n\n <!-- Score Distribution Histogram -->\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-chart-simple ps-muted\"></i>\n <span>{{ outcomeConfig.ScoreLabel }} Distribution (10 Bins)</span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">Cohort Mean: <strong>{{ meanScoreFormatted }}</strong></span>\n @if (selectedDecileIndex !== null) {\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Clear Decile Filter\n </button>\n }\n </div>\n </div>\n\n <!-- Modern Interactive Flex Histogram -->\n <div class=\"pg-histogram\">\n <div class=\"pg-h-columns\">\n @for (b of histogramBins; track b.label) {\n <div\n class=\"pg-h-col\"\n [class.active]=\"selectedDecileIndex === b.idx\"\n [class.empty]=\"b.count === 0\"\n (click)=\"selectDecile(b.idx)\">\n\n <!-- Count label above bar -->\n <span class=\"pg-h-count\" [title]=\"b.count + ' records'\">\n {{ b.count > 0 ? (b.count | number) : '0' }}\n </span>\n\n <!-- Bar track & fill -->\n <div class=\"pg-h-bar-track\">\n <div\n class=\"pg-h-bar\"\n [style.height.px]=\"b.height\"\n [style.background]=\"b.color\">\n </div>\n </div>\n\n <!-- Footer labels -->\n <div class=\"pg-h-footer\">\n <span class=\"pg-h-range\">{{ b.shortLabel }}</span>\n <span class=\"pg-h-pct\">{{ b.pctFormatted }}</span>\n </div>\n\n <!-- Tooltip card -->\n <div class=\"pg-h-tooltip\">\n <div class=\"pg-h-tt-head\">{{ b.label }} {{ outcomeConfig.ScoreLabel }}</div>\n <div class=\"pg-h-tt-row\">\n <span class=\"pg-h-tt-val\">{{ b.count | number }} records</span>\n <span class=\"pg-h-tt-pct\">({{ b.pctFormatted }} of cohort)</span>\n </div>\n <div class=\"pg-h-tt-badge\" [style.color]=\"b.color\">{{ b.riskLabel }}</div>\n <div class=\"pg-h-tt-hint\">{{ selectedDecileIndex === b.idx ? 'Click to clear filter' : 'Click to filter grid' }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Predicted Class Breakdown (for Classification) -->\n @if (classBreakdown.length > 0) {\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <span><i class=\"fa-solid fa-layer-group ps-muted\"></i> Predicted Outcome Classes</span>\n </div>\n <div style=\"display:flex;height:24px;border-radius:var(--mj-radius-full);overflow:hidden;background:var(--mj-bg-surface-sunken);margin-bottom:8px\">\n @for (c of classBreakdown; track c.name) {\n <div\n [style.width.%]=\"c.pct\"\n [style.background]=\"c.color\"\n [title]=\"c.name + ': ' + c.count + ' (' + c.pct + '%)'\">\n </div>\n }\n </div>\n <div style=\"display:flex;gap:16px;flex-wrap:wrap\">\n @for (c of classBreakdown; track c.name) {\n <div style=\"display:flex;align-items:center;gap:6px;font-size:var(--mj-text-xs)\">\n <span [style.background]=\"c.color\" style=\"width:10px;height:10px;border-radius:2px;display:inline-block\"></span>\n <strong>{{ c.name }}</strong>\n <span class=\"ps-muted\">{{ c.count }} ({{ c.pct }}%)</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Segment Drilldown Grid Section \u2014 Only shown when a decile segment is selected -->\n @if (selectedDecileIndex !== null) {\n <div id=\"pg-drilldown-anchor\" class=\"pg-chart-section pg-chart-drilldown-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-table-list ps-muted\"></i>\n <span>\n Decile Drill-Down:\n <strong style=\"color:var(--mj-brand-primary)\">{{ selectedDecileLabel }}</strong>\n {{ outcomeConfig.ScoreLabel }}\n @if (histogramBins[selectedDecileIndex]) {\n <span class=\"ps-badge\" [style.color]=\"histogramBins[selectedDecileIndex].color\" style=\"margin-left:6px\">\n {{ histogramBins[selectedDecileIndex].riskLabel }}\n </span>\n }\n </span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">\n Showing <strong>{{ filteredRows.length | number }}</strong> of {{ allRows.length | number }} records\n </span>\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Show All Deciles\n </button>\n </div>\n </div>\n\n <!-- Drill-Down AG Grid -->\n <div class=\"pg-chart-grid-host\">\n <ag-grid-angular\n class=\"pg-grid pg-chart-ag-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"chartGridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onChartGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n </div>\n\n <div class=\"pg-drilldown-footer\">\n <span class=\"ps-muted\">Click any row to inspect explainability drivers and score history in the slide-in drawer</span>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE-IN DETAIL PANEL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (detailOpen && selectedRow) {\n <mj-slide-panel\n Mode=\"slide\"\n Title=\"Record Prediction & Score History\"\n [Resizable]=\"true\"\n [WidthPx]=\"drawerWidthPx\"\n (WidthChanged)=\"onDrawerWidthChanged($event)\"\n (Closed)=\"closeDetail()\">\n\n <div class=\"pg-detail-body\">\n <!-- Record header -->\n <div class=\"pg-detail-record-head\">\n <div class=\"pg-detail-record-info\">\n <h3>{{ selectedRow.recordName || selectedRow.recordId }}</h3>\n <div style=\"display:flex;align-items:center;gap:8px\">\n <span class=\"ps-badge blue\">{{ entityDisplayName || 'Entity Record' }}</span>\n <span class=\"ps-mono ps-small ps-muted\">{{ selectedRow.recordId }}</span>\n </div>\n </div>\n <div class=\"pg-detail-record-actions\" style=\"display:flex;gap:8px;align-items:center;flex-wrap:wrap\">\n <button\n mjButton\n variant=\"primary\"\n size=\"sm\"\n (click)=\"drillThrough(selectedRow)\"\n title=\"Open record in Explorer\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open {{ entityDisplayName || 'Record' }}\n </button>\n @if (subjectEntityName && subjectRecordId) {\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n (click)=\"openSubjectRecord()\"\n title=\"Open subject record (e.g. Person, Account) in Explorer\">\n <i class=\"fa-solid fa-user\"></i> Open {{ subjectEntityName.replace('MJ_BizApps_Common: ', '').replace('MJ_BizApps_', '') }} ({{ subjectRecordName || 'Profile' }})\n </button>\n }\n </div>\n </div>\n\n <!-- Prediction Summary Card -->\n <div class=\"pg-detail-pred-card\">\n <div class=\"pg-detail-score-circle\" [class]=\"'badge-' + (selectedRow.badgeColor || 'gray')\">\n {{ selectedRow.scoreFormatted }}\n </div>\n <div class=\"pg-detail-meta\">\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.StatusLabel }}:</strong>\n <span class=\"ps-badge\" [class]=\"selectedRow.badgeColor || 'gray'\" style=\"margin-left:6px\">\n @if (selectedRow.icon) {\n <i class=\"fa-solid {{ selectedRow.icon }}\"></i>\n }\n {{ selectedRow.status || selectedRow.band }}\n </span>\n </div>\n @if (selectedRow.class) {\n <div class=\"pg-detail-meta-line\">\n <strong>Predicted Outcome:</strong>\n <span class=\"ps-badge\" [class]=\"getOutcomeBadgeClass(selectedRow.class)\">\n {{ selectedRow.class }}\n </span>\n </div>\n }\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.ScoreLabel }}:</strong>\n <span style=\"font-weight:700;color:var(--mj-text-primary)\">{{ selectedRow.scoreFormatted }}</span>\n </div>\n <div class=\"pg-detail-meta-sub\">\n Scored: {{ selectedRow.scoredAtDate ? (selectedRow.scoredAtDate | date:'medium') : '\u2014' }}\n </div>\n </div>\n </div>\n\n <!-- Explainability: Local Feature Drivers -->\n <div class=\"pg-detail-drivers-wrap\">\n <div class=\"ps-section-title\">\n <i class=\"fa-solid fa-lightbulb\" style=\"color:var(--mj-status-warning)\"></i> Key Decision Drivers (Explainability)\n </div>\n @if (!selectedRow.drivers || selectedRow.drivers.length === 0) {\n <div class=\"ps-small ps-muted\">No individual driver breakdown was recorded for this row.</div>\n } @else {\n <div class=\"pg-detail-drivers-list\">\n @for (d of selectedRow.drivers; track d.label) {\n <div class=\"pg-detail-driver-item\">\n <div class=\"pg-detail-driver-label\">\n <i class=\"fa-solid\" [class.fa-arrow-up]=\"d.up\" [class.fa-arrow-down]=\"!d.up\" [style.color]=\"d.up ? 'var(--mj-status-error)' : 'var(--mj-status-success)'\"></i>\n {{ d.label }}\n </div>\n <span class=\"ps-badge\" [class]=\"d.up ? 'red' : 'green'\">\n {{ d.up ? 'Increases Risk' : 'Lowers Risk' }}\n </span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Historical Trendline across Runs -->\n <div class=\"pg-trendline-wrap\">\n <div class=\"ps-section-title\" style=\"display:flex;align-items:center;justify-content:space-between\">\n <span><i class=\"fa-solid fa-clock-rotate-left ps-muted\"></i> Historical Score Trendline</span>\n <span class=\"ps-small ps-muted\">{{ historyPoints.length }} run{{ historyPoints.length === 1 ? '' : 's' }} recorded</span>\n </div>\n\n @if (historyLoading) {\n <mj-loading text=\"Loading score history...\" size=\"small\"></mj-loading>\n } @else if (historyPoints.length > 1) {\n <!-- Interactive SVG Trendline -->\n <svg class=\"pg-trendline-svg\" viewBox=\"0 0 540 160\" preserveAspectRatio=\"none\">\n <!-- Background grid lines -->\n <line x1=\"40\" y1=\"20\" x2=\"520\" y2=\"20\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"75\" x2=\"520\" y2=\"75\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"130\" x2=\"520\" y2=\"130\" stroke=\"var(--mj-border-default)\" />\n\n <!-- Y-axis labels -->\n <text x=\"32\" y=\"24\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">100%</text>\n <text x=\"32\" y=\"79\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">50%</text>\n <text x=\"32\" y=\"134\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">0%</text>\n\n <!-- Filled area under curve -->\n <polygon [attr.points]=\"trendlineAreaPoints\" fill=\"color-mix(in srgb, var(--mj-brand-primary) 12%, transparent)\" />\n\n <!-- Trend line path -->\n <polyline [attr.points]=\"trendlineLinePoints\" fill=\"none\" stroke=\"var(--mj-brand-primary)\" stroke-width=\"2.5\" />\n\n <!-- Data points -->\n @for (p of trendlinePlotPoints; track p.runId) {\n <circle\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y\"\n r=\"5\"\n [attr.fill]=\"p.color\"\n stroke=\"var(--mj-bg-surface)\"\n stroke-width=\"2\">\n <title>{{ p.dateStr }}: {{ p.scoreFormatted }} ({{ p.class || 'No class' }})</title>\n </circle>\n <text\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y - 9\"\n font-size=\"10\"\n font-weight=\"700\"\n text-anchor=\"middle\"\n fill=\"var(--mj-text-primary)\">\n {{ p.scoreFormatted }}\n </text>\n }\n </svg>\n\n <!-- Runs Table -->\n <table class=\"pg-history-table\">\n <thead>\n <tr>\n <th>When</th>\n <th>Status</th>\n <th>Score</th>\n <th>Change</th>\n <th>Class</th>\n </tr>\n </thead>\n <tbody>\n @for (pt of historyPoints; track pt.runId) {\n <tr>\n <td>{{ pt.RunDate | date:'short' }}</td>\n <td><span class=\"ps-badge\" [class]=\"pt.status === 'Succeeded' ? 'green' : 'gray'\">{{ pt.status }}</span></td>\n <td><strong class=\"ps-mono\">{{ pt.ScoreFormatted }}</strong></td>\n <td>\n @if (pt.Delta == null) {\n <span class=\"pg-delta-pill neutral\">Baseline</span>\n } @else if (pt.Delta > 0.005) {\n <span class=\"pg-delta-pill up\"><i class=\"fa-solid fa-arrow-up\"></i> +{{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else if (pt.Delta < -0.005) {\n <span class=\"pg-delta-pill down\"><i class=\"fa-solid fa-arrow-down\"></i> {{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else {\n <span class=\"pg-delta-pill neutral\">0%</span>\n }\n </td>\n <td>{{ pt.class || '\u2014' }}</td>\n </tr>\n }\n </tbody>\n </table>\n } @else if (historyPoints.length === 1) {\n <div class=\"ps-small ps-muted\">\n This record has been scored once so far ({{ historyPoints[0].RunDate | date:'medium' }}). As more runs occur over time, the score trendline will track changes here.\n </div>\n } @else {\n <div class=\"ps-small ps-muted\">No historical runs found for this record.</div>\n }\n </div>\n </div>\n </mj-slide-panel>\n }\n</div>\n", styles: ["/* ============================================================================\n Predictive Studio \u2014 shared panel styles (design-token compliant)\n Maps the mockup design system onto MemberJunction semantic --mj-* tokens.\n Loaded by every PS panel component (styleUrls) under ViewEncapsulation.None,\n so the class names are global within the PS dashboard subtree.\n No hardcoded colors except the intentional categorical node/algorithm palette\n (declared once as --ps-* custom props below) which must stay distinct across\n light/dark to remain readable as diagram accents.\n ============================================================================ */\n\n/* Categorical accents for DAG node types + algorithm chips. These are\n data-visualization colors that must remain distinct regardless of theme\n (allowed exception #3 in the design-token rules). */\n.ps-panel {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n /* budget-gauge categorical accents (reuse the node palette so light/dark stay distinct) */\n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel {\n display: block;\n height: 100%;\n}\n\n/* ---- generic layout helpers ---- */\n.ps-row { display: flex; gap: 16px; }\n.ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap { flex-wrap: wrap; }\n.ps-spacer { flex: 1; }\n.ps-muted { color: var(--mj-text-muted); }\n.ps-small { font-size: 12.5px; }\n.ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head h3 { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body { padding: 16px; }\n\n/* ---- KPI tiles ---- */\n.ps-kpi {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi .label { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi .val { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n/* ---- badges ---- */\n.ps-badge {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n/* recommendation-level chips (the ranking matrix payoff) */\n.ps-lvl {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary { background: var(--mj-status-success); }\n.ps-lvl-Strong { background: var(--mj-status-info); }\n.ps-lvl-Viable { background: var(--mj-status-warning); }\n.ps-lvl-Weak { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* ---- tags ---- */\n.ps-tag {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted { opacity: .6; }\n.ps-divider { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n/* ---- tables ---- */\n.ps-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table th {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table td { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table tr:hover td { background: var(--mj-bg-surface-hover); }\n.ps-table .num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n/* ---- progress bars ---- */\n.ps-bar { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn > span { background: var(--mj-status-warning); }\n.ps-bar.run > span { background: var(--mj-brand-primary); }\n\n.ps-fbar { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar + .ps-fbar { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar .track { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar .track > span { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar .track > span.warn { background: var(--mj-status-warning); }\n.ps-fbar .name { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar > .ps-mono { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n/* gauge */\n.ps-gauge {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge .g-val { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n/* warning / info callouts */\n.ps-callout { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout i { font-size: 16px; margin-top: 1px; }\n\n/* lifecycle stepper */\n.ps-stepper { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step .pip {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done { color: var(--mj-status-success-text); }\n.ps-step.done .pip { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr { color: var(--mj-brand-primary); }\n.ps-step.curr .pip { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step .ln { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n/* ---- DAG flow canvas ---- */\n.ps-flow {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node .nh {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node .nh i.tile {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node .nh .ps-tag { margin-left: auto; }\n.ps-node .nb { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node .nb-row { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node .nb-row .k { color: var(--mj-text-muted); }\n.ps-node.src { border-left-color: var(--ps-node-source); }\n.ps-node.src .nh i.tile { background: var(--ps-node-source); }\n.ps-node.feat { border-left-color: var(--ps-node-feature); }\n.ps-node.feat .nh i.tile { background: var(--ps-node-feature); }\n.ps-node.emb { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb .nh i.tile { background: var(--ps-node-embedding); }\n.ps-node.target { border-left-color: var(--ps-node-target); }\n.ps-node.target .nh i.tile { background: var(--ps-node-target); }\n.ps-node.algo { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo .nh i.tile { background: var(--ps-node-algorithm); }\n.ps-node.output { border-left-color: var(--mj-status-success); }\n.ps-node.output .nh i.tile { background: var(--mj-status-success); }\n.ps-node.selected {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node .port {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node .port.in { left: -6px; }\n.ps-node .port.out { right: -6px; }\nsvg.ps-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges path { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n/* palette chips */\n.ps-pchip {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip i { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s i { background: var(--ps-node-source); }\n.ps-pchip.f i { background: var(--ps-node-feature); }\n.ps-pchip.e i { background: var(--ps-node-embedding); }\n.ps-pchip.t i { background: var(--ps-node-target); }\n.ps-pchip.a i { background: var(--ps-node-algorithm); }\n\n/* segmented control */\n.ps-seg { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg button {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg button:last-child { border-right: none; }\n.ps-seg button.on { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n/* field control */\n.ps-field { margin-bottom: 14px; }\n.ps-field > label {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n/* loading container */\n.ps-loading { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n/* ---- empty / prompt states ---- */\n.ps-empty {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty .ps-empty-ico {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty h3 { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty p { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n/* ---- confirm modal ---- */\n.ps-modal-backdrop {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head .ico {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn .ico { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger .ico { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head h3 { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body .ps-field { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot .ps-spacer { flex: 1; }\n", "/* ============================================================================\n Predictive Studio \u2014 Unified Predictions Grid & Detail Panel styles\n Design-token compliant (all --mj-* semantic tokens).\n ============================================================================ */\n\n.ps-pred-grid-host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box i {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill button {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 GRID CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-view-container {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n/* AG Grid cell styling overrides */\n.pg-record-cell {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link:hover .pg-record-name {\n text-decoration: underline;\n}\n\n.pg-record-open-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link:hover .pg-record-open-icon {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high,\n.pg-score-fill.badge-red { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium,\n.pg-score-fill.badge-amber { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low,\n.pg-score-fill.badge-green { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray { background: var(--mj-text-muted); }\n\n.pg-score-val {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high,\n.pg-score-val.badge-red { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium,\n.pg-score-val.badge-amber { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low,\n.pg-score-val.badge-green { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray { color: var(--mj-text-muted); }\n\n.pg-drivers-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 FOOTER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART VIEW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-container {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MODERN HISTOGRAM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-histogram {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col:hover .pg-h-bar {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active .pg-h-bar {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n/* Tooltip card */\n.pg-h-tooltip {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col:hover .pg-h-tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE PANEL DETAIL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-detail-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info h3 {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high,\n.pg-detail-score-circle.badge-red { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium,\n.pg-detail-score-circle.badge-amber { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low,\n.pg-detail-score-circle.badge-green { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray { background: var(--mj-text-muted); }\n\n.pg-detail-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.pg-detail-drivers-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.pg-detail-driver-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-subtle);\n border-radius: var(--mj-radius-sm);\n}\n\n.pg-detail-driver-label {\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TRENDLINE CHART & TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-trendline-wrap {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table th {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table td {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table tr:last-child td {\n border-bottom: none;\n}\n\n.pg-delta-pill {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART DRILLDOWN GRID \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-drilldown-section {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}\n"] }]
|
|
2269
|
+
PSRowDriversComponent,
|
|
2270
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ps-pred-grid-host\" [style.height]=\"height\">\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-toolbar\">\n <div class=\"pg-toolbar-left\">\n <div class=\"pg-search-box\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <input\n type=\"text\"\n class=\"pg-search-input\"\n placeholder=\"Filter records, outcome, factors...\"\n [value]=\"searchText\"\n (input)=\"onSearchInput($event)\" />\n @if (searchText) {\n <button type=\"button\" class=\"pg-search-clear\" (click)=\"clearSearch()\" title=\"Clear filter\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n }\n </div>\n\n <div class=\"pg-tier-filters\">\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === 'all'\"\n (click)=\"setTier('all')\">\n All <span class=\"pg-count-pill\">({{ allRows.length | number }})</span>\n </button>\n @for (b of visibleBands; track b.key) {\n <button\n type=\"button\"\n class=\"pg-tier-btn\"\n [class.active]=\"selectedTier === b.key\"\n (click)=\"setTier(b.key)\">\n {{ b.label }} <span class=\"pg-count-pill\">({{ b.count | number }})</span>\n </button>\n }\n\n @if (selectedDecileIndex !== null) {\n <div class=\"pg-decile-pill\">\n <i class=\"fa-solid fa-filter\"></i>\n <span>Decile {{ selectedDecileLabel }}</span>\n <button type=\"button\" (click)=\"clearDecileFilter()\" title=\"Clear decile filter\"><i class=\"fa-solid fa-xmark\"></i></button>\n </div>\n }\n </div>\n </div>\n\n <div class=\"pg-toolbar-right\">\n <mj-view-toggle\n [Options]=\"viewOptions\"\n [ActiveKey]=\"activeView\"\n (KeyChange)=\"onViewToggle($event)\">\n </mj-view-toggle>\n\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n [disabled]=\"allRows.length === 0\"\n (click)=\"exportCSV()\">\n <i class=\"fa-solid fa-file-export\"></i> Export\n </button>\n </div>\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MAIN VIEW CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"pg-view-container\">\n @if (isLoading) {\n <mj-loading text=\"Loading predictions...\" size=\"medium\"></mj-loading>\n } @else if (loadError) {\n <div class=\"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 predictions</strong>\n <span class=\"ps-load-error-detail\">{{ loadError }}</span>\n </div>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"reload()\"><i class=\"fa-solid fa-rotate-right\"></i> Try again</button>\n </div>\n } @else if (allRows.length === 0) {\n <div class=\"ps-empty\" style=\"padding: 32px\">\n <span class=\"ps-empty-ico\"><i class=\"fa-solid fa-chart-line\"></i></span>\n <h3>No predictions available</h3>\n <p>Run this model from Models in Production or wait for the scheduled job to produce predictions.</p>\n </div>\n } @else {\n <!-- GRID VIEW -->\n @if (activeView === 'grid') {\n <ag-grid-angular\n class=\"pg-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"GridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n\n <div class=\"pg-footer\">\n <span>Showing <strong>{{ filteredRows.length }}</strong> of {{ allRows.length }} predictions</span>\n @if (selectedTier !== 'all' || searchText) {\n <span class=\"ps-muted\">Filtered by {{ SelectedTierLabel }}{{ searchText ? ' query \"' + searchText + '\"' : '' }}</span>\n }\n @if (DetailRowsCapped) {\n <span class=\"ps-muted\" data-testid=\"ps-predictions-capped\">Showing the first {{ MaxRunDetailRowsLabel }} predictions</span>\n }\n <span class=\"ps-muted\">Click any row to inspect details & score history</span>\n </div>\n }\n\n <!-- CHART VIEW -->\n @if (activeView === 'chart') {\n <div class=\"pg-chart-container\">\n <!-- KPI Summary Cards -->\n <div class=\"pg-chart-cards\">\n <div class=\"pg-chart-card total\">\n <span class=\"pg-chart-card-lbl\"><i class=\"fa-solid fa-users ps-muted\"></i> Scored Cohort</span>\n <span class=\"pg-chart-card-val\">{{ allRows.length | number }}</span>\n <span class=\"pg-chart-card-sub\">Total records</span>\n </div>\n @for (b of visibleBands; track b.key) {\n <div class=\"pg-chart-card\" [class]=\"'tier-' + b.key\" (click)=\"setTierAndGrid(b.key)\">\n <span class=\"pg-chart-card-lbl\">\n @if (b.icon) {\n <i class=\"fa-solid {{ b.icon }}\" [style.color]=\"getBadgeColorVar(b.badgeColor)\"></i>\n }\n {{ b.label }}\n </span>\n <span class=\"pg-chart-card-val\" [style.color]=\"getBadgeColorVar(b.badgeColor)\">\n {{ b.count | number }}\n </span>\n <span class=\"pg-chart-card-sub\">{{ b.pct }}% of cohort (avg {{ b.avgScoreFormatted }} {{ outcomeConfig.ScoreLabel }})</span>\n </div>\n }\n </div>\n\n <!-- Score Distribution Histogram -->\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-chart-simple ps-muted\"></i>\n <span>{{ outcomeConfig.ScoreLabel }} Distribution (10 Bins)</span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">Cohort Mean: <strong>{{ meanScoreFormatted }}</strong></span>\n @if (selectedDecileIndex !== null) {\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Clear Decile Filter\n </button>\n }\n </div>\n </div>\n\n <!-- Modern Interactive Flex Histogram -->\n <div class=\"pg-histogram\">\n <div class=\"pg-h-columns\">\n @for (b of histogramBins; track b.label) {\n <div\n class=\"pg-h-col\"\n [class.active]=\"selectedDecileIndex === b.idx\"\n [class.empty]=\"b.count === 0\"\n (click)=\"selectDecile(b.idx)\">\n\n <!-- Count label above bar -->\n <span class=\"pg-h-count\" [title]=\"b.count + ' records'\">\n {{ b.count > 0 ? (b.count | number) : '0' }}\n </span>\n\n <!-- Bar track & fill -->\n <div class=\"pg-h-bar-track\">\n <div\n class=\"pg-h-bar\"\n [style.height.px]=\"b.height\"\n [style.background]=\"b.color\">\n </div>\n </div>\n\n <!-- Footer labels -->\n <div class=\"pg-h-footer\">\n <span class=\"pg-h-range\">{{ b.shortLabel }}</span>\n <span class=\"pg-h-pct\">{{ b.pctFormatted }}</span>\n </div>\n\n <!-- Tooltip card -->\n <div class=\"pg-h-tooltip\">\n <div class=\"pg-h-tt-head\">{{ b.label }} {{ outcomeConfig.ScoreLabel }}</div>\n <div class=\"pg-h-tt-row\">\n <span class=\"pg-h-tt-val\">{{ b.count | number }} records</span>\n <span class=\"pg-h-tt-pct\">({{ b.pctFormatted }} of cohort)</span>\n </div>\n <div class=\"pg-h-tt-badge\" [style.color]=\"b.color\">{{ b.riskLabel }}</div>\n <div class=\"pg-h-tt-hint\">{{ selectedDecileIndex === b.idx ? 'Click to clear filter' : 'Click to filter grid' }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <!-- Predicted Class Breakdown (for Classification) -->\n @if (classBreakdown.length > 0) {\n <div class=\"pg-chart-section\">\n <div class=\"pg-chart-section-title\">\n <span><i class=\"fa-solid fa-layer-group ps-muted\"></i> Predicted Outcome Classes</span>\n </div>\n <div style=\"display:flex;height:24px;border-radius:var(--mj-radius-full);overflow:hidden;background:var(--mj-bg-surface-sunken);margin-bottom:8px\">\n @for (c of classBreakdown; track c.name) {\n <div\n [style.width.%]=\"c.pct\"\n [style.background]=\"c.color\"\n [title]=\"c.name + ': ' + c.count + ' (' + c.pct + '%)'\">\n </div>\n }\n </div>\n <div style=\"display:flex;gap:16px;flex-wrap:wrap\">\n @for (c of classBreakdown; track c.name) {\n <div style=\"display:flex;align-items:center;gap:6px;font-size:var(--mj-text-xs)\">\n <span [style.background]=\"c.color\" style=\"width:10px;height:10px;border-radius:2px;display:inline-block\"></span>\n <strong>{{ c.name }}</strong>\n <span class=\"ps-muted\">{{ c.count }} ({{ c.pct }}%)</span>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Segment Drilldown Grid Section \u2014 Only shown when a decile segment is selected -->\n @if (selectedDecileIndex !== null) {\n <div id=\"pg-drilldown-anchor\" class=\"pg-chart-section pg-chart-drilldown-section\">\n <div class=\"pg-chart-section-title\">\n <div style=\"display:flex;align-items:center;gap:8px\">\n <i class=\"fa-solid fa-table-list ps-muted\"></i>\n <span>\n Decile Drill-Down:\n <strong style=\"color:var(--mj-brand-primary)\">{{ selectedDecileLabel }}</strong>\n {{ outcomeConfig.ScoreLabel }}\n @if (histogramBins[selectedDecileIndex]) {\n <span class=\"ps-badge\" [style.color]=\"histogramBins[selectedDecileIndex].color\" style=\"margin-left:6px\">\n {{ histogramBins[selectedDecileIndex].riskLabel }}\n </span>\n }\n </span>\n </div>\n <div class=\"pg-chart-meta\">\n <span class=\"ps-small ps-muted\">\n Showing <strong>{{ filteredRows.length | number }}</strong> of {{ allRows.length | number }} records\n </span>\n <button type=\"button\" class=\"pg-clear-decile-btn\" (click)=\"clearDecileFilter()\">\n <i class=\"fa-solid fa-xmark\"></i> Show All Deciles\n </button>\n </div>\n </div>\n\n <!-- Drill-Down AG Grid -->\n <div class=\"pg-chart-grid-host\">\n <ag-grid-angular\n class=\"pg-grid pg-chart-ag-grid\"\n [theme]=\"Theme\"\n [columnDefs]=\"columnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [gridOptions]=\"chartGridOptions\"\n [rowData]=\"filteredRows\"\n (gridReady)=\"onChartGridReady($event)\"\n (rowClicked)=\"onRowClicked($event)\"\n (cellClicked)=\"onCellClicked($event)\">\n </ag-grid-angular>\n </div>\n\n <div class=\"pg-drilldown-footer\">\n <span class=\"ps-muted\">Click any row to inspect explainability drivers and score history in the slide-in drawer</span>\n </div>\n </div>\n }\n </div>\n }\n }\n </div>\n\n <!-- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE-IN DETAIL PANEL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n @if (detailOpen && selectedRow) {\n <mj-slide-panel\n Mode=\"slide\"\n Title=\"Record Prediction & Score History\"\n [Resizable]=\"true\"\n [WidthPx]=\"drawerWidthPx\"\n (WidthChanged)=\"onDrawerWidthChanged($event)\"\n (Closed)=\"closeDetail()\">\n\n <div class=\"pg-detail-body\">\n <!-- Record header -->\n <div class=\"pg-detail-record-head\">\n <div class=\"pg-detail-record-info\">\n <h3>{{ selectedRow.recordName || selectedRow.recordId }}</h3>\n <div style=\"display:flex;align-items:center;gap:8px\">\n <span class=\"ps-badge blue\">{{ entityDisplayName || 'Entity Record' }}</span>\n <span class=\"ps-mono ps-small ps-muted\">{{ selectedRow.recordId }}</span>\n </div>\n </div>\n <div class=\"pg-detail-record-actions\" style=\"display:flex;gap:8px;align-items:center;flex-wrap:wrap\">\n <button\n mjButton\n variant=\"primary\"\n size=\"sm\"\n (click)=\"drillThrough(selectedRow)\"\n title=\"Open record in Explorer\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open {{ entityDisplayName || 'Record' }}\n </button>\n @if (subjectEntityName && subjectRecordId) {\n <button\n mjButton\n variant=\"secondary\"\n size=\"sm\"\n (click)=\"openSubjectRecord()\"\n title=\"Open subject record (e.g. Person, Account) in Explorer\">\n <i class=\"fa-solid fa-user\"></i> Open {{ subjectEntityName.replace('MJ_BizApps_Common: ', '').replace('MJ_BizApps_', '') }} ({{ subjectRecordName || 'Profile' }})\n </button>\n }\n </div>\n </div>\n\n <!-- Prediction Summary Card -->\n <div class=\"pg-detail-pred-card\">\n <div class=\"pg-detail-score-circle\" [class]=\"'badge-' + (selectedRow.badgeColor || 'gray')\">\n {{ selectedRow.scoreFormatted }}\n </div>\n <div class=\"pg-detail-meta\">\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.StatusLabel }}:</strong>\n <span class=\"ps-badge\" [class]=\"selectedRow.badgeColor || 'gray'\" style=\"margin-left:6px\">\n @if (selectedRow.icon) {\n <i class=\"fa-solid {{ selectedRow.icon }}\"></i>\n }\n {{ selectedRow.status || selectedRow.band }}\n </span>\n </div>\n @if (selectedRow.class) {\n <div class=\"pg-detail-meta-line\">\n <strong>Predicted Outcome:</strong>\n <span class=\"ps-badge\" [class]=\"getOutcomeBadgeClass(selectedRow.class)\">\n {{ selectedRow.class }}\n </span>\n </div>\n }\n <div class=\"pg-detail-meta-line\">\n <strong>{{ outcomeConfig.ScoreLabel }}:</strong>\n <span style=\"font-weight:700;color:var(--mj-text-primary)\">{{ selectedRow.scoreFormatted }}</span>\n </div>\n <div class=\"pg-detail-meta-sub\">\n Scored: {{ selectedRow.scoredAtDate ? (selectedRow.scoredAtDate | date:'medium') : '\u2014' }}\n </div>\n </div>\n </div>\n\n <!-- Explainability: Local Feature Drivers -->\n <div class=\"pg-detail-drivers-wrap\">\n <div class=\"ps-section-title\">\n <i class=\"fa-solid fa-lightbulb\" style=\"color:var(--mj-status-warning)\"></i> Factors behind this score (associations, not causes)\n </div>\n <ps-row-drivers [Drivers]=\"selectedRow.drivers\"></ps-row-drivers>\n </div>\n\n <!-- Historical Trendline across Runs -->\n <div class=\"pg-trendline-wrap\">\n <div class=\"ps-section-title\" style=\"display:flex;align-items:center;justify-content:space-between\">\n <span><i class=\"fa-solid fa-clock-rotate-left ps-muted\"></i> Historical Score Trendline</span>\n <span class=\"ps-small ps-muted\">{{ historyPoints.length }} run{{ historyPoints.length === 1 ? '' : 's' }} recorded</span>\n </div>\n\n @if (historyLoading) {\n <mj-loading text=\"Loading score history...\" size=\"small\"></mj-loading>\n } @else if (historyPoints.length > 1) {\n <!-- Interactive SVG Trendline -->\n <svg class=\"pg-trendline-svg\" viewBox=\"0 0 540 160\" preserveAspectRatio=\"none\">\n <!-- Background grid lines -->\n <line x1=\"40\" y1=\"20\" x2=\"520\" y2=\"20\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"75\" x2=\"520\" y2=\"75\" stroke=\"var(--mj-border-subtle)\" stroke-dasharray=\"3,3\" />\n <line x1=\"40\" y1=\"130\" x2=\"520\" y2=\"130\" stroke=\"var(--mj-border-default)\" />\n\n <!-- Y-axis labels -->\n <text x=\"32\" y=\"24\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">100%</text>\n <text x=\"32\" y=\"79\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">50%</text>\n <text x=\"32\" y=\"134\" font-size=\"10\" text-anchor=\"end\" fill=\"var(--mj-text-muted)\">0%</text>\n\n <!-- Filled area under curve -->\n <polygon [attr.points]=\"trendlineAreaPoints\" fill=\"color-mix(in srgb, var(--mj-brand-primary) 12%, transparent)\" />\n\n <!-- Trend line path -->\n <polyline [attr.points]=\"trendlineLinePoints\" fill=\"none\" stroke=\"var(--mj-brand-primary)\" stroke-width=\"2.5\" />\n\n <!-- Data points -->\n @for (p of trendlinePlotPoints; track p.runId) {\n <circle\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y\"\n r=\"5\"\n [attr.fill]=\"p.color\"\n stroke=\"var(--mj-bg-surface)\"\n stroke-width=\"2\">\n <title>{{ p.dateStr }}: {{ p.scoreFormatted }} ({{ p.class || 'No class' }})</title>\n </circle>\n <text\n [attr.cx]=\"p.x\"\n [attr.cy]=\"p.y - 9\"\n font-size=\"10\"\n font-weight=\"700\"\n text-anchor=\"middle\"\n fill=\"var(--mj-text-primary)\">\n {{ p.scoreFormatted }}\n </text>\n }\n </svg>\n\n <!-- Runs Table -->\n <table class=\"pg-history-table\">\n <thead>\n <tr>\n <th>When</th>\n <th>Status</th>\n <th>Score</th>\n <th>Change</th>\n <th>Class</th>\n </tr>\n </thead>\n <tbody>\n @for (pt of historyPoints; track pt.runId) {\n <tr>\n <td>{{ pt.RunDate | date:'short' }}</td>\n <td><span class=\"ps-badge\" [class]=\"pt.status === 'Succeeded' ? 'green' : 'gray'\">{{ pt.status }}</span></td>\n <td><strong class=\"ps-mono\">{{ pt.ScoreFormatted }}</strong></td>\n <td>\n @if (pt.Delta == null) {\n <span class=\"pg-delta-pill neutral\">Baseline</span>\n } @else if (pt.Delta > 0.005) {\n <span class=\"pg-delta-pill up\"><i class=\"fa-solid fa-arrow-up\"></i> +{{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else if (pt.Delta < -0.005) {\n <span class=\"pg-delta-pill down\"><i class=\"fa-solid fa-arrow-down\"></i> {{ (pt.Delta * 100).toFixed(1) }}%</span>\n } @else {\n <span class=\"pg-delta-pill neutral\">0%</span>\n }\n </td>\n <td>{{ pt.class || '\u2014' }}</td>\n </tr>\n }\n </tbody>\n </table>\n } @else if (historyPoints.length === 1) {\n <div class=\"ps-small ps-muted\">\n This record has been scored once so far ({{ historyPoints[0].RunDate | date:'medium' }}). As more runs occur over time, the score trendline will track changes here.\n </div>\n } @else {\n <div class=\"ps-small ps-muted\">No historical runs found for this record.</div>\n }\n </div>\n </div>\n </mj-slide-panel>\n }\n</div>\n", styles: ["/* ============================================================================\n Predictive Studio \u2014 shared panel styles (design-token compliant)\n Maps the mockup design system onto MemberJunction semantic --mj-* tokens.\n Loaded by every PS panel component (styleUrls) under ViewEncapsulation.None,\n so the class names are global within the PS dashboard subtree.\n No hardcoded colors except the intentional categorical node/algorithm palette\n (declared once as --ps-* custom props below) which must stay distinct across\n light/dark to remain readable as diagram accents.\n ============================================================================ */\n\n/* Categorical accents for DAG node types + algorithm chips. These are\n data-visualization colors that must remain distinct regardless of theme\n (allowed exception #3 in the design-token rules). */\n.ps-panel {\n --ps-node-source: #6b7280;\n --ps-node-feature: #2050c8;\n --ps-node-embedding: #7b3ff0;\n --ps-node-target: #1f9d57;\n --ps-node-algorithm: #d98213;\n /* budget-gauge categorical accents (reuse the node palette so light/dark stay distinct) */\n --ps-gauge-cost: var(--ps-node-algorithm);\n --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel {\n display: block;\n height: 100%;\n}\n\n/* ---- generic layout helpers ---- */\n.ps-row { display: flex; gap: 16px; }\n.ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap { flex-wrap: wrap; }\n.ps-spacer { flex: 1; }\n.ps-muted { color: var(--mj-text-muted); }\n.ps-small { font-size: 12.5px; }\n.ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title {\n font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n}\n.ps-card-head {\n display: flex; align-items: center; gap: 10px;\n padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head h3 { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body { padding: 16px; }\n\n/* ---- KPI tiles ---- */\n.ps-kpi {\n background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n border-radius: 8px; padding: 16px 18px;\n}\n.ps-kpi .label { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi .val { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n/* ---- badges ---- */\n.ps-badge {\n display: inline-flex; align-items: center; gap: 5px;\n padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n/* recommendation-level chips (the ranking matrix payoff) */\n.ps-lvl {\n display: inline-flex; align-items: center; justify-content: center;\n min-width: 92px; padding: 4px 10px; border-radius: 7px;\n font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary { background: var(--mj-status-success); }\n.ps-lvl-Strong { background: var(--mj-status-info); }\n.ps-lvl-Viable { background: var(--mj-status-warning); }\n.ps-lvl-Weak { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* ---- tags ---- */\n.ps-tag {\n display: inline-block; padding: 2px 8px; border-radius: 6px;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted { opacity: .6; }\n.ps-divider { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n/* ---- tables ---- */\n.ps-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table th {\n text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table td { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table tr:hover td { background: var(--mj-bg-surface-hover); }\n.ps-table .num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank {\n width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n/* ---- progress bars ---- */\n.ps-bar { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn > span { background: var(--mj-status-warning); }\n.ps-bar.run > span { background: var(--mj-brand-primary); }\n\n.ps-fbar { display: grid; grid-template-columns: minmax(150px, 1.3fr) 2fr 56px; align-items: center; gap: 14px; padding: 8px 0; }\n.ps-fbar + .ps-fbar { border-top: 1px solid var(--mj-border-subtle); }\n.ps-fbar .track { height: 10px; border-radius: var(--mj-radius-full); background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar .track > span { display: block; height: 100%; border-radius: var(--mj-radius-full); background: var(--mj-brand-primary); }\n.ps-fbar .track > span.warn { background: var(--mj-status-warning); }\n.ps-fbar .name { color: var(--mj-text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ps-fbar > .ps-mono { text-align: right; color: var(--mj-text-secondary); font-variant-numeric: tabular-nums; }\n\n/* gauge */\n.ps-gauge {\n position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n display: grid; place-items: center;\n}\n.ps-gauge::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge .g-val { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n/* warning / info callouts */\n.ps-callout { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout i { font-size: 16px; margin-top: 1px; }\n\n/* lifecycle stepper */\n.ps-stepper { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step .pip {\n width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done { color: var(--mj-status-success-text); }\n.ps-step.done .pip { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr { color: var(--mj-brand-primary); }\n.ps-step.curr .pip { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step .ln { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n/* ---- DAG flow canvas ---- */\n.ps-flow {\n position: relative;\n background:\n linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default); border-radius: 10px;\n min-height: 620px; overflow: hidden;\n}\n.ps-node {\n position: absolute; width: 190px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 8px;\n cursor: pointer;\n}\n.ps-node .nh {\n display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node .nh i.tile {\n width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node .nh .ps-tag { margin-left: auto; }\n.ps-node .nb { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node .nb-row { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node .nb-row .k { color: var(--mj-text-muted); }\n.ps-node.src { border-left-color: var(--ps-node-source); }\n.ps-node.src .nh i.tile { background: var(--ps-node-source); }\n.ps-node.feat { border-left-color: var(--ps-node-feature); }\n.ps-node.feat .nh i.tile { background: var(--ps-node-feature); }\n.ps-node.emb { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb .nh i.tile { background: var(--ps-node-embedding); }\n.ps-node.target { border-left-color: var(--ps-node-target); }\n.ps-node.target .nh i.tile { background: var(--ps-node-target); }\n.ps-node.algo { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo .nh i.tile { background: var(--ps-node-algorithm); }\n.ps-node.output { border-left-color: var(--mj-status-success); }\n.ps-node.output .nh i.tile { background: var(--mj-status-success); }\n.ps-node.selected {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node .port {\n position: absolute; width: 11px; height: 11px; border-radius: 50%;\n background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n top: 50%; transform: translateY(-50%);\n}\n.ps-node .port.in { left: -6px; }\n.ps-node .port.out { right: -6px; }\nsvg.ps-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges path { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n/* palette chips */\n.ps-pchip {\n display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip i { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s i { background: var(--ps-node-source); }\n.ps-pchip.f i { background: var(--ps-node-feature); }\n.ps-pchip.e i { background: var(--ps-node-embedding); }\n.ps-pchip.t i { background: var(--ps-node-target); }\n.ps-pchip.a i { background: var(--ps-node-algorithm); }\n\n/* segmented control */\n.ps-seg { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg button {\n border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg button:last-child { border-right: none; }\n.ps-seg button.on { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n/* field control */\n.ps-field { margin-bottom: 14px; }\n.ps-field > label {\n display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input {\n width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n box-sizing: border-box;\n}\n.ps-input:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n/* loading container */\n.ps-loading { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n/* ---- empty / prompt states ---- */\n.ps-empty {\n display: flex; flex-direction: column; align-items: center; justify-content: center;\n text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty .ps-empty-ico {\n width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty h3 { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty p { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n/* ---- confirm modal ---- */\n.ps-modal-backdrop {\n position: fixed; inset: 0; z-index: 1000;\n background: var(--mj-bg-overlay);\n display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal {\n width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default); border-radius: 14px;\n box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head {\n display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head .ico {\n width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n font-size: 16px; flex: 0 0 auto;\n background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn .ico { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger .ico { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head h3 { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body .ps-field { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot {\n display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot .ps-spacer { flex: 1; }\n", "/* ============================================================================\n Predictive Studio \u2014 Unified Predictions Grid & Detail Panel styles\n Design-token compliant (all --mj-* semantic tokens).\n ============================================================================ */\n\n.ps-pred-grid-host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TOOLBAR \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n\n.pg-toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 240px;\n}\n\n.pg-search-box {\n position: relative;\n display: flex;\n align-items: center;\n max-width: 260px;\n width: 100%;\n}\n\n.pg-search-box i {\n position: absolute;\n left: 10px;\n color: var(--mj-text-muted);\n font-size: 12px;\n pointer-events: none;\n}\n\n.pg-search-input {\n width: 100%;\n padding: 6px 10px 6px 30px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-primary);\n outline: none;\n transition: border-color .15s;\n}\n\n.pg-search-input:focus {\n border-color: var(--mj-brand-primary);\n}\n\n.pg-search-clear {\n position: absolute;\n right: 8px;\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n color: var(--mj-text-muted);\n font-size: 11px;\n}\n\n.pg-search-clear:hover {\n color: var(--mj-text-primary);\n}\n\n.pg-decile-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n border: 1px solid var(--mj-brand-primary);\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.pg-decile-pill button {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n color: var(--mj-brand-primary);\n font-size: 10px;\n}\n\n.pg-tier-filters {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.pg-tier-btn {\n cursor: pointer;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-full);\n padding: 3px 10px;\n font-size: var(--mj-text-xs);\n font-weight: 600;\n color: var(--mj-text-secondary);\n transition: all .15s;\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.pg-tier-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.pg-tier-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pg-tier-btn.tier-high.active {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.pg-tier-btn.tier-medium.active {\n background: var(--mj-status-warning);\n border-color: var(--mj-status-warning);\n}\n\n.pg-tier-btn.tier-low.active {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.pg-count-pill {\n font-size: 10px;\n opacity: .85;\n}\n\n.pg-toolbar-right {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 GRID CONTAINER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-view-container {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n.pg-grid {\n width: 100%;\n flex: 1;\n min-height: 380px;\n}\n\n/* AG Grid cell styling overrides */\n.pg-record-cell {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 2px;\n height: 100%;\n min-width: 0;\n line-height: 1.2;\n}\n\n.pg-record-title-row {\n display: flex;\n align-items: center;\n min-width: 0;\n}\n\n.pg-record-link {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n max-width: 100%;\n text-decoration: none;\n cursor: pointer;\n min-width: 0;\n}\n\n.pg-record-name {\n font-weight: 600;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-link);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-record-link:hover .pg-record-name {\n text-decoration: underline;\n}\n\n.pg-record-open-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n flex-shrink: 0;\n transition: transform .15s, color .15s;\n}\n\n.pg-record-link:hover .pg-record-open-icon {\n transform: translateY(-1px) translateX(1px);\n color: var(--mj-text-primary);\n}\n\n.pg-record-id {\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.pg-score-cell {\n display: flex;\n align-items: center;\n gap: 8px;\n height: 100%;\n min-width: 0;\n}\n\n.pg-score-bar {\n flex: 1;\n height: 8px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.pg-score-fill {\n display: block;\n height: 100%;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-score-fill.risk-high,\n.pg-score-fill.badge-red { background: var(--mj-status-error); }\n.pg-score-fill.risk-medium,\n.pg-score-fill.badge-amber { background: var(--mj-status-warning); }\n.pg-score-fill.risk-low,\n.pg-score-fill.badge-green { background: var(--mj-status-success); }\n.pg-score-fill.badge-blue { background: var(--mj-brand-primary); }\n.pg-score-fill.badge-gray { background: var(--mj-text-muted); }\n\n.pg-score-val {\n font-weight: 700;\n font-size: var(--mj-text-xs);\n font-variant-numeric: tabular-nums;\n min-width: 44px;\n text-align: right;\n}\n\n.pg-score-val.risk-high,\n.pg-score-val.badge-red { color: var(--mj-status-error-text, var(--mj-status-error)); }\n.pg-score-val.risk-medium,\n.pg-score-val.badge-amber { color: var(--mj-status-warning-text, var(--mj-status-warning)); }\n.pg-score-val.risk-low,\n.pg-score-val.badge-green { color: var(--mj-status-success-text, var(--mj-status-success)); }\n.pg-score-val.badge-blue { color: var(--mj-brand-primary); }\n.pg-score-val.badge-gray { color: var(--mj-text-muted); }\n\n.pg-drivers-cell {\n display: flex;\n align-items: center;\n gap: 6px;\n height: 100%;\n overflow: hidden;\n flex-wrap: nowrap;\n}\n\n.pg-action-btn {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 6px 8px;\n border-radius: 6px;\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: all .15s;\n}\n\n.pg-action-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 FOOTER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART VIEW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-container {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 4px 0 12px;\n}\n\n.pg-chart-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n}\n\n.pg-chart-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 14px 16px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n cursor: pointer;\n transition: all .15s;\n}\n\n.pg-chart-card:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.pg-chart-card.total { border-left: 4px solid var(--mj-brand-primary); }\n.pg-chart-card.tier-high { border-left: 4px solid var(--mj-status-error); }\n.pg-chart-card.tier-medium { border-left: 4px solid var(--mj-status-warning); }\n.pg-chart-card.tier-low { border-left: 4px solid var(--mj-status-success); }\n\n.pg-chart-card-val {\n font-size: var(--mj-text-xl);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-chart-card-lbl {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.pg-chart-card-sub {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.pg-chart-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 18px 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pg-chart-section-title {\n font-size: var(--mj-text-sm);\n font-weight: 650;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.pg-chart-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.pg-clear-decile-btn {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n padding: 2px 10px;\n font-size: 11px;\n font-weight: 600;\n cursor: pointer;\n color: var(--mj-text-secondary);\n transition: all .15s;\n}\n\n.pg-clear-decile-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-border-subtle);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 MODERN HISTOGRAM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-histogram {\n position: relative;\n width: 100%;\n padding-top: 8px;\n padding-bottom: 28px;\n}\n\n.pg-h-columns {\n display: flex;\n align-items: flex-end;\n justify-content: space-between;\n gap: 8px;\n height: 200px;\n padding: 0 4px;\n border-bottom: 2px solid var(--mj-border-default);\n}\n\n.pg-h-col {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-end;\n height: 100%;\n cursor: pointer;\n position: relative;\n transition: transform .15s;\n user-select: none;\n}\n\n.pg-h-col:hover {\n transform: translateY(-2px);\n}\n\n.pg-h-count {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 6px;\n white-space: nowrap;\n font-variant-numeric: tabular-nums;\n}\n\n.pg-h-bar-track {\n width: 100%;\n max-width: 52px;\n display: flex;\n align-items: flex-end;\n justify-content: center;\n}\n\n.pg-h-bar {\n width: 100%;\n border-radius: 4px 4px 0 0;\n transition: height .3s cubic-bezier(0.4, 0, 0.2, 1), opacity .15s, box-shadow .15s;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);\n}\n\n.pg-h-col:hover .pg-h-bar {\n filter: brightness(1.1);\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);\n}\n\n.pg-h-col.active .pg-h-bar {\n outline: 3px solid var(--mj-brand-primary);\n outline-offset: 1px;\n}\n\n.pg-h-footer {\n display: flex;\n flex-direction: column;\n align-items: center;\n margin-top: 8px;\n position: absolute;\n top: 100%;\n left: 0;\n right: 0;\n}\n\n.pg-h-range {\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.pg-h-pct {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n/* Tooltip card */\n.pg-h-tooltip {\n position: absolute;\n bottom: calc(100% + 4px);\n left: 50%;\n transform: translateX(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);\n border-radius: var(--mj-radius-md);\n padding: 8px 12px;\n white-space: nowrap;\n pointer-events: none;\n opacity: 0;\n visibility: hidden;\n transition: opacity .15s, visibility .15s;\n z-index: 50;\n}\n\n.pg-h-col:hover .pg-h-tooltip {\n opacity: 1;\n visibility: visible;\n}\n\n.pg-h-tt-head {\n font-size: 11px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.pg-h-tt-row {\n display: flex;\n gap: 6px;\n align-items: center;\n font-size: 11px;\n}\n\n.pg-h-tt-val {\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.pg-h-tt-pct {\n color: var(--mj-text-muted);\n}\n\n.pg-h-tt-badge {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 3px;\n}\n\n.pg-h-tt-hint {\n font-size: 9px;\n color: var(--mj-text-muted);\n font-style: italic;\n margin-top: 4px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 SLIDE PANEL DETAIL \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-detail-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 18px 20px 32px;\n}\n\n.pg-detail-record-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding-bottom: 14px;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.pg-detail-record-info h3 {\n margin: 0 0 4px;\n font-size: var(--mj-text-lg);\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.pg-detail-pred-card {\n display: flex;\n align-items: center;\n gap: 20px;\n padding: 16px 18px;\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-detail-score-circle {\n width: 72px;\n height: 72px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 19px;\n font-weight: 800;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, .12);\n}\n\n.pg-detail-score-circle.risk-high,\n.pg-detail-score-circle.badge-red { background: var(--mj-status-error); }\n.pg-detail-score-circle.risk-medium,\n.pg-detail-score-circle.badge-amber { background: var(--mj-status-warning); }\n.pg-detail-score-circle.risk-low,\n.pg-detail-score-circle.badge-green { background: var(--mj-status-success); }\n.pg-detail-score-circle.badge-blue { background: var(--mj-brand-primary); }\n.pg-detail-score-circle.badge-gray { background: var(--mj-text-muted); }\n\n.pg-detail-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n}\n\n.pg-detail-meta-line {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.pg-detail-meta-sub {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.pg-detail-drivers-wrap {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 TRENDLINE CHART & TABLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-trendline-wrap {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n}\n\n.pg-trendline-svg {\n width: 100%;\n height: 180px;\n overflow: visible;\n}\n\n.pg-history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--mj-text-xs);\n margin-top: 6px;\n}\n\n.pg-history-table th {\n text-align: left;\n padding: 6px 8px;\n border-bottom: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: .03em;\n}\n\n.pg-history-table td {\n padding: 7px 8px;\n border-bottom: 1px solid var(--mj-border-subtle);\n color: var(--mj-text-secondary);\n}\n\n.pg-history-table tr:last-child td {\n border-bottom: none;\n}\n\n.pg-delta-pill {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-weight: 700;\n font-size: 11px;\n padding: 1px 6px;\n border-radius: var(--mj-radius-full);\n}\n\n.pg-delta-pill.up { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.pg-delta-pill.down { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.pg-delta-pill.neutral { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CHART DRILLDOWN GRID \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pg-chart-drilldown-section {\n padding: 16px 18px;\n gap: 12px;\n}\n\n.pg-chart-grid-host {\n width: 100%;\n height: 440px;\n min-height: 320px;\n border-radius: var(--mj-radius-sm);\n overflow: hidden;\n border: 1px solid var(--mj-border-default);\n}\n\n.pg-chart-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n.pg-drilldown-footer {\n display: flex;\n justify-content: flex-end;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n padding-top: 2px;\n}\n"] }]
|
|
2266
2271
|
}], null, { modelId: [{
|
|
2267
2272
|
type: Input
|
|
2268
2273
|
}], RunId: [{
|
|
@@ -2283,6 +2288,10 @@ export class PSPredictionsGridComponent extends BaseAngularComponent {
|
|
|
2283
2288
|
type: Input
|
|
2284
2289
|
}], readOnly: [{
|
|
2285
2290
|
type: Input
|
|
2291
|
+
}], RowsLoaded: [{
|
|
2292
|
+
type: Output
|
|
2293
|
+
}], RowsLoadFailed: [{
|
|
2294
|
+
type: Output
|
|
2286
2295
|
}] }); })();
|
|
2287
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSPredictionsGridComponent, { className: "PSPredictionsGridComponent", filePath: "src/PredictiveStudio/components/ps-predictions-grid.component.ts", lineNumber:
|
|
2296
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSPredictionsGridComponent, { className: "PSPredictionsGridComponent", filePath: "src/PredictiveStudio/components/ps-predictions-grid.component.ts", lineNumber: 168 }); })();
|
|
2288
2297
|
//# sourceMappingURL=ps-predictions-grid.component.js.map
|