@memberjunction/ng-core-entity-forms 6.2.0-edge.5 → 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.
Files changed (145) hide show
  1. package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.d.ts +2 -0
  2. package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.d.ts.map +1 -1
  3. package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.js +103 -95
  4. package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.js.map +1 -1
  5. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts +6 -0
  6. package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
  7. package/dist/lib/custom/AIAgents/ai-agent-form.component.js +6 -0
  8. package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
  9. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts +2 -0
  10. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts.map +1 -1
  11. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +2 -0
  12. package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
  13. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts +2 -0
  14. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
  15. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +21 -1
  16. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
  17. package/dist/lib/custom/Actions/action-form.component.d.ts +2 -0
  18. package/dist/lib/custom/Actions/action-form.component.d.ts.map +1 -1
  19. package/dist/lib/custom/Actions/action-form.component.js +29 -11
  20. package/dist/lib/custom/Actions/action-form.component.js.map +1 -1
  21. package/dist/lib/custom/EntityActions/entityaction.form.component.d.ts +2 -0
  22. package/dist/lib/custom/EntityActions/entityaction.form.component.d.ts.map +1 -1
  23. package/dist/lib/custom/EntityActions/entityaction.form.component.js +2 -0
  24. package/dist/lib/custom/EntityActions/entityaction.form.component.js.map +1 -1
  25. package/dist/lib/custom/MLModels/ml-model-view-models.d.ts +11 -4
  26. package/dist/lib/custom/MLModels/ml-model-view-models.d.ts.map +1 -1
  27. package/dist/lib/custom/MLModels/ml-model-view-models.js +14 -0
  28. package/dist/lib/custom/MLModels/ml-model-view-models.js.map +1 -1
  29. package/dist/lib/custom/MLModels/ps-model-detail.component.d.ts +15 -0
  30. package/dist/lib/custom/MLModels/ps-model-detail.component.d.ts.map +1 -1
  31. package/dist/lib/custom/MLModels/ps-model-detail.component.js +186 -92
  32. package/dist/lib/custom/MLModels/ps-model-detail.component.js.map +1 -1
  33. package/dist/lib/custom/Queries/query-form.component.d.ts +2 -0
  34. package/dist/lib/custom/Queries/query-form.component.d.ts.map +1 -1
  35. package/dist/lib/custom/Queries/query-form.component.js +2 -0
  36. package/dist/lib/custom/Queries/query-form.component.js.map +1 -1
  37. package/dist/lib/custom/Templates/templates-form.component.d.ts +19 -1
  38. package/dist/lib/custom/Templates/templates-form.component.d.ts.map +1 -1
  39. package/dist/lib/custom/Templates/templates-form.component.js +20 -27
  40. package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
  41. package/dist/lib/custom/Tests/entity-link-pill.component.d.ts.map +1 -1
  42. package/dist/lib/custom/Tests/entity-link-pill.component.js +14 -6
  43. package/dist/lib/custom/Tests/entity-link-pill.component.js.map +1 -1
  44. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
  45. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +121 -111
  46. package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
  47. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +105 -103
  48. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js.map +1 -1
  49. package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.js +2 -2
  50. package/dist/lib/generated/Entities/MJAIAgentSession/mjaiagentsession.form.component.js.map +1 -1
  51. package/dist/lib/generated/Entities/MJCalendarEventLink/mjcalendareventlink.form.component.d.ts +10 -0
  52. package/dist/lib/generated/Entities/MJCalendarEventLink/mjcalendareventlink.form.component.d.ts.map +1 -0
  53. package/dist/lib/generated/Entities/MJCalendarEventLink/mjcalendareventlink.form.component.js +74 -0
  54. package/dist/lib/generated/Entities/MJCalendarEventLink/mjcalendareventlink.form.component.js.map +1 -0
  55. package/dist/lib/generated/Entities/MJCalendarSyncState/mjcalendarsyncstate.form.component.d.ts +10 -0
  56. package/dist/lib/generated/Entities/MJCalendarSyncState/mjcalendarsyncstate.form.component.d.ts.map +1 -0
  57. package/dist/lib/generated/Entities/MJCalendarSyncState/mjcalendarsyncstate.form.component.js +64 -0
  58. package/dist/lib/generated/Entities/MJCalendarSyncState/mjcalendarsyncstate.form.component.js.map +1 -0
  59. package/dist/lib/generated/Entities/MJCommunicationProvider/mjcommunicationprovider.form.component.d.ts.map +1 -1
  60. package/dist/lib/generated/Entities/MJCommunicationProvider/mjcommunicationprovider.form.component.js +62 -16
  61. package/dist/lib/generated/Entities/MJCommunicationProvider/mjcommunicationprovider.form.component.js.map +1 -1
  62. package/dist/lib/generated/Entities/MJCompanyIntegration/mjcompanyintegration.form.component.d.ts.map +1 -1
  63. package/dist/lib/generated/Entities/MJCompanyIntegration/mjcompanyintegration.form.component.js +28 -10
  64. package/dist/lib/generated/Entities/MJCompanyIntegration/mjcompanyintegration.form.component.js.map +1 -1
  65. package/dist/lib/generated/Entities/MJCompanyIntegrationObject/mjcompanyintegrationobject.form.component.d.ts +10 -0
  66. package/dist/lib/generated/Entities/MJCompanyIntegrationObject/mjcompanyintegrationobject.form.component.d.ts.map +1 -0
  67. package/dist/lib/generated/Entities/MJCompanyIntegrationObject/mjcompanyintegrationobject.form.component.js +189 -0
  68. package/dist/lib/generated/Entities/MJCompanyIntegrationObject/mjcompanyintegrationobject.form.component.js.map +1 -0
  69. package/dist/lib/generated/Entities/MJCompanyIntegrationObjectField/mjcompanyintegrationobjectfield.form.component.d.ts +10 -0
  70. package/dist/lib/generated/Entities/MJCompanyIntegrationObjectField/mjcompanyintegrationobjectfield.form.component.d.ts.map +1 -0
  71. package/dist/lib/generated/Entities/MJCompanyIntegrationObjectField/mjcompanyintegrationobjectfield.form.component.js +116 -0
  72. package/dist/lib/generated/Entities/MJCompanyIntegrationObjectField/mjcompanyintegrationobjectfield.form.component.js.map +1 -0
  73. package/dist/lib/generated/Entities/MJComponent/mjcomponent.form.component.d.ts.map +1 -1
  74. package/dist/lib/generated/Entities/MJComponent/mjcomponent.form.component.js +51 -35
  75. package/dist/lib/generated/Entities/MJComponent/mjcomponent.form.component.js.map +1 -1
  76. package/dist/lib/generated/Entities/MJContentFileType/mjcontentfiletype.form.component.d.ts.map +1 -1
  77. package/dist/lib/generated/Entities/MJContentFileType/mjcontentfiletype.form.component.js +36 -18
  78. package/dist/lib/generated/Entities/MJContentFileType/mjcontentfiletype.form.component.js.map +1 -1
  79. package/dist/lib/generated/Entities/MJContentItem/mjcontentitem.form.component.d.ts.map +1 -1
  80. package/dist/lib/generated/Entities/MJContentItem/mjcontentitem.form.component.js +74 -60
  81. package/dist/lib/generated/Entities/MJContentItem/mjcontentitem.form.component.js.map +1 -1
  82. package/dist/lib/generated/Entities/MJContentItemChunk/mjcontentitemchunk.form.component.d.ts.map +1 -1
  83. package/dist/lib/generated/Entities/MJContentItemChunk/mjcontentitemchunk.form.component.js +30 -32
  84. package/dist/lib/generated/Entities/MJContentItemChunk/mjcontentitemchunk.form.component.js.map +1 -1
  85. package/dist/lib/generated/Entities/MJContentSource/mjcontentsource.form.component.js +43 -35
  86. package/dist/lib/generated/Entities/MJContentSource/mjcontentsource.form.component.js.map +1 -1
  87. package/dist/lib/generated/Entities/MJContentType/mjcontenttype.form.component.js +21 -19
  88. package/dist/lib/generated/Entities/MJContentType/mjcontenttype.form.component.js.map +1 -1
  89. package/dist/lib/generated/Entities/MJDashboard/mjdashboard.form.component.d.ts.map +1 -1
  90. package/dist/lib/generated/Entities/MJDashboard/mjdashboard.form.component.js +45 -29
  91. package/dist/lib/generated/Entities/MJDashboard/mjdashboard.form.component.js.map +1 -1
  92. package/dist/lib/generated/Entities/MJDuplicateRun/mjduplicaterun.form.component.js +19 -17
  93. package/dist/lib/generated/Entities/MJDuplicateRun/mjduplicaterun.form.component.js.map +1 -1
  94. package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.d.ts.map +1 -1
  95. package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js +128 -92
  96. package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js.map +1 -1
  97. package/dist/lib/generated/Entities/MJEntityAlternateBaseView/mjentityalternatebaseview.form.component.d.ts +10 -0
  98. package/dist/lib/generated/Entities/MJEntityAlternateBaseView/mjentityalternatebaseview.form.component.d.ts.map +1 -0
  99. package/dist/lib/generated/Entities/MJEntityAlternateBaseView/mjentityalternatebaseview.form.component.js +129 -0
  100. package/dist/lib/generated/Entities/MJEntityAlternateBaseView/mjentityalternatebaseview.form.component.js.map +1 -0
  101. package/dist/lib/generated/Entities/MJEntityDocument/mjentitydocument.form.component.d.ts.map +1 -1
  102. package/dist/lib/generated/Entities/MJEntityDocument/mjentitydocument.form.component.js +27 -9
  103. package/dist/lib/generated/Entities/MJEntityDocument/mjentitydocument.form.component.js.map +1 -1
  104. package/dist/lib/generated/Entities/MJFile/mjfile.form.component.d.ts.map +1 -1
  105. package/dist/lib/generated/Entities/MJFile/mjfile.form.component.js +30 -12
  106. package/dist/lib/generated/Entities/MJFile/mjfile.form.component.js.map +1 -1
  107. package/dist/lib/generated/Entities/MJIntegration/mjintegration.form.component.d.ts.map +1 -1
  108. package/dist/lib/generated/Entities/MJIntegration/mjintegration.form.component.js +26 -8
  109. package/dist/lib/generated/Entities/MJIntegration/mjintegration.form.component.js.map +1 -1
  110. package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.d.ts.map +1 -1
  111. package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.js +24 -6
  112. package/dist/lib/generated/Entities/MJIntegrationObject/mjintegrationobject.form.component.js.map +1 -1
  113. package/dist/lib/generated/Entities/MJIntegrationObjectField/mjintegrationobjectfield.form.component.d.ts.map +1 -1
  114. package/dist/lib/generated/Entities/MJIntegrationObjectField/mjintegrationobjectfield.form.component.js +25 -6
  115. package/dist/lib/generated/Entities/MJIntegrationObjectField/mjintegrationobjectfield.form.component.js.map +1 -1
  116. package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.d.ts.map +1 -1
  117. package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.js +73 -59
  118. package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.js.map +1 -1
  119. package/dist/lib/generated/Entities/MJQueryEntity/mjqueryentity.form.component.js +10 -8
  120. package/dist/lib/generated/Entities/MJQueryEntity/mjqueryentity.form.component.js.map +1 -1
  121. package/dist/lib/generated/Entities/MJQueryParameter/mjqueryparameter.form.component.d.ts.map +1 -1
  122. package/dist/lib/generated/Entities/MJQueryParameter/mjqueryparameter.form.component.js +12 -4
  123. package/dist/lib/generated/Entities/MJQueryParameter/mjqueryparameter.form.component.js.map +1 -1
  124. package/dist/lib/generated/Entities/MJUser/mjuser.form.component.d.ts.map +1 -1
  125. package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js +209 -137
  126. package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js.map +1 -1
  127. package/dist/lib/generated/Entities/MJUserView/mjuserview.form.component.js +50 -38
  128. package/dist/lib/generated/Entities/MJUserView/mjuserview.form.component.js.map +1 -1
  129. package/dist/lib/generated/generated-forms.module.d.ts +446 -441
  130. package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
  131. package/dist/lib/generated/generated-forms.module.js +15 -0
  132. package/dist/lib/generated/generated-forms.module.js.map +1 -1
  133. package/dist/lib/panels/model-predictions/model-prediction.logic.d.ts +10 -0
  134. package/dist/lib/panels/model-predictions/model-prediction.logic.d.ts.map +1 -1
  135. package/dist/lib/panels/model-predictions/model-prediction.logic.js +15 -1
  136. package/dist/lib/panels/model-predictions/model-prediction.logic.js.map +1 -1
  137. package/dist/lib/panels/model-predictions/model-prediction.panel.d.ts +4 -0
  138. package/dist/lib/panels/model-predictions/model-prediction.panel.d.ts.map +1 -1
  139. package/dist/lib/panels/model-predictions/model-prediction.panel.js +77 -61
  140. package/dist/lib/panels/model-predictions/model-prediction.panel.js.map +1 -1
  141. package/dist/lib/shared/components/template-editor.component.d.ts +37 -0
  142. package/dist/lib/shared/components/template-editor.component.d.ts.map +1 -1
  143. package/dist/lib/shared/components/template-editor.component.js +424 -285
  144. package/dist/lib/shared/components/template-editor.component.js.map +1 -1
  145. package/package.json +48 -48
@@ -4,7 +4,8 @@ import { FormsModule } from '@angular/forms';
4
4
  import { MJButtonDirective } from '@memberjunction/ng-ui-components';
5
5
  import { MJNotificationService } from '@memberjunction/ng-notifications';
6
6
  import { PredictiveStudioPromoteModelOperation, } from '@memberjunction/core-entities';
7
- import { PS_FEATURE_DOMINANCE_THRESHOLD, FormatMetricValue, HumanizeFeatureName, MaxFeatureImportance, MetricsToDisplay, OverfitGap, ParseFeatureImportance, ParseMetrics, PrimaryModelScore, } from './ml-model-view-models';
7
+ import { ImportanceDisplay } from '@memberjunction/predictive-studio-core';
8
+ import { PS_FEATURE_DOMINANCE_THRESHOLD, FormatMetricValue, HumanizeFeatureName, MaxFeatureImportance, MetricsToDisplay, ModelImportanceView, OverfitGap, ParseFeatureImportance, ParseMetrics, PrimaryModelScore, } from './ml-model-view-models';
8
9
  import * as i0 from "@angular/core";
9
10
  import * as i1 from "@angular/forms";
10
11
  const _forTrack0 = ($index, $item) => $item.key;
@@ -84,7 +85,16 @@ function PSModelDetailComponent_Conditional_1_Conditional_46_Template(rf, ctx) {
84
85
  i0.ɵɵadvance();
85
86
  i0.ɵɵtextInterpolate1(" ", ctx_r4.gapVerdict, ". ");
86
87
  } }
87
- function PSModelDetailComponent_Conditional_1_Conditional_54_For_1_Template(rf, ctx) { if (rf & 1) {
88
+ function PSModelDetailComponent_Conditional_1_Conditional_51_Template(rf, ctx) { if (rf & 1) {
89
+ i0.ɵɵelementStart(0, "span", 23);
90
+ i0.ɵɵtext(1);
91
+ i0.ɵɵelementEnd();
92
+ } if (rf & 2) {
93
+ const ctx_r4 = i0.ɵɵnextContext(2);
94
+ i0.ɵɵadvance();
95
+ i0.ɵɵtextInterpolate(ctx_r4.ImportanceCaption);
96
+ } }
97
+ function PSModelDetailComponent_Conditional_1_Conditional_53_For_1_Template(rf, ctx) { if (rf & 1) {
88
98
  i0.ɵɵelementStart(0, "div", 31)(1, "span", 32);
89
99
  i0.ɵɵtext(2);
90
100
  i0.ɵɵelementEnd();
@@ -106,18 +116,47 @@ function PSModelDetailComponent_Conditional_1_Conditional_54_For_1_Template(rf,
106
116
  i0.ɵɵadvance(2);
107
117
  i0.ɵɵtextInterpolate(f_r7.value);
108
118
  } }
109
- function PSModelDetailComponent_Conditional_1_Conditional_54_Template(rf, ctx) { if (rf & 1) {
110
- i0.ɵɵrepeaterCreate(0, PSModelDetailComponent_Conditional_1_Conditional_54_For_1_Template, 7, 7, "div", 31, _forTrack1);
119
+ function PSModelDetailComponent_Conditional_1_Conditional_53_Template(rf, ctx) { if (rf & 1) {
120
+ i0.ɵɵrepeaterCreate(0, PSModelDetailComponent_Conditional_1_Conditional_53_For_1_Template, 7, 7, "div", 31, _forTrack1);
111
121
  } if (rf & 2) {
112
122
  const ctx_r4 = i0.ɵɵnextContext(2);
113
- i0.ɵɵrepeater(ctx_r4.importance);
123
+ i0.ɵɵrepeater(ctx_r4.DisplayedImportance);
114
124
  } }
115
- function PSModelDetailComponent_Conditional_1_Conditional_55_Template(rf, ctx) { if (rf & 1) {
116
- i0.ɵɵelementStart(0, "div", 23);
125
+ function PSModelDetailComponent_Conditional_1_Conditional_54_Conditional_0_Template(rf, ctx) { if (rf & 1) {
126
+ i0.ɵɵelementStart(0, "div", 35);
127
+ i0.ɵɵtext(1);
128
+ i0.ɵɵelementEnd();
129
+ } if (rf & 2) {
130
+ const ctx_r4 = i0.ɵɵnextContext(3);
131
+ i0.ɵɵadvance();
132
+ i0.ɵɵtextInterpolate(ctx_r4.ImportanceHiddenNote);
133
+ } }
134
+ function PSModelDetailComponent_Conditional_1_Conditional_54_Conditional_1_Template(rf, ctx) { if (rf & 1) {
135
+ i0.ɵɵelementStart(0, "div", 36);
117
136
  i0.ɵɵtext(1, "No feature-importance data was recorded for this model.");
118
137
  i0.ɵɵelementEnd();
119
138
  } }
120
- function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_3_Template(rf, ctx) { if (rf & 1) {
139
+ function PSModelDetailComponent_Conditional_1_Conditional_54_Template(rf, ctx) { if (rf & 1) {
140
+ i0.ɵɵconditionalCreate(0, PSModelDetailComponent_Conditional_1_Conditional_54_Conditional_0_Template, 2, 1, "div", 35)(1, PSModelDetailComponent_Conditional_1_Conditional_54_Conditional_1_Template, 2, 0, "div", 36);
141
+ } if (rf & 2) {
142
+ const ctx_r4 = i0.ɵɵnextContext(2);
143
+ i0.ɵɵconditional(ctx_r4.ImportanceHidden ? 0 : 1);
144
+ } }
145
+ function PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
146
+ i0.ɵɵelementStart(0, "strong");
147
+ i0.ɵɵtext(1, "Leakage flag raised.");
148
+ i0.ɵɵelementEnd();
149
+ i0.ɵɵtext(2, " A single feature's split share is at or above the ");
150
+ i0.ɵɵelementStart(3, "strong");
151
+ i0.ɵɵtext(4);
152
+ i0.ɵɵelementEnd();
153
+ i0.ɵɵtext(5, " dominance threshold. ");
154
+ } if (rf & 2) {
155
+ const ctx_r4 = i0.ɵɵnextContext(4);
156
+ i0.ɵɵadvance(4);
157
+ i0.ɵɵtextInterpolate(ctx_r4.dominanceThreshold);
158
+ } }
159
+ function PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
121
160
  i0.ɵɵelementStart(0, "strong");
122
161
  i0.ɵɵtext(1, "Leakage flag raised.");
123
162
  i0.ɵɵelementEnd();
@@ -130,18 +169,38 @@ function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_3_Templ
130
169
  i0.ɵɵtext(7);
131
170
  i0.ɵɵelementEnd();
132
171
  i0.ɵɵtext(8, " dominance threshold. ");
133
- i0.ɵɵelementStart(9, "div", 36);
134
- i0.ɵɵelement(10, "i", 37);
135
- i0.ɵɵtext(11, " Sign-off with a reason is required to publish this model. ");
172
+ } if (rf & 2) {
173
+ const ctx_r4 = i0.ɵɵnextContext(4);
174
+ i0.ɵɵadvance(4);
175
+ i0.ɵɵtextInterpolate2("", ctx_r4.TopFeatureName, " at ", ctx_r4.TopFeatureValue);
176
+ i0.ɵɵadvance(3);
177
+ i0.ɵɵtextInterpolate(ctx_r4.dominanceThreshold);
178
+ } }
179
+ function PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_3_Template(rf, ctx) { if (rf & 1) {
180
+ i0.ɵɵconditionalCreate(0, PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_3_Conditional_0_Template, 6, 1)(1, PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_3_Conditional_1_Template, 9, 3);
181
+ i0.ɵɵelementStart(2, "div", 38);
182
+ i0.ɵɵelement(3, "i", 39);
183
+ i0.ɵɵtext(4, " Sign-off with a reason is required to publish this model. ");
136
184
  i0.ɵɵelementEnd();
137
185
  } if (rf & 2) {
138
186
  const ctx_r4 = i0.ɵɵnextContext(3);
187
+ i0.ɵɵconditional(ctx_r4.ImportanceHidden ? 0 : 1);
188
+ } }
189
+ function PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_4_Conditional_0_Template(rf, ctx) { if (rf & 1) {
190
+ i0.ɵɵelementStart(0, "strong");
191
+ i0.ɵɵtext(1, "Leakage gate clear.");
192
+ i0.ɵɵelementEnd();
193
+ i0.ɵɵtext(2, " No single feature's split share is at or above the ");
194
+ i0.ɵɵelementStart(3, "strong");
195
+ i0.ɵɵtext(4);
196
+ i0.ɵɵelementEnd();
197
+ i0.ɵɵtext(5, " dominance threshold. ");
198
+ } if (rf & 2) {
199
+ const ctx_r4 = i0.ɵɵnextContext(4);
139
200
  i0.ɵɵadvance(4);
140
- i0.ɵɵtextInterpolate2("", ctx_r4.topFeatureName, " at ", ctx_r4.topFeatureValue);
141
- i0.ɵɵadvance(3);
142
201
  i0.ɵɵtextInterpolate(ctx_r4.dominanceThreshold);
143
202
  } }
144
- function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_4_Template(rf, ctx) { if (rf & 1) {
203
+ function PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
145
204
  i0.ɵɵelementStart(0, "strong");
146
205
  i0.ɵɵtext(1, "Leakage gate clear.");
147
206
  i0.ɵɵelementEnd();
@@ -154,62 +213,68 @@ function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_4_Templ
154
213
  i0.ɵɵtext(7);
155
214
  i0.ɵɵelementEnd();
156
215
  i0.ɵɵtext(8, " dominance threshold. ");
157
- i0.ɵɵelementStart(9, "div", 36);
158
- i0.ɵɵelement(10, "i", 28);
159
- i0.ɵɵtext(11, " Sign-off required before any Validated \u2192 Published promotion. ");
160
- i0.ɵɵelementEnd();
161
216
  } if (rf & 2) {
162
- const ctx_r4 = i0.ɵɵnextContext(3);
217
+ const ctx_r4 = i0.ɵɵnextContext(4);
163
218
  i0.ɵɵadvance(4);
164
- i0.ɵɵtextInterpolate2("", ctx_r4.topFeatureName, " at ", ctx_r4.topFeatureValue);
219
+ i0.ɵɵtextInterpolate2("", ctx_r4.TopFeatureName, " at ", ctx_r4.TopFeatureValue);
165
220
  i0.ɵɵadvance(3);
166
221
  i0.ɵɵtextInterpolate(ctx_r4.dominanceThreshold);
167
222
  } }
168
- function PSModelDetailComponent_Conditional_1_Conditional_56_Template(rf, ctx) { if (rf & 1) {
169
- i0.ɵɵelementStart(0, "div", 35);
223
+ function PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_4_Template(rf, ctx) { if (rf & 1) {
224
+ i0.ɵɵconditionalCreate(0, PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_4_Conditional_0_Template, 6, 1)(1, PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_4_Conditional_1_Template, 9, 3);
225
+ i0.ɵɵelementStart(2, "div", 38);
226
+ i0.ɵɵelement(3, "i", 28);
227
+ i0.ɵɵtext(4, " Sign-off required before any Validated \u2192 Published promotion. ");
228
+ i0.ɵɵelementEnd();
229
+ } if (rf & 2) {
230
+ const ctx_r4 = i0.ɵɵnextContext(3);
231
+ i0.ɵɵconditional(ctx_r4.ImportanceHidden ? 0 : 1);
232
+ } }
233
+ function PSModelDetailComponent_Conditional_1_Conditional_55_Template(rf, ctx) { if (rf & 1) {
234
+ i0.ɵɵelementStart(0, "div", 37);
170
235
  i0.ɵɵelement(1, "i");
171
236
  i0.ɵɵelementStart(2, "div");
172
- i0.ɵɵconditionalCreate(3, PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_3_Template, 12, 3)(4, PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_4_Template, 12, 3);
237
+ i0.ɵɵconditionalCreate(3, PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_3_Template, 5, 1)(4, PSModelDetailComponent_Conditional_1_Conditional_55_Conditional_4_Template, 5, 1);
173
238
  i0.ɵɵelementEnd()();
174
239
  } if (rf & 2) {
175
240
  const ctx_r4 = i0.ɵɵnextContext(2);
176
- i0.ɵɵclassProp("success", !ctx_r4.leakageFlagged)("warn", ctx_r4.leakageFlagged);
241
+ i0.ɵɵclassProp("success", !ctx_r4.LeakageFlagged)("warn", ctx_r4.LeakageFlagged);
177
242
  i0.ɵɵadvance();
178
- i0.ɵɵclassMap(ctx_r4.leakageFlagged ? "fa-solid fa-triangle-exclamation" : "fa-solid fa-shield-halved");
243
+ i0.ɵɵclassMap(ctx_r4.LeakageFlagged ? "fa-solid fa-triangle-exclamation" : "fa-solid fa-shield-halved");
179
244
  i0.ɵɵadvance(2);
180
- i0.ɵɵconditional(ctx_r4.leakageFlagged ? 3 : 4);
245
+ i0.ɵɵconditional(ctx_r4.LeakageFlagged ? 3 : 4);
181
246
  } }
182
- function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_4_Template(rf, ctx) { if (rf & 1) {
247
+ function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_4_Template(rf, ctx) { if (rf & 1) {
183
248
  const _r8 = i0.ɵɵgetCurrentView();
184
- i0.ɵɵelementStart(0, "button", 43);
185
- i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r4 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r4.requestPromote("Validated")); });
186
- i0.ɵɵelement(1, "i", 44);
249
+ i0.ɵɵelementStart(0, "button", 45);
250
+ i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r4 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r4.requestPromote("Validated")); });
251
+ i0.ɵɵelement(1, "i", 46);
187
252
  i0.ɵɵtext(2, " Mark Validated ");
188
253
  i0.ɵɵelementEnd();
189
254
  } }
190
- function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_5_Template(rf, ctx) { if (rf & 1) {
255
+ function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_5_Template(rf, ctx) { if (rf & 1) {
191
256
  const _r9 = i0.ɵɵgetCurrentView();
192
- i0.ɵɵelementStart(0, "button", 45);
193
- i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r4 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r4.requestPromote("Published")); });
194
- i0.ɵɵelement(1, "i", 46);
257
+ i0.ɵɵelementStart(0, "button", 47);
258
+ i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r4 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r4.requestPromote("Published")); });
259
+ i0.ɵɵelement(1, "i", 48);
195
260
  i0.ɵɵtext(2, " Promote to Published ");
196
261
  i0.ɵɵelementEnd();
197
262
  } }
198
- function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_6_Template(rf, ctx) { if (rf & 1) {
263
+ function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_6_Template(rf, ctx) { if (rf & 1) {
199
264
  const _r10 = i0.ɵɵgetCurrentView();
200
- i0.ɵɵelementStart(0, "button", 47);
201
- i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r4 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r4.requestPromote("Archived")); });
202
- i0.ɵɵelement(1, "i", 48);
265
+ i0.ɵɵelementStart(0, "button", 49);
266
+ i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r4 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r4.requestPromote("Archived")); });
267
+ i0.ɵɵelement(1, "i", 50);
203
268
  i0.ɵɵtext(2, " Archive ");
204
269
  i0.ɵɵelementEnd();
205
270
  } }
206
- function PSModelDetailComponent_Conditional_1_Conditional_57_Template(rf, ctx) { if (rf & 1) {
207
- i0.ɵɵelementStart(0, "div", 2)(1, "div", 38)(2, "span", 39);
271
+ function PSModelDetailComponent_Conditional_1_Conditional_56_Template(rf, ctx) { if (rf & 1) {
272
+ i0.ɵɵelementStart(0, "div", 2)(1, "div", 40)(2, "span", 41);
208
273
  i0.ɵɵtext(3);
209
274
  i0.ɵɵelementEnd();
210
- i0.ɵɵconditionalCreate(4, PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_4_Template, 3, 0, "button", 40);
211
- i0.ɵɵconditionalCreate(5, PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_5_Template, 3, 0, "button", 41);
212
- i0.ɵɵconditionalCreate(6, PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_6_Template, 3, 0, "button", 42);
275
+ i0.ɵɵconditionalCreate(4, PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_4_Template, 3, 0, "button", 42);
276
+ i0.ɵɵconditionalCreate(5, PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_5_Template, 3, 0, "button", 43);
277
+ i0.ɵɵconditionalCreate(6, PSModelDetailComponent_Conditional_1_Conditional_56_Conditional_6_Template, 3, 0, "button", 44);
213
278
  i0.ɵɵelementEnd()();
214
279
  } if (rf & 2) {
215
280
  const ctx_r4 = i0.ɵɵnextContext(2);
@@ -222,13 +287,13 @@ function PSModelDetailComponent_Conditional_1_Conditional_57_Template(rf, ctx) {
222
287
  i0.ɵɵadvance();
223
288
  i0.ɵɵconditional(ctx_r4.canArchive ? 6 : -1);
224
289
  } }
225
- function PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_9_Template(rf, ctx) { if (rf & 1) {
290
+ function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_9_Template(rf, ctx) { if (rf & 1) {
226
291
  const _r12 = i0.ɵɵgetCurrentView();
227
- i0.ɵɵelementStart(0, "div", 55)(1, "label");
292
+ i0.ɵɵelementStart(0, "div", 57)(1, "label");
228
293
  i0.ɵɵtext(2);
229
294
  i0.ɵɵelementEnd();
230
- i0.ɵɵelementStart(3, "textarea", 62);
231
- i0.ɵɵtwoWayListener("ngModelChange", function PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_9_Template_textarea_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r4 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r4.pendingReason, $event) || (ctx_r4.pendingReason = $event); return i0.ɵɵresetView($event); });
295
+ i0.ɵɵelementStart(3, "textarea", 64);
296
+ i0.ɵɵtwoWayListener("ngModelChange", function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_9_Template_textarea_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r4 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r4.pendingReason, $event) || (ctx_r4.pendingReason = $event); return i0.ɵɵresetView($event); });
232
297
  i0.ɵɵelementEnd()();
233
298
  } if (rf & 2) {
234
299
  const ctx_r4 = i0.ɵɵnextContext(3);
@@ -238,39 +303,39 @@ function PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_9_Templ
238
303
  i0.ɵɵtwoWayProperty("ngModel", ctx_r4.pendingReason);
239
304
  i0.ɵɵproperty("placeholder", ctx_r4.pending.leakageFlagged ? "Explain why this model is safe to publish despite the leakage flag\u2026" : "Add an optional note for the record\u2026")("disabled", ctx_r4.busy);
240
305
  } }
241
- function PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_12_Template(rf, ctx) { if (rf & 1) {
242
- i0.ɵɵelement(0, "i", 58);
306
+ function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_12_Template(rf, ctx) { if (rf & 1) {
307
+ i0.ɵɵelement(0, "i", 60);
243
308
  } }
244
- function PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_13_Template(rf, ctx) { if (rf & 1) {
309
+ function PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_13_Template(rf, ctx) { if (rf & 1) {
245
310
  i0.ɵɵelement(0, "i");
246
311
  } if (rf & 2) {
247
312
  const ctx_r4 = i0.ɵɵnextContext(3);
248
313
  i0.ɵɵclassMap(ctx_r4.pendingIcon);
249
314
  } }
250
- function PSModelDetailComponent_Conditional_1_Conditional_58_Template(rf, ctx) { if (rf & 1) {
315
+ function PSModelDetailComponent_Conditional_1_Conditional_57_Template(rf, ctx) { if (rf & 1) {
251
316
  const _r11 = i0.ɵɵgetCurrentView();
252
- i0.ɵɵelementStart(0, "div", 49);
253
- i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_58_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r4 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r4.cancelPromote()); });
254
- i0.ɵɵelementStart(1, "div", 50);
255
- i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_58_Template_div_click_1_listener($event) { return $event.stopPropagation(); });
256
- i0.ɵɵelementStart(2, "div", 51)(3, "span", 52);
317
+ i0.ɵɵelementStart(0, "div", 51);
318
+ i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_57_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r4 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r4.cancelPromote()); });
319
+ i0.ɵɵelementStart(1, "div", 52);
320
+ i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_57_Template_div_click_1_listener($event) { return $event.stopPropagation(); });
321
+ i0.ɵɵelementStart(2, "div", 53)(3, "span", 54);
257
322
  i0.ɵɵelement(4, "i");
258
323
  i0.ɵɵelementEnd();
259
324
  i0.ɵɵelementStart(5, "h3");
260
325
  i0.ɵɵtext(6);
261
326
  i0.ɵɵelementEnd()();
262
- i0.ɵɵelementStart(7, "div", 53);
263
- i0.ɵɵelement(8, "div", 54);
264
- i0.ɵɵconditionalCreate(9, PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_9_Template, 4, 5, "div", 55);
327
+ i0.ɵɵelementStart(7, "div", 55);
328
+ i0.ɵɵelement(8, "div", 56);
329
+ i0.ɵɵconditionalCreate(9, PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_9_Template, 4, 5, "div", 57);
265
330
  i0.ɵɵelementEnd();
266
- i0.ɵɵelementStart(10, "div", 56)(11, "button", 57);
267
- i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_58_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r11); const ctx_r4 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r4.confirmPromote(ctx_r4.pendingReason.trim())); });
268
- i0.ɵɵconditionalCreate(12, PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_12_Template, 1, 0, "i", 58)(13, PSModelDetailComponent_Conditional_1_Conditional_58_Conditional_13_Template, 1, 2, "i", 59);
331
+ i0.ɵɵelementStart(10, "div", 58)(11, "button", 59);
332
+ i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_57_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r11); const ctx_r4 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r4.confirmPromote(ctx_r4.pendingReason.trim())); });
333
+ i0.ɵɵconditionalCreate(12, PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_12_Template, 1, 0, "i", 60)(13, PSModelDetailComponent_Conditional_1_Conditional_57_Conditional_13_Template, 1, 2, "i", 61);
269
334
  i0.ɵɵtext(14);
270
335
  i0.ɵɵelementEnd();
271
- i0.ɵɵelement(15, "span", 60);
272
- i0.ɵɵelementStart(16, "button", 61);
273
- i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_58_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r11); const ctx_r4 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r4.cancelPromote()); });
336
+ i0.ɵɵelement(15, "span", 62);
337
+ i0.ɵɵelementStart(16, "button", 63);
338
+ i0.ɵɵlistener("click", function PSModelDetailComponent_Conditional_1_Conditional_57_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r11); const ctx_r4 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r4.cancelPromote()); });
274
339
  i0.ɵɵtext(17, " Cancel ");
275
340
  i0.ɵɵelementEnd()()()();
276
341
  } if (rf & 2) {
@@ -348,15 +413,14 @@ function PSModelDetailComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
348
413
  i0.ɵɵelementStart(47, "div", 2)(48, "div", 15)(49, "h3");
349
414
  i0.ɵɵtext(50, "Feature Importance");
350
415
  i0.ɵɵelementEnd();
351
- i0.ɵɵelementStart(51, "span", 16);
352
- i0.ɵɵtext(52);
353
- i0.ɵɵelementEnd()();
354
- i0.ɵɵelementStart(53, "div", 11);
355
- i0.ɵɵconditionalCreate(54, PSModelDetailComponent_Conditional_1_Conditional_54_Template, 2, 0)(55, PSModelDetailComponent_Conditional_1_Conditional_55_Template, 2, 0, "div", 23);
416
+ i0.ɵɵconditionalCreate(51, PSModelDetailComponent_Conditional_1_Conditional_51_Template, 2, 1, "span", 23);
417
+ i0.ɵɵelementEnd();
418
+ i0.ɵɵelementStart(52, "div", 11);
419
+ i0.ɵɵconditionalCreate(53, PSModelDetailComponent_Conditional_1_Conditional_53_Template, 2, 0)(54, PSModelDetailComponent_Conditional_1_Conditional_54_Template, 2, 1);
356
420
  i0.ɵɵelementEnd()();
357
- i0.ɵɵconditionalCreate(56, PSModelDetailComponent_Conditional_1_Conditional_56_Template, 5, 7, "div", 24);
358
- i0.ɵɵconditionalCreate(57, PSModelDetailComponent_Conditional_1_Conditional_57_Template, 7, 4, "div", 2);
359
- i0.ɵɵconditionalCreate(58, PSModelDetailComponent_Conditional_1_Conditional_58_Template, 18, 14, "div", 25);
421
+ i0.ɵɵconditionalCreate(55, PSModelDetailComponent_Conditional_1_Conditional_55_Template, 5, 7, "div", 24);
422
+ i0.ɵɵconditionalCreate(56, PSModelDetailComponent_Conditional_1_Conditional_56_Template, 7, 4, "div", 2);
423
+ i0.ɵɵconditionalCreate(57, PSModelDetailComponent_Conditional_1_Conditional_57_Template, 18, 14, "div", 25);
360
424
  } if (rf & 2) {
361
425
  const ctx_r4 = i0.ɵɵnextContext();
362
426
  i0.ɵɵadvance(6);
@@ -383,25 +447,25 @@ function PSModelDetailComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
383
447
  i0.ɵɵconditional(ctx_r4.secondaryMetrics.length > 0 ? 44 : 45);
384
448
  i0.ɵɵadvance(2);
385
449
  i0.ɵɵconditional(ctx_r4.gapText ? 46 : -1);
386
- i0.ɵɵadvance(6);
387
- i0.ɵɵtextInterpolate(ctx_r4.importanceCaption);
450
+ i0.ɵɵadvance(5);
451
+ i0.ɵɵconditional(!ctx_r4.ImportanceHidden ? 51 : -1);
388
452
  i0.ɵɵadvance(2);
389
- i0.ɵɵconditional(ctx_r4.importance.length > 0 ? 54 : 55);
453
+ i0.ɵɵconditional(ctx_r4.DisplayedImportance.length > 0 ? 53 : 54);
390
454
  i0.ɵɵadvance(2);
391
- i0.ɵɵconditional(ctx_r4.importance.length > 0 ? 56 : -1);
455
+ i0.ɵɵconditional(ctx_r4.Importance.length > 0 ? 55 : -1);
392
456
  i0.ɵɵadvance();
393
- i0.ɵɵconditional(ctx_r4.showActions ? 57 : -1);
457
+ i0.ɵɵconditional(ctx_r4.showActions ? 56 : -1);
394
458
  i0.ɵɵadvance();
395
- i0.ɵɵconditional(ctx_r4.pending ? 58 : -1);
459
+ i0.ɵɵconditional(ctx_r4.pending ? 57 : -1);
396
460
  } }
397
461
  function PSModelDetailComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
398
- i0.ɵɵelementStart(0, "div", 1)(1, "span", 63);
462
+ i0.ɵɵelementStart(0, "div", 1)(1, "span", 65);
399
463
  i0.ɵɵelement(2, "i", 5);
400
464
  i0.ɵɵelementEnd();
401
465
  i0.ɵɵelementStart(3, "h3");
402
466
  i0.ɵɵtext(4, "No Model Selected");
403
467
  i0.ɵɵelementEnd();
404
- i0.ɵɵelementStart(5, "p", 64);
468
+ i0.ɵɵelementStart(5, "p", 66);
405
469
  i0.ɵɵtext(6, "Select an ML Model from the list to inspect its configuration and metrics.");
406
470
  i0.ɵɵelementEnd()();
407
471
  } }
@@ -441,6 +505,11 @@ export class PSModelDetailComponent {
441
505
  this.Pending = null;
442
506
  this.PendingReason = '';
443
507
  this.Busy = false;
508
+ // ── Feature Importance & Leakage Gate ──
509
+ /** Cached parsed and displayed importance bars for the last (Lineage JSON, importance JSON) pair. */
510
+ this.importanceCache = null;
511
+ /** The note shown in place of hidden importance. */
512
+ this.ImportanceHiddenNote = ImportanceDisplay.HiddenNote;
444
513
  }
445
514
  /** @deprecated Use {@link Model}. */
446
515
  set model(value) {
@@ -632,19 +701,44 @@ export class PSModelDetailComponent {
632
701
  get gapVerdict() {
633
702
  return this.GapVerdict;
634
703
  }
635
- // ── Feature Importance & Leakage Gate ──
636
- get Importance() {
704
+ get cachedImportance() {
637
705
  if (!this.Model)
638
- return [];
639
- return ParseFeatureImportance(this.Model.FeatureImportance, 6).map((b) => ({
640
- ...b,
641
- name: HumanizeFeatureName(b.name),
642
- }));
706
+ return { allBars: [], displayedBars: [] };
707
+ const key = `${this.Model.Lineage}\u0000${this.Model.FeatureImportance}`;
708
+ if (this.importanceCache?.key !== key) {
709
+ const allBars = ParseFeatureImportance(this.Model.FeatureImportance, 6).map((b) => ({
710
+ ...b,
711
+ name: HumanizeFeatureName(b.name),
712
+ }));
713
+ const displayedBars = ModelImportanceView.DisplayedFeatureImportance(this.Model.Lineage, this.Model.FeatureImportance, 6).map((b) => ({
714
+ ...b,
715
+ name: HumanizeFeatureName(b.name),
716
+ }));
717
+ this.importanceCache = { key, allBars, displayedBars };
718
+ }
719
+ return this.importanceCache;
720
+ }
721
+ get Importance() {
722
+ return this.cachedImportance.allBars;
643
723
  }
644
724
  /** @deprecated Use {@link Importance}. */
645
725
  get importance() {
646
726
  return this.Importance;
647
727
  }
728
+ /**
729
+ * The importance bars shown in the Feature Importance card (empty for split / impurity importance). Cached on the
730
+ * Lineage JSON (which holds the stored importance kind) and the importance JSON, so the parse runs once per model and
731
+ * again whenever either value changes
732
+ * (coding standards §7: getters Angular bindings hit).
733
+ */
734
+ get DisplayedImportance() {
735
+ return this.cachedImportance.displayedBars;
736
+ }
737
+ /** True when the model has importance data that is hidden because of its kind. */
738
+ get ImportanceHidden() {
739
+ return this.Importance.length > 0 && this.DisplayedImportance.length === 0;
740
+ }
741
+ /** The Feature Importance card's caption. The template hides it when {@link ImportanceHidden}, along with the bars. */
648
742
  get ImportanceCaption() {
649
743
  const n = this.Importance.length;
650
744
  return n === 0 ? 'no data' : `normalized · top ${n}`;
@@ -844,9 +938,9 @@ export class PSModelDetailComponent {
844
938
  .replace(/"/g, '"');
845
939
  }
846
940
  static { this.ɵfac = function PSModelDetailComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PSModelDetailComponent)(); }; }
847
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSModelDetailComponent, selectors: [["ps-model-detail"]], inputs: { Model: "Model", model: "model", Provider: "Provider", provider: "provider", CurrentUser: "CurrentUser", currentUser: "currentUser", ShowActions: "ShowActions", showActions: "showActions", displayName: "displayName" }, outputs: { StatusChanged: "StatusChanged", statusChanged: "statusChanged" }, decls: 3, vars: 1, consts: [["data-testid", "ps-model-detail", 1, "ps-model-detail"], [1, "ps-empty", 2, "padding", "32px", "text-align", "center"], [1, "ps-card"], [1, "ps-card-body", "dh"], [1, "big-ico"], [1, "fa-solid", "fa-cube"], [2, "flex", "1", "min-width", "0"], ["data-testid", "ps-registry-detail-name"], [1, "ps-tag", "ps-mono"], [1, "ps-muted", "ps-small", "sub"], [1, "ps-badge"], [1, "ps-card-body"], [1, "ps-section-title"], [1, "ps-stepper"], [1, "ps-small", "ps-muted", 2, "margin-top", "10px"], [1, "ps-card-head"], [1, "ps-muted", "ps-small"], [1, "metric-pair"], [1, "mtile"], [1, "v"], [1, "mtile", "honest"], [1, "stat-bar"], [1, "ps-small", "ps-muted", 2, "margin-top", "6px"], [1, "ps-small", "ps-muted"], [1, "ps-callout", "gate", 3, "success", "warn"], [1, "ps-modal-backdrop"], [1, "ps-step"], [1, "pip"], [1, "fa-solid", "fa-check"], [1, "ln"], [1, "b"], [1, "ps-fbar"], [1, "name", "ps-small", 3, "title"], [1, "track"], [1, "ps-mono"], [1, "ps-callout", "gate"], [1, "ps-small", 2, "margin-top", "6px"], [1, "fa-solid", "fa-pen"], [1, "ps-card-body", "ps-row", 2, "align-items", "center", "flex-wrap", "wrap", "gap", "8px"], [1, "ps-muted", "ps-small", 2, "flex", "1"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-validate"], ["mjButton", "", "variant", "primary", "size", "sm", "data-testid", "ps-registry-promote"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-archive"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-validate", 3, "click"], [1, "fa-solid", "fa-circle-check"], ["mjButton", "", "variant", "primary", "size", "sm", "data-testid", "ps-registry-promote", 3, "click"], [1, "fa-solid", "fa-arrow-up"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-archive", 3, "click"], [1, "fa-solid", "fa-box-archive"], [1, "ps-modal-backdrop", 3, "click"], ["data-testid", "ps-confirm-modal", 1, "ps-modal", 3, "click"], [1, "ps-modal-head"], [1, "ico"], [1, "ps-modal-body"], [3, "innerHTML"], [1, "ps-field", 2, "margin-top", "12px"], [1, "ps-modal-foot"], ["mjButton", "", "size", "sm", 3, "click", "variant", "disabled"], [1, "fa-solid", "fa-circle-notch", "fa-spin"], [3, "class"], [1, "ps-spacer", 2, "flex", "1"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], ["rows", "3", 1, "ps-input", 3, "ngModelChange", "ngModel", "placeholder", "disabled"], [1, "ps-empty-ico"], [1, "ps-muted"]], template: function PSModelDetailComponent_Template(rf, ctx) { if (rf & 1) {
941
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSModelDetailComponent, selectors: [["ps-model-detail"]], inputs: { Model: "Model", model: "model", Provider: "Provider", provider: "provider", CurrentUser: "CurrentUser", currentUser: "currentUser", ShowActions: "ShowActions", showActions: "showActions", displayName: "displayName" }, outputs: { StatusChanged: "StatusChanged", statusChanged: "statusChanged" }, decls: 3, vars: 1, consts: [["data-testid", "ps-model-detail", 1, "ps-model-detail"], [1, "ps-empty", 2, "padding", "32px", "text-align", "center"], [1, "ps-card"], [1, "ps-card-body", "dh"], [1, "big-ico"], [1, "fa-solid", "fa-cube"], [2, "flex", "1", "min-width", "0"], ["data-testid", "ps-registry-detail-name"], [1, "ps-tag", "ps-mono"], [1, "ps-muted", "ps-small", "sub"], [1, "ps-badge"], [1, "ps-card-body"], [1, "ps-section-title"], [1, "ps-stepper"], [1, "ps-small", "ps-muted", 2, "margin-top", "10px"], [1, "ps-card-head"], [1, "ps-muted", "ps-small"], [1, "metric-pair"], [1, "mtile"], [1, "v"], [1, "mtile", "honest"], [1, "stat-bar"], [1, "ps-small", "ps-muted", 2, "margin-top", "6px"], ["data-testid", "ps-importance-caption", 1, "ps-muted", "ps-small"], ["data-testid", "ps-leakage-gate", 1, "ps-callout", "gate", 3, "success", "warn"], [1, "ps-modal-backdrop"], [1, "ps-step"], [1, "pip"], [1, "fa-solid", "fa-check"], [1, "ln"], [1, "b"], [1, "ps-fbar"], [1, "name", "ps-small", 3, "title"], [1, "track"], [1, "ps-mono"], ["data-testid", "ps-importance-hidden", 1, "ps-small", "ps-muted"], [1, "ps-small", "ps-muted"], ["data-testid", "ps-leakage-gate", 1, "ps-callout", "gate"], [1, "ps-small", 2, "margin-top", "6px"], [1, "fa-solid", "fa-pen"], [1, "ps-card-body", "ps-row", 2, "align-items", "center", "flex-wrap", "wrap", "gap", "8px"], [1, "ps-muted", "ps-small", 2, "flex", "1"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-validate"], ["mjButton", "", "variant", "primary", "size", "sm", "data-testid", "ps-registry-promote"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-archive"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-validate", 3, "click"], [1, "fa-solid", "fa-circle-check"], ["mjButton", "", "variant", "primary", "size", "sm", "data-testid", "ps-registry-promote", 3, "click"], [1, "fa-solid", "fa-arrow-up"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-registry-archive", 3, "click"], [1, "fa-solid", "fa-box-archive"], [1, "ps-modal-backdrop", 3, "click"], ["data-testid", "ps-confirm-modal", 1, "ps-modal", 3, "click"], [1, "ps-modal-head"], [1, "ico"], [1, "ps-modal-body"], [3, "innerHTML"], [1, "ps-field", 2, "margin-top", "12px"], [1, "ps-modal-foot"], ["mjButton", "", "size", "sm", 3, "click", "variant", "disabled"], [1, "fa-solid", "fa-circle-notch", "fa-spin"], [3, "class"], [1, "ps-spacer", 2, "flex", "1"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click", "disabled"], ["rows", "3", 1, "ps-input", 3, "ngModelChange", "ngModel", "placeholder", "disabled"], [1, "ps-empty-ico"], [1, "ps-muted"]], template: function PSModelDetailComponent_Template(rf, ctx) { if (rf & 1) {
848
942
  i0.ɵɵelementStart(0, "div", 0);
849
- i0.ɵɵconditionalCreate(1, PSModelDetailComponent_Conditional_1_Template, 59, 18)(2, PSModelDetailComponent_Conditional_2_Template, 7, 0, "div", 1);
943
+ i0.ɵɵconditionalCreate(1, PSModelDetailComponent_Conditional_1_Template, 58, 18)(2, PSModelDetailComponent_Conditional_2_Template, 7, 0, "div", 1);
850
944
  i0.ɵɵelementEnd();
851
945
  } if (rf & 2) {
852
946
  i0.ɵɵadvance();
@@ -855,7 +949,7 @@ export class PSModelDetailComponent {
855
949
  }
856
950
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PSModelDetailComponent, [{
857
951
  type: Component,
858
- args: [{ standalone: true, selector: 'ps-model-detail', imports: [CommonModule, FormsModule, MJButtonDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ps-model-detail\" data-testid=\"ps-model-detail\">\n @if (model) {\n <!-- 1. Header Card -->\n <div class=\"ps-card\">\n <div class=\"ps-card-body dh\">\n <div class=\"big-ico\"><i class=\"fa-solid fa-cube\"></i></div>\n <div style=\"flex:1;min-width:0;\">\n <h2 data-testid=\"ps-registry-detail-name\">\n {{ modelDisplayName }}\n <span class=\"ps-tag ps-mono\">v{{ model.Version }}</span>\n </h2>\n <div class=\"ps-muted ps-small sub\">\n {{ model.Algorithm || 'Model' }}{{ targetSuffix }} &bull; immutable snapshot\n </div>\n </div>\n <span class=\"ps-badge\" [class]=\"statusBadgeClass(model.Status)\">{{ model.Status }}</span>\n </div>\n </div>\n\n <!-- 2. Lifecycle Stepper -->\n <div class=\"ps-card\">\n <div class=\"ps-card-body\">\n <div class=\"ps-section-title\">Lifecycle</div>\n <div class=\"ps-stepper\">\n @for (step of lifecycleSteps; track step; let last = $last) {\n <div class=\"ps-step\" [class.done]=\"stepState(step) === 'done'\" [class.curr]=\"stepState(step) === 'curr'\">\n <span class=\"pip\">\n @if (stepState(step) === 'done') {\n <i class=\"fa-solid fa-check\"></i>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n {{ step }}\n </div>\n @if (!last) {\n <span class=\"ln\"></span>\n }\n }\n </div>\n <div class=\"ps-small ps-muted\" style=\"margin-top:10px\">\n Models are immutable once registered; promotion only changes lifecycle state, never weights.\n </div>\n </div>\n </div>\n\n <!-- 3. Performance Metrics -->\n <div class=\"ps-card\">\n <div class=\"ps-card-head\">\n <h3>Performance</h3>\n <span class=\"ps-muted ps-small\">Holdout = held-out test fold, never seen in training</span>\n </div>\n <div class=\"ps-card-body\">\n <div class=\"metric-pair\">\n <div class=\"mtile\">\n <div class=\"ps-section-title\">Train {{ primaryScoreLabel }}</div>\n <div class=\"v\">{{ trainPrimaryScore }}</div>\n <div class=\"ps-muted ps-small\">in-sample &bull; optimistic</div>\n </div>\n <div class=\"mtile honest\">\n <div class=\"ps-section-title\">Holdout {{ primaryScoreLabel }}</div>\n <div class=\"v\">{{ holdoutPrimaryScore }}</div>\n <div class=\"ps-muted ps-small\">out-of-sample &bull; the honest number</div>\n </div>\n </div>\n\n @if (secondaryMetrics.length > 0) {\n <div class=\"stat-bar\">\n @for (s of secondaryMetrics; track s.key) {\n <div class=\"b\">\n <span class=\"ps-muted ps-small\">{{ s.label }}</span>\n <strong>{{ s.value }}</strong>\n </div>\n }\n </div>\n } @else {\n <div class=\"ps-small ps-muted\" style=\"margin-top:6px\">No secondary metrics recorded for this model.</div>\n }\n\n @if (gapText) {\n <div class=\"ps-small ps-muted\" style=\"margin-top:10px\">\n Train\u2013holdout gap of <strong>{{ gapText }}</strong> {{ gapVerdict }}.\n </div>\n }\n </div>\n </div>\n\n <!-- 4. Feature Importance -->\n <div class=\"ps-card\">\n <div class=\"ps-card-head\">\n <h3>Feature Importance</h3>\n <span class=\"ps-muted ps-small\">{{ importanceCaption }}</span>\n </div>\n <div class=\"ps-card-body\">\n @if (importance.length > 0) {\n @for (f of importance; track f.name) {\n <div class=\"ps-fbar\">\n <span class=\"name ps-small\" [title]=\"f.name\">{{ f.name }}</span>\n <div class=\"track\">\n <span [class.warn]=\"f.warning\" [style.width.%]=\"f.pct\"></span>\n </div>\n <span class=\"ps-mono\">{{ f.value }}</span>\n </div>\n }\n } @else {\n <div class=\"ps-small ps-muted\">No feature-importance data was recorded for this model.</div>\n }\n </div>\n </div>\n\n <!-- 5. Leakage Sign-Off Gate -->\n @if (importance.length > 0) {\n <div class=\"ps-callout gate\" [class.success]=\"!leakageFlagged\" [class.warn]=\"leakageFlagged\">\n <i [class]=\"leakageFlagged ? 'fa-solid fa-triangle-exclamation' : 'fa-solid fa-shield-halved'\"></i>\n <div>\n @if (leakageFlagged) {\n <strong>Leakage flag raised.</strong> A single feature dominates \u2014 top importance is\n <strong>{{ topFeatureName }} at {{ topFeatureValue }}</strong>, at/above the\n <strong>{{ dominanceThreshold }}</strong> dominance threshold.\n <div class=\"ps-small\" style=\"margin-top:6px\">\n <i class=\"fa-solid fa-pen\"></i> Sign-off with a reason is required to publish this model.\n </div>\n } @else {\n <strong>Leakage gate clear.</strong> No single feature dominates \u2014 top importance is\n <strong>{{ topFeatureName }} at {{ topFeatureValue }}</strong>, below the\n <strong>{{ dominanceThreshold }}</strong> dominance threshold.\n <div class=\"ps-small\" style=\"margin-top:6px\">\n <i class=\"fa-solid fa-check\"></i> Sign-off required before any Validated &rarr; Published promotion.\n </div>\n }\n </div>\n </div>\n }\n\n <!-- 6. Lifecycle Actions -->\n @if (showActions) {\n <div class=\"ps-card\">\n <div class=\"ps-card-body ps-row\" style=\"align-items:center;flex-wrap:wrap;gap:8px\">\n <span class=\"ps-muted ps-small\" style=\"flex:1\">{{ actionHint }}</span>\n @if (canValidate) {\n <button mjButton variant=\"secondary\" size=\"sm\" data-testid=\"ps-registry-validate\" (click)=\"requestPromote('Validated')\">\n <i class=\"fa-solid fa-circle-check\"></i> Mark Validated\n </button>\n }\n @if (canPublish) {\n <button mjButton variant=\"primary\" size=\"sm\" data-testid=\"ps-registry-promote\" (click)=\"requestPromote('Published')\">\n <i class=\"fa-solid fa-arrow-up\"></i> Promote to Published\n </button>\n }\n @if (canArchive) {\n <button mjButton variant=\"secondary\" size=\"sm\" data-testid=\"ps-registry-archive\" (click)=\"requestPromote('Archived')\">\n <i class=\"fa-solid fa-box-archive\"></i> Archive\n </button>\n }\n </div>\n </div>\n }\n\n <!-- 7. Confirm Promotion Modal -->\n @if (pending) {\n <div class=\"ps-modal-backdrop\" (click)=\"cancelPromote()\">\n <div class=\"ps-modal\" (click)=\"$event.stopPropagation()\" data-testid=\"ps-confirm-modal\">\n <div class=\"ps-modal-head\" [class.warn]=\"pendingVariant === 'warn'\" [class.danger]=\"pendingVariant === 'danger'\">\n <span class=\"ico\"><i [class]=\"pendingIcon\"></i></span>\n <h3>{{ pendingTitle }}</h3>\n </div>\n <div class=\"ps-modal-body\">\n <div [innerHTML]=\"pendingMessage\"></div>\n @if (pending.leakageFlagged || pending.targetStatus === 'Archived') {\n <div class=\"ps-field\" style=\"margin-top:12px\">\n <label>\n {{ pending.leakageFlagged ? 'Leakage sign-off reason' : 'Reason (optional)' }}\n {{ pending.leakageFlagged ? ' *' : '' }}\n </label>\n <textarea\n class=\"ps-input\"\n rows=\"3\"\n [(ngModel)]=\"pendingReason\"\n [placeholder]=\"pending.leakageFlagged ? 'Explain why this model is safe to publish despite the leakage flag\u2026' : 'Add an optional note for the record\u2026'\"\n [disabled]=\"busy\"></textarea>\n </div>\n }\n </div>\n <div class=\"ps-modal-foot\">\n <button\n mjButton\n [variant]=\"pendingVariant === 'danger' ? 'danger' : 'primary'\"\n size=\"sm\"\n [disabled]=\"busy || (pending.leakageFlagged && !pendingReason.trim())\"\n (click)=\"confirmPromote(pendingReason.trim())\">\n @if (busy) {\n <i class=\"fa-solid fa-circle-notch fa-spin\"></i>\n } @else {\n <i [class]=\"pendingIcon\"></i>\n }\n {{ pendingConfirmLabel }}\n </button>\n <span class=\"ps-spacer\" style=\"flex:1\"></span>\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"busy\" (click)=\"cancelPromote()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"ps-empty\" style=\"padding: 32px; text-align: center;\">\n <span class=\"ps-empty-ico\"><i class=\"fa-solid fa-cube\"></i></span>\n <h3>No Model Selected</h3>\n <p class=\"ps-muted\">Select an ML Model from the list to inspect its configuration and metrics.</p>\n </div>\n }\n</div>\n", styles: ["/* PSModelDetailComponent Styles \u2014 Design Token Compliant */\n\n.ps-model-detail {\n display: flex;\n flex-direction: column;\n gap: 16px;\n width: 100%;\n color: var(--mj-text-primary);\n background: transparent;\n font-family: inherit;\n}\n\n/* ---- generic helpers ---- */\n.ps-model-detail .ps-row { display: flex; gap: 16px; }\n.ps-model-detail .ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-model-detail .ps-spacer { flex: 1; }\n.ps-model-detail .ps-muted { color: var(--mj-text-muted); }\n.ps-model-detail .ps-small { font-size: 12.5px; }\n.ps-model-detail .ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-model-detail .ps-section-title {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: .06em;\n color: var(--mj-text-muted);\n margin: 4px 0 2px;\n font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-model-detail .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-model-detail .ps-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n border-bottom: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n}\n.ps-model-detail .ps-card-head h3 {\n font-size: 14.5px;\n margin: 0;\n font-weight: 650;\n color: var(--mj-text-primary);\n}\n.ps-model-detail .ps-card-body {\n padding: 16px;\n}\n\n/* ---- badges & tags ---- */\n.ps-model-detail .ps-badge {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 3px 10px;\n border-radius: 999px;\n font-size: 11.5px;\n font-weight: 650;\n line-height: 1.5;\n}\n.ps-model-detail .ps-badge.gray { background: var(--mj-bg-surface-sunken, #f3f4f6); color: var(--mj-text-secondary); }\n.ps-model-detail .ps-badge.blue { background: var(--mj-status-info-bg, #eff6ff); color: var(--mj-status-info-text, #1d4ed8); }\n.ps-model-detail .ps-badge.green { background: var(--mj-status-success-bg, #f0fdf4); color: var(--mj-status-success-text, #15803d); }\n.ps-model-detail .ps-badge.amber { background: var(--mj-status-warning-bg, #fffbeb); color: var(--mj-status-warning-text, #b45309); }\n.ps-model-detail .ps-badge.red { background: var(--mj-status-error-bg, #fef2f2); color: var(--mj-status-error-text, #b91c1c); }\n\n.ps-model-detail .ps-tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 7px;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n background: var(--mj-bg-surface-sunken, #f3f4f6);\n color: var(--mj-text-secondary);\n}\n\n/* ---- detail header ---- */\n.ps-model-detail .dh {\n display: flex;\n align-items: center;\n gap: 14px;\n}\n.ps-model-detail .big-ico {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n display: grid;\n place-items: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 20px;\n flex: 0 0 auto;\n}\n.ps-model-detail .dh h2 {\n font-size: 18px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n font-weight: 700;\n}\n.ps-model-detail .dh .sub {\n margin-top: 2px;\n}\n\n/* ---- stepper ---- */\n.ps-model-detail .ps-stepper {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n.ps-model-detail .ps-step {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.ps-model-detail .ps-step.curr {\n color: var(--mj-text-primary);\n}\n.ps-model-detail .ps-step.done {\n color: var(--mj-status-success, #15803d);\n}\n.ps-model-detail .ps-step .pip {\n width: 22px;\n height: 22px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 11px;\n border: 1.5px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n.ps-model-detail .ps-step.curr .pip {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n font-weight: 700;\n}\n.ps-model-detail .ps-step.done .pip {\n background: var(--mj-status-success, #15803d);\n border-color: var(--mj-status-success, #15803d);\n color: var(--mj-text-inverse);\n}\n.ps-model-detail .ps-stepper .ln {\n flex: 1;\n min-width: 16px;\n height: 2px;\n background: var(--mj-border-default);\n}\n\n/* ---- performance metrics ---- */\n.ps-model-detail .metric-pair {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px;\n}\n@media (max-width: 640px) {\n .ps-model-detail .metric-pair {\n grid-template-columns: 1fr;\n }\n}\n.ps-model-detail .mtile {\n border: 1px solid var(--mj-border-default);\n border-radius: 9px;\n padding: 14px;\n background: var(--mj-bg-surface);\n}\n.ps-model-detail .mtile .v {\n font-size: 28px;\n font-weight: 720;\n color: var(--mj-text-primary);\n letter-spacing: -.02em;\n}\n.ps-model-detail .mtile.honest {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n.ps-model-detail .mtile.honest .v {\n color: var(--mj-brand-primary);\n}\n\n.ps-model-detail .stat-bar {\n display: flex;\n gap: 10px;\n margin-top: 14px;\n flex-wrap: wrap;\n}\n.ps-model-detail .stat-bar .b {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n border-radius: 8px;\n flex: 1;\n min-width: 90px;\n}\n.ps-model-detail .stat-bar .b strong {\n color: var(--mj-text-primary);\n font-size: 15px;\n}\n\n/* ---- feature importance bars ---- */\n.ps-model-detail .ps-fbar {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 8px;\n}\n.ps-model-detail .ps-fbar .name {\n width: 170px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex-shrink: 0;\n color: var(--mj-text-secondary);\n}\n.ps-model-detail .ps-fbar .track {\n flex: 1;\n height: 8px;\n background: var(--mj-bg-surface-sunken, #f3f4f6);\n border-radius: 999px;\n overflow: hidden;\n}\n.ps-model-detail .ps-fbar .track span {\n display: block;\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 999px;\n}\n.ps-model-detail .ps-fbar .track span.warn {\n background: var(--mj-status-warning, #d98213);\n}\n\n/* ---- leakage gate callout ---- */\n.ps-model-detail .ps-callout {\n display: flex;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n.ps-model-detail .ps-callout.gate {\n align-items: flex-start;\n}\n.ps-model-detail .ps-callout.gate i {\n font-size: 20px;\n margin-top: 2px;\n}\n.ps-model-detail .ps-callout.success {\n background: var(--mj-status-success-bg, #f0fdf4);\n border-color: color-mix(in srgb, var(--mj-status-success) 25%, transparent);\n color: var(--mj-status-success-text, #15803d);\n}\n.ps-model-detail .ps-callout.warn {\n background: var(--mj-status-warning-bg, #fffbeb);\n border-color: color-mix(in srgb, var(--mj-status-warning) 25%, transparent);\n color: var(--mj-status-warning-text, #b45309);\n}\n\n/* ---- confirmation modal ---- */\n.ps-model-detail .ps-modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n}\n.ps-model-detail .ps-modal {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n width: 100%;\n max-width: 480px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n}\n.ps-model-detail .ps-modal-head {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n}\n.ps-model-detail .ps-modal-head .ico {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: grid;\n place-items: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 15px;\n}\n.ps-model-detail .ps-modal-head.warn .ico {\n background: var(--mj-status-warning, #d98213);\n}\n.ps-model-detail .ps-modal-head.danger .ico {\n background: var(--mj-status-error, #b91c1c);\n}\n.ps-model-detail .ps-modal-head h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 700;\n}\n.ps-model-detail .ps-modal-body {\n padding: 20px;\n font-size: 13.5px;\n line-height: 1.5;\n}\n.ps-model-detail .ps-modal-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n background: var(--mj-bg-surface-sunken, #f9fafb);\n}\n.ps-model-detail .ps-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.ps-model-detail .ps-field label {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.ps-model-detail .ps-input {\n width: 100%;\n padding: 8px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 13px;\n resize: vertical;\n}\n.ps-model-detail .ps-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n"] }]
952
+ args: [{ standalone: true, selector: 'ps-model-detail', imports: [CommonModule, FormsModule, MJButtonDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ps-model-detail\" data-testid=\"ps-model-detail\">\n @if (model) {\n <!-- 1. Header Card -->\n <div class=\"ps-card\">\n <div class=\"ps-card-body dh\">\n <div class=\"big-ico\"><i class=\"fa-solid fa-cube\"></i></div>\n <div style=\"flex:1;min-width:0;\">\n <h2 data-testid=\"ps-registry-detail-name\">\n {{ modelDisplayName }}\n <span class=\"ps-tag ps-mono\">v{{ model.Version }}</span>\n </h2>\n <div class=\"ps-muted ps-small sub\">\n {{ model.Algorithm || 'Model' }}{{ targetSuffix }} &bull; immutable snapshot\n </div>\n </div>\n <span class=\"ps-badge\" [class]=\"statusBadgeClass(model.Status)\">{{ model.Status }}</span>\n </div>\n </div>\n\n <!-- 2. Lifecycle Stepper -->\n <div class=\"ps-card\">\n <div class=\"ps-card-body\">\n <div class=\"ps-section-title\">Lifecycle</div>\n <div class=\"ps-stepper\">\n @for (step of lifecycleSteps; track step; let last = $last) {\n <div class=\"ps-step\" [class.done]=\"stepState(step) === 'done'\" [class.curr]=\"stepState(step) === 'curr'\">\n <span class=\"pip\">\n @if (stepState(step) === 'done') {\n <i class=\"fa-solid fa-check\"></i>\n } @else {\n {{ $index + 1 }}\n }\n </span>\n {{ step }}\n </div>\n @if (!last) {\n <span class=\"ln\"></span>\n }\n }\n </div>\n <div class=\"ps-small ps-muted\" style=\"margin-top:10px\">\n Models are immutable once registered; promotion only changes lifecycle state, never weights.\n </div>\n </div>\n </div>\n\n <!-- 3. Performance Metrics -->\n <div class=\"ps-card\">\n <div class=\"ps-card-head\">\n <h3>Performance</h3>\n <span class=\"ps-muted ps-small\">Holdout = held-out test fold, never seen in training</span>\n </div>\n <div class=\"ps-card-body\">\n <div class=\"metric-pair\">\n <div class=\"mtile\">\n <div class=\"ps-section-title\">Train {{ primaryScoreLabel }}</div>\n <div class=\"v\">{{ trainPrimaryScore }}</div>\n <div class=\"ps-muted ps-small\">in-sample &bull; optimistic</div>\n </div>\n <div class=\"mtile honest\">\n <div class=\"ps-section-title\">Holdout {{ primaryScoreLabel }}</div>\n <div class=\"v\">{{ holdoutPrimaryScore }}</div>\n <div class=\"ps-muted ps-small\">out-of-sample &bull; the honest number</div>\n </div>\n </div>\n\n @if (secondaryMetrics.length > 0) {\n <div class=\"stat-bar\">\n @for (s of secondaryMetrics; track s.key) {\n <div class=\"b\">\n <span class=\"ps-muted ps-small\">{{ s.label }}</span>\n <strong>{{ s.value }}</strong>\n </div>\n }\n </div>\n } @else {\n <div class=\"ps-small ps-muted\" style=\"margin-top:6px\">No secondary metrics recorded for this model.</div>\n }\n\n @if (gapText) {\n <div class=\"ps-small ps-muted\" style=\"margin-top:10px\">\n Train\u2013holdout gap of <strong>{{ gapText }}</strong> {{ gapVerdict }}.\n </div>\n }\n </div>\n </div>\n\n <!-- 4. Feature Importance -->\n <div class=\"ps-card\">\n <div class=\"ps-card-head\">\n <h3>Feature Importance</h3>\n @if (!ImportanceHidden) {\n <span class=\"ps-muted ps-small\" data-testid=\"ps-importance-caption\">{{ ImportanceCaption }}</span>\n }\n </div>\n <div class=\"ps-card-body\">\n @if (DisplayedImportance.length > 0) {\n @for (f of DisplayedImportance; track f.name) {\n <div class=\"ps-fbar\">\n <span class=\"name ps-small\" [title]=\"f.name\">{{ f.name }}</span>\n <div class=\"track\">\n <span [class.warn]=\"f.warning\" [style.width.%]=\"f.pct\"></span>\n </div>\n <span class=\"ps-mono\">{{ f.value }}</span>\n </div>\n }\n } @else {\n @if (ImportanceHidden) {\n <div class=\"ps-small ps-muted\" data-testid=\"ps-importance-hidden\">{{ ImportanceHiddenNote }}</div>\n } @else {\n <div class=\"ps-small ps-muted\">No feature-importance data was recorded for this model.</div>\n }\n }\n </div>\n </div>\n\n <!-- 5. Leakage Sign-Off Gate -->\n @if (Importance.length > 0) {\n <div class=\"ps-callout gate\" data-testid=\"ps-leakage-gate\" [class.success]=\"!LeakageFlagged\" [class.warn]=\"LeakageFlagged\">\n <i [class]=\"LeakageFlagged ? 'fa-solid fa-triangle-exclamation' : 'fa-solid fa-shield-halved'\"></i>\n <div>\n @if (LeakageFlagged) {\n @if (ImportanceHidden) {\n <strong>Leakage flag raised.</strong> A single feature's split share is at or above the\n <strong>{{ dominanceThreshold }}</strong> dominance threshold.\n } @else {\n <strong>Leakage flag raised.</strong> A single feature dominates \u2014 top importance is\n <strong>{{ TopFeatureName }} at {{ TopFeatureValue }}</strong>, at/above the\n <strong>{{ dominanceThreshold }}</strong> dominance threshold.\n }\n <div class=\"ps-small\" style=\"margin-top:6px\">\n <i class=\"fa-solid fa-pen\"></i> Sign-off with a reason is required to publish this model.\n </div>\n } @else {\n @if (ImportanceHidden) {\n <strong>Leakage gate clear.</strong> No single feature's split share is at or above the\n <strong>{{ dominanceThreshold }}</strong> dominance threshold.\n } @else {\n <strong>Leakage gate clear.</strong> No single feature dominates \u2014 top importance is\n <strong>{{ TopFeatureName }} at {{ TopFeatureValue }}</strong>, below the\n <strong>{{ dominanceThreshold }}</strong> dominance threshold.\n }\n <div class=\"ps-small\" style=\"margin-top:6px\">\n <i class=\"fa-solid fa-check\"></i> Sign-off required before any Validated &rarr; Published promotion.\n </div>\n }\n </div>\n </div>\n }\n\n <!-- 6. Lifecycle Actions -->\n @if (showActions) {\n <div class=\"ps-card\">\n <div class=\"ps-card-body ps-row\" style=\"align-items:center;flex-wrap:wrap;gap:8px\">\n <span class=\"ps-muted ps-small\" style=\"flex:1\">{{ actionHint }}</span>\n @if (canValidate) {\n <button mjButton variant=\"secondary\" size=\"sm\" data-testid=\"ps-registry-validate\" (click)=\"requestPromote('Validated')\">\n <i class=\"fa-solid fa-circle-check\"></i> Mark Validated\n </button>\n }\n @if (canPublish) {\n <button mjButton variant=\"primary\" size=\"sm\" data-testid=\"ps-registry-promote\" (click)=\"requestPromote('Published')\">\n <i class=\"fa-solid fa-arrow-up\"></i> Promote to Published\n </button>\n }\n @if (canArchive) {\n <button mjButton variant=\"secondary\" size=\"sm\" data-testid=\"ps-registry-archive\" (click)=\"requestPromote('Archived')\">\n <i class=\"fa-solid fa-box-archive\"></i> Archive\n </button>\n }\n </div>\n </div>\n }\n\n <!-- 7. Confirm Promotion Modal -->\n @if (pending) {\n <div class=\"ps-modal-backdrop\" (click)=\"cancelPromote()\">\n <div class=\"ps-modal\" (click)=\"$event.stopPropagation()\" data-testid=\"ps-confirm-modal\">\n <div class=\"ps-modal-head\" [class.warn]=\"pendingVariant === 'warn'\" [class.danger]=\"pendingVariant === 'danger'\">\n <span class=\"ico\"><i [class]=\"pendingIcon\"></i></span>\n <h3>{{ pendingTitle }}</h3>\n </div>\n <div class=\"ps-modal-body\">\n <div [innerHTML]=\"pendingMessage\"></div>\n @if (pending.leakageFlagged || pending.targetStatus === 'Archived') {\n <div class=\"ps-field\" style=\"margin-top:12px\">\n <label>\n {{ pending.leakageFlagged ? 'Leakage sign-off reason' : 'Reason (optional)' }}\n {{ pending.leakageFlagged ? ' *' : '' }}\n </label>\n <textarea\n class=\"ps-input\"\n rows=\"3\"\n [(ngModel)]=\"pendingReason\"\n [placeholder]=\"pending.leakageFlagged ? 'Explain why this model is safe to publish despite the leakage flag\u2026' : 'Add an optional note for the record\u2026'\"\n [disabled]=\"busy\"></textarea>\n </div>\n }\n </div>\n <div class=\"ps-modal-foot\">\n <button\n mjButton\n [variant]=\"pendingVariant === 'danger' ? 'danger' : 'primary'\"\n size=\"sm\"\n [disabled]=\"busy || (pending.leakageFlagged && !pendingReason.trim())\"\n (click)=\"confirmPromote(pendingReason.trim())\">\n @if (busy) {\n <i class=\"fa-solid fa-circle-notch fa-spin\"></i>\n } @else {\n <i [class]=\"pendingIcon\"></i>\n }\n {{ pendingConfirmLabel }}\n </button>\n <span class=\"ps-spacer\" style=\"flex:1\"></span>\n <button mjButton variant=\"secondary\" size=\"sm\" [disabled]=\"busy\" (click)=\"cancelPromote()\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n } @else {\n <div class=\"ps-empty\" style=\"padding: 32px; text-align: center;\">\n <span class=\"ps-empty-ico\"><i class=\"fa-solid fa-cube\"></i></span>\n <h3>No Model Selected</h3>\n <p class=\"ps-muted\">Select an ML Model from the list to inspect its configuration and metrics.</p>\n </div>\n }\n</div>\n", styles: ["/* PSModelDetailComponent Styles \u2014 Design Token Compliant */\n\n.ps-model-detail {\n display: flex;\n flex-direction: column;\n gap: 16px;\n width: 100%;\n color: var(--mj-text-primary);\n background: transparent;\n font-family: inherit;\n}\n\n/* ---- generic helpers ---- */\n.ps-model-detail .ps-row { display: flex; gap: 16px; }\n.ps-model-detail .ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-model-detail .ps-spacer { flex: 1; }\n.ps-model-detail .ps-muted { color: var(--mj-text-muted); }\n.ps-model-detail .ps-small { font-size: 12.5px; }\n.ps-model-detail .ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-model-detail .ps-section-title {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: .06em;\n color: var(--mj-text-muted);\n margin: 4px 0 2px;\n font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-model-detail .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-model-detail .ps-card-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n border-bottom: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n}\n.ps-model-detail .ps-card-head h3 {\n font-size: 14.5px;\n margin: 0;\n font-weight: 650;\n color: var(--mj-text-primary);\n}\n.ps-model-detail .ps-card-body {\n padding: 16px;\n}\n\n/* ---- badges & tags ---- */\n.ps-model-detail .ps-badge {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n padding: 3px 10px;\n border-radius: 999px;\n font-size: 11.5px;\n font-weight: 650;\n line-height: 1.5;\n}\n.ps-model-detail .ps-badge.gray { background: var(--mj-bg-surface-sunken, #f3f4f6); color: var(--mj-text-secondary); }\n.ps-model-detail .ps-badge.blue { background: var(--mj-status-info-bg, #eff6ff); color: var(--mj-status-info-text, #1d4ed8); }\n.ps-model-detail .ps-badge.green { background: var(--mj-status-success-bg, #f0fdf4); color: var(--mj-status-success-text, #15803d); }\n.ps-model-detail .ps-badge.amber { background: var(--mj-status-warning-bg, #fffbeb); color: var(--mj-status-warning-text, #b45309); }\n.ps-model-detail .ps-badge.red { background: var(--mj-status-error-bg, #fef2f2); color: var(--mj-status-error-text, #b91c1c); }\n\n.ps-model-detail .ps-tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 7px;\n border-radius: 4px;\n font-size: 11px;\n font-weight: 600;\n background: var(--mj-bg-surface-sunken, #f3f4f6);\n color: var(--mj-text-secondary);\n}\n\n/* ---- detail header ---- */\n.ps-model-detail .dh {\n display: flex;\n align-items: center;\n gap: 14px;\n}\n.ps-model-detail .big-ico {\n width: 48px;\n height: 48px;\n border-radius: 12px;\n display: grid;\n place-items: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 20px;\n flex: 0 0 auto;\n}\n.ps-model-detail .dh h2 {\n font-size: 18px;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n font-weight: 700;\n}\n.ps-model-detail .dh .sub {\n margin-top: 2px;\n}\n\n/* ---- stepper ---- */\n.ps-model-detail .ps-stepper {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n.ps-model-detail .ps-step {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-muted);\n}\n.ps-model-detail .ps-step.curr {\n color: var(--mj-text-primary);\n}\n.ps-model-detail .ps-step.done {\n color: var(--mj-status-success, #15803d);\n}\n.ps-model-detail .ps-step .pip {\n width: 22px;\n height: 22px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n font-size: 11px;\n border: 1.5px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n.ps-model-detail .ps-step.curr .pip {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n font-weight: 700;\n}\n.ps-model-detail .ps-step.done .pip {\n background: var(--mj-status-success, #15803d);\n border-color: var(--mj-status-success, #15803d);\n color: var(--mj-text-inverse);\n}\n.ps-model-detail .ps-stepper .ln {\n flex: 1;\n min-width: 16px;\n height: 2px;\n background: var(--mj-border-default);\n}\n\n/* ---- performance metrics ---- */\n.ps-model-detail .metric-pair {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px;\n}\n@media (max-width: 640px) {\n .ps-model-detail .metric-pair {\n grid-template-columns: 1fr;\n }\n}\n.ps-model-detail .mtile {\n border: 1px solid var(--mj-border-default);\n border-radius: 9px;\n padding: 14px;\n background: var(--mj-bg-surface);\n}\n.ps-model-detail .mtile .v {\n font-size: 28px;\n font-weight: 720;\n color: var(--mj-text-primary);\n letter-spacing: -.02em;\n}\n.ps-model-detail .mtile.honest {\n border-color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n}\n.ps-model-detail .mtile.honest .v {\n color: var(--mj-brand-primary);\n}\n\n.ps-model-detail .stat-bar {\n display: flex;\n gap: 10px;\n margin-top: 14px;\n flex-wrap: wrap;\n}\n.ps-model-detail .stat-bar .b {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding: 8px 12px;\n border: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n border-radius: 8px;\n flex: 1;\n min-width: 90px;\n}\n.ps-model-detail .stat-bar .b strong {\n color: var(--mj-text-primary);\n font-size: 15px;\n}\n\n/* ---- feature importance bars ---- */\n.ps-model-detail .ps-fbar {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 8px;\n}\n.ps-model-detail .ps-fbar .name {\n width: 170px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n flex-shrink: 0;\n color: var(--mj-text-secondary);\n}\n.ps-model-detail .ps-fbar .track {\n flex: 1;\n height: 8px;\n background: var(--mj-bg-surface-sunken, #f3f4f6);\n border-radius: 999px;\n overflow: hidden;\n}\n.ps-model-detail .ps-fbar .track span {\n display: block;\n height: 100%;\n background: var(--mj-brand-primary);\n border-radius: 999px;\n}\n.ps-model-detail .ps-fbar .track span.warn {\n background: var(--mj-status-warning, #d98213);\n}\n\n/* ---- leakage gate callout ---- */\n.ps-model-detail .ps-callout {\n display: flex;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 8px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n.ps-model-detail .ps-callout.gate {\n align-items: flex-start;\n}\n.ps-model-detail .ps-callout.gate i {\n font-size: 20px;\n margin-top: 2px;\n}\n.ps-model-detail .ps-callout.success {\n background: var(--mj-status-success-bg, #f0fdf4);\n border-color: color-mix(in srgb, var(--mj-status-success) 25%, transparent);\n color: var(--mj-status-success-text, #15803d);\n}\n.ps-model-detail .ps-callout.warn {\n background: var(--mj-status-warning-bg, #fffbeb);\n border-color: color-mix(in srgb, var(--mj-status-warning) 25%, transparent);\n color: var(--mj-status-warning-text, #b45309);\n}\n\n/* ---- confirmation modal ---- */\n.ps-model-detail .ps-modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n z-index: 10000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n}\n.ps-model-detail .ps-modal {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n width: 100%;\n max-width: 480px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n}\n.ps-model-detail .ps-modal-head {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px 20px;\n border-bottom: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n}\n.ps-model-detail .ps-modal-head .ico {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: grid;\n place-items: center;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 15px;\n}\n.ps-model-detail .ps-modal-head.warn .ico {\n background: var(--mj-status-warning, #d98213);\n}\n.ps-model-detail .ps-modal-head.danger .ico {\n background: var(--mj-status-error, #b91c1c);\n}\n.ps-model-detail .ps-modal-head h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 700;\n}\n.ps-model-detail .ps-modal-body {\n padding: 20px;\n font-size: 13.5px;\n line-height: 1.5;\n}\n.ps-model-detail .ps-modal-foot {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 14px 20px;\n border-top: 1px solid var(--mj-border-subtle, var(--mj-border-default));\n background: var(--mj-bg-surface-sunken, #f9fafb);\n}\n.ps-model-detail .ps-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.ps-model-detail .ps-field label {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n.ps-model-detail .ps-input {\n width: 100%;\n padding: 8px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-family: inherit;\n font-size: 13px;\n resize: vertical;\n}\n.ps-model-detail .ps-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n}\n"] }]
859
953
  }], null, { Model: [{
860
954
  type: Input
861
955
  }], model: [{
@@ -879,5 +973,5 @@ export class PSModelDetailComponent {
879
973
  }], displayName: [{
880
974
  type: Input
881
975
  }] }); })();
882
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSModelDetailComponent, { className: "PSModelDetailComponent", filePath: "src/lib/custom/MLModels/ps-model-detail.component.ts", lineNumber: 65 }); })();
976
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSModelDetailComponent, { className: "PSModelDetailComponent", filePath: "src/lib/custom/MLModels/ps-model-detail.component.ts", lineNumber: 67 }); })();
883
977
  //# sourceMappingURL=ps-model-detail.component.js.map