@memberjunction/ng-core-entity-forms 6.2.0-edge.1 → 6.2.0-edge.2

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 (161) hide show
  1. package/dist/lib/custom/AIAgents/agent-form-tabs.d.ts +1 -0
  2. package/dist/lib/custom/AIAgents/agent-form-tabs.d.ts.map +1 -1
  3. package/dist/lib/custom/AIAgents/agent-form-tabs.js +2 -0
  4. package/dist/lib/custom/AIAgents/agent-form-tabs.js.map +1 -1
  5. package/dist/lib/custom/AIAgents/ai-agent-form.component.js +528 -521
  6. package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
  7. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
  8. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +10 -16
  9. package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
  10. package/dist/lib/custom/AIPrompts/pending-records.d.ts +11 -0
  11. package/dist/lib/custom/AIPrompts/pending-records.d.ts.map +1 -0
  12. package/dist/lib/custom/AIPrompts/pending-records.js +21 -0
  13. package/dist/lib/custom/AIPrompts/pending-records.js.map +1 -0
  14. package/dist/lib/custom/Entities/entity-form.component.d.ts +8 -1
  15. package/dist/lib/custom/Entities/entity-form.component.d.ts.map +1 -1
  16. package/dist/lib/custom/Entities/entity-form.component.js +240 -147
  17. package/dist/lib/custom/Entities/entity-form.component.js.map +1 -1
  18. package/dist/lib/custom/RecordProcesses/record-process-form.component.d.ts +19 -0
  19. package/dist/lib/custom/RecordProcesses/record-process-form.component.d.ts.map +1 -1
  20. package/dist/lib/custom/RecordProcesses/record-process-form.component.js +50 -8
  21. package/dist/lib/custom/RecordProcesses/record-process-form.component.js.map +1 -1
  22. package/dist/lib/custom/Rubrics/evaluation-form.component.d.ts +37 -0
  23. package/dist/lib/custom/Rubrics/evaluation-form.component.d.ts.map +1 -0
  24. package/dist/lib/custom/Rubrics/evaluation-form.component.js +399 -0
  25. package/dist/lib/custom/Rubrics/evaluation-form.component.js.map +1 -0
  26. package/dist/lib/custom/Rubrics/record-forms.component.d.ts +69 -0
  27. package/dist/lib/custom/Rubrics/record-forms.component.d.ts.map +1 -0
  28. package/dist/lib/custom/Rubrics/record-forms.component.js +587 -0
  29. package/dist/lib/custom/Rubrics/record-forms.component.js.map +1 -0
  30. package/dist/lib/custom/Rubrics/rubric-form.component.d.ts +67 -0
  31. package/dist/lib/custom/Rubrics/rubric-form.component.d.ts.map +1 -0
  32. package/dist/lib/custom/Rubrics/rubric-form.component.js +534 -0
  33. package/dist/lib/custom/Rubrics/rubric-form.component.js.map +1 -0
  34. package/dist/lib/custom/Rubrics/rubric-form.panels.d.ts +25 -0
  35. package/dist/lib/custom/Rubrics/rubric-form.panels.d.ts.map +1 -0
  36. package/dist/lib/custom/Rubrics/rubric-form.panels.js +299 -0
  37. package/dist/lib/custom/Rubrics/rubric-form.panels.js.map +1 -0
  38. package/dist/lib/custom/Rubrics/scale-form.component.d.ts +31 -0
  39. package/dist/lib/custom/Rubrics/scale-form.component.d.ts.map +1 -0
  40. package/dist/lib/custom/Rubrics/scale-form.component.js +395 -0
  41. package/dist/lib/custom/Rubrics/scale-form.component.js.map +1 -0
  42. package/dist/lib/custom/Templates/templates-form.component.d.ts +13 -4
  43. package/dist/lib/custom/Templates/templates-form.component.d.ts.map +1 -1
  44. package/dist/lib/custom/Templates/templates-form.component.js +110 -113
  45. package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
  46. package/dist/lib/custom/Tests/test-form.component.d.ts +6 -0
  47. package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
  48. package/dist/lib/custom/Tests/test-form.component.js +402 -361
  49. package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
  50. package/dist/lib/custom/Tests/test-suite-form.component.d.ts +5 -0
  51. package/dist/lib/custom/Tests/test-suite-form.component.d.ts.map +1 -1
  52. package/dist/lib/custom/Tests/test-suite-form.component.js +704 -664
  53. package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
  54. package/dist/lib/custom/Users/user-overview.panel.js +1 -1
  55. package/dist/lib/custom/Users/user-overview.panel.js.map +1 -1
  56. package/dist/lib/custom/custom-forms.module.d.ts +56 -48
  57. package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
  58. package/dist/lib/custom/custom-forms.module.js +60 -0
  59. package/dist/lib/custom/custom-forms.module.js.map +1 -1
  60. package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.d.ts.map +1 -1
  61. package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js +61 -43
  62. package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js.map +1 -1
  63. package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.d.ts +10 -0
  64. package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.d.ts.map +1 -0
  65. package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.js +74 -0
  66. package/dist/lib/generated/Entities/MJAIAgentRubric/mjaiagentrubric.form.component.js.map +1 -0
  67. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.d.ts.map +1 -1
  68. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +37 -19
  69. package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js.map +1 -1
  70. package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.d.ts.map +1 -1
  71. package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js +31 -13
  72. package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js.map +1 -1
  73. package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.d.ts.map +1 -1
  74. package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js +156 -84
  75. package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js.map +1 -1
  76. package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.d.ts +10 -0
  77. package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.d.ts.map +1 -0
  78. package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.js +62 -0
  79. package/dist/lib/generated/Entities/MJFeaturePipelineType/mjfeaturepipelinetype.form.component.js.map +1 -0
  80. package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.d.ts.map +1 -1
  81. package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.js +24 -6
  82. package/dist/lib/generated/Entities/MJProcessRun/mjprocessrun.form.component.js.map +1 -1
  83. package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.d.ts.map +1 -1
  84. package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.js +24 -16
  85. package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.js.map +1 -1
  86. package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.d.ts +10 -0
  87. package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.d.ts.map +1 -0
  88. package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.js +107 -0
  89. package/dist/lib/generated/Entities/MJRecordCloneLog/mjrecordclonelog.form.component.js.map +1 -0
  90. package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.d.ts +10 -0
  91. package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.d.ts.map +1 -0
  92. package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.js +74 -0
  93. package/dist/lib/generated/Entities/MJRecordCloneLogItem/mjrecordclonelogitem.form.component.js.map +1 -0
  94. package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.d.ts +10 -0
  95. package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.d.ts.map +1 -0
  96. package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.js +135 -0
  97. package/dist/lib/generated/Entities/MJRubric/mjrubric.form.component.js.map +1 -0
  98. package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.d.ts +10 -0
  99. package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.d.ts.map +1 -0
  100. package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.js +87 -0
  101. package/dist/lib/generated/Entities/MJRubricBand/mjrubricband.form.component.js.map +1 -0
  102. package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.d.ts +10 -0
  103. package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.d.ts.map +1 -0
  104. package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.js +107 -0
  105. package/dist/lib/generated/Entities/MJRubricCategory/mjrubriccategory.form.component.js.map +1 -0
  106. package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.d.ts +10 -0
  107. package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.d.ts.map +1 -0
  108. package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.js +155 -0
  109. package/dist/lib/generated/Entities/MJRubricCriterion/mjrubriccriterion.form.component.js.map +1 -0
  110. package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.d.ts +10 -0
  111. package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.d.ts.map +1 -0
  112. package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.js +62 -0
  113. package/dist/lib/generated/Entities/MJRubricCriterionLevel/mjrubriccriterionlevel.form.component.js.map +1 -0
  114. package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.d.ts +10 -0
  115. package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.d.ts.map +1 -0
  116. package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.js +183 -0
  117. package/dist/lib/generated/Entities/MJRubricEvaluation/mjrubricevaluation.form.component.js.map +1 -0
  118. package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.d.ts +10 -0
  119. package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.d.ts.map +1 -0
  120. package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.js +120 -0
  121. package/dist/lib/generated/Entities/MJRubricEvaluationScore/mjrubricevaluationscore.form.component.js.map +1 -0
  122. package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.d.ts +10 -0
  123. package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.d.ts.map +1 -0
  124. package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.js +107 -0
  125. package/dist/lib/generated/Entities/MJRubricScale/mjrubricscale.form.component.js.map +1 -0
  126. package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.d.ts +10 -0
  127. package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.d.ts.map +1 -0
  128. package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.js +103 -0
  129. package/dist/lib/generated/Entities/MJRubricScaleLevel/mjrubricscalelevel.form.component.js.map +1 -0
  130. package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.d.ts +10 -0
  131. package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.d.ts.map +1 -0
  132. package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.js +171 -0
  133. package/dist/lib/generated/Entities/MJRubricVersion/mjrubricversion.form.component.js.map +1 -0
  134. package/dist/lib/generated/Entities/MJTest/mjtest.form.component.d.ts.map +1 -1
  135. package/dist/lib/generated/Entities/MJTest/mjtest.form.component.js +24 -16
  136. package/dist/lib/generated/Entities/MJTest/mjtest.form.component.js.map +1 -1
  137. package/dist/lib/generated/Entities/MJTestSuite/mjtestsuite.form.component.js +27 -25
  138. package/dist/lib/generated/Entities/MJTestSuite/mjtestsuite.form.component.js.map +1 -1
  139. package/dist/lib/generated/Entities/MJTestSuiteRun/mjtestsuiterun.form.component.d.ts.map +1 -1
  140. package/dist/lib/generated/Entities/MJTestSuiteRun/mjtestsuiterun.form.component.js +19 -11
  141. package/dist/lib/generated/Entities/MJTestSuiteRun/mjtestsuiterun.form.component.js.map +1 -1
  142. package/dist/lib/generated/Entities/MJUser/mjuser.form.component.d.ts.map +1 -1
  143. package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js +172 -118
  144. package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js.map +1 -1
  145. package/dist/lib/generated/generated-forms.module.d.ts +436 -422
  146. package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
  147. package/dist/lib/generated/generated-forms.module.js +44 -2
  148. package/dist/lib/generated/generated-forms.module.js.map +1 -1
  149. package/dist/lib/panels/record-clone/entity-clone-config-editor.component.d.ts +116 -0
  150. package/dist/lib/panels/record-clone/entity-clone-config-editor.component.d.ts.map +1 -0
  151. package/dist/lib/panels/record-clone/entity-clone-config-editor.component.js +820 -0
  152. package/dist/lib/panels/record-clone/entity-clone-config-editor.component.js.map +1 -0
  153. package/dist/lib/shared/components/template-editor.component.d.ts +25 -1
  154. package/dist/lib/shared/components/template-editor.component.d.ts.map +1 -1
  155. package/dist/lib/shared/components/template-editor.component.js +67 -3
  156. package/dist/lib/shared/components/template-editor.component.js.map +1 -1
  157. package/dist/public-api.d.ts +5 -0
  158. package/dist/public-api.d.ts.map +1 -1
  159. package/dist/public-api.js +5 -0
  160. package/dist/public-api.js.map +1 -1
  161. package/package.json +47 -43
@@ -14,7 +14,7 @@ import { RegisterClass } from '@memberjunction/global';
14
14
  import { SharedService, NavigationService } from '@memberjunction/ng-shared';
15
15
  import { ApplicationManager } from '@memberjunction/ng-base-application';
16
16
  import { MJTestFormComponent } from '../../generated/Entities/MJTest/mjtest.form.component';
17
- import { TestingDialogService, TagsHelper, EvaluationPreferencesService } from '@memberjunction/ng-testing';
17
+ import { TestingDialogService, TagsHelper, EvaluationPreferencesService, RubricPickerOptions } from '@memberjunction/ng-testing';
18
18
  import { createCopyOnlyToolbar } from '@memberjunction/ng-code-editor';
19
19
  import { MJConfirmService } from '@memberjunction/ng-ui-components';
20
20
  import * as i0 from "@angular/core";
@@ -27,7 +27,8 @@ import * as i6 from "@memberjunction/ng-shared-generic";
27
27
  import * as i7 from "./entity-link-pill.component";
28
28
  const _c0 = () => [1, 2, 3, 4, 5];
29
29
  const _c1 = () => [1, 2, 3];
30
- const _forTrack0 = ($index, $item) => $item.ID;
30
+ const _forTrack0 = ($index, $item) => $item.id;
31
+ const _forTrack1 = ($index, $item) => $item.ID;
31
32
  function MJTestFormComponentExtended_Conditional_21_Template(rf, ctx) { if (rf & 1) {
32
33
  i0.ɵɵelementStart(0, "span", 14);
33
34
  i0.ɵɵtext(1, "\u25CF");
@@ -257,30 +258,40 @@ function MJTestFormComponentExtended_Conditional_64_For_25_Template(rf, ctx) { i
257
258
  i0.ɵɵadvance();
258
259
  i0.ɵɵtextInterpolate(opt_r4);
259
260
  } }
260
- function MJTestFormComponentExtended_Conditional_64_For_31_Template(rf, ctx) { if (rf & 1) {
261
+ function MJTestFormComponentExtended_Conditional_64_For_33_Template(rf, ctx) { if (rf & 1) {
261
262
  i0.ɵɵelementStart(0, "option", 93);
262
263
  i0.ɵɵtext(1);
263
264
  i0.ɵɵelementEnd();
264
265
  } if (rf & 2) {
265
- const t_r5 = ctx.$implicit;
266
- i0.ɵɵproperty("ngValue", t_r5.ID);
266
+ const rubric_r5 = ctx.$implicit;
267
+ i0.ɵɵproperty("ngValue", rubric_r5.id);
267
268
  i0.ɵɵadvance();
268
- i0.ɵɵtextInterpolate(t_r5.Name);
269
+ i0.ɵɵtextInterpolate(rubric_r5.name);
269
270
  } }
270
- function MJTestFormComponentExtended_Conditional_64_For_37_Template(rf, ctx) { if (rf & 1) {
271
- const _r7 = i0.ɵɵgetCurrentView();
272
- i0.ɵɵelementStart(0, "span", 98);
271
+ function MJTestFormComponentExtended_Conditional_64_For_39_Template(rf, ctx) { if (rf & 1) {
272
+ i0.ɵɵelementStart(0, "option", 93);
273
+ i0.ɵɵtext(1);
274
+ i0.ɵɵelementEnd();
275
+ } if (rf & 2) {
276
+ const t_r6 = ctx.$implicit;
277
+ i0.ɵɵproperty("ngValue", t_r6.ID);
278
+ i0.ɵɵadvance();
279
+ i0.ɵɵtextInterpolate(t_r6.Name);
280
+ } }
281
+ function MJTestFormComponentExtended_Conditional_64_For_45_Template(rf, ctx) { if (rf & 1) {
282
+ const _r8 = i0.ɵɵgetCurrentView();
283
+ i0.ɵɵelementStart(0, "span", 100);
273
284
  i0.ɵɵtext(1);
274
- i0.ɵɵelementStart(2, "button", 121);
275
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_For_37_Template_button_click_2_listener($event) { const tag_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); ctx_r0.removeTag(tag_r8); return i0.ɵɵresetView($event.stopPropagation()); });
276
- i0.ɵɵelement(3, "i", 122);
285
+ i0.ɵɵelementStart(2, "button", 123);
286
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_For_45_Template_button_click_2_listener($event) { const tag_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); ctx_r0.removeTag(tag_r9); return i0.ɵɵresetView($event.stopPropagation()); });
287
+ i0.ɵɵelement(3, "i", 124);
277
288
  i0.ɵɵelementEnd()();
278
289
  } if (rf & 2) {
279
- const tag_r8 = ctx.$implicit;
290
+ const tag_r9 = ctx.$implicit;
280
291
  i0.ɵɵadvance();
281
- i0.ɵɵtextInterpolate1(" ", tag_r8, " ");
292
+ i0.ɵɵtextInterpolate1(" ", tag_r9, " ");
282
293
  i0.ɵɵadvance();
283
- i0.ɵɵattribute("aria-label", "Remove tag " + tag_r8);
294
+ i0.ɵɵattribute("aria-label", "Remove tag " + tag_r9);
284
295
  } }
285
296
  function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf & 1) {
286
297
  const _r3 = i0.ɵɵgetCurrentView();
@@ -313,108 +324,118 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
313
324
  i0.ɵɵrepeaterCreate(24, MJTestFormComponentExtended_Conditional_64_For_25_Template, 2, 2, "option", 93, i0.ɵɵrepeaterTrackByIdentity);
314
325
  i0.ɵɵelementEnd()()();
315
326
  i0.ɵɵelementStart(26, "div", 89)(27, "label", 94);
316
- i0.ɵɵtext(28, "Test Type");
327
+ i0.ɵɵtext(28, "Rubric");
317
328
  i0.ɵɵelementEnd();
318
329
  i0.ɵɵelementStart(29, "select", 95);
319
- i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_select_ngModelChange_29_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.TypeID, $event) || (ctx_r0.record.TypeID = $event); return i0.ɵɵresetView($event); });
320
- i0.ɵɵrepeaterCreate(30, MJTestFormComponentExtended_Conditional_64_For_31_Template, 2, 2, "option", 93, _forTrack0);
330
+ i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_select_ngModelChange_29_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.RubricID = $event || null); });
331
+ i0.ɵɵelementStart(30, "option", 93);
332
+ i0.ɵɵtext(31, "\u2014 None \u2014");
333
+ i0.ɵɵelementEnd();
334
+ i0.ɵɵrepeaterCreate(32, MJTestFormComponentExtended_Conditional_64_For_33_Template, 2, 2, "option", 93, _forTrack0);
321
335
  i0.ɵɵelementEnd()();
322
- i0.ɵɵelementStart(32, "div", 83)(33, "label", 96);
323
- i0.ɵɵtext(34, "Tags");
324
- i0.ɵɵelementEnd();
325
- i0.ɵɵelementStart(35, "div", 97);
326
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_div_click_35_listener() { i0.ɵɵrestoreView(_r3); const tagInput_r6 = i0.ɵɵreference(39); return i0.ɵɵresetView(tagInput_r6.focus()); });
327
- i0.ɵɵrepeaterCreate(36, MJTestFormComponentExtended_Conditional_64_For_37_Template, 4, 2, "span", 98, i0.ɵɵrepeaterTrackByIdentity);
328
- i0.ɵɵelementStart(38, "input", 99, 0);
329
- i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_38_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.tagDraft, $event) || (ctx_r0.tagDraft = $event); return i0.ɵɵresetView($event); });
330
- i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_Conditional_64_Template_input_keydown_38_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onTagInputKeydown($event)); })("blur", function MJTestFormComponentExtended_Conditional_64_Template_input_blur_38_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.addTagFromDraft()); });
336
+ i0.ɵɵelementStart(34, "div", 89)(35, "label", 96);
337
+ i0.ɵɵtext(36, "Test Type");
338
+ i0.ɵɵelementEnd();
339
+ i0.ɵɵelementStart(37, "select", 97);
340
+ i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_select_ngModelChange_37_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.TypeID, $event) || (ctx_r0.record.TypeID = $event); return i0.ɵɵresetView($event); });
341
+ i0.ɵɵrepeaterCreate(38, MJTestFormComponentExtended_Conditional_64_For_39_Template, 2, 2, "option", 93, _forTrack1);
331
342
  i0.ɵɵelementEnd()();
332
- i0.ɵɵelementStart(40, "span", 100);
333
- i0.ɵɵtext(41, "Press Enter or comma to add a tag. Backspace on empty input removes the last tag.");
343
+ i0.ɵɵelementStart(40, "div", 83)(41, "label", 98);
344
+ i0.ɵɵtext(42, "Tags");
345
+ i0.ɵɵelementEnd();
346
+ i0.ɵɵelementStart(43, "div", 99);
347
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_div_click_43_listener() { i0.ɵɵrestoreView(_r3); const tagInput_r7 = i0.ɵɵreference(47); return i0.ɵɵresetView(tagInput_r7.focus()); });
348
+ i0.ɵɵrepeaterCreate(44, MJTestFormComponentExtended_Conditional_64_For_45_Template, 4, 2, "span", 100, i0.ɵɵrepeaterTrackByIdentity);
349
+ i0.ɵɵelementStart(46, "input", 101, 0);
350
+ i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_46_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.tagDraft, $event) || (ctx_r0.tagDraft = $event); return i0.ɵɵresetView($event); });
351
+ i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_Conditional_64_Template_input_keydown_46_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onTagInputKeydown($event)); })("blur", function MJTestFormComponentExtended_Conditional_64_Template_input_blur_46_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.addTagFromDraft()); });
352
+ i0.ɵɵelementEnd()();
353
+ i0.ɵɵelementStart(48, "span", 102);
354
+ i0.ɵɵtext(49, "Press Enter or comma to add a tag. Backspace on empty input removes the last tag.");
334
355
  i0.ɵɵelementEnd()()()();
335
- i0.ɵɵelementStart(42, "section", 78)(43, "header", 79)(44, "h3");
336
- i0.ɵɵelement(45, "i", 101);
337
- i0.ɵɵtext(46, " Execution Settings");
356
+ i0.ɵɵelementStart(50, "section", 78)(51, "header", 79)(52, "h3");
357
+ i0.ɵɵelement(53, "i", 103);
358
+ i0.ɵɵtext(54, " Execution Settings");
338
359
  i0.ɵɵelementEnd()();
339
- i0.ɵɵelementStart(47, "div", 82)(48, "div", 89)(49, "label", 102);
340
- i0.ɵɵtext(50, "Priority");
360
+ i0.ɵɵelementStart(55, "div", 82)(56, "div", 89)(57, "label", 104);
361
+ i0.ɵɵtext(58, "Priority");
341
362
  i0.ɵɵelementEnd();
342
- i0.ɵɵelementStart(51, "input", 103);
343
- i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_51_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Priority = $event === "" || $event === null ? null : +$event); });
363
+ i0.ɵɵelementStart(59, "input", 105);
364
+ i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_59_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Priority = $event === "" || $event === null ? null : +$event); });
344
365
  i0.ɵɵelementEnd();
345
- i0.ɵɵelementStart(52, "span", 100);
346
- i0.ɵɵtext(53, "Lower numbers run first.");
366
+ i0.ɵɵelementStart(60, "span", 102);
367
+ i0.ɵɵtext(61, "Lower numbers run first.");
347
368
  i0.ɵɵelementEnd()();
348
- i0.ɵɵelementStart(54, "div", 89)(55, "label", 104);
349
- i0.ɵɵtext(56, "Repeat Count");
369
+ i0.ɵɵelementStart(62, "div", 89)(63, "label", 106);
370
+ i0.ɵɵtext(64, "Repeat Count");
350
371
  i0.ɵɵelementEnd();
351
- i0.ɵɵelementStart(57, "input", 105);
352
- i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_57_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.RepeatCount = $event === "" || $event === null ? null : +$event); });
372
+ i0.ɵɵelementStart(65, "input", 107);
373
+ i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_65_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.RepeatCount = $event === "" || $event === null ? null : +$event); });
353
374
  i0.ɵɵelementEnd();
354
- i0.ɵɵelementStart(58, "span", 100);
355
- i0.ɵɵtext(59, "Number of times to repeat for statistical analysis.");
375
+ i0.ɵɵelementStart(66, "span", 102);
376
+ i0.ɵɵtext(67, "Number of times to repeat for statistical analysis.");
356
377
  i0.ɵɵelementEnd()();
357
- i0.ɵɵelementStart(60, "div", 89)(61, "label", 106);
358
- i0.ɵɵtext(62, "Estimated Duration (seconds)");
378
+ i0.ɵɵelementStart(68, "div", 89)(69, "label", 108);
379
+ i0.ɵɵtext(70, "Estimated Duration (seconds)");
359
380
  i0.ɵɵelementEnd();
360
- i0.ɵɵelementStart(63, "input", 107);
361
- i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_63_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedDurationSeconds = $event === "" || $event === null ? null : +$event); });
381
+ i0.ɵɵelementStart(71, "input", 109);
382
+ i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_71_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedDurationSeconds = $event === "" || $event === null ? null : +$event); });
362
383
  i0.ɵɵelementEnd()();
363
- i0.ɵɵelementStart(64, "div", 89)(65, "label", 108);
364
- i0.ɵɵtext(66, "Estimated Cost (USD)");
384
+ i0.ɵɵelementStart(72, "div", 89)(73, "label", 110);
385
+ i0.ɵɵtext(74, "Estimated Cost (USD)");
365
386
  i0.ɵɵelementEnd();
366
- i0.ɵɵelementStart(67, "input", 109);
367
- i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_67_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedCostUSD = $event === "" || $event === null ? null : +$event); });
387
+ i0.ɵɵelementStart(75, "input", 111);
388
+ i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_75_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedCostUSD = $event === "" || $event === null ? null : +$event); });
368
389
  i0.ɵɵelementEnd()();
369
- i0.ɵɵelementStart(68, "div", 83)(69, "label", 110);
370
- i0.ɵɵtext(70, "Max Execution Time (ms)");
390
+ i0.ɵɵelementStart(76, "div", 83)(77, "label", 112);
391
+ i0.ɵɵtext(78, "Max Execution Time (ms)");
371
392
  i0.ɵɵelementEnd();
372
- i0.ɵɵelementStart(71, "input", 111);
373
- i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_71_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.MaxExecutionTimeMS = $event === "" || $event === null ? null : +$event); });
393
+ i0.ɵɵelementStart(79, "input", 113);
394
+ i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_79_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.MaxExecutionTimeMS = $event === "" || $event === null ? null : +$event); });
374
395
  i0.ɵɵelementEnd();
375
- i0.ɵɵelementStart(72, "span", 100);
376
- i0.ɵɵtext(73);
396
+ i0.ɵɵelementStart(80, "span", 102);
397
+ i0.ɵɵtext(81);
377
398
  i0.ɵɵelementEnd()()()();
378
- i0.ɵɵelementStart(74, "div", 112)(75, "h3");
379
- i0.ɵɵelement(76, "i", 72);
380
- i0.ɵɵtext(77, " Input Definition (JSON)");
399
+ i0.ɵɵelementStart(82, "div", 114)(83, "h3");
400
+ i0.ɵɵelement(84, "i", 72);
401
+ i0.ɵɵtext(85, " Input Definition (JSON)");
381
402
  i0.ɵɵelementEnd();
382
- i0.ɵɵelementStart(78, "div", 113)(79, "mj-code-editor", 114);
383
- i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_79_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.InputDefinition = $event); });
403
+ i0.ɵɵelementStart(86, "div", 115)(87, "mj-code-editor", 116);
404
+ i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_87_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.InputDefinition = $event); });
384
405
  i0.ɵɵelementEnd()()();
385
- i0.ɵɵelementStart(80, "div", 112)(81, "h3");
386
- i0.ɵɵelement(82, "i", 73);
387
- i0.ɵɵtext(83, " Expected Outcomes (JSON)");
406
+ i0.ɵɵelementStart(88, "div", 114)(89, "h3");
407
+ i0.ɵɵelement(90, "i", 73);
408
+ i0.ɵɵtext(91, " Expected Outcomes (JSON)");
388
409
  i0.ɵɵelementEnd();
389
- i0.ɵɵelementStart(84, "div", 113)(85, "mj-code-editor", 114);
390
- i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_85_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.ExpectedOutcomes = $event); });
410
+ i0.ɵɵelementStart(92, "div", 115)(93, "mj-code-editor", 116);
411
+ i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_93_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.ExpectedOutcomes = $event); });
391
412
  i0.ɵɵelementEnd()()();
392
- i0.ɵɵelementStart(86, "div", 112)(87, "h3");
393
- i0.ɵɵelement(88, "i", 74);
394
- i0.ɵɵtext(89, " Configuration (JSON)");
413
+ i0.ɵɵelementStart(94, "div", 114)(95, "h3");
414
+ i0.ɵɵelement(96, "i", 74);
415
+ i0.ɵɵtext(97, " Configuration (JSON)");
395
416
  i0.ɵɵelementEnd();
396
- i0.ɵɵelementStart(90, "div", 113)(91, "mj-code-editor", 114);
397
- i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_91_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Configuration = $event); });
417
+ i0.ɵɵelementStart(98, "div", 115)(99, "mj-code-editor", 116);
418
+ i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_99_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Configuration = $event); });
398
419
  i0.ɵɵelementEnd()()();
399
- i0.ɵɵelementStart(92, "section", 115)(93, "div", 116)(94, "div", 117)(95, "div", 118);
400
- i0.ɵɵtext(96, "Created");
420
+ i0.ɵɵelementStart(100, "section", 117)(101, "div", 118)(102, "div", 119)(103, "div", 120);
421
+ i0.ɵɵtext(104, "Created");
401
422
  i0.ɵɵelementEnd();
402
- i0.ɵɵelementStart(97, "div", 119);
403
- i0.ɵɵtext(98);
404
- i0.ɵɵpipe(99, "date");
423
+ i0.ɵɵelementStart(105, "div", 121);
424
+ i0.ɵɵtext(106);
425
+ i0.ɵɵpipe(107, "date");
405
426
  i0.ɵɵelementEnd()();
406
- i0.ɵɵelementStart(100, "div", 117)(101, "div", 118);
407
- i0.ɵɵtext(102, "Last updated");
427
+ i0.ɵɵelementStart(108, "div", 119)(109, "div", 120);
428
+ i0.ɵɵtext(110, "Last updated");
408
429
  i0.ɵɵelementEnd();
409
- i0.ɵɵelementStart(103, "div", 119);
410
- i0.ɵɵtext(104);
411
- i0.ɵɵpipe(105, "date");
430
+ i0.ɵɵelementStart(111, "div", 121);
431
+ i0.ɵɵtext(112);
432
+ i0.ɵɵpipe(113, "date");
412
433
  i0.ɵɵelementEnd()();
413
- i0.ɵɵelementStart(106, "div", 117)(107, "div", 118);
414
- i0.ɵɵtext(108, "Test ID");
434
+ i0.ɵɵelementStart(114, "div", 119)(115, "div", 120);
435
+ i0.ɵɵtext(116, "Test ID");
415
436
  i0.ɵɵelementEnd();
416
- i0.ɵɵelementStart(109, "div", 120);
417
- i0.ɵɵtext(110);
437
+ i0.ɵɵelementStart(117, "div", 122);
438
+ i0.ɵɵtext(118);
418
439
  i0.ɵɵelementEnd()()()()();
419
440
  } if (rf & 2) {
420
441
  const ctx_r0 = i0.ɵɵnextContext();
@@ -427,6 +448,12 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
427
448
  i0.ɵɵadvance();
428
449
  i0.ɵɵrepeater(ctx_r0.statusOptions);
429
450
  i0.ɵɵadvance(5);
451
+ i0.ɵɵproperty("ngModel", ctx_r0.record.RubricID);
452
+ i0.ɵɵadvance();
453
+ i0.ɵɵproperty("ngValue", null);
454
+ i0.ɵɵadvance(2);
455
+ i0.ɵɵrepeater(ctx_r0.RubricOptions);
456
+ i0.ɵɵadvance(5);
430
457
  i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.TypeID);
431
458
  i0.ɵɵadvance();
432
459
  i0.ɵɵrepeater(ctx_r0.testTypeOptions);
@@ -454,22 +481,22 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
454
481
  i0.ɵɵadvance(6);
455
482
  i0.ɵɵproperty("value", ctx_r0.record.Configuration || "")("readonly", false)("lineWrapping", true);
456
483
  i0.ɵɵadvance(7);
457
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(99, 24, ctx_r0.record.__mj_CreatedAt, "medium"));
484
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(107, 26, ctx_r0.record.__mj_CreatedAt, "medium"));
458
485
  i0.ɵɵadvance(6);
459
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(105, 27, ctx_r0.record.__mj_UpdatedAt, "medium"));
486
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(113, 29, ctx_r0.record.__mj_UpdatedAt, "medium"));
460
487
  i0.ɵɵadvance(6);
461
488
  i0.ɵɵtextInterpolate(ctx_r0.record.ID);
462
489
  } }
463
490
  function MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
464
- i0.ɵɵelementStart(0, "div", 127);
465
- i0.ɵɵelement(1, "div", 128);
466
- i0.ɵɵelementStart(2, "div", 129);
467
- i0.ɵɵelement(3, "div", 130)(4, "div", 131);
491
+ i0.ɵɵelementStart(0, "div", 129);
492
+ i0.ɵɵelement(1, "div", 130);
493
+ i0.ɵɵelementStart(2, "div", 131);
494
+ i0.ɵɵelement(3, "div", 132)(4, "div", 133);
468
495
  i0.ɵɵelementEnd()();
469
496
  } }
470
497
  function MJTestFormComponentExtended_Conditional_65_Conditional_1_Template(rf, ctx) { if (rf & 1) {
471
- i0.ɵɵelementStart(0, "div", 123)(1, "div", 126);
472
- i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template, 5, 0, "div", 127, i0.ɵɵrepeaterTrackByIdentity);
498
+ i0.ɵɵelementStart(0, "div", 125)(1, "div", 128);
499
+ i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template, 5, 0, "div", 129, i0.ɵɵrepeaterTrackByIdentity);
473
500
  i0.ɵɵelementEnd()();
474
501
  } if (rf & 2) {
475
502
  i0.ɵɵadvance(2);
@@ -477,190 +504,190 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_1_Template(rf, c
477
504
  } }
478
505
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
479
506
  i0.ɵɵelementStart(0, "span");
480
- i0.ɵɵelement(1, "i", 147);
507
+ i0.ɵɵelement(1, "i", 149);
481
508
  i0.ɵɵtext(2);
482
509
  i0.ɵɵelementEnd();
483
510
  } if (rf & 2) {
484
- const run_r10 = i0.ɵɵnextContext().$implicit;
511
+ const run_r11 = i0.ɵɵnextContext().$implicit;
485
512
  const ctx_r0 = i0.ɵɵnextContext(3);
486
513
  i0.ɵɵadvance(2);
487
- i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(run_r10.DurationSeconds));
514
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(run_r11.DurationSeconds));
488
515
  } }
489
516
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_14_Template(rf, ctx) { if (rf & 1) {
490
517
  i0.ɵɵelementStart(0, "span");
491
- i0.ɵɵelement(1, "i", 148);
518
+ i0.ɵɵelement(1, "i", 150);
492
519
  i0.ɵɵtext(2);
493
520
  i0.ɵɵelementEnd();
494
521
  } if (rf & 2) {
495
- const run_r10 = i0.ɵɵnextContext().$implicit;
522
+ const run_r11 = i0.ɵɵnextContext().$implicit;
496
523
  const ctx_r0 = i0.ɵɵnextContext(3);
497
524
  i0.ɵɵadvance(2);
498
- i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(run_r10.CostUSD));
525
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(run_r11.CostUSD));
499
526
  } }
500
527
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template(rf, ctx) { if (rf & 1) {
501
- i0.ɵɵelement(0, "mj-entity-link-pill", 142);
528
+ i0.ɵɵelement(0, "mj-entity-link-pill", 144);
502
529
  } if (rf & 2) {
503
- const run_r10 = i0.ɵɵnextContext().$implicit;
504
- i0.ɵɵproperty("entityName", run_r10.TargetLogEntity)("recordId", run_r10.TargetLogID);
530
+ const run_r11 = i0.ɵɵnextContext().$implicit;
531
+ i0.ɵɵproperty("entityName", run_r11.TargetLogEntity)("recordId", run_r11.TargetLogID);
505
532
  } }
506
533
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
507
- i0.ɵɵelementStart(0, "span", 144);
508
- i0.ɵɵelement(1, "i", 135);
534
+ i0.ɵɵelementStart(0, "span", 146);
535
+ i0.ɵɵelement(1, "i", 137);
509
536
  i0.ɵɵelementStart(2, "span");
510
537
  i0.ɵɵtext(3);
511
538
  i0.ɵɵelementEnd()();
512
539
  } if (rf & 2) {
513
- const run_r10 = i0.ɵɵnextContext().$implicit;
540
+ const run_r11 = i0.ɵɵnextContext().$implicit;
514
541
  const ctx_r0 = i0.ɵɵnextContext(3);
515
- i0.ɵɵproperty("ngClass", "status-" + run_r10.Status.toLowerCase())("title", ctx_r0.getStatusTooltip(run_r10.Status));
542
+ i0.ɵɵproperty("ngClass", "status-" + run_r11.Status.toLowerCase())("title", ctx_r0.getStatusTooltip(run_r11.Status));
516
543
  i0.ɵɵadvance();
517
- i0.ɵɵclassProp("fa-check", run_r10.Status === "Passed")("fa-times", run_r10.Status === "Failed")("fa-exclamation", run_r10.Status === "Error")("fa-hourglass-end", run_r10.Status === "Timeout")("fa-forward", run_r10.Status === "Skipped")("fa-spinner", run_r10.Status === "Running")("fa-clock", run_r10.Status === "Pending");
544
+ i0.ɵɵclassProp("fa-check", run_r11.Status === "Passed")("fa-times", run_r11.Status === "Failed")("fa-exclamation", run_r11.Status === "Error")("fa-hourglass-end", run_r11.Status === "Timeout")("fa-forward", run_r11.Status === "Skipped")("fa-spinner", run_r11.Status === "Running")("fa-clock", run_r11.Status === "Pending");
518
545
  i0.ɵɵadvance(2);
519
- i0.ɵɵtextInterpolate(run_r10.Status);
546
+ i0.ɵɵtextInterpolate(run_r11.Status);
520
547
  } }
521
548
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
522
- i0.ɵɵelementStart(0, "span", 149);
523
- i0.ɵɵelement(1, "i", 151);
549
+ i0.ɵɵelementStart(0, "span", 151);
550
+ i0.ɵɵelement(1, "i", 153);
524
551
  i0.ɵɵelementEnd();
525
552
  } }
526
553
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template(rf, ctx) { if (rf & 1) {
527
- i0.ɵɵelementStart(0, "span", 152);
528
- i0.ɵɵelement(1, "i", 153);
554
+ i0.ɵɵelementStart(0, "span", 154);
555
+ i0.ɵɵelement(1, "i", 155);
529
556
  i0.ɵɵelementStart(2, "span");
530
557
  i0.ɵɵtext(3);
531
558
  i0.ɵɵelementEnd()();
532
559
  } if (rf & 2) {
533
560
  let tmp_19_0;
534
- const rating_r11 = ctx;
535
- const run_r10 = i0.ɵɵnextContext(2).$implicit;
561
+ const rating_r12 = ctx;
562
+ const run_r11 = i0.ɵɵnextContext(2).$implicit;
536
563
  const ctx_r0 = i0.ɵɵnextContext(3);
537
- i0.ɵɵclassProp("rating-low", rating_r11 <= 4)("rating-medium", rating_r11 >= 5 && rating_r11 <= 6)("rating-good", rating_r11 >= 7 && rating_r11 <= 8)("rating-excellent", rating_r11 >= 9);
538
- i0.ɵɵproperty("title", ctx_r0.getHumanTooltip(rating_r11, ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_19_0.CorrectionSummary) || ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_19_0.Comments) || null));
564
+ i0.ɵɵclassProp("rating-low", rating_r12 <= 4)("rating-medium", rating_r12 >= 5 && rating_r12 <= 6)("rating-good", rating_r12 >= 7 && rating_r12 <= 8)("rating-excellent", rating_r12 >= 9);
565
+ i0.ɵɵproperty("title", ctx_r0.getHumanTooltip(rating_r12, ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_19_0.CorrectionSummary) || ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_19_0.Comments) || null));
539
566
  i0.ɵɵadvance(3);
540
- i0.ɵɵtextInterpolate(rating_r11);
567
+ i0.ɵɵtextInterpolate(rating_r12);
541
568
  } }
542
569
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
543
- i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template, 2, 0, "span", 149);
544
- i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template, 4, 10, "span", 150);
570
+ i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template, 2, 0, "span", 151);
571
+ i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template, 4, 10, "span", 152);
545
572
  } if (rf & 2) {
546
573
  let tmp_13_0;
547
574
  let tmp_14_0;
548
- const run_r10 = i0.ɵɵnextContext().$implicit;
575
+ const run_r11 = i0.ɵɵnextContext().$implicit;
549
576
  const ctx_r0 = i0.ɵɵnextContext(3);
550
- i0.ɵɵconditional(!((tmp_13_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_13_0.Rating) ? 0 : -1);
577
+ i0.ɵɵconditional(!((tmp_13_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_13_0.Rating) ? 0 : -1);
551
578
  i0.ɵɵadvance();
552
- i0.ɵɵconditional((tmp_14_0 = (tmp_14_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_14_0.Rating) ? 1 : -1, tmp_14_0);
579
+ i0.ɵɵconditional((tmp_14_0 = (tmp_14_0 = ctx_r0.getFeedbackForRun(run_r11.ID)) == null ? null : tmp_14_0.Rating) ? 1 : -1, tmp_14_0);
553
580
  } }
554
581
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template(rf, ctx) { if (rf & 1) {
555
- i0.ɵɵelementStart(0, "span", 154);
556
- i0.ɵɵelement(1, "i", 156);
582
+ i0.ɵɵelementStart(0, "span", 156);
583
+ i0.ɵɵelement(1, "i", 158);
557
584
  i0.ɵɵelementEnd();
558
585
  } }
559
586
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template(rf, ctx) { if (rf & 1) {
560
- i0.ɵɵelementStart(0, "span", 157);
561
- i0.ɵɵelement(1, "i", 156);
587
+ i0.ɵɵelementStart(0, "span", 159);
588
+ i0.ɵɵelement(1, "i", 158);
562
589
  i0.ɵɵelementStart(2, "span");
563
590
  i0.ɵɵtext(3);
564
591
  i0.ɵɵelementEnd()();
565
592
  } if (rf & 2) {
566
- const run_r10 = i0.ɵɵnextContext(2).$implicit;
567
- i0.ɵɵclassProp("score-low", run_r10.Score < 0.5)("score-medium", run_r10.Score >= 0.5 && run_r10.Score < 0.7)("score-good", run_r10.Score >= 0.7 && run_r10.Score < 0.85)("score-excellent", run_r10.Score >= 0.85);
568
- i0.ɵɵproperty("title", "Auto Score: " + (run_r10.Score * 100).toFixed(0) + "% automated evaluation");
593
+ const run_r11 = i0.ɵɵnextContext(2).$implicit;
594
+ i0.ɵɵclassProp("score-low", run_r11.Score < 0.5)("score-medium", run_r11.Score >= 0.5 && run_r11.Score < 0.7)("score-good", run_r11.Score >= 0.7 && run_r11.Score < 0.85)("score-excellent", run_r11.Score >= 0.85);
595
+ i0.ɵɵproperty("title", "Auto Score: " + (run_r11.Score * 100).toFixed(0) + "% automated evaluation");
569
596
  i0.ɵɵadvance(3);
570
- i0.ɵɵtextInterpolate1("", (run_r10.Score * 100).toFixed(0), "%");
597
+ i0.ɵɵtextInterpolate1("", (run_r11.Score * 100).toFixed(0), "%");
571
598
  } }
572
599
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
573
- i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template, 2, 0, "span", 154);
574
- i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template, 4, 10, "span", 155);
600
+ i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template, 2, 0, "span", 156);
601
+ i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template, 4, 10, "span", 157);
575
602
  } if (rf & 2) {
576
- const run_r10 = i0.ɵɵnextContext().$implicit;
577
- i0.ɵɵconditional(run_r10.Score == null ? 0 : -1);
603
+ const run_r11 = i0.ɵɵnextContext().$implicit;
604
+ i0.ɵɵconditional(run_r11.Score == null ? 0 : -1);
578
605
  i0.ɵɵadvance();
579
- i0.ɵɵconditional(run_r10.Score != null ? 1 : -1);
606
+ i0.ɵɵconditional(run_r11.Score != null ? 1 : -1);
580
607
  } }
581
608
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
582
- i0.ɵɵelementStart(0, "span", 158);
609
+ i0.ɵɵelementStart(0, "span", 160);
583
610
  i0.ɵɵtext(1);
584
611
  i0.ɵɵelementEnd();
585
612
  } if (rf & 2) {
586
- const tag_r12 = ctx.$implicit;
613
+ const tag_r13 = ctx.$implicit;
587
614
  i0.ɵɵadvance();
588
- i0.ɵɵtextInterpolate(tag_r12);
615
+ i0.ɵɵtextInterpolate(tag_r13);
589
616
  } }
590
617
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template(rf, ctx) { if (rf & 1) {
591
- i0.ɵɵelementStart(0, "span", 159);
618
+ i0.ɵɵelementStart(0, "span", 161);
592
619
  i0.ɵɵtext(1);
593
620
  i0.ɵɵelementEnd();
594
621
  } if (rf & 2) {
595
- const run_r10 = i0.ɵɵnextContext(2).$implicit;
622
+ const run_r11 = i0.ɵɵnextContext(2).$implicit;
596
623
  const ctx_r0 = i0.ɵɵnextContext(3);
597
624
  i0.ɵɵadvance();
598
- i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(run_r10).length - 3);
625
+ i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(run_r11).length - 3);
599
626
  } }
600
627
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
601
- i0.ɵɵelementStart(0, "div", 145);
602
- i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template, 2, 1, "span", 158, i0.ɵɵrepeaterTrackByIdentity);
603
- i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template, 2, 1, "span", 159);
628
+ i0.ɵɵelementStart(0, "div", 147);
629
+ i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template, 2, 1, "span", 160, i0.ɵɵrepeaterTrackByIdentity);
630
+ i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template, 2, 1, "span", 161);
604
631
  i0.ɵɵelementEnd();
605
632
  } if (rf & 2) {
606
- const run_r10 = i0.ɵɵnextContext().$implicit;
633
+ const run_r11 = i0.ɵɵnextContext().$implicit;
607
634
  const ctx_r0 = i0.ɵɵnextContext(3);
608
635
  i0.ɵɵadvance();
609
- i0.ɵɵrepeater(ctx_r0.getRunTags(run_r10).slice(0, 3));
636
+ i0.ɵɵrepeater(ctx_r0.getRunTags(run_r11).slice(0, 3));
610
637
  i0.ɵɵadvance(2);
611
- i0.ɵɵconditional(ctx_r0.getRunTags(run_r10).length > 3 ? 3 : -1);
638
+ i0.ɵɵconditional(ctx_r0.getRunTags(run_r11).length > 3 ? 3 : -1);
612
639
  } }
613
640
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
614
- const _r9 = i0.ɵɵgetCurrentView();
615
- i0.ɵɵelementStart(0, "div", 133);
616
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template_div_click_0_listener() { const run_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestRun(run_r10.ID)); });
617
- i0.ɵɵelementStart(1, "div", 134);
618
- i0.ɵɵelement(2, "i", 135);
641
+ const _r10 = i0.ɵɵgetCurrentView();
642
+ i0.ɵɵelementStart(0, "div", 135);
643
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template_div_click_0_listener() { const run_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestRun(run_r11.ID)); });
644
+ i0.ɵɵelementStart(1, "div", 136);
645
+ i0.ɵɵelement(2, "i", 137);
619
646
  i0.ɵɵelementEnd();
620
- i0.ɵɵelementStart(3, "div", 136)(4, "div", 137)(5, "span", 138);
647
+ i0.ɵɵelementStart(3, "div", 138)(4, "div", 139)(5, "span", 140);
621
648
  i0.ɵɵtext(6);
622
649
  i0.ɵɵelementEnd();
623
- i0.ɵɵelementStart(7, "span", 139);
650
+ i0.ɵɵelementStart(7, "span", 141);
624
651
  i0.ɵɵtext(8);
625
652
  i0.ɵɵelementEnd()();
626
- i0.ɵɵelementStart(9, "div", 140)(10, "span");
627
- i0.ɵɵelement(11, "i", 141);
653
+ i0.ɵɵelementStart(9, "div", 142)(10, "span");
654
+ i0.ɵɵelement(11, "i", 143);
628
655
  i0.ɵɵtext(12);
629
656
  i0.ɵɵelementEnd();
630
657
  i0.ɵɵconditionalCreate(13, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_13_Template, 3, 1, "span");
631
658
  i0.ɵɵconditionalCreate(14, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_14_Template, 3, 1, "span");
632
- i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template, 1, 2, "mj-entity-link-pill", 142);
659
+ i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template, 1, 2, "mj-entity-link-pill", 144);
633
660
  i0.ɵɵelementEnd();
634
- i0.ɵɵelementStart(16, "div", 143);
635
- i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template, 4, 17, "span", 144);
661
+ i0.ɵɵelementStart(16, "div", 145);
662
+ i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template, 4, 17, "span", 146);
636
663
  i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Template, 2, 2);
637
664
  i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Template, 2, 2);
638
665
  i0.ɵɵelementEnd();
639
- i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template, 4, 1, "div", 145);
666
+ i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template, 4, 1, "div", 147);
640
667
  i0.ɵɵelementEnd();
641
- i0.ɵɵelement(21, "i", 146);
668
+ i0.ɵɵelement(21, "i", 148);
642
669
  i0.ɵɵelementEnd();
643
670
  } if (rf & 2) {
644
- const run_r10 = ctx.$implicit;
671
+ const run_r11 = ctx.$implicit;
645
672
  const ctx_r0 = i0.ɵɵnextContext(3);
646
673
  i0.ɵɵadvance();
647
- i0.ɵɵstyleProp("background-color", ctx_r0.getRunStatusColor(run_r10.Status));
674
+ i0.ɵɵstyleProp("background-color", ctx_r0.getRunStatusColor(run_r11.Status));
648
675
  i0.ɵɵadvance();
649
- i0.ɵɵclassProp("fa-check", run_r10.Status === "Passed")("fa-times", run_r10.Status === "Failed")("fa-exclamation", run_r10.Status === "Error")("fa-stopwatch", run_r10.Status === "Timeout")("fa-spinner", run_r10.Status === "Running")("fa-clock", run_r10.Status === "Pending");
676
+ i0.ɵɵclassProp("fa-check", run_r11.Status === "Passed")("fa-times", run_r11.Status === "Failed")("fa-exclamation", run_r11.Status === "Error")("fa-stopwatch", run_r11.Status === "Timeout")("fa-spinner", run_r11.Status === "Running")("fa-clock", run_r11.Status === "Pending");
650
677
  i0.ɵɵadvance(4);
651
- i0.ɵɵtextInterpolate1("Run #", run_r10.ID.substring(0, 8));
678
+ i0.ɵɵtextInterpolate1("Run #", run_r11.ID.substring(0, 8));
652
679
  i0.ɵɵadvance();
653
- i0.ɵɵstyleProp("color", ctx_r0.getRunStatusColor(run_r10.Status));
680
+ i0.ɵɵstyleProp("color", ctx_r0.getRunStatusColor(run_r11.Status));
654
681
  i0.ɵɵadvance();
655
- i0.ɵɵtextInterpolate(run_r10.Status);
682
+ i0.ɵɵtextInterpolate(run_r11.Status);
656
683
  i0.ɵɵadvance(4);
657
- i0.ɵɵtextInterpolate1(" ", ctx_r0.getRelativeTime(run_r10.StartedAt));
684
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.getRelativeTime(run_r11.StartedAt));
658
685
  i0.ɵɵadvance();
659
- i0.ɵɵconditional(run_r10.DurationSeconds ? 13 : -1);
686
+ i0.ɵɵconditional(run_r11.DurationSeconds ? 13 : -1);
660
687
  i0.ɵɵadvance();
661
- i0.ɵɵconditional(run_r10.CostUSD ? 14 : -1);
688
+ i0.ɵɵconditional(run_r11.CostUSD ? 14 : -1);
662
689
  i0.ɵɵadvance();
663
- i0.ɵɵconditional(run_r10.TargetLogEntityID && run_r10.TargetLogID ? 15 : -1);
690
+ i0.ɵɵconditional(run_r11.TargetLogEntityID && run_r11.TargetLogID ? 15 : -1);
664
691
  i0.ɵɵadvance(2);
665
692
  i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 17 : -1);
666
693
  i0.ɵɵadvance();
@@ -668,11 +695,11 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template
668
695
  i0.ɵɵadvance();
669
696
  i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 19 : -1);
670
697
  i0.ɵɵadvance();
671
- i0.ɵɵconditional(ctx_r0.getRunTags(run_r10).length > 0 ? 20 : -1);
698
+ i0.ɵɵconditional(ctx_r0.getRunTags(run_r11).length > 0 ? 20 : -1);
672
699
  } }
673
700
  function MJTestFormComponentExtended_Conditional_65_Conditional_2_Template(rf, ctx) { if (rf & 1) {
674
- i0.ɵɵelementStart(0, "div", 124);
675
- i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template, 22, 26, "div", 132, i0.ɵɵrepeaterTrackByIdentity);
701
+ i0.ɵɵelementStart(0, "div", 126);
702
+ i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template, 22, 26, "div", 134, i0.ɵɵrepeaterTrackByIdentity);
676
703
  i0.ɵɵelementEnd();
677
704
  } if (rf & 2) {
678
705
  const ctx_r0 = i0.ɵɵnextContext(2);
@@ -680,16 +707,16 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Template(rf, c
680
707
  i0.ɵɵrepeater(ctx_r0.testRuns);
681
708
  } }
682
709
  function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template(rf, ctx) { if (rf & 1) {
683
- const _r13 = i0.ɵɵgetCurrentView();
684
- i0.ɵɵelementStart(0, "mj-empty-state", 160);
685
- i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.runTest()); });
710
+ const _r14 = i0.ɵɵgetCurrentView();
711
+ i0.ɵɵelementStart(0, "mj-empty-state", 162);
712
+ i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.runTest()); });
686
713
  i0.ɵɵelementEnd();
687
714
  } }
688
715
  function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf & 1) {
689
716
  i0.ɵɵelementStart(0, "div", 38);
690
- i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_1_Template, 4, 1, "div", 123);
691
- i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_2_Template, 3, 0, "div", 124);
692
- i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_3_Template, 1, 0, "mj-empty-state", 125);
717
+ i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_1_Template, 4, 1, "div", 125);
718
+ i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_2_Template, 3, 0, "div", 126);
719
+ i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_3_Template, 1, 0, "mj-empty-state", 127);
693
720
  i0.ɵɵelementEnd();
694
721
  } if (rf & 2) {
695
722
  const ctx_r0 = i0.ɵɵnextContext();
@@ -701,15 +728,15 @@ function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf &
701
728
  i0.ɵɵconditional(ctx_r0.testRunsLoaded && !ctx_r0.loadingRuns && ctx_r0.testRuns.length === 0 ? 3 : -1);
702
729
  } }
703
730
  function MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
704
- i0.ɵɵelementStart(0, "div", 127);
705
- i0.ɵɵelement(1, "div", 128);
706
- i0.ɵɵelementStart(2, "div", 129);
707
- i0.ɵɵelement(3, "div", 130)(4, "div", 131);
731
+ i0.ɵɵelementStart(0, "div", 129);
732
+ i0.ɵɵelement(1, "div", 130);
733
+ i0.ɵɵelementStart(2, "div", 131);
734
+ i0.ɵɵelement(3, "div", 132)(4, "div", 133);
708
735
  i0.ɵɵelementEnd()();
709
736
  } }
710
737
  function MJTestFormComponentExtended_Conditional_66_Conditional_1_Template(rf, ctx) { if (rf & 1) {
711
- i0.ɵɵelementStart(0, "div", 123)(1, "div", 126);
712
- i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template, 5, 0, "div", 127, i0.ɵɵrepeaterTrackByIdentity);
738
+ i0.ɵɵelementStart(0, "div", 125)(1, "div", 128);
739
+ i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template, 5, 0, "div", 129, i0.ɵɵrepeaterTrackByIdentity);
713
740
  i0.ɵɵelementEnd()();
714
741
  } if (rf & 2) {
715
742
  i0.ɵɵadvance(2);
@@ -721,40 +748,40 @@ function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditio
721
748
  i0.ɵɵtext(2);
722
749
  i0.ɵɵelementEnd();
723
750
  } if (rf & 2) {
724
- const suiteTest_r15 = i0.ɵɵnextContext().$implicit;
751
+ const suiteTest_r16 = i0.ɵɵnextContext().$implicit;
725
752
  i0.ɵɵadvance(2);
726
- i0.ɵɵtextInterpolate1(" ", suiteTest_r15.Status);
753
+ i0.ɵɵtextInterpolate1(" ", suiteTest_r16.Status);
727
754
  } }
728
755
  function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
729
- const _r14 = i0.ɵɵgetCurrentView();
730
- i0.ɵɵelementStart(0, "div", 164);
731
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template_div_click_0_listener() { const suiteTest_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestSuite(suiteTest_r15.SuiteID)); });
732
- i0.ɵɵelementStart(1, "div", 165);
756
+ const _r15 = i0.ɵɵgetCurrentView();
757
+ i0.ɵɵelementStart(0, "div", 166);
758
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template_div_click_0_listener() { const suiteTest_r16 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestSuite(suiteTest_r16.SuiteID)); });
759
+ i0.ɵɵelementStart(1, "div", 167);
733
760
  i0.ɵɵelement(2, "i", 33);
734
761
  i0.ɵɵelementEnd();
735
- i0.ɵɵelementStart(3, "div", 166)(4, "div", 167);
762
+ i0.ɵɵelementStart(3, "div", 168)(4, "div", 169);
736
763
  i0.ɵɵtext(5);
737
764
  i0.ɵɵelementEnd();
738
- i0.ɵɵelementStart(6, "div", 168)(7, "span");
739
- i0.ɵɵelement(8, "i", 169);
765
+ i0.ɵɵelementStart(6, "div", 170)(7, "span");
766
+ i0.ɵɵelement(8, "i", 171);
740
767
  i0.ɵɵtext(9);
741
768
  i0.ɵɵelementEnd();
742
769
  i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_10_Template, 3, 1, "span");
743
770
  i0.ɵɵelementEnd()();
744
- i0.ɵɵelement(11, "i", 146);
771
+ i0.ɵɵelement(11, "i", 148);
745
772
  i0.ɵɵelementEnd();
746
773
  } if (rf & 2) {
747
- const suiteTest_r15 = ctx.$implicit;
774
+ const suiteTest_r16 = ctx.$implicit;
748
775
  i0.ɵɵadvance(5);
749
- i0.ɵɵtextInterpolate(suiteTest_r15.Suite);
776
+ i0.ɵɵtextInterpolate(suiteTest_r16.Suite);
750
777
  i0.ɵɵadvance(4);
751
- i0.ɵɵtextInterpolate1(" Sequence: ", suiteTest_r15.Sequence);
778
+ i0.ɵɵtextInterpolate1(" Sequence: ", suiteTest_r16.Sequence);
752
779
  i0.ɵɵadvance();
753
- i0.ɵɵconditional(suiteTest_r15.Status ? 10 : -1);
780
+ i0.ɵɵconditional(suiteTest_r16.Status ? 10 : -1);
754
781
  } }
755
782
  function MJTestFormComponentExtended_Conditional_66_Conditional_2_Template(rf, ctx) { if (rf & 1) {
756
- i0.ɵɵelementStart(0, "div", 161);
757
- i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template, 12, 3, "div", 163, i0.ɵɵrepeaterTrackByIdentity);
783
+ i0.ɵɵelementStart(0, "div", 163);
784
+ i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template, 12, 3, "div", 165, i0.ɵɵrepeaterTrackByIdentity);
758
785
  i0.ɵɵelementEnd();
759
786
  } if (rf & 2) {
760
787
  const ctx_r0 = i0.ɵɵnextContext(2);
@@ -762,13 +789,13 @@ function MJTestFormComponentExtended_Conditional_66_Conditional_2_Template(rf, c
762
789
  i0.ɵɵrepeater(ctx_r0.suiteTests);
763
790
  } }
764
791
  function MJTestFormComponentExtended_Conditional_66_Conditional_3_Template(rf, ctx) { if (rf & 1) {
765
- i0.ɵɵelement(0, "mj-empty-state", 162);
792
+ i0.ɵɵelement(0, "mj-empty-state", 164);
766
793
  } }
767
794
  function MJTestFormComponentExtended_Conditional_66_Template(rf, ctx) { if (rf & 1) {
768
795
  i0.ɵɵelementStart(0, "div", 39);
769
- i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_1_Template, 4, 1, "div", 123);
770
- i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_2_Template, 3, 0, "div", 161);
771
- i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_66_Conditional_3_Template, 1, 0, "mj-empty-state", 162);
796
+ i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_1_Template, 4, 1, "div", 125);
797
+ i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_2_Template, 3, 0, "div", 163);
798
+ i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_66_Conditional_3_Template, 1, 0, "mj-empty-state", 164);
772
799
  i0.ɵɵelementEnd();
773
800
  } if (rf & 2) {
774
801
  const ctx_r0 = i0.ɵɵnextContext();
@@ -780,19 +807,19 @@ function MJTestFormComponentExtended_Conditional_66_Template(rf, ctx) { if (rf &
780
807
  i0.ɵɵconditional(ctx_r0.suiteTestsLoaded && !ctx_r0.loadingSuites && ctx_r0.suiteTests.length === 0 ? 3 : -1);
781
808
  } }
782
809
  function MJTestFormComponentExtended_Conditional_67_Conditional_1_Template(rf, ctx) { if (rf & 1) {
783
- i0.ɵɵelementStart(0, "div", 123);
784
- i0.ɵɵelement(1, "mj-loading", 171);
810
+ i0.ɵɵelementStart(0, "div", 125);
811
+ i0.ɵɵelement(1, "mj-loading", 173);
785
812
  i0.ɵɵelementEnd();
786
813
  } }
787
814
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template(rf, ctx) { if (rf & 1) {
788
- i0.ɵɵelementStart(0, "div", 181)(1, "div", 187);
789
- i0.ɵɵelement(2, "i", 188);
815
+ i0.ɵɵelementStart(0, "div", 183)(1, "div", 189);
816
+ i0.ɵɵelement(2, "i", 190);
790
817
  i0.ɵɵelementEnd();
791
- i0.ɵɵelementStart(3, "div", 184)(4, "div", 185);
818
+ i0.ɵɵelementStart(3, "div", 186)(4, "div", 187);
792
819
  i0.ɵɵtext(5);
793
- i0.ɵɵelement(6, "i", 189);
820
+ i0.ɵɵelement(6, "i", 191);
794
821
  i0.ɵɵelementEnd();
795
- i0.ɵɵelementStart(7, "div", 186);
822
+ i0.ɵɵelementStart(7, "div", 188);
796
823
  i0.ɵɵtext(8, "Pass Rate");
797
824
  i0.ɵɵelementEnd()()();
798
825
  } if (rf & 2) {
@@ -803,13 +830,13 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17
803
830
  i0.ɵɵclassProp("fa-arrow-up", ctx_r0.getPassRateTrend() === "up")("fa-arrow-down", ctx_r0.getPassRateTrend() === "down")("fa-minus", ctx_r0.getPassRateTrend() === "stable")("trend-up", ctx_r0.getPassRateTrend() === "up")("trend-down", ctx_r0.getPassRateTrend() === "down");
804
831
  } }
805
832
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template(rf, ctx) { if (rf & 1) {
806
- i0.ɵɵelementStart(0, "div", 181)(1, "div", 182);
807
- i0.ɵɵelement(2, "i", 190);
833
+ i0.ɵɵelementStart(0, "div", 183)(1, "div", 184);
834
+ i0.ɵɵelement(2, "i", 192);
808
835
  i0.ɵɵelementEnd();
809
- i0.ɵɵelementStart(3, "div", 184)(4, "div", 185);
836
+ i0.ɵɵelementStart(3, "div", 186)(4, "div", 187);
810
837
  i0.ɵɵtext(5);
811
838
  i0.ɵɵelementEnd();
812
- i0.ɵɵelementStart(6, "div", 186);
839
+ i0.ɵɵelementStart(6, "div", 188);
813
840
  i0.ɵɵtext(7, "Avg Score");
814
841
  i0.ɵɵelementEnd()()();
815
842
  } if (rf & 2) {
@@ -818,33 +845,33 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17
818
845
  i0.ɵɵtextInterpolate1("", (ctx_r0.getOverallAvgScore() * 100).toFixed(1), "%");
819
846
  } }
820
847
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
821
- i0.ɵɵelementStart(0, "div", 178)(1, "div", 181)(2, "div", 182);
822
- i0.ɵɵelement(3, "i", 183);
848
+ i0.ɵɵelementStart(0, "div", 180)(1, "div", 183)(2, "div", 184);
849
+ i0.ɵɵelement(3, "i", 185);
823
850
  i0.ɵɵelementEnd();
824
- i0.ɵɵelementStart(4, "div", 184)(5, "div", 185);
851
+ i0.ɵɵelementStart(4, "div", 186)(5, "div", 187);
825
852
  i0.ɵɵtext(6);
826
853
  i0.ɵɵelementEnd();
827
- i0.ɵɵelementStart(7, "div", 186);
854
+ i0.ɵɵelementStart(7, "div", 188);
828
855
  i0.ɵɵtext(8, "Total Runs");
829
856
  i0.ɵɵelementEnd()()();
830
- i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template, 9, 11, "div", 181);
831
- i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template, 8, 1, "div", 181);
832
- i0.ɵɵelementStart(11, "div", 181)(12, "div", 182);
833
- i0.ɵɵelement(13, "i", 147);
857
+ i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template, 9, 11, "div", 183);
858
+ i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template, 8, 1, "div", 183);
859
+ i0.ɵɵelementStart(11, "div", 183)(12, "div", 184);
860
+ i0.ɵɵelement(13, "i", 149);
834
861
  i0.ɵɵelementEnd();
835
- i0.ɵɵelementStart(14, "div", 184)(15, "div", 185);
862
+ i0.ɵɵelementStart(14, "div", 186)(15, "div", 187);
836
863
  i0.ɵɵtext(16);
837
864
  i0.ɵɵelementEnd();
838
- i0.ɵɵelementStart(17, "div", 186);
865
+ i0.ɵɵelementStart(17, "div", 188);
839
866
  i0.ɵɵtext(18, "Avg Duration");
840
867
  i0.ɵɵelementEnd()()();
841
- i0.ɵɵelementStart(19, "div", 181)(20, "div", 182);
842
- i0.ɵɵelement(21, "i", 148);
868
+ i0.ɵɵelementStart(19, "div", 183)(20, "div", 184);
869
+ i0.ɵɵelement(21, "i", 150);
843
870
  i0.ɵɵelementEnd();
844
- i0.ɵɵelementStart(22, "div", 184)(23, "div", 185);
871
+ i0.ɵɵelementStart(22, "div", 186)(23, "div", 187);
845
872
  i0.ɵɵtext(24);
846
873
  i0.ɵɵelementEnd();
847
- i0.ɵɵelementStart(25, "div", 186);
874
+ i0.ɵɵelementStart(25, "div", 188);
848
875
  i0.ɵɵtext(26, "Avg Cost");
849
876
  i0.ɵɵelementEnd()()()();
850
877
  } if (rf & 2) {
@@ -881,70 +908,70 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
881
908
  i0.ɵɵelementEnd();
882
909
  } }
883
910
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template(rf, ctx) { if (rf & 1) {
884
- i0.ɵɵelementStart(0, "td", 196);
911
+ i0.ɵɵelementStart(0, "td", 198);
885
912
  i0.ɵɵtext(1);
886
913
  i0.ɵɵelementEnd();
887
914
  } if (rf & 2) {
888
- const day_r17 = i0.ɵɵnextContext().$implicit;
915
+ const day_r18 = i0.ɵɵnextContext().$implicit;
889
916
  i0.ɵɵadvance();
890
- i0.ɵɵtextInterpolate(day_r17.passCount);
917
+ i0.ɵɵtextInterpolate(day_r18.passCount);
891
918
  } }
892
919
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template(rf, ctx) { if (rf & 1) {
893
- i0.ɵɵelementStart(0, "td", 197);
920
+ i0.ɵɵelementStart(0, "td", 199);
894
921
  i0.ɵɵtext(1);
895
922
  i0.ɵɵelementEnd();
896
923
  } if (rf & 2) {
897
- const day_r17 = i0.ɵɵnextContext().$implicit;
924
+ const day_r18 = i0.ɵɵnextContext().$implicit;
898
925
  i0.ɵɵadvance();
899
- i0.ɵɵtextInterpolate(day_r17.failCount);
926
+ i0.ɵɵtextInterpolate(day_r18.failCount);
900
927
  } }
901
928
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template(rf, ctx) { if (rf & 1) {
902
- i0.ɵɵelementStart(0, "td", 198)(1, "div", 202);
903
- i0.ɵɵelement(2, "div", 203);
904
- i0.ɵɵelementStart(3, "span", 204);
929
+ i0.ɵɵelementStart(0, "td", 200)(1, "div", 204);
930
+ i0.ɵɵelement(2, "div", 205);
931
+ i0.ɵɵelementStart(3, "span", 206);
905
932
  i0.ɵɵtext(4);
906
933
  i0.ɵɵelementEnd()()();
907
934
  } if (rf & 2) {
908
- const day_r17 = i0.ɵɵnextContext().$implicit;
935
+ const day_r18 = i0.ɵɵnextContext().$implicit;
909
936
  i0.ɵɵadvance(2);
910
- i0.ɵɵstyleProp("width", day_r17.passRate, "%");
937
+ i0.ɵɵstyleProp("width", day_r18.passRate, "%");
911
938
  i0.ɵɵadvance(2);
912
- i0.ɵɵtextInterpolate1("", day_r17.passRate.toFixed(1), "%");
939
+ i0.ɵɵtextInterpolate1("", day_r18.passRate.toFixed(1), "%");
913
940
  } }
914
941
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template(rf, ctx) { if (rf & 1) {
915
- i0.ɵɵelementStart(0, "td", 199);
942
+ i0.ɵɵelementStart(0, "td", 201);
916
943
  i0.ɵɵtext(1);
917
944
  i0.ɵɵelementEnd();
918
945
  } if (rf & 2) {
919
- const day_r17 = i0.ɵɵnextContext().$implicit;
946
+ const day_r18 = i0.ɵɵnextContext().$implicit;
920
947
  i0.ɵɵadvance();
921
- i0.ɵɵtextInterpolate1("", (day_r17.avgScore * 100).toFixed(1), "%");
948
+ i0.ɵɵtextInterpolate1("", (day_r18.avgScore * 100).toFixed(1), "%");
922
949
  } }
923
950
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Template(rf, ctx) { if (rf & 1) {
924
- i0.ɵɵelementStart(0, "tr")(1, "td", 194);
951
+ i0.ɵɵelementStart(0, "tr")(1, "td", 196);
925
952
  i0.ɵɵtext(2);
926
953
  i0.ɵɵpipe(3, "date");
927
954
  i0.ɵɵelementEnd();
928
- i0.ɵɵelementStart(4, "td", 195);
955
+ i0.ɵɵelementStart(4, "td", 197);
929
956
  i0.ɵɵtext(5);
930
957
  i0.ɵɵelementEnd();
931
- i0.ɵɵconditionalCreate(6, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template, 2, 1, "td", 196);
932
- i0.ɵɵconditionalCreate(7, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template, 2, 1, "td", 197);
933
- i0.ɵɵconditionalCreate(8, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template, 5, 3, "td", 198);
934
- i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template, 2, 1, "td", 199);
935
- i0.ɵɵelementStart(10, "td", 200);
958
+ i0.ɵɵconditionalCreate(6, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template, 2, 1, "td", 198);
959
+ i0.ɵɵconditionalCreate(7, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template, 2, 1, "td", 199);
960
+ i0.ɵɵconditionalCreate(8, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template, 5, 3, "td", 200);
961
+ i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template, 2, 1, "td", 201);
962
+ i0.ɵɵelementStart(10, "td", 202);
936
963
  i0.ɵɵtext(11);
937
964
  i0.ɵɵelementEnd();
938
- i0.ɵɵelementStart(12, "td", 201);
965
+ i0.ɵɵelementStart(12, "td", 203);
939
966
  i0.ɵɵtext(13);
940
967
  i0.ɵɵelementEnd()();
941
968
  } if (rf & 2) {
942
- const day_r17 = ctx.$implicit;
969
+ const day_r18 = ctx.$implicit;
943
970
  const ctx_r0 = i0.ɵɵnextContext(4);
944
971
  i0.ɵɵadvance(2);
945
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 8, day_r17.date, "mediumDate"));
972
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 8, day_r18.date, "mediumDate"));
946
973
  i0.ɵɵadvance(3);
947
- i0.ɵɵtextInterpolate(day_r17.runCount);
974
+ i0.ɵɵtextInterpolate(day_r18.runCount);
948
975
  i0.ɵɵadvance();
949
976
  i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 6 : -1);
950
977
  i0.ɵɵadvance();
@@ -954,16 +981,16 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
954
981
  i0.ɵɵadvance();
955
982
  i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 9 : -1);
956
983
  i0.ɵɵadvance(2);
957
- i0.ɵɵtextInterpolate(ctx_r0.formatDuration(day_r17.avgDuration));
984
+ i0.ɵɵtextInterpolate(ctx_r0.formatDuration(day_r18.avgDuration));
958
985
  i0.ɵɵadvance(2);
959
- i0.ɵɵtextInterpolate(ctx_r0.formatCost(day_r17.avgCost));
986
+ i0.ɵɵtextInterpolate(ctx_r0.formatCost(day_r18.avgCost));
960
987
  } }
961
988
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
962
- i0.ɵɵelementStart(0, "div", 179)(1, "h3");
963
- i0.ɵɵelement(2, "i", 191);
989
+ i0.ɵɵelementStart(0, "div", 181)(1, "h3");
990
+ i0.ɵɵelement(2, "i", 193);
964
991
  i0.ɵɵtext(3, " Daily Performance");
965
992
  i0.ɵɵelementEnd();
966
- i0.ɵɵelementStart(4, "div", 192)(5, "table", 193)(6, "thead")(7, "tr")(8, "th");
993
+ i0.ɵɵelementStart(4, "div", 194)(5, "table", 195)(6, "thead")(7, "tr")(8, "th");
967
994
  i0.ɵɵtext(9, "Date");
968
995
  i0.ɵɵelementEnd();
969
996
  i0.ɵɵelementStart(10, "th");
@@ -996,134 +1023,134 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
996
1023
  i0.ɵɵrepeater(ctx_r0.historyData);
997
1024
  } }
998
1025
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
999
- i0.ɵɵelementStart(0, "span", 216);
1026
+ i0.ɵɵelementStart(0, "span", 218);
1000
1027
  i0.ɵɵtext(1);
1001
1028
  i0.ɵɵelementEnd();
1002
1029
  } if (rf & 2) {
1003
- const tag_r20 = ctx.$implicit;
1030
+ const tag_r21 = ctx.$implicit;
1004
1031
  i0.ɵɵadvance();
1005
- i0.ɵɵtextInterpolate(tag_r20);
1032
+ i0.ɵɵtextInterpolate(tag_r21);
1006
1033
  } }
1007
1034
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
1008
- i0.ɵɵelementStart(0, "span", 217);
1035
+ i0.ɵɵelementStart(0, "span", 219);
1009
1036
  i0.ɵɵtext(1);
1010
1037
  i0.ɵɵelementEnd();
1011
1038
  } if (rf & 2) {
1012
- const suite_r19 = i0.ɵɵnextContext(2).$implicit;
1039
+ const suite_r20 = i0.ɵɵnextContext(2).$implicit;
1013
1040
  i0.ɵɵadvance();
1014
- i0.ɵɵtextInterpolate1("+", suite_r19.tags.length - 3);
1041
+ i0.ɵɵtextInterpolate1("+", suite_r20.tags.length - 3);
1015
1042
  } }
1016
1043
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
1017
- i0.ɵɵelementStart(0, "div", 210);
1018
- i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template, 2, 1, "span", 216, i0.ɵɵrepeaterTrackByIdentity);
1019
- i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template, 2, 1, "span", 217);
1044
+ i0.ɵɵelementStart(0, "div", 212);
1045
+ i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template, 2, 1, "span", 218, i0.ɵɵrepeaterTrackByIdentity);
1046
+ i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template, 2, 1, "span", 219);
1020
1047
  i0.ɵɵelementEnd();
1021
1048
  } if (rf & 2) {
1022
- const suite_r19 = i0.ɵɵnextContext().$implicit;
1049
+ const suite_r20 = i0.ɵɵnextContext().$implicit;
1023
1050
  i0.ɵɵadvance();
1024
- i0.ɵɵrepeater(suite_r19.tags.slice(0, 3));
1051
+ i0.ɵɵrepeater(suite_r20.tags.slice(0, 3));
1025
1052
  i0.ɵɵadvance(2);
1026
- i0.ɵɵconditional(suite_r19.tags.length > 3 ? 3 : -1);
1053
+ i0.ɵɵconditional(suite_r20.tags.length > 3 ? 3 : -1);
1027
1054
  } }
1028
1055
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template(rf, ctx) { if (rf & 1) {
1029
- i0.ɵɵelementStart(0, "div", 212)(1, "span", 218);
1056
+ i0.ɵɵelementStart(0, "div", 214)(1, "span", 220);
1030
1057
  i0.ɵɵtext(2);
1031
1058
  i0.ɵɵelementEnd();
1032
- i0.ɵɵelementStart(3, "span", 214);
1059
+ i0.ɵɵelementStart(3, "span", 216);
1033
1060
  i0.ɵɵtext(4, "Pass Rate");
1034
1061
  i0.ɵɵelementEnd()();
1035
1062
  } if (rf & 2) {
1036
- const suite_r19 = i0.ɵɵnextContext().$implicit;
1063
+ const suite_r20 = i0.ɵɵnextContext().$implicit;
1037
1064
  i0.ɵɵadvance();
1038
- i0.ɵɵclassProp("high", suite_r19.passRate >= 80)("low", suite_r19.passRate < 50);
1065
+ i0.ɵɵclassProp("high", suite_r20.passRate >= 80)("low", suite_r20.passRate < 50);
1039
1066
  i0.ɵɵadvance();
1040
- i0.ɵɵtextInterpolate1(" ", suite_r19.passRate.toFixed(1), "% ");
1067
+ i0.ɵɵtextInterpolate1(" ", suite_r20.passRate.toFixed(1), "% ");
1041
1068
  } }
1042
1069
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template(rf, ctx) { if (rf & 1) {
1043
- i0.ɵɵelementStart(0, "div", 212)(1, "span", 213);
1070
+ i0.ɵɵelementStart(0, "div", 214)(1, "span", 215);
1044
1071
  i0.ɵɵtext(2);
1045
1072
  i0.ɵɵelementEnd();
1046
- i0.ɵɵelementStart(3, "span", 214);
1073
+ i0.ɵɵelementStart(3, "span", 216);
1047
1074
  i0.ɵɵtext(4, "Avg Score");
1048
1075
  i0.ɵɵelementEnd()();
1049
1076
  } if (rf & 2) {
1050
- const suite_r19 = i0.ɵɵnextContext().$implicit;
1077
+ const suite_r20 = i0.ɵɵnextContext().$implicit;
1051
1078
  i0.ɵɵadvance(2);
1052
- i0.ɵɵtextInterpolate1("", (suite_r19.avgScore * 100).toFixed(1), "%");
1079
+ i0.ɵɵtextInterpolate1("", (suite_r20.avgScore * 100).toFixed(1), "%");
1053
1080
  } }
1054
1081
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template(rf, ctx) { if (rf & 1) {
1055
- i0.ɵɵelementStart(0, "div", 212)(1, "span", 213);
1082
+ i0.ɵɵelementStart(0, "div", 214)(1, "span", 215);
1056
1083
  i0.ɵɵtext(2);
1057
1084
  i0.ɵɵelementEnd();
1058
- i0.ɵɵelementStart(3, "span", 214);
1085
+ i0.ɵɵelementStart(3, "span", 216);
1059
1086
  i0.ɵɵtext(4, "Last Run");
1060
1087
  i0.ɵɵelementEnd()();
1061
1088
  } if (rf & 2) {
1062
- const suite_r19 = i0.ɵɵnextContext().$implicit;
1089
+ const suite_r20 = i0.ɵɵnextContext().$implicit;
1063
1090
  const ctx_r0 = i0.ɵɵnextContext(4);
1064
1091
  i0.ɵɵadvance(2);
1065
- i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(suite_r19.lastRun));
1092
+ i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(suite_r20.lastRun));
1066
1093
  } }
1067
1094
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template(rf, ctx) { if (rf & 1) {
1068
- const _r18 = i0.ɵɵgetCurrentView();
1069
- i0.ɵɵelementStart(0, "div", 207);
1070
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template_div_click_0_listener() { const suite_r19 = i0.ɵɵrestoreView(_r18).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.openSuiteFromHistory(suite_r19.suiteId)); });
1071
- i0.ɵɵelementStart(1, "div", 208)(2, "div", 209);
1095
+ const _r19 = i0.ɵɵgetCurrentView();
1096
+ i0.ɵɵelementStart(0, "div", 209);
1097
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template_div_click_0_listener() { const suite_r20 = i0.ɵɵrestoreView(_r19).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.openSuiteFromHistory(suite_r20.suiteId)); });
1098
+ i0.ɵɵelementStart(1, "div", 210)(2, "div", 211);
1072
1099
  i0.ɵɵtext(3);
1073
1100
  i0.ɵɵelementEnd();
1074
- i0.ɵɵconditionalCreate(4, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template, 4, 1, "div", 210);
1101
+ i0.ɵɵconditionalCreate(4, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template, 4, 1, "div", 212);
1075
1102
  i0.ɵɵelementEnd();
1076
- i0.ɵɵelementStart(5, "div", 211)(6, "div", 212)(7, "span", 213);
1103
+ i0.ɵɵelementStart(5, "div", 213)(6, "div", 214)(7, "span", 215);
1077
1104
  i0.ɵɵtext(8);
1078
1105
  i0.ɵɵelementEnd();
1079
- i0.ɵɵelementStart(9, "span", 214);
1106
+ i0.ɵɵelementStart(9, "span", 216);
1080
1107
  i0.ɵɵtext(10, "Runs");
1081
1108
  i0.ɵɵelementEnd()();
1082
- i0.ɵɵconditionalCreate(11, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template, 5, 5, "div", 212);
1083
- i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template, 5, 1, "div", 212);
1084
- i0.ɵɵelementStart(13, "div", 212)(14, "span", 213);
1109
+ i0.ɵɵconditionalCreate(11, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template, 5, 5, "div", 214);
1110
+ i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template, 5, 1, "div", 214);
1111
+ i0.ɵɵelementStart(13, "div", 214)(14, "span", 215);
1085
1112
  i0.ɵɵtext(15);
1086
1113
  i0.ɵɵelementEnd();
1087
- i0.ɵɵelementStart(16, "span", 214);
1114
+ i0.ɵɵelementStart(16, "span", 216);
1088
1115
  i0.ɵɵtext(17, "Avg Duration");
1089
1116
  i0.ɵɵelementEnd()();
1090
- i0.ɵɵelementStart(18, "div", 212)(19, "span", 213);
1117
+ i0.ɵɵelementStart(18, "div", 214)(19, "span", 215);
1091
1118
  i0.ɵɵtext(20);
1092
1119
  i0.ɵɵelementEnd();
1093
- i0.ɵɵelementStart(21, "span", 214);
1120
+ i0.ɵɵelementStart(21, "span", 216);
1094
1121
  i0.ɵɵtext(22, "Avg Cost");
1095
1122
  i0.ɵɵelementEnd()();
1096
- i0.ɵɵconditionalCreate(23, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template, 5, 1, "div", 212);
1123
+ i0.ɵɵconditionalCreate(23, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template, 5, 1, "div", 214);
1097
1124
  i0.ɵɵelementEnd();
1098
- i0.ɵɵelement(24, "i", 215);
1125
+ i0.ɵɵelement(24, "i", 217);
1099
1126
  i0.ɵɵelementEnd();
1100
1127
  } if (rf & 2) {
1101
- const suite_r19 = ctx.$implicit;
1128
+ const suite_r20 = ctx.$implicit;
1102
1129
  const ctx_r0 = i0.ɵɵnextContext(4);
1103
1130
  i0.ɵɵadvance(3);
1104
- i0.ɵɵtextInterpolate(suite_r19.suiteName);
1131
+ i0.ɵɵtextInterpolate(suite_r20.suiteName);
1105
1132
  i0.ɵɵadvance();
1106
- i0.ɵɵconditional(suite_r19.tags.length > 0 ? 4 : -1);
1133
+ i0.ɵɵconditional(suite_r20.tags.length > 0 ? 4 : -1);
1107
1134
  i0.ɵɵadvance(4);
1108
- i0.ɵɵtextInterpolate(suite_r19.totalRuns);
1135
+ i0.ɵɵtextInterpolate(suite_r20.totalRuns);
1109
1136
  i0.ɵɵadvance(3);
1110
1137
  i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 11 : -1);
1111
1138
  i0.ɵɵadvance();
1112
1139
  i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 12 : -1);
1113
1140
  i0.ɵɵadvance(3);
1114
- i0.ɵɵtextInterpolate(ctx_r0.formatDuration(suite_r19.avgDuration));
1141
+ i0.ɵɵtextInterpolate(ctx_r0.formatDuration(suite_r20.avgDuration));
1115
1142
  i0.ɵɵadvance(5);
1116
- i0.ɵɵtextInterpolate(ctx_r0.formatCost(suite_r19.avgCost));
1143
+ i0.ɵɵtextInterpolate(ctx_r0.formatCost(suite_r20.avgCost));
1117
1144
  i0.ɵɵadvance(3);
1118
- i0.ɵɵconditional(suite_r19.lastRun ? 23 : -1);
1145
+ i0.ɵɵconditional(suite_r20.lastRun ? 23 : -1);
1119
1146
  } }
1120
1147
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
1121
- i0.ɵɵelementStart(0, "div", 179)(1, "h3");
1148
+ i0.ɵɵelementStart(0, "div", 181)(1, "h3");
1122
1149
  i0.ɵɵelement(2, "i", 33);
1123
1150
  i0.ɵɵtext(3, " Performance by Suite");
1124
1151
  i0.ɵɵelementEnd();
1125
- i0.ɵɵelementStart(4, "div", 205);
1126
- i0.ɵɵrepeaterCreate(5, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template, 25, 8, "div", 206, i0.ɵɵrepeaterTrackByIdentity);
1152
+ i0.ɵɵelementStart(4, "div", 207);
1153
+ i0.ɵɵrepeaterCreate(5, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template, 25, 8, "div", 208, i0.ɵɵrepeaterTrackByIdentity);
1127
1154
  i0.ɵɵelementEnd()();
1128
1155
  } if (rf & 2) {
1129
1156
  const ctx_r0 = i0.ɵɵnextContext(3);
@@ -1131,41 +1158,41 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
1131
1158
  i0.ɵɵrepeater(ctx_r0.suitePerformance);
1132
1159
  } }
1133
1160
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
1134
- const _r21 = i0.ɵɵgetCurrentView();
1135
- i0.ɵɵelementStart(0, "mj-empty-state", 219);
1136
- i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(_r21); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.runTest()); });
1161
+ const _r22 = i0.ɵɵgetCurrentView();
1162
+ i0.ɵɵelementStart(0, "mj-empty-state", 221);
1163
+ i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(_r22); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.runTest()); });
1137
1164
  i0.ɵɵelementEnd();
1138
1165
  } }
1139
1166
  function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template(rf, ctx) { if (rf & 1) {
1140
- const _r16 = i0.ɵɵgetCurrentView();
1141
- i0.ɵɵelementStart(0, "div", 170)(1, "div", 172)(2, "div", 173)(3, "span", 174);
1167
+ const _r17 = i0.ɵɵgetCurrentView();
1168
+ i0.ɵɵelementStart(0, "div", 172)(1, "div", 174)(2, "div", 175)(3, "span", 176);
1142
1169
  i0.ɵɵtext(4, "Time Range:");
1143
1170
  i0.ɵɵelementEnd();
1144
- i0.ɵɵelementStart(5, "button", 175);
1145
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("7d")); });
1171
+ i0.ɵɵelementStart(5, "button", 177);
1172
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("7d")); });
1146
1173
  i0.ɵɵtext(6, "7 Days");
1147
1174
  i0.ɵɵelementEnd();
1148
- i0.ɵɵelementStart(7, "button", 175);
1149
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("30d")); });
1175
+ i0.ɵɵelementStart(7, "button", 177);
1176
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("30d")); });
1150
1177
  i0.ɵɵtext(8, "30 Days");
1151
1178
  i0.ɵɵelementEnd();
1152
- i0.ɵɵelementStart(9, "button", 175);
1153
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("90d")); });
1179
+ i0.ɵɵelementStart(9, "button", 177);
1180
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("90d")); });
1154
1181
  i0.ɵɵtext(10, "90 Days");
1155
1182
  i0.ɵɵelementEnd();
1156
- i0.ɵɵelementStart(11, "button", 175);
1157
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("all")); });
1183
+ i0.ɵɵelementStart(11, "button", 177);
1184
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("all")); });
1158
1185
  i0.ɵɵtext(12, "All Time");
1159
1186
  i0.ɵɵelementEnd()();
1160
- i0.ɵɵelementStart(13, "div", 176)(14, "button", 23);
1161
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.exportHistoryToCSV()); });
1162
- i0.ɵɵelement(15, "i", 177);
1187
+ i0.ɵɵelementStart(13, "div", 178)(14, "button", 23);
1188
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.exportHistoryToCSV()); });
1189
+ i0.ɵɵelement(15, "i", 179);
1163
1190
  i0.ɵɵtext(16, " Export CSV ");
1164
1191
  i0.ɵɵelementEnd()()();
1165
- i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template, 27, 5, "div", 178);
1166
- i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template, 23, 4, "div", 179);
1167
- i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template, 7, 0, "div", 179);
1168
- i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template, 1, 0, "mj-empty-state", 180);
1192
+ i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template, 27, 5, "div", 180);
1193
+ i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template, 23, 4, "div", 181);
1194
+ i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template, 7, 0, "div", 181);
1195
+ i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template, 1, 0, "mj-empty-state", 182);
1169
1196
  i0.ɵɵelementEnd();
1170
1197
  } if (rf & 2) {
1171
1198
  const ctx_r0 = i0.ɵɵnextContext(2);
@@ -1190,8 +1217,8 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template(rf, c
1190
1217
  } }
1191
1218
  function MJTestFormComponentExtended_Conditional_67_Template(rf, ctx) { if (rf & 1) {
1192
1219
  i0.ɵɵelementStart(0, "div", 40);
1193
- i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_1_Template, 2, 0, "div", 123);
1194
- i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_67_Conditional_2_Template, 21, 13, "div", 170);
1220
+ i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_1_Template, 2, 0, "div", 125);
1221
+ i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_67_Conditional_2_Template, 21, 13, "div", 172);
1195
1222
  i0.ɵɵelementEnd();
1196
1223
  } if (rf & 2) {
1197
1224
  const ctx_r0 = i0.ɵɵnextContext();
@@ -1201,45 +1228,45 @@ function MJTestFormComponentExtended_Conditional_67_Template(rf, ctx) { if (rf &
1201
1228
  i0.ɵɵconditional(!ctx_r0.loadingHistory && ctx_r0.historyLoaded ? 2 : -1);
1202
1229
  } }
1203
1230
  function MJTestFormComponentExtended_Conditional_70_Template(rf, ctx) { if (rf & 1) {
1204
- const _r22 = i0.ɵɵgetCurrentView();
1205
- i0.ɵɵelementStart(0, "div", 43)(1, "div", 220);
1231
+ const _r23 = i0.ɵɵgetCurrentView();
1232
+ i0.ɵɵelementStart(0, "div", 43)(1, "div", 222);
1206
1233
  i0.ɵɵelement(2, "i", 42);
1207
1234
  i0.ɵɵtext(3, " Shortcuts ");
1208
- i0.ɵɵelementStart(4, "button", 221);
1209
- i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_70_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r22); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleShortcuts()); });
1210
- i0.ɵɵelement(5, "i", 122);
1235
+ i0.ɵɵelementStart(4, "button", 223);
1236
+ i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_70_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r23); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleShortcuts()); });
1237
+ i0.ɵɵelement(5, "i", 124);
1211
1238
  i0.ɵɵelementEnd()();
1212
- i0.ɵɵelementStart(6, "div", 222)(7, "div", 223)(8, "span");
1239
+ i0.ɵɵelementStart(6, "div", 224)(7, "div", 225)(8, "span");
1213
1240
  i0.ɵɵtext(9, "Save changes");
1214
1241
  i0.ɵɵelementEnd();
1215
- i0.ɵɵelementStart(10, "span", 224)(11, "kbd");
1242
+ i0.ɵɵelementStart(10, "span", 226)(11, "kbd");
1216
1243
  i0.ɵɵtext(12, "Cmd");
1217
1244
  i0.ɵɵelementEnd();
1218
1245
  i0.ɵɵelementStart(13, "kbd");
1219
1246
  i0.ɵɵtext(14, "S");
1220
1247
  i0.ɵɵelementEnd()()();
1221
- i0.ɵɵelementStart(15, "div", 223)(16, "span");
1248
+ i0.ɵɵelementStart(15, "div", 225)(16, "span");
1222
1249
  i0.ɵɵtext(17, "Refresh");
1223
1250
  i0.ɵɵelementEnd();
1224
- i0.ɵɵelementStart(18, "span", 224)(19, "kbd");
1251
+ i0.ɵɵelementStart(18, "span", 226)(19, "kbd");
1225
1252
  i0.ɵɵtext(20, "Cmd");
1226
1253
  i0.ɵɵelementEnd();
1227
1254
  i0.ɵɵelementStart(21, "kbd");
1228
1255
  i0.ɵɵtext(22, "R");
1229
1256
  i0.ɵɵelementEnd()()();
1230
- i0.ɵɵelementStart(23, "div", 223)(24, "span");
1257
+ i0.ɵɵelementStart(23, "div", 225)(24, "span");
1231
1258
  i0.ɵɵtext(25, "Run Test");
1232
1259
  i0.ɵɵelementEnd();
1233
- i0.ɵɵelementStart(26, "span", 224)(27, "kbd");
1260
+ i0.ɵɵelementStart(26, "span", 226)(27, "kbd");
1234
1261
  i0.ɵɵtext(28, "Cmd");
1235
1262
  i0.ɵɵelementEnd();
1236
1263
  i0.ɵɵelementStart(29, "kbd");
1237
1264
  i0.ɵɵtext(30, "Enter");
1238
1265
  i0.ɵɵelementEnd()()();
1239
- i0.ɵɵelementStart(31, "div", 223)(32, "span");
1266
+ i0.ɵɵelementStart(31, "div", 225)(32, "span");
1240
1267
  i0.ɵɵtext(33, "Switch Tabs");
1241
1268
  i0.ɵɵelementEnd();
1242
- i0.ɵɵelementStart(34, "span", 224)(35, "kbd");
1269
+ i0.ɵɵelementStart(34, "span", 226)(35, "kbd");
1243
1270
  i0.ɵɵtext(36, "1");
1244
1271
  i0.ɵɵelementEnd();
1245
1272
  i0.ɵɵtext(37, "-");
@@ -1248,11 +1275,11 @@ function MJTestFormComponentExtended_Conditional_70_Template(rf, ctx) { if (rf &
1248
1275
  i0.ɵɵelementEnd()()()()();
1249
1276
  } }
1250
1277
  function MJTestFormComponentExtended_Conditional_71_Template(rf, ctx) { if (rf & 1) {
1251
- const _r23 = i0.ɵɵgetCurrentView();
1252
- i0.ɵɵelementStart(0, "mj-slide-panel", 225);
1253
- i0.ɵɵlistener("Closed", function MJTestFormComponentExtended_Conditional_71_Template_mj_slide_panel_Closed_0_listener() { i0.ɵɵrestoreView(_r23); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
1254
- i0.ɵɵelementStart(1, "app-test-run-dialog", 226);
1255
- i0.ɵɵlistener("PanelClose", function MJTestFormComponentExtended_Conditional_71_Template_app_test_run_dialog_PanelClose_1_listener() { i0.ɵɵrestoreView(_r23); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
1278
+ const _r24 = i0.ɵɵgetCurrentView();
1279
+ i0.ɵɵelementStart(0, "mj-slide-panel", 227);
1280
+ i0.ɵɵlistener("Closed", function MJTestFormComponentExtended_Conditional_71_Template_mj_slide_panel_Closed_0_listener() { i0.ɵɵrestoreView(_r24); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
1281
+ i0.ɵɵelementStart(1, "app-test-run-dialog", 228);
1282
+ i0.ɵɵlistener("PanelClose", function MJTestFormComponentExtended_Conditional_71_Template_app_test_run_dialog_PanelClose_1_listener() { i0.ɵɵrestoreView(_r24); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
1256
1283
  i0.ɵɵelementEnd()();
1257
1284
  } if (rf & 2) {
1258
1285
  const ctx_r0 = i0.ɵɵnextContext();
@@ -1273,13 +1300,13 @@ function MJTestFormComponentExtended_Conditional_81_Template(rf, ctx) { if (rf &
1273
1300
  i0.ɵɵtextInterpolate1(" ", ctx_r0.dirtyFieldNames.length, " fields edited ");
1274
1301
  } }
1275
1302
  function MJTestFormComponentExtended_Conditional_84_Template(rf, ctx) { if (rf & 1) {
1276
- i0.ɵɵelement(0, "i", 227);
1303
+ i0.ɵɵelement(0, "i", 229);
1277
1304
  i0.ɵɵtext(1, " Saving\u2026 ");
1278
1305
  } }
1279
1306
  function MJTestFormComponentExtended_Conditional_85_Template(rf, ctx) { if (rf & 1) {
1280
- i0.ɵɵelement(0, "i", 228);
1307
+ i0.ɵɵelement(0, "i", 230);
1281
1308
  i0.ɵɵtext(1, " Save changes ");
1282
- i0.ɵɵelementStart(2, "span", 229)(3, "kbd");
1309
+ i0.ɵɵelementStart(2, "span", 231)(3, "kbd");
1283
1310
  i0.ɵɵtext(4, "\u2318");
1284
1311
  i0.ɵɵelementEnd();
1285
1312
  i0.ɵɵelementStart(5, "kbd");
@@ -1336,6 +1363,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
1336
1363
  // Edit state
1337
1364
  this.IsSaving = false;
1338
1365
  this.TestTypeOptions = [];
1366
+ this.RubricOptions = [];
1339
1367
  this.TagDraft = '';
1340
1368
  this.StatusOptions = ['Active', 'Pending', 'Disabled'];
1341
1369
  }
@@ -1557,6 +1585,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
1557
1585
  this.loadShortcutsSetting();
1558
1586
  // Fire-and-forget: test type list for the edit form
1559
1587
  this.loadTestTypeOptions();
1588
+ void this.loadRubricOptions();
1560
1589
  // Subscribe to evaluation preferences
1561
1590
  this.evalPrefsService.preferences$
1562
1591
  .pipe(takeUntil(this.destroy$))
@@ -2420,6 +2449,18 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
2420
2449
  get tags() {
2421
2450
  return TagsHelper.parseTags(this.record?.Tags);
2422
2451
  }
2452
+ /** Active rubrics for the RubricID picker. */
2453
+ async loadRubricOptions() {
2454
+ try {
2455
+ const rv = RunView.FromMetadataProvider(this.ProviderToUse);
2456
+ const result = await rv.RunView({ EntityName: 'MJ: Rubrics', ExtraFilter: `Status='Active'`, OrderBy: 'Name', ResultType: 'simple', MaxRows: 500 });
2457
+ this.RubricOptions = RubricPickerOptions((result.Results ?? []));
2458
+ this.cdr.markForCheck();
2459
+ }
2460
+ catch (error) {
2461
+ console.warn('Failed to load rubric options:', error);
2462
+ }
2463
+ }
2423
2464
  /** Load test types for the Type dropdown. */
2424
2465
  async loadTestTypeOptions() {
2425
2466
  try {
@@ -2535,7 +2576,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
2535
2576
  static { this.ɵfac = /*@__PURE__*/ (() => { let ɵMJTestFormComponentExtended_BaseFactory; return function MJTestFormComponentExtended_Factory(__ngFactoryType__) { return (ɵMJTestFormComponentExtended_BaseFactory || (ɵMJTestFormComponentExtended_BaseFactory = i0.ɵɵgetInheritedFactory(MJTestFormComponentExtended)))(__ngFactoryType__ || MJTestFormComponentExtended); }; })(); }
2536
2577
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTestFormComponentExtended, selectors: [["mj-test-form"]], hostBindings: function MJTestFormComponentExtended_HostBindings(rf, ctx) { if (rf & 1) {
2537
2578
  i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, i0.ɵɵresolveDocument)("beforeunload", function MJTestFormComponentExtended_beforeunload_HostBindingHandler($event) { return ctx.handleBeforeUnload($event); }, i0.ɵɵresolveWindow);
2538
- } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 89, vars: 51, consts: [["tagInput", ""], [1, "test-form"], [1, "test-header"], ["aria-label", "Breadcrumb", 1, "breadcrumb"], ["href", "javascript:void(0)", 3, "click"], [1, "fas", "fa-vial"], [1, "breadcrumb-text"], [1, "current"], [1, "fas", "fa-chevron-right", "separator"], [1, "fas", "fa-flask"], [1, "header-content"], [1, "header-left"], [1, "test-icon"], [1, "test-info"], ["title", "You have unsaved changes", "aria-label", "Unsaved changes", 1, "dirty-indicator"], [1, "test-meta"], [1, "status-badge", 3, "ngClass"], [1, "fas", 3, "ngClass"], [1, "test-type"], ["title", "You have unsaved changes", 1, "unsaved-pill"], [1, "header-actions"], ["mjButton", "", "variant", "primary", 3, "click"], [1, "fas", "fa-play"], ["mjButton", "", 3, "click", "disabled"], [1, "test-description"], [1, "metrics-bar"], [1, "tabs-container"], ["role", "tablist", 1, "tabs"], ["role", "tab", 1, "tab", 3, "click"], [1, "fas", "fa-th-large"], [1, "fas", "fa-sliders-h"], [1, "fas", "fa-history"], [1, "tab-badge"], [1, "fas", "fa-layer-group"], [1, "fas", "fa-chart-line"], [1, "tab-content"], [1, "overview-tab"], [1, "config-tab"], [1, "runs-tab"], [1, "suites-tab"], [1, "history-tab"], [1, "shortcuts-toggle", 3, "click", "title"], [1, "fas", "fa-keyboard"], [1, "keyboard-shortcuts"], ["Mode", "slide", 3, "Title", "Resizable"], ["role", "region", "aria-label", "Unsaved changes", 1, "save-bar"], [1, "save-bar-message"], ["aria-hidden", "true", 1, "save-bar-dot"], [1, "save-bar-text"], [1, "save-bar-fields"], [1, "save-bar-actions"], ["type", "button", "title", "Save changes (\u2318S)", 1, "save-bar-btn", "save-bar-btn--primary", 3, "click", "disabled"], ["type", "button", "title", "Discard changes", 1, "save-bar-btn", "save-bar-btn--ghost", 3, "click", "disabled"], [1, "fas", "fa-undo"], [1, "fas", "fa-tag"], [1, "fas", "fa-circle"], [1, "metric-card"], [1, "metric-label"], [1, "metric-value"], [1, "metric-progress"], [1, "metric-progress-fill"], [1, "info-section"], [1, "fas", "fa-info-circle"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], [1, "status-badge-inline", 3, "ngClass"], [1, "json-section"], [1, "fas", "fa-code"], [1, "json-tabs"], [1, "json-tab", 3, "click"], [1, "fas", "fa-sign-in-alt"], [1, "fas", "fa-check-double"], [1, "fas", "fa-cog"], [1, "fas", "fa-tags"], [1, "code-editor-container"], ["language", "json", 3, "value", "readonly", "toolbar", "lineWrapping"], [1, "edit-section"], [1, "edit-section-header"], [1, "fas", "fa-pen-to-square"], [1, "edit-section-sub"], [1, "edit-grid"], [1, "edit-field", "edit-field--full"], ["for", "test-name"], [1, "required"], ["id", "test-name", "type", "text", "placeholder", "e.g., Agent Response Quality Test", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-description"], ["id", "test-description", "rows", "3", "placeholder", "What does this test evaluate?", 1, "config-input", "config-textarea", 3, "ngModelChange", "ngModel"], [1, "edit-field"], ["for", "test-status"], [1, "select-wrapper"], ["id", "test-status", 1, "config-input", 3, "ngModelChange", "ngModel"], [3, "ngValue"], ["for", "test-type"], ["id", "test-type", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-tags"], [1, "tag-editor", 3, "click"], [1, "tag-chip-editable"], ["id", "test-tags", "type", "text", 1, "tag-input-inline", 3, "ngModelChange", "keydown", "blur", "placeholder", "ngModel"], [1, "config-hint"], [1, "fas", "fa-cogs"], ["for", "test-priority"], ["id", "test-priority", "type", "number", "placeholder", "0 (lower runs first)", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-repeat"], ["id", "test-repeat", "type", "number", "min", "1", "placeholder", "1", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-duration"], ["id", "test-duration", "type", "number", "placeholder", "0", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-cost"], ["id", "test-cost", "type", "number", "step", "0.000001", "placeholder", "0.00", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-timeout"], ["id", "test-timeout", "type", "number", "placeholder", "Default: 300000 (5 min)", 1, "config-input", 3, "ngModelChange", "ngModel"], [1, "config-section"], [1, "config-editor-container"], ["language", "json", 3, "change", "value", "readonly", "lineWrapping"], [1, "meta-section"], [1, "meta-grid"], [1, "meta-item"], [1, "meta-label"], [1, "meta-value"], [1, "meta-value", "meta-mono"], ["type", "button", 1, "tag-remove", 3, "click"], [1, "fas", "fa-times"], [1, "loading-state"], [1, "runs-list"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "skeleton-list"], [1, "skeleton-card"], [1, "skeleton-icon"], [1, "skeleton-content"], [1, "skeleton-line", "wide"], [1, "skeleton-line", "narrow"], [1, "run-item"], [1, "run-item", 3, "click"], [1, "run-icon"], [1, "fas"], [1, "run-content"], [1, "run-header"], [1, "run-id"], [1, "run-status"], [1, "run-meta"], [1, "fas", "fa-calendar"], [3, "entityName", "recordId"], [1, "run-eval-stack"], [1, "eval-pill", "status-pill", 3, "ngClass", "title"], [1, "run-tags"], [1, "fas", "fa-chevron-right"], [1, "fas", "fa-clock"], [1, "fas", "fa-dollar-sign"], ["title", "Human Review: No rating submitted yet", 1, "eval-pill", "human-pill", "no-feedback"], [1, "eval-pill", "human-pill", "has-feedback", 3, "rating-low", "rating-medium", "rating-good", "rating-excellent", "title"], [1, "fas", "fa-user-slash"], [1, "eval-pill", "human-pill", "has-feedback", 3, "title"], [1, "fas", "fa-user"], ["title", "Auto Score: No automated score available", 1, "eval-pill", "auto-pill", "no-score"], [1, "eval-pill", "auto-pill", "has-score", 3, "score-low", "score-medium", "score-good", "score-excellent", "title"], [1, "fas", "fa-robot"], [1, "eval-pill", "auto-pill", "has-score", 3, "title"], [1, "run-tag"], [1, "run-tag-more"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "suites-list"], ["Icon", "fa-solid fa-folder-open", "Title", "Not Part of Any Suite", "Message", "This test is not included in any test suites. Add it to a suite to run it with other tests."], [1, "suite-item"], [1, "suite-item", 3, "click"], [1, "suite-icon"], [1, "suite-content"], [1, "suite-name"], [1, "suite-meta"], [1, "fas", "fa-sort-numeric-up"], [1, "history-content"], ["text", "Loading history..."], [1, "history-filters"], [1, "time-range-filters"], [1, "filter-label"], [1, "filter-btn", 3, "click"], [1, "history-actions"], [1, "fas", "fa-download"], [1, "history-kpi-cards"], [1, "history-section"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "kpi-card"], [1, "kpi-icon"], [1, "fas", "fa-play-circle"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-icon", "pass-rate"], [1, "fas", "fa-percentage"], [1, "fas", "trend-icon"], [1, "fas", "fa-star"], [1, "fas", "fa-calendar-alt"], [1, "history-table-container"], [1, "history-table"], [1, "date-cell"], [1, "runs-cell"], [1, "passed-cell"], [1, "failed-cell"], [1, "pass-rate-cell"], [1, "score-cell"], [1, "duration-cell"], [1, "cost-cell"], [1, "pass-rate-bar"], [1, "pass-rate-fill"], [1, "pass-rate-text"], [1, "suite-performance-list"], [1, "suite-perf-card"], [1, "suite-perf-card", 3, "click"], [1, "suite-perf-header"], [1, "suite-perf-name"], [1, "suite-perf-tags"], [1, "suite-perf-stats"], [1, "suite-stat"], [1, "stat-value"], [1, "stat-label"], [1, "fas", "fa-chevron-right", "suite-perf-arrow"], [1, "tag-mini"], [1, "tag-more"], [1, "stat-value", "pass-rate"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "shortcuts-header"], ["title", "Hide shortcuts", 1, "shortcuts-close", 3, "click"], [1, "shortcut-list"], [1, "shortcut-item"], [1, "shortcut-keys"], ["Mode", "slide", 3, "Closed", "Title", "Resizable"], [3, "PanelClose", "PanelMode", "selectedTestId", "selectedSuiteId", "runMode"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-check"], [1, "save-bar-kbd"]], template: function MJTestFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
2579
+ } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 89, vars: 51, consts: [["tagInput", ""], [1, "test-form"], [1, "test-header"], ["aria-label", "Breadcrumb", 1, "breadcrumb"], ["href", "javascript:void(0)", 3, "click"], [1, "fas", "fa-vial"], [1, "breadcrumb-text"], [1, "current"], [1, "fas", "fa-chevron-right", "separator"], [1, "fas", "fa-flask"], [1, "header-content"], [1, "header-left"], [1, "test-icon"], [1, "test-info"], ["title", "You have unsaved changes", "aria-label", "Unsaved changes", 1, "dirty-indicator"], [1, "test-meta"], [1, "status-badge", 3, "ngClass"], [1, "fas", 3, "ngClass"], [1, "test-type"], ["title", "You have unsaved changes", 1, "unsaved-pill"], [1, "header-actions"], ["mjButton", "", "variant", "primary", 3, "click"], [1, "fas", "fa-play"], ["mjButton", "", 3, "click", "disabled"], [1, "test-description"], [1, "metrics-bar"], [1, "tabs-container"], ["role", "tablist", 1, "tabs"], ["role", "tab", 1, "tab", 3, "click"], [1, "fas", "fa-th-large"], [1, "fas", "fa-sliders-h"], [1, "fas", "fa-history"], [1, "tab-badge"], [1, "fas", "fa-layer-group"], [1, "fas", "fa-chart-line"], [1, "tab-content"], [1, "overview-tab"], [1, "config-tab"], [1, "runs-tab"], [1, "suites-tab"], [1, "history-tab"], [1, "shortcuts-toggle", 3, "click", "title"], [1, "fas", "fa-keyboard"], [1, "keyboard-shortcuts"], ["Mode", "slide", 3, "Title", "Resizable"], ["role", "region", "aria-label", "Unsaved changes", 1, "save-bar"], [1, "save-bar-message"], ["aria-hidden", "true", 1, "save-bar-dot"], [1, "save-bar-text"], [1, "save-bar-fields"], [1, "save-bar-actions"], ["type", "button", "title", "Save changes (\u2318S)", 1, "save-bar-btn", "save-bar-btn--primary", 3, "click", "disabled"], ["type", "button", "title", "Discard changes", 1, "save-bar-btn", "save-bar-btn--ghost", 3, "click", "disabled"], [1, "fas", "fa-undo"], [1, "fas", "fa-tag"], [1, "fas", "fa-circle"], [1, "metric-card"], [1, "metric-label"], [1, "metric-value"], [1, "metric-progress"], [1, "metric-progress-fill"], [1, "info-section"], [1, "fas", "fa-info-circle"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], [1, "status-badge-inline", 3, "ngClass"], [1, "json-section"], [1, "fas", "fa-code"], [1, "json-tabs"], [1, "json-tab", 3, "click"], [1, "fas", "fa-sign-in-alt"], [1, "fas", "fa-check-double"], [1, "fas", "fa-cog"], [1, "fas", "fa-tags"], [1, "code-editor-container"], ["language", "json", 3, "value", "readonly", "toolbar", "lineWrapping"], [1, "edit-section"], [1, "edit-section-header"], [1, "fas", "fa-pen-to-square"], [1, "edit-section-sub"], [1, "edit-grid"], [1, "edit-field", "edit-field--full"], ["for", "test-name"], [1, "required"], ["id", "test-name", "type", "text", "placeholder", "e.g., Agent Response Quality Test", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-description"], ["id", "test-description", "rows", "3", "placeholder", "What does this test evaluate?", 1, "config-input", "config-textarea", 3, "ngModelChange", "ngModel"], [1, "edit-field"], ["for", "test-status"], [1, "select-wrapper"], ["id", "test-status", 1, "config-input", 3, "ngModelChange", "ngModel"], [3, "ngValue"], ["for", "test-rubric"], ["id", "test-rubric", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-type"], ["id", "test-type", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-tags"], [1, "tag-editor", 3, "click"], [1, "tag-chip-editable"], ["id", "test-tags", "type", "text", 1, "tag-input-inline", 3, "ngModelChange", "keydown", "blur", "placeholder", "ngModel"], [1, "config-hint"], [1, "fas", "fa-cogs"], ["for", "test-priority"], ["id", "test-priority", "type", "number", "placeholder", "0 (lower runs first)", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-repeat"], ["id", "test-repeat", "type", "number", "min", "1", "placeholder", "1", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-duration"], ["id", "test-duration", "type", "number", "placeholder", "0", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-cost"], ["id", "test-cost", "type", "number", "step", "0.000001", "placeholder", "0.00", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-timeout"], ["id", "test-timeout", "type", "number", "placeholder", "Default: 300000 (5 min)", 1, "config-input", 3, "ngModelChange", "ngModel"], [1, "config-section"], [1, "config-editor-container"], ["language", "json", 3, "change", "value", "readonly", "lineWrapping"], [1, "meta-section"], [1, "meta-grid"], [1, "meta-item"], [1, "meta-label"], [1, "meta-value"], [1, "meta-value", "meta-mono"], ["type", "button", 1, "tag-remove", 3, "click"], [1, "fas", "fa-times"], [1, "loading-state"], [1, "runs-list"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "skeleton-list"], [1, "skeleton-card"], [1, "skeleton-icon"], [1, "skeleton-content"], [1, "skeleton-line", "wide"], [1, "skeleton-line", "narrow"], [1, "run-item"], [1, "run-item", 3, "click"], [1, "run-icon"], [1, "fas"], [1, "run-content"], [1, "run-header"], [1, "run-id"], [1, "run-status"], [1, "run-meta"], [1, "fas", "fa-calendar"], [3, "entityName", "recordId"], [1, "run-eval-stack"], [1, "eval-pill", "status-pill", 3, "ngClass", "title"], [1, "run-tags"], [1, "fas", "fa-chevron-right"], [1, "fas", "fa-clock"], [1, "fas", "fa-dollar-sign"], ["title", "Human Review: No rating submitted yet", 1, "eval-pill", "human-pill", "no-feedback"], [1, "eval-pill", "human-pill", "has-feedback", 3, "rating-low", "rating-medium", "rating-good", "rating-excellent", "title"], [1, "fas", "fa-user-slash"], [1, "eval-pill", "human-pill", "has-feedback", 3, "title"], [1, "fas", "fa-user"], ["title", "Auto Score: No automated score available", 1, "eval-pill", "auto-pill", "no-score"], [1, "eval-pill", "auto-pill", "has-score", 3, "score-low", "score-medium", "score-good", "score-excellent", "title"], [1, "fas", "fa-robot"], [1, "eval-pill", "auto-pill", "has-score", 3, "title"], [1, "run-tag"], [1, "run-tag-more"], ["Icon", "fa-solid fa-circle-play", "Title", "No Test Runs Yet", "Message", "Run this test to see execution history and results here.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "suites-list"], ["Icon", "fa-solid fa-folder-open", "Title", "Not Part of Any Suite", "Message", "This test is not included in any test suites. Add it to a suite to run it with other tests."], [1, "suite-item"], [1, "suite-item", 3, "click"], [1, "suite-icon"], [1, "suite-content"], [1, "suite-name"], [1, "suite-meta"], [1, "fas", "fa-sort-numeric-up"], [1, "history-content"], ["text", "Loading history..."], [1, "history-filters"], [1, "time-range-filters"], [1, "filter-label"], [1, "filter-btn", 3, "click"], [1, "history-actions"], [1, "fas", "fa-download"], [1, "history-kpi-cards"], [1, "history-section"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play"], [1, "kpi-card"], [1, "kpi-icon"], [1, "fas", "fa-play-circle"], [1, "kpi-content"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-icon", "pass-rate"], [1, "fas", "fa-percentage"], [1, "fas", "trend-icon"], [1, "fas", "fa-star"], [1, "fas", "fa-calendar-alt"], [1, "history-table-container"], [1, "history-table"], [1, "date-cell"], [1, "runs-cell"], [1, "passed-cell"], [1, "failed-cell"], [1, "pass-rate-cell"], [1, "score-cell"], [1, "duration-cell"], [1, "cost-cell"], [1, "pass-rate-bar"], [1, "pass-rate-fill"], [1, "pass-rate-text"], [1, "suite-performance-list"], [1, "suite-perf-card"], [1, "suite-perf-card", 3, "click"], [1, "suite-perf-header"], [1, "suite-perf-name"], [1, "suite-perf-tags"], [1, "suite-perf-stats"], [1, "suite-stat"], [1, "stat-value"], [1, "stat-label"], [1, "fas", "fa-chevron-right", "suite-perf-arrow"], [1, "tag-mini"], [1, "tag-more"], [1, "stat-value", "pass-rate"], ["Icon", "fa-solid fa-chart-line", "Title", "No History Available", "Message", "Run this test to start building history and analytics data.", "ActionText", "Run Test Now", "ActionIcon", "fa-solid fa-play", 3, "Action"], [1, "shortcuts-header"], ["title", "Hide shortcuts", 1, "shortcuts-close", 3, "click"], [1, "shortcut-list"], [1, "shortcut-item"], [1, "shortcut-keys"], ["Mode", "slide", 3, "Closed", "Title", "Resizable"], [3, "PanelClose", "PanelMode", "selectedTestId", "selectedSuiteId", "runMode"], [1, "fas", "fa-spinner", "fa-spin"], [1, "fas", "fa-check"], [1, "save-bar-kbd"]], template: function MJTestFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
2539
2580
  i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "nav", 3)(3, "ol")(4, "li")(5, "a", 4);
2540
2581
  i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_a_click_5_listener() { return ctx.navigateToTestingDashboard(); });
2541
2582
  i0.ɵɵelement(6, "i", 5);
@@ -2612,7 +2653,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
2612
2653
  i0.ɵɵelementEnd()()()();
2613
2654
  i0.ɵɵelementStart(62, "div", 35);
2614
2655
  i0.ɵɵconditionalCreate(63, MJTestFormComponentExtended_Conditional_63_Template, 78, 29, "div", 36);
2615
- i0.ɵɵconditionalCreate(64, MJTestFormComponentExtended_Conditional_64_Template, 111, 30, "div", 37);
2656
+ i0.ɵɵconditionalCreate(64, MJTestFormComponentExtended_Conditional_64_Template, 119, 32, "div", 37);
2616
2657
  i0.ɵɵconditionalCreate(65, MJTestFormComponentExtended_Conditional_65_Template, 4, 3, "div", 38);
2617
2658
  i0.ɵɵconditionalCreate(66, MJTestFormComponentExtended_Conditional_66_Template, 4, 3, "div", 39);
2618
2659
  i0.ɵɵconditionalCreate(67, MJTestFormComponentExtended_Conditional_67_Template, 3, 2, "div", 40);
@@ -2728,7 +2769,7 @@ MJTestFormComponentExtended = __decorate([
2728
2769
  export { MJTestFormComponentExtended };
2729
2770
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJTestFormComponentExtended, [{
2730
2771
  type: Component,
2731
- args: [{ standalone: false, selector: 'mj-test-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-form\">\n <!-- Header Section -->\n <div class=\"test-header\">\n <!-- Breadcrumb Navigation -->\n <nav class=\"breadcrumb\" aria-label=\"Breadcrumb\">\n <ol>\n <li>\n <a href=\"javascript:void(0)\" (click)=\"navigateToTestingDashboard()\">\n <i class=\"fas fa-vial\"></i>\n <span class=\"breadcrumb-text\">Testing</span>\n </a>\n </li>\n <li class=\"current\">\n <i class=\"fas fa-chevron-right separator\"></i>\n <i class=\"fas fa-flask\"></i>\n <span>{{ record.Name }}</span>\n </li>\n </ol>\n </nav>\n\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"test-icon\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas fa-flask\"></i>\n </div>\n <div class=\"test-info\">\n <h1>\n {{ record.Name }}\n @if (isDirty) {\n <span class=\"dirty-indicator\" title=\"You have unsaved changes\" aria-label=\"Unsaved changes\">\u25CF</span>\n }\n </h1>\n <div class=\"test-meta\">\n <span class=\"status-badge\" [ngClass]=\"getStatusClass()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n @if (record.Type) {\n <span class=\"test-type\">\n <i class=\"fas fa-tag\"></i>\n {{ record.Type }}\n </span>\n }\n @if (isDirty) {\n <span class=\"unsaved-pill\" title=\"You have unsaved changes\">\n <i class=\"fas fa-circle\"></i> Unsaved\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <app-evaluation-mode-toggle></app-evaluation-mode-toggle>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test\n </button>\n <button mjButton (click)=\"refresh()\" [disabled]=\"isRefreshing\">\n <i class=\"fas\" [ngClass]=\"isRefreshing ? 'fa-sync fa-spin' : 'fa-sync'\"></i>\n {{ isRefreshing ? 'Refreshing...' : 'Refresh' }}\n </button>\n </div>\n </div>\n\n <!-- Test Description -->\n @if (record.Description) {\n <div class=\"test-description\">\n <p>{{ record.Description }}</p>\n </div>\n }\n\n <!-- Metrics Bar -->\n @if (testRunsLoaded && testRuns.length > 0) {\n <div class=\"metrics-bar\">\n <div class=\"metric-card\">\n <div class=\"metric-label\">Total Runs</div>\n <div class=\"metric-value\">{{ testRuns.length }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Pass Rate</div>\n <div class=\"metric-value\">{{ getPassRate().toFixed(1) }}%</div>\n <div class=\"metric-progress\">\n <div class=\"metric-progress-fill\" [style.width.%]=\"getPassRate()\"></div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Cost</div>\n <div class=\"metric-value\">{{ formatCost(getAverageCost()) }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Duration</div>\n <div class=\"metric-value\">{{ formatDuration(getAverageDuration()) }}</div>\n </div>\n </div>\n }\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs-container\">\n <div class=\"tabs\" role=\"tablist\">\n <button class=\"tab\"\n [class.active]=\"activeTab === 'overview'\"\n (click)=\"changeTab('overview')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'overview'\">\n <i class=\"fas fa-th-large\"></i>\n <span>Overview</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'config'\"\n (click)=\"changeTab('config')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'config'\">\n <i class=\"fas fa-sliders-h\"></i>\n <span>Configuration</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'runs'\"\n (click)=\"changeTab('runs')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'runs'\">\n <i class=\"fas fa-history\"></i>\n <span>Runs</span>\n @if (testRunsLoaded) {\n <span class=\"tab-badge\">{{ testRuns.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'suites'\"\n (click)=\"changeTab('suites')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'suites'\">\n <i class=\"fas fa-layer-group\"></i>\n <span>Test Suites</span>\n @if (suiteTestsLoaded) {\n <span class=\"tab-badge\">{{ suiteTests.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'analytics'\"\n (click)=\"changeTab('analytics')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'analytics'\">\n <i class=\"fas fa-chart-line\"></i>\n <span>Analytics</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\" [class.has-savebar]=\"isDirty\">\n <!-- Overview Tab -->\n @if (activeTab === 'overview') {\n <div class=\"overview-tab\">\n <!-- Basic Information -->\n <div class=\"info-section\">\n <h3><i class=\"fas fa-info-circle\"></i> Test Information</h3>\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <div class=\"info-label\">Name</div>\n <div class=\"info-value\">{{ record.Name }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Type</div>\n <div class=\"info-value\">{{ record.Type || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Status</div>\n <div class=\"info-value\">\n <span class=\"status-badge-inline\" [ngClass]=\"getStatusClass()\">{{ record.Status }}</span>\n </div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Priority</div>\n <div class=\"info-value\">{{ record.Priority || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Duration</div>\n <div class=\"info-value\">{{ record.EstimatedDurationSeconds ? formatDuration(record.EstimatedDurationSeconds) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Cost</div>\n <div class=\"info-value\">{{ record.EstimatedCostUSD ? formatCost(record.EstimatedCostUSD) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Repeat Count</div>\n <div class=\"info-value\">{{ record.RepeatCount || 1 }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Max Execution Time</div>\n <div class=\"info-value\">{{ formatTimeout(record.MaxExecutionTimeMS) }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Created</div>\n <div class=\"info-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Updated</div>\n <div class=\"info-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n </div>\n </div>\n <!-- JSON Data Views -->\n <div class=\"json-section\">\n <h3><i class=\"fas fa-code\"></i> Test Definition</h3>\n <div class=\"json-tabs\">\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'input'\"\n (click)=\"setJsonView('input')\">\n <i class=\"fas fa-sign-in-alt\"></i>\n Input Definition\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'expected'\"\n (click)=\"setJsonView('expected')\">\n <i class=\"fas fa-check-double\"></i>\n Expected Outcomes\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'config'\"\n (click)=\"setJsonView('config')\">\n <i class=\"fas fa-cog\"></i>\n Configuration\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'tags'\"\n (click)=\"setJsonView('tags')\">\n <i class=\"fas fa-tags\"></i>\n Tags\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"getJsonData()\"\n language=\"json\"\n [readonly]=\"true\"\n [toolbar]=\"jsonToolbar\"\n [lineWrapping]=\"true\">\n </mj-code-editor>\n </div>\n </div>\n </div>\n }\n\n <!-- Configuration Tab -->\n @if (activeTab === 'config') {\n <div class=\"config-tab\">\n <!-- Details -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-pen-to-square\"></i> Details</h3>\n <p class=\"edit-section-sub\">Edit any field \u2014 changes are saved with the bar at the bottom.</p>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-name\">Name <span class=\"required\">*</span></label>\n <input\n id=\"test-name\"\n type=\"text\"\n class=\"config-input\"\n placeholder=\"e.g., Agent Response Quality Test\"\n [(ngModel)]=\"record.Name\"\n />\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-description\">Description</label>\n <textarea\n id=\"test-description\"\n class=\"config-input config-textarea\"\n rows=\"3\"\n placeholder=\"What does this test evaluate?\"\n [ngModel]=\"record.Description\"\n (ngModelChange)=\"record.Description = $event || null\"\n ></textarea>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-status\">Status</label>\n <div class=\"select-wrapper\">\n <select\n id=\"test-status\"\n class=\"config-input\"\n [(ngModel)]=\"record.Status\"\n >\n @for (opt of statusOptions; track opt) {\n <option [ngValue]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-type\">Test Type</label>\n <select\n id=\"test-type\"\n class=\"config-input\"\n [(ngModel)]=\"record.TypeID\"\n >\n @for (t of testTypeOptions; track t.ID) {\n <option [ngValue]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-tags\">Tags</label>\n <div class=\"tag-editor\" (click)=\"tagInput.focus()\">\n @for (tag of tags; track tag) {\n <span class=\"tag-chip-editable\">\n {{ tag }}\n <button type=\"button\" class=\"tag-remove\" (click)=\"removeTag(tag); $event.stopPropagation()\" [attr.aria-label]=\"'Remove tag ' + tag\">\n <i class=\"fas fa-times\"></i>\n </button>\n </span>\n }\n <input\n #tagInput\n id=\"test-tags\"\n type=\"text\"\n class=\"tag-input-inline\"\n [placeholder]=\"tags.length === 0 ? 'Add tags, press Enter or comma...' : ''\"\n [(ngModel)]=\"tagDraft\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTagFromDraft()\"\n />\n </div>\n <span class=\"config-hint\">Press Enter or comma to add a tag. Backspace on empty input removes the last tag.</span>\n </div>\n </div>\n </section>\n\n <!-- Execution Settings -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-cogs\"></i> Execution Settings</h3>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field\">\n <label for=\"test-priority\">Priority</label>\n <input\n id=\"test-priority\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0 (lower runs first)\"\n [ngModel]=\"record.Priority\"\n (ngModelChange)=\"record.Priority = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Lower numbers run first.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-repeat\">Repeat Count</label>\n <input\n id=\"test-repeat\"\n type=\"number\"\n class=\"config-input\"\n min=\"1\"\n placeholder=\"1\"\n [ngModel]=\"record.RepeatCount\"\n (ngModelChange)=\"record.RepeatCount = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Number of times to repeat for statistical analysis.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-duration\">Estimated Duration (seconds)</label>\n <input\n id=\"test-duration\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0\"\n [ngModel]=\"record.EstimatedDurationSeconds\"\n (ngModelChange)=\"record.EstimatedDurationSeconds = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field\">\n <label for=\"test-cost\">Estimated Cost (USD)</label>\n <input\n id=\"test-cost\"\n type=\"number\"\n step=\"0.000001\"\n class=\"config-input\"\n placeholder=\"0.00\"\n [ngModel]=\"record.EstimatedCostUSD\"\n (ngModelChange)=\"record.EstimatedCostUSD = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-timeout\">Max Execution Time (ms)</label>\n <input\n id=\"test-timeout\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"Default: 300000 (5 min)\"\n [ngModel]=\"record.MaxExecutionTimeMS\"\n (ngModelChange)=\"record.MaxExecutionTimeMS = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Leave empty for the default 5 minute timeout. Currently: {{ formatTimeout(record.MaxExecutionTimeMS) }}</span>\n </div>\n </div>\n </section>\n\n <!-- JSON editors (preserved from original layout) -->\n <div class=\"config-section\">\n <h3><i class=\"fas fa-sign-in-alt\"></i> Input Definition (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.InputDefinition || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.InputDefinition = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-check-double\"></i> Expected Outcomes (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.ExpectedOutcomes || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.ExpectedOutcomes = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-cog\"></i> Configuration (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.Configuration || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.Configuration = $event\">\n </mj-code-editor>\n </div>\n </div>\n\n <!-- Metadata (read-only) -->\n <section class=\"meta-section\">\n <div class=\"meta-grid\">\n <div class=\"meta-item\">\n <div class=\"meta-label\">Created</div>\n <div class=\"meta-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Last updated</div>\n <div class=\"meta-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Test ID</div>\n <div class=\"meta-value meta-mono\">{{ record.ID }}</div>\n </div>\n </div>\n </section>\n </div>\n }\n\n <!-- Test Runs Tab -->\n @if (activeTab === 'runs') {\n <div class=\"runs-tab\">\n <!-- Loading State -->\n @if (loadingRuns) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3,4,5]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Runs List -->\n @if (!loadingRuns && testRuns.length > 0) {\n <div class=\"runs-list\">\n @for (run of testRuns; track run) {\n <div class=\"run-item\" (click)=\"openTestRun(run.ID)\">\n <div class=\"run-icon\" [style.background-color]=\"getRunStatusColor(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-stopwatch]=\"run.Status === 'Timeout'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n </div>\n <div class=\"run-content\">\n <div class=\"run-header\">\n <span class=\"run-id\">Run #{{ run.ID.substring(0, 8) }}</span>\n <span class=\"run-status\" [style.color]=\"getRunStatusColor(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-meta\">\n <span><i class=\"fas fa-calendar\"></i> {{ getRelativeTime(run.StartedAt) }}</span>\n @if (run.DurationSeconds) {\n <span><i class=\"fas fa-clock\"></i> {{ formatDuration(run.DurationSeconds) }}</span>\n }\n @if (run.CostUSD) {\n <span><i class=\"fas fa-dollar-sign\"></i> {{ formatCost(run.CostUSD) }}</span>\n }\n @if (run.TargetLogEntityID && run.TargetLogID) {\n <mj-entity-link-pill\n [entityName]=\"run.TargetLogEntity\"\n [recordId]=\"run.TargetLogID\">\n </mj-entity-link-pill>\n }\n </div>\n <!-- Evaluation indicators -->\n <div class=\"run-eval-stack\">\n <!-- Status indicator -->\n @if (evalPreferences.showExecution) {\n <span class=\"eval-pill status-pill\"\n [ngClass]=\"'status-' + run.Status.toLowerCase()\"\n [title]=\"getStatusTooltip(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-hourglass-end]=\"run.Status === 'Timeout'\"\n [class.fa-forward]=\"run.Status === 'Skipped'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n <span>{{ run.Status }}</span>\n </span>\n }\n <!-- Human feedback indicator -->\n @if (evalPreferences.showHuman) {\n @if (!getFeedbackForRun(run.ID)?.Rating) {\n <span class=\"eval-pill human-pill no-feedback\"\n title=\"Human Review: No rating submitted yet\">\n <i class=\"fas fa-user-slash\"></i>\n </span>\n }\n @if (getFeedbackForRun(run.ID)?.Rating; as rating) {\n <span class=\"eval-pill human-pill has-feedback\"\n [class.rating-low]=\"rating <= 4\"\n [class.rating-medium]=\"rating >= 5 && rating <= 6\"\n [class.rating-good]=\"rating >= 7 && rating <= 8\"\n [class.rating-excellent]=\"rating >= 9\"\n [title]=\"getHumanTooltip(rating, getFeedbackForRun(run.ID)?.CorrectionSummary || getFeedbackForRun(run.ID)?.Comments || null)\">\n <i class=\"fas fa-user\"></i>\n <span>{{ rating }}</span>\n </span>\n }\n }\n <!-- Auto score indicator -->\n @if (evalPreferences.showAuto) {\n @if (run.Score == null) {\n <span class=\"eval-pill auto-pill no-score\"\n title=\"Auto Score: No automated score available\">\n <i class=\"fas fa-robot\"></i>\n </span>\n }\n @if (run.Score != null) {\n <span class=\"eval-pill auto-pill has-score\"\n [class.score-low]=\"run.Score < 0.5\"\n [class.score-medium]=\"run.Score >= 0.5 && run.Score < 0.7\"\n [class.score-good]=\"run.Score >= 0.7 && run.Score < 0.85\"\n [class.score-excellent]=\"run.Score >= 0.85\"\n [title]=\"'Auto Score: ' + (run.Score * 100).toFixed(0) + '% automated evaluation'\">\n <i class=\"fas fa-robot\"></i>\n <span>{{ (run.Score * 100).toFixed(0) }}%</span>\n </span>\n }\n }\n </div>\n @if (getRunTags(run).length > 0) {\n <div class=\"run-tags\">\n @for (tag of getRunTags(run).slice(0, 3); track tag) {\n <span class=\"run-tag\">{{ tag }}</span>\n }\n @if (getRunTags(run).length > 3) {\n <span class=\"run-tag-more\">+{{ getRunTags(run).length - 3 }}</span>\n }\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (testRunsLoaded && !loadingRuns && testRuns.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-circle-play\"\n Title=\"No Test Runs Yet\"\n Message=\"Run this test to see execution history and results here.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n\n <!-- Test Suites Tab -->\n @if (activeTab === 'suites') {\n <div class=\"suites-tab\">\n <!-- Loading State -->\n @if (loadingSuites) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Suites List -->\n @if (!loadingSuites && suiteTests.length > 0) {\n <div class=\"suites-list\">\n @for (suiteTest of suiteTests; track suiteTest) {\n <div class=\"suite-item\" (click)=\"openTestSuite(suiteTest.SuiteID)\">\n <div class=\"suite-icon\">\n <i class=\"fas fa-layer-group\"></i>\n </div>\n <div class=\"suite-content\">\n <div class=\"suite-name\">{{ suiteTest.Suite }}</div>\n <div class=\"suite-meta\">\n <span><i class=\"fas fa-sort-numeric-up\"></i> Sequence: {{ suiteTest.Sequence }}</span>\n @if (suiteTest.Status) {\n <span><i class=\"fas fa-info-circle\"></i> {{ suiteTest.Status }}</span>\n }\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (suiteTestsLoaded && !loadingSuites && suiteTests.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-folder-open\"\n Title=\"Not Part of Any Suite\"\n Message=\"This test is not included in any test suites. Add it to a suite to run it with other tests.\" />\n }\n </div>\n }\n\n <!-- Analytics Tab -->\n @if (activeTab === 'analytics') {\n <div class=\"history-tab\">\n <!-- Loading State -->\n @if (loadingHistory) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading history...\"></mj-loading>\n </div>\n }\n <!-- History Content -->\n @if (!loadingHistory && historyLoaded) {\n <div class=\"history-content\">\n <!-- Filters -->\n <div class=\"history-filters\">\n <div class=\"time-range-filters\">\n <span class=\"filter-label\">Time Range:</span>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '7d'\"\n (click)=\"setHistoryTimeRange('7d')\">7 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '30d'\"\n (click)=\"setHistoryTimeRange('30d')\">30 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '90d'\"\n (click)=\"setHistoryTimeRange('90d')\">90 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === 'all'\"\n (click)=\"setHistoryTimeRange('all')\">All Time</button>\n </div>\n <div class=\"history-actions\">\n <button mjButton (click)=\"exportHistoryToCSV()\" [disabled]=\"historyData.length === 0\">\n <i class=\"fas fa-download\"></i> Export CSV\n </button>\n </div>\n </div>\n <!-- KPI Cards -->\n @if (historyData.length > 0) {\n <div class=\"history-kpi-cards\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-play-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ getTotalRuns() }}</div>\n <div class=\"kpi-label\">Total Runs</div>\n </div>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon pass-rate\">\n <i class=\"fas fa-percentage\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">\n {{ getOverallPassRate().toFixed(1) }}%\n <i class=\"fas trend-icon\"\n [class.fa-arrow-up]=\"getPassRateTrend() === 'up'\"\n [class.fa-arrow-down]=\"getPassRateTrend() === 'down'\"\n [class.fa-minus]=\"getPassRateTrend() === 'stable'\"\n [class.trend-up]=\"getPassRateTrend() === 'up'\"\n [class.trend-down]=\"getPassRateTrend() === 'down'\"></i>\n </div>\n <div class=\"kpi-label\">Pass Rate</div>\n </div>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-star\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ (getOverallAvgScore() * 100).toFixed(1) }}%</div>\n <div class=\"kpi-label\">Avg Score</div>\n </div>\n </div>\n }\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-clock\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatDuration(getOverallAvgDuration()) }}</div>\n <div class=\"kpi-label\">Avg Duration</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-dollar-sign\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatCost(getOverallAvgCost()) }}</div>\n <div class=\"kpi-label\">Avg Cost</div>\n </div>\n </div>\n </div>\n }\n <!-- Daily History Table -->\n @if (historyData.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-calendar-alt\"></i> Daily Performance</h3>\n <div class=\"history-table-container\">\n <table class=\"history-table\">\n <thead>\n <tr>\n <th>Date</th>\n <th>Runs</th>\n @if (evalPreferences.showExecution) {\n <th>Passed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Failed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Pass Rate</th>\n }\n @if (evalPreferences.showAuto) {\n <th>Avg Score</th>\n }\n <th>Avg Duration</th>\n <th>Avg Cost</th>\n </tr>\n </thead>\n <tbody>\n @for (day of historyData; track day) {\n <tr>\n <td class=\"date-cell\">{{ day.date | date:'mediumDate' }}</td>\n <td class=\"runs-cell\">{{ day.runCount }}</td>\n @if (evalPreferences.showExecution) {\n <td class=\"passed-cell\">{{ day.passCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"failed-cell\">{{ day.failCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"pass-rate-cell\">\n <div class=\"pass-rate-bar\">\n <div class=\"pass-rate-fill\" [style.width.%]=\"day.passRate\"></div>\n <span class=\"pass-rate-text\">{{ day.passRate.toFixed(1) }}%</span>\n </div>\n </td>\n }\n @if (evalPreferences.showAuto) {\n <td class=\"score-cell\">{{ (day.avgScore * 100).toFixed(1) }}%</td>\n }\n <td class=\"duration-cell\">{{ formatDuration(day.avgDuration) }}</td>\n <td class=\"cost-cell\">{{ formatCost(day.avgCost) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n <!-- Suite Performance -->\n @if (suitePerformance.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-layer-group\"></i> Performance by Suite</h3>\n <div class=\"suite-performance-list\">\n @for (suite of suitePerformance; track suite) {\n <div class=\"suite-perf-card\" (click)=\"openSuiteFromHistory(suite.suiteId)\">\n <div class=\"suite-perf-header\">\n <div class=\"suite-perf-name\">{{ suite.suiteName }}</div>\n @if (suite.tags.length > 0) {\n <div class=\"suite-perf-tags\">\n @for (tag of suite.tags.slice(0, 3); track tag) {\n <span class=\"tag-mini\">{{ tag }}</span>\n }\n @if (suite.tags.length > 3) {\n <span class=\"tag-more\">+{{ suite.tags.length - 3 }}</span>\n }\n </div>\n }\n </div>\n <div class=\"suite-perf-stats\">\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ suite.totalRuns }}</span>\n <span class=\"stat-label\">Runs</span>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"suite-stat\">\n <span class=\"stat-value pass-rate\" [class.high]=\"suite.passRate >= 80\" [class.low]=\"suite.passRate < 50\">\n {{ suite.passRate.toFixed(1) }}%\n </span>\n <span class=\"stat-label\">Pass Rate</span>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ (suite.avgScore * 100).toFixed(1) }}%</span>\n <span class=\"stat-label\">Avg Score</span>\n </div>\n }\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatDuration(suite.avgDuration) }}</span>\n <span class=\"stat-label\">Avg Duration</span>\n </div>\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatCost(suite.avgCost) }}</span>\n <span class=\"stat-label\">Avg Cost</span>\n </div>\n @if (suite.lastRun) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ getRelativeTime(suite.lastRun) }}</span>\n <span class=\"stat-label\">Last Run</span>\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right suite-perf-arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n <!-- Empty State -->\n @if (historyData.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-chart-line\"\n Title=\"No History Available\"\n Message=\"Run this test to start building history and analytics data.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Keyboard Shortcuts Toggle Button -->\n <button class=\"shortcuts-toggle\" (click)=\"toggleShortcuts()\" [title]=\"showShortcuts ? 'Hide keyboard shortcuts' : 'Show keyboard shortcuts'\">\n <i class=\"fas fa-keyboard\"></i>\n </button>\n\n <!-- Keyboard Shortcuts Hint (Desktop Only) -->\n @if (showShortcuts) {\n <div class=\"keyboard-shortcuts\">\n <div class=\"shortcuts-header\">\n <i class=\"fas fa-keyboard\"></i>\n Shortcuts\n <button class=\"shortcuts-close\" (click)=\"toggleShortcuts()\" title=\"Hide shortcuts\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n <div class=\"shortcut-list\">\n <div class=\"shortcut-item\">\n <span>Save changes</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>S</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Refresh</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>R</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Run Test</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>Enter</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Switch Tabs</span>\n <span class=\"shortcut-keys\"><kbd>1</kbd>-<kbd>5</kbd></span>\n </div>\n </div>\n </div>\n }\n\n <!-- Slide Panel for Test Execution -->\n @if (testingDialogService.IsPanelOpen) {\n <mj-slide-panel\n Mode=\"slide\"\n [Title]=\"testingDialogService.PanelOptions?.testId ? 'Test Execution' : 'Run Test'\"\n [Resizable]=\"true\"\n (Closed)=\"OnPanelClosed()\">\n <app-test-run-dialog\n [PanelMode]=\"true\"\n [selectedTestId]=\"testingDialogService.PanelOptions?.testId ?? null\"\n [selectedSuiteId]=\"testingDialogService.PanelOptions?.suiteId ?? null\"\n [runMode]=\"testingDialogService.PanelOptions?.mode ?? 'test'\"\n (PanelClose)=\"OnPanelClosed()\">\n </app-test-run-dialog>\n </mj-slide-panel>\n }\n\n <!-- Sticky Save Bar \u2014 always in the DOM so CSS transitions can fire reliably.\n Visibility is controlled by the .save-bar--visible class, driven by isDirty. -->\n <div\n class=\"save-bar\"\n [class.save-bar--visible]=\"isDirty\"\n [attr.aria-hidden]=\"!isDirty\"\n role=\"region\"\n aria-label=\"Unsaved changes\"\n >\n <div class=\"save-bar-message\">\n <span class=\"save-bar-dot\" aria-hidden=\"true\">\u25CF</span>\n <span class=\"save-bar-text\">\n <strong>Unsaved changes</strong>\n <span class=\"save-bar-fields\">\n @if (dirtyFieldNames.length === 1) {\n {{ dirtyFieldNames[0] }} edited\n } @else if (dirtyFieldNames.length > 1) {\n {{ dirtyFieldNames.length }} fields edited\n }\n </span>\n </span>\n </div>\n <div class=\"save-bar-actions\">\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--primary\"\n (click)=\"saveChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Save changes (\u2318S)\"\n >\n @if (isSaving) {\n <i class=\"fas fa-spinner fa-spin\"></i> Saving\u2026\n } @else {\n <i class=\"fas fa-check\"></i> Save changes\n <span class=\"save-bar-kbd\"><kbd>\u2318</kbd><kbd>S</kbd></span>\n }\n </button>\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--ghost\"\n (click)=\"discardChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Discard changes\"\n >\n <i class=\"fas fa-undo\"></i> Discard\n </button>\n </div>\n </div>\n</div>\n", styles: ["/* ===========================\n Test Form - World-Class UX\n Premium Test Definition Styles\n =========================== */\n\n/* CSS Custom Properties for Theming - using :host for Angular encapsulation */\n:host {\n --test-primary: var(--mj-brand-primary);\n --test-primary-light: var(--mj-brand-primary);\n --test-primary-dark: var(--mj-brand-primary-hover);\n --test-success: var(--mj-status-success);\n --test-success-light: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n --test-error: var(--mj-status-error);\n --test-error-light: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n --test-warning: var(--mj-status-warning);\n --test-warning-light: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n --test-disabled: var(--mj-text-muted);\n --test-bg: var(--mj-bg-surface-card);\n --test-surface: var(--mj-bg-surface);\n --test-border: var(--mj-border-default);\n --test-text: var(--mj-text-primary);\n --test-text-secondary: var(--mj-text-muted);\n --test-text-muted: var(--mj-text-disabled);\n --test-radius-sm: 6px;\n --test-radius-md: 10px;\n --test-radius-lg: 16px;\n --test-shadow-sm: var(--mj-shadow-sm);\n --test-shadow-md: var(--mj-shadow-md);\n --test-shadow-lg: var(--mj-shadow-lg);\n --test-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: block;\n height: 100%;\n}\n\n/* Breadcrumb */\n.breadcrumb {\n margin-bottom: 16px;\n}\n\n.breadcrumb ol {\n display: flex;\n align-items: center;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n font-size: 13px;\n}\n\n.breadcrumb li {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.breadcrumb a {\n color: var(--test-primary);\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n\n.breadcrumb a:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n text-decoration: none;\n}\n\n.breadcrumb .separator {\n font-size: 10px;\n color: var(--test-text-muted);\n margin: 0 4px;\n}\n\n.breadcrumb .current {\n color: var(--test-text-secondary);\n font-weight: 500;\n}\n\n.breadcrumb-text {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Base Container */\n.test-form {\n position: relative;\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--test-bg);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* ===========================\n Header Section\n =========================== */\n.test-header {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n padding: 20px;\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 16px;\n gap: 16px;\n}\n\n.header-left {\n display: flex;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Test Icon */\n.test-icon {\n width: 56px;\n height: 56px;\n border-radius: var(--test-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 24px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-md);\n transition: var(--test-transition);\n}\n\n.test-icon:hover {\n transform: scale(1.05);\n}\n\n/* Test Info */\n.test-info {\n flex: 1;\n min-width: 0;\n}\n\n.test-info h1 {\n margin: 0 0 8px 0;\n font-size: clamp(18px, 4vw, 24px);\n font-weight: 700;\n color: var(--test-text);\n line-height: 1.2;\n word-wrap: break-word;\n}\n\n.test-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* Status Badge */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.status-badge.status-active { background: var(--mj-status-success); }\n.status-badge.status-disabled { background: var(--mj-text-secondary); }\n.status-badge.status-pending { background: var(--mj-status-warning); }\n\n.status-badge-inline {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: 10px;\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n}\n\n.status-badge-inline.status-active { background: var(--test-success); }\n.status-badge-inline.status-disabled { background: var(--test-disabled); }\n.status-badge-inline.status-pending { background: var(--test-warning); }\n\n.test-type {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--test-text-secondary);\n padding: 4px 10px;\n background: var(--test-bg);\n border-radius: var(--test-radius-sm);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.header-actions button {\n white-space: nowrap;\n}\n\n/* Test Description */\n.test-description {\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n margin-bottom: 16px;\n border: 1px solid var(--test-border);\n}\n\n.test-description p {\n margin: 0;\n color: var(--test-text-secondary);\n line-height: 1.6;\n font-size: 14px;\n}\n\n/* ===========================\n Metrics Bar\n =========================== */\n.metrics-bar {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n}\n\n.metric-card {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 14px;\n text-align: center;\n transition: var(--test-transition);\n}\n\n.metric-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.metric-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n margin-bottom: 6px;\n}\n\n.metric-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n/* Progress bar in metric card */\n.metric-progress {\n margin-top: 8px;\n height: 4px;\n background: var(--test-border);\n border-radius: 2px;\n overflow: hidden;\n}\n\n.metric-progress-fill {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.5s ease-out;\n}\n\n/* ===========================\n Tabs Navigation\n =========================== */\n.tabs-container {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.tabs {\n display: flex;\n padding: 0 20px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.tabs::-webkit-scrollbar {\n display: none;\n}\n\n.tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 18px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: var(--test-text-secondary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n white-space: nowrap;\n}\n\n.tab:hover {\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.tab.active {\n color: var(--test-primary);\n border-bottom-color: var(--test-primary);\n font-weight: 600;\n}\n\n.tab i {\n font-size: 15px;\n}\n\n.tab-badge {\n background: var(--test-border);\n color: var(--test-text-secondary);\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.tab.active .tab-badge {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--test-primary);\n}\n\n.tab-shortcut {\n font-size: 10px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 600;\n margin-left: 4px;\n}\n\n/* ===========================\n Tab Content Area\n =========================== */\n.tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n/* ===========================\n Overview Tab\n =========================== */\n.overview-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* Info Section */\n.info-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.info-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.info-section h3 i {\n color: var(--test-primary);\n}\n\n.info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n}\n\n.info-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.info-label {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.info-value {\n font-size: 14px;\n color: var(--test-text);\n word-wrap: break-word;\n font-weight: 500;\n}\n\n/* JSON Section */\n.json-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-section h3 {\n margin: 0 0 16px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.json-section h3 i {\n color: var(--test-primary);\n}\n\n.json-tabs {\n display: flex;\n gap: 4px;\n margin-bottom: 16px;\n background: var(--test-bg);\n border-radius: var(--test-radius-md);\n padding: 4px;\n flex-wrap: wrap;\n}\n\n.json-tab {\n flex: 1;\n min-width: 100px;\n padding: 10px 14px;\n border: none;\n background: transparent;\n color: var(--test-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n border-radius: var(--test-radius-sm);\n transition: var(--test-transition);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n}\n\n.json-tab:hover {\n color: var(--test-text);\n background: var(--mj-bg-overlay);\n}\n\n.json-tab.active {\n background: var(--test-surface);\n color: var(--test-primary);\n font-weight: 600;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-tab i {\n font-size: 12px;\n}\n\n.code-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n max-height: 400px;\n}\n\n/* ===========================\n Configuration Tab\n =========================== */\n.config-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n.config-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.config-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.config-section h3 i {\n color: var(--test-primary);\n}\n\n.config-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 20px;\n}\n\n.config-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.config-item.full-width {\n grid-column: 1 / -1;\n}\n\n.config-item label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.config-input {\n padding: 10px 14px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n font-size: 14px;\n transition: var(--test-transition);\n background: var(--test-surface);\n}\n\n.config-input:focus {\n outline: none;\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.config-input::placeholder {\n color: var(--test-text-muted);\n}\n\n.config-hint {\n font-size: 11px;\n color: var(--test-text-muted);\n margin-top: 4px;\n}\n\n.config-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n}\n\n.config-editor-container.small {\n min-height: 100px;\n max-height: 150px;\n}\n\n/* ===========================\n Runs Tab\n =========================== */\n.runs-tab,\n.suites-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n/* Loading States & Skeletons */\n.loading-state {\n padding: 0;\n}\n\n.skeleton-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.skeleton-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n border: 1px solid var(--test-border);\n}\n\n.skeleton-icon {\n width: 44px;\n height: 44px;\n border-radius: var(--test-radius-md);\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n flex-shrink: 0;\n}\n\n.skeleton-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.skeleton-line {\n height: 14px;\n border-radius: 4px;\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n}\n\n.skeleton-line.wide { width: 70%; }\n.skeleton-line.narrow { width: 40%; }\n\n@keyframes shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Runs List */\n.runs-list,\n.suites-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.run-item,\n.suite-item {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.run-item:hover,\n.suite-item:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n box-shadow: var(--test-shadow-sm);\n}\n\n.run-icon,\n.suite-icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 18px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-sm);\n}\n\n.suite-icon {\n background: var(--mj-status-warning);\n}\n\n.run-content,\n.suite-content {\n flex: 1;\n min-width: 0;\n}\n\n.run-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-id {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.run-status {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.suite-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 4px;\n}\n\n.run-meta,\n.suite-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--test-text-secondary);\n flex-wrap: wrap;\n}\n\n.run-meta span,\n.suite-meta span {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-meta span i,\n.suite-meta span i {\n color: var(--test-text-muted);\n font-size: 11px;\n}\n\n.run-item > i.fa-chevron-right,\n.suite-item > i.fa-chevron-right {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.run-item:hover > i.fa-chevron-right,\n.suite-item:hover > i.fa-chevron-right {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* Run Evaluation Stack */\n.run-eval-stack {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n/* Evaluation Pills */\n.eval-pill {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.eval-pill i {\n font-size: 10px;\n}\n\n/* Status pill colors */\n.eval-pill.status-pill.status-passed {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.status-pill.status-failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.status-pill.status-error {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-timeout {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-skipped,\n.eval-pill.status-pill.status-pending {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.eval-pill.status-pill.status-running {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* Human feedback pills */\n.eval-pill.human-pill.no-feedback {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.human-pill.has-feedback.rating-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.human-pill.has-feedback.rating-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.human-pill.has-feedback.rating-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.human-pill.has-feedback.rating-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Auto score pills */\n.eval-pill.auto-pill.no-score {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.auto-pill.has-score.score-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.auto-pill.has-score.score-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.auto-pill.has-score.score-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.auto-pill.has-score.score-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Run Tags */\n.run-tags {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n.run-tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n.run-tag-more {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n/* ===========================\n Keyboard Shortcuts Popup\n =========================== */\n/* Keyboard shortcuts toggle button */\n.shortcuts-toggle {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n box-shadow: var(--test-shadow-md);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--test-text-secondary);\n font-size: 14px;\n z-index: 99;\n transition: var(--test-transition);\n opacity: 0.7;\n}\n\n.shortcuts-toggle:hover {\n opacity: 1;\n transform: scale(1.1);\n color: var(--test-primary);\n border-color: var(--test-primary);\n}\n\n.keyboard-shortcuts {\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 12px 16px;\n box-shadow: var(--test-shadow-lg);\n font-size: 12px;\n color: var(--test-text-secondary);\n z-index: 100;\n max-width: 260px;\n}\n\n.shortcuts-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--test-border);\n font-weight: 600;\n color: var(--test-text);\n}\n\n.shortcuts-close {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--test-text-muted);\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 4px;\n transition: var(--test-transition);\n}\n\n.shortcuts-close:hover {\n color: var(--test-text);\n background: var(--test-border);\n}\n\n.shortcut-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.shortcut-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.shortcut-keys {\n display: flex;\n gap: 4px;\n}\n\n.shortcut-keys kbd {\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: 4px;\n padding: 2px 6px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 11px;\n color: var(--test-text);\n}\n\n/* ===========================\n Responsive Design - Tablet\n =========================== */\n@media (max-width: 1024px) {\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .config-grid {\n grid-template-columns: 1fr;\n }\n\n .keyboard-shortcuts, .shortcuts-toggle {\n display: none;\n }\n}\n\n/* ===========================\n Responsive Design - Mobile\n =========================== */\n@media (max-width: 768px) {\n .test-form {\n height: auto;\n min-height: 100%;\n }\n\n .test-header {\n padding: 16px;\n }\n\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-left {\n width: 100%;\n }\n\n .test-icon {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .test-info h1 {\n font-size: 18px;\n }\n\n .test-meta {\n gap: 8px;\n }\n\n .status-badge {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .header-actions {\n width: 100%;\n justify-content: stretch;\n }\n\n .header-actions button {\n flex: 1;\n }\n\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .metric-card {\n padding: 12px;\n }\n\n .metric-value {\n font-size: 16px;\n }\n\n .tabs {\n padding: 0 12px;\n }\n\n .tab {\n padding: 12px 14px;\n font-size: 13px;\n gap: 6px;\n }\n\n .tab i {\n font-size: 14px;\n }\n\n .tab-shortcut {\n display: none;\n }\n\n .tab-content {\n padding: 16px;\n }\n\n .info-section,\n .json-section,\n .config-section {\n padding: 18px;\n }\n\n .info-grid {\n grid-template-columns: 1fr;\n }\n\n .json-tabs {\n flex-direction: column;\n }\n\n .json-tab {\n min-width: 0;\n justify-content: flex-start;\n }\n\n .run-item,\n .suite-item {\n padding: 14px;\n }\n\n .run-icon,\n .suite-icon {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .run-meta,\n .suite-meta {\n flex-direction: column;\n gap: 4px;\n }\n\n}\n\n/* ===========================\n Responsive Design - Small Mobile\n =========================== */\n@media (max-width: 480px) {\n .test-header {\n padding: 12px;\n }\n\n .header-left {\n gap: 12px;\n }\n\n .test-icon {\n width: 40px;\n height: 40px;\n font-size: 18px;\n border-radius: 8px;\n }\n\n .test-info h1 {\n font-size: 16px;\n }\n\n .metrics-bar {\n grid-template-columns: 1fr 1fr;\n }\n\n .tabs {\n padding: 0 8px;\n }\n\n .tab {\n padding: 10px 12px;\n font-size: 12px;\n }\n\n .tab-badge {\n display: none;\n }\n\n .tab-content {\n padding: 12px;\n }\n\n .run-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n}\n\n/* ===========================\n Touch Device Optimizations\n =========================== */\n@media (hover: none) and (pointer: coarse) {\n .tab,\n .json-tab,\n .run-item,\n .suite-item {\n -webkit-tap-highlight-color: transparent;\n }\n\n .run-item:active,\n .suite-item:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n transform: scale(0.98);\n }\n\n .tab:active,\n .json-tab:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n /* Larger touch targets */\n .tab {\n min-height: 48px;\n }\n\n .run-item,\n .suite-item {\n min-height: 64px;\n }\n}\n\n/* ===========================\n Reduced Motion\n =========================== */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n .skeleton-icon,\n .skeleton-line {\n animation: none;\n background: var(--mj-border-default);\n }\n}\n\n/* ===========================\n History Tab\n =========================== */\n.history-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n.history-content {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n/* History Filters */\n.history-filters {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n}\n\n.time-range-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--test-text-secondary);\n margin-right: 4px;\n}\n\n.filter-btn {\n padding: 8px 16px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n color: var(--test-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.filter-btn:hover {\n border-color: var(--test-primary-light);\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.filter-btn.active {\n background: var(--test-primary);\n color: var(--mj-text-inverse);\n border-color: var(--test-primary);\n}\n\n.history-actions {\n display: flex;\n gap: 8px;\n}\n\n/* KPI Cards */\n.history-kpi-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n transition: var(--test-transition);\n}\n\n.kpi-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.kpi-icon {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 20px;\n flex-shrink: 0;\n}\n\n.kpi-icon.pass-rate {\n background: var(--mj-status-success);\n}\n\n.kpi-content {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.trend-icon {\n font-size: 14px;\n}\n\n.trend-icon.trend-up {\n color: var(--test-success);\n}\n\n.trend-icon.trend-down {\n color: var(--test-error);\n}\n\n/* History Section */\n.history-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.history-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.history-section h3 i {\n color: var(--test-primary);\n}\n\n/* History Table */\n.history-table-container {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 14px;\n}\n\n.history-table th,\n.history-table td {\n padding: 12px 16px;\n text-align: left;\n border-bottom: 1px solid var(--test-border);\n}\n\n.history-table th {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n}\n\n.history-table tbody tr:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, transparent);\n}\n\n.date-cell {\n font-weight: 600;\n color: var(--test-text);\n}\n\n.passed-cell {\n color: var(--test-success);\n font-weight: 600;\n}\n\n.failed-cell {\n color: var(--test-error);\n font-weight: 600;\n}\n\n.pass-rate-cell {\n min-width: 120px;\n}\n\n.pass-rate-bar {\n position: relative;\n height: 24px;\n background: var(--test-bg);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.pass-rate-fill {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 12px;\n transition: width 0.5s ease-out;\n}\n\n.pass-rate-text {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n font-size: 11px;\n font-weight: 700;\n color: var(--test-text);\n z-index: 1;\n}\n\n/* Suite Performance List */\n.suite-performance-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.suite-perf-card {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 18px;\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n}\n\n.suite-perf-header {\n flex: 1;\n min-width: 0;\n}\n\n.suite-perf-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 6px;\n}\n\n.suite-perf-tags {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.tag-mini {\n display: inline-flex;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.tag-more {\n display: inline-flex;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.suite-perf-stats {\n display: flex;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.suite-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n}\n\n.suite-stat .stat-value {\n font-size: 16px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n.suite-stat .stat-value.pass-rate.high {\n color: var(--test-success);\n}\n\n.suite-stat .stat-value.pass-rate.low {\n color: var(--test-error);\n}\n\n.suite-stat .stat-label {\n font-size: 10px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.suite-perf-arrow {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover .suite-perf-arrow {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* ===========================\n Print Styles\n =========================== */\n@media print {\n .test-form {\n background: var(--mj-bg-surface);\n height: auto;\n }\n\n .header-actions,\n .tabs-container,\n .keyboard-shortcuts {\n display: none !important;\n }\n\n .tab-content {\n overflow: visible;\n padding: 0;\n }\n\n .info-section,\n .json-section,\n .config-section {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}\n\n/* ===========================\n Editable Form Sections (Config tab)\n =========================== */\n\n.edit-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.edit-section-header {\n margin: 0 0 18px 0;\n}\n\n.edit-section-header h3 {\n margin: 0 0 4px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.edit-section-header h3 i {\n color: var(--test-primary);\n}\n\n.edit-section-sub {\n margin: 0;\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.edit-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 18px;\n}\n\n@media (max-width: 720px) {\n .edit-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.edit-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.edit-field--full {\n grid-column: 1 / -1;\n}\n\n.edit-field label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.edit-field .required {\n color: var(--mj-status-error);\n margin-left: 2px;\n}\n\n.config-textarea {\n resize: vertical;\n min-height: 72px;\n font-family: inherit;\n line-height: 1.5;\n}\n\n.select-wrapper {\n position: relative;\n}\n\n.select-wrapper select.config-input {\n padding-right: 36px;\n appearance: none;\n background-color: var(--test-surface);\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748b' d='M1.41 0L6 4.59 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 14px center;\n background-size: 10px 7px;\n}\n\n/* Tag editor (chips + inline input) */\n.tag-editor {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 10px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n transition: var(--test-transition);\n cursor: text;\n min-height: 42px;\n align-items: center;\n}\n\n.tag-editor:focus-within {\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.tag-chip-editable {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 4px 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n.tag-chip-editable .tag-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 10px;\n transition: background 0.15s;\n}\n\n.tag-chip-editable .tag-remove:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n color: var(--mj-brand-primary-hover);\n}\n\n.tag-input-inline {\n flex: 1;\n min-width: 140px;\n border: none;\n background: transparent;\n outline: none;\n font-size: 13px;\n color: var(--test-text);\n padding: 4px 2px;\n}\n\n.tag-input-inline::placeholder {\n color: var(--test-text-muted);\n}\n\n/* Read-only metadata block at bottom of Config tab */\n.meta-section {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n padding: 14px 18px;\n border: 1px solid var(--test-border);\n}\n\n.meta-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n}\n\n.meta-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.meta-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.meta-value {\n font-size: 12px;\n color: var(--test-text-secondary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.meta-mono {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n font-size: 11px;\n}\n\n/* Dirty indicator next to the title */\n.dirty-indicator {\n display: inline-block;\n margin-left: 8px;\n font-size: 14px;\n color: var(--mj-status-warning);\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n vertical-align: middle;\n}\n\n@keyframes pulseDot {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.85); }\n}\n\n.unsaved-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.unsaved-pill i {\n font-size: 6px;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n/* Pad the bottom of the tab content when the save bar is visible\n so the bar doesn't cover the last form field. */\n.tab-content.has-savebar {\n padding-bottom: 84px;\n}\n\n/* ===========================\n Sticky Save Bar\n =========================== */\n\n.save-bar {\n position: absolute;\n left: 16px;\n right: 96px; /* leaves room for the bottom-right chat launcher */\n bottom: 16px;\n z-index: 50;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 12px 16px 12px 20px;\n background: var(--mj-bg-surface-elevated, var(--test-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--test-border));\n border-radius: 14px;\n box-shadow: 0 12px 32px color-mix(in srgb, var(--mj-status-warning) 10%, rgba(0, 0, 0, 0.18));\n backdrop-filter: blur(8px);\n /* Hidden / off-screen state by default. The .save-bar--visible class\n animates it up into view. Using `transition` (not `animation`)\n guarantees the change runs every time isDirty toggles. */\n opacity: 0;\n transform: translateY(calc(100% + 32px));\n pointer-events: none;\n transition:\n transform 420ms cubic-bezier(0.16, 1, 0.3, 1),\n opacity 260ms cubic-bezier(0.16, 1, 0.3, 1);\n will-change: transform, opacity;\n}\n\n.save-bar--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .save-bar {\n transition: opacity 180ms ease-out;\n transform: none;\n }\n .save-bar--visible {\n transform: none;\n }\n}\n\n.save-bar-message {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.save-bar-dot {\n color: var(--mj-status-warning);\n font-size: 12px;\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n.save-bar-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.save-bar-text strong {\n font-size: 14px;\n color: var(--test-text);\n font-weight: 700;\n}\n\n.save-bar-fields {\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.save-bar-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.save-bar-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 9px 16px;\n font-size: 13px;\n font-weight: 600;\n border-radius: 8px;\n border: 1px solid transparent;\n cursor: pointer;\n transition: var(--test-transition);\n font-family: inherit;\n}\n\n.save-bar-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.save-bar-btn--primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, white);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n}\n\n.save-bar-btn--primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n\n.save-bar-btn--primary:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.save-bar-btn--ghost {\n background: transparent;\n color: var(--test-text-secondary);\n border-color: var(--test-border);\n}\n\n.save-bar-btn--ghost:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover, var(--mj-bg-surface-card));\n color: var(--test-text);\n border-color: var(--test-text-muted);\n}\n\n.save-bar-kbd {\n display: inline-flex;\n gap: 3px;\n margin-left: 6px;\n opacity: 0.85;\n}\n\n.save-bar-kbd kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 4px;\n font-size: 10px;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n background: color-mix(in srgb, white 18%, transparent);\n border: 1px solid color-mix(in srgb, white 35%, transparent);\n border-radius: 4px;\n color: inherit;\n}\n\n@media (max-width: 640px) {\n .save-bar {\n left: 8px;\n right: 8px;\n bottom: 88px; /* push above the chat launcher on small screens */\n flex-direction: column;\n align-items: stretch;\n padding: 12px;\n }\n .save-bar-actions {\n justify-content: space-between;\n }\n .save-bar-kbd {\n display: none;\n }\n}\n\n"] }]
2772
+ args: [{ standalone: false, selector: 'mj-test-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-form\">\n <!-- Header Section -->\n <div class=\"test-header\">\n <!-- Breadcrumb Navigation -->\n <nav class=\"breadcrumb\" aria-label=\"Breadcrumb\">\n <ol>\n <li>\n <a href=\"javascript:void(0)\" (click)=\"navigateToTestingDashboard()\">\n <i class=\"fas fa-vial\"></i>\n <span class=\"breadcrumb-text\">Testing</span>\n </a>\n </li>\n <li class=\"current\">\n <i class=\"fas fa-chevron-right separator\"></i>\n <i class=\"fas fa-flask\"></i>\n <span>{{ record.Name }}</span>\n </li>\n </ol>\n </nav>\n\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"test-icon\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas fa-flask\"></i>\n </div>\n <div class=\"test-info\">\n <h1>\n {{ record.Name }}\n @if (isDirty) {\n <span class=\"dirty-indicator\" title=\"You have unsaved changes\" aria-label=\"Unsaved changes\">\u25CF</span>\n }\n </h1>\n <div class=\"test-meta\">\n <span class=\"status-badge\" [ngClass]=\"getStatusClass()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n @if (record.Type) {\n <span class=\"test-type\">\n <i class=\"fas fa-tag\"></i>\n {{ record.Type }}\n </span>\n }\n @if (isDirty) {\n <span class=\"unsaved-pill\" title=\"You have unsaved changes\">\n <i class=\"fas fa-circle\"></i> Unsaved\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <app-evaluation-mode-toggle></app-evaluation-mode-toggle>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test\n </button>\n <button mjButton (click)=\"refresh()\" [disabled]=\"isRefreshing\">\n <i class=\"fas\" [ngClass]=\"isRefreshing ? 'fa-sync fa-spin' : 'fa-sync'\"></i>\n {{ isRefreshing ? 'Refreshing...' : 'Refresh' }}\n </button>\n </div>\n </div>\n\n <!-- Test Description -->\n @if (record.Description) {\n <div class=\"test-description\">\n <p>{{ record.Description }}</p>\n </div>\n }\n\n <!-- Metrics Bar -->\n @if (testRunsLoaded && testRuns.length > 0) {\n <div class=\"metrics-bar\">\n <div class=\"metric-card\">\n <div class=\"metric-label\">Total Runs</div>\n <div class=\"metric-value\">{{ testRuns.length }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Pass Rate</div>\n <div class=\"metric-value\">{{ getPassRate().toFixed(1) }}%</div>\n <div class=\"metric-progress\">\n <div class=\"metric-progress-fill\" [style.width.%]=\"getPassRate()\"></div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Cost</div>\n <div class=\"metric-value\">{{ formatCost(getAverageCost()) }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Duration</div>\n <div class=\"metric-value\">{{ formatDuration(getAverageDuration()) }}</div>\n </div>\n </div>\n }\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs-container\">\n <div class=\"tabs\" role=\"tablist\">\n <button class=\"tab\"\n [class.active]=\"activeTab === 'overview'\"\n (click)=\"changeTab('overview')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'overview'\">\n <i class=\"fas fa-th-large\"></i>\n <span>Overview</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'config'\"\n (click)=\"changeTab('config')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'config'\">\n <i class=\"fas fa-sliders-h\"></i>\n <span>Configuration</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'runs'\"\n (click)=\"changeTab('runs')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'runs'\">\n <i class=\"fas fa-history\"></i>\n <span>Runs</span>\n @if (testRunsLoaded) {\n <span class=\"tab-badge\">{{ testRuns.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'suites'\"\n (click)=\"changeTab('suites')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'suites'\">\n <i class=\"fas fa-layer-group\"></i>\n <span>Test Suites</span>\n @if (suiteTestsLoaded) {\n <span class=\"tab-badge\">{{ suiteTests.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'analytics'\"\n (click)=\"changeTab('analytics')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'analytics'\">\n <i class=\"fas fa-chart-line\"></i>\n <span>Analytics</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\" [class.has-savebar]=\"isDirty\">\n <!-- Overview Tab -->\n @if (activeTab === 'overview') {\n <div class=\"overview-tab\">\n <!-- Basic Information -->\n <div class=\"info-section\">\n <h3><i class=\"fas fa-info-circle\"></i> Test Information</h3>\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <div class=\"info-label\">Name</div>\n <div class=\"info-value\">{{ record.Name }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Type</div>\n <div class=\"info-value\">{{ record.Type || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Status</div>\n <div class=\"info-value\">\n <span class=\"status-badge-inline\" [ngClass]=\"getStatusClass()\">{{ record.Status }}</span>\n </div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Priority</div>\n <div class=\"info-value\">{{ record.Priority || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Duration</div>\n <div class=\"info-value\">{{ record.EstimatedDurationSeconds ? formatDuration(record.EstimatedDurationSeconds) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Cost</div>\n <div class=\"info-value\">{{ record.EstimatedCostUSD ? formatCost(record.EstimatedCostUSD) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Repeat Count</div>\n <div class=\"info-value\">{{ record.RepeatCount || 1 }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Max Execution Time</div>\n <div class=\"info-value\">{{ formatTimeout(record.MaxExecutionTimeMS) }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Created</div>\n <div class=\"info-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Updated</div>\n <div class=\"info-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n </div>\n </div>\n <!-- JSON Data Views -->\n <div class=\"json-section\">\n <h3><i class=\"fas fa-code\"></i> Test Definition</h3>\n <div class=\"json-tabs\">\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'input'\"\n (click)=\"setJsonView('input')\">\n <i class=\"fas fa-sign-in-alt\"></i>\n Input Definition\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'expected'\"\n (click)=\"setJsonView('expected')\">\n <i class=\"fas fa-check-double\"></i>\n Expected Outcomes\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'config'\"\n (click)=\"setJsonView('config')\">\n <i class=\"fas fa-cog\"></i>\n Configuration\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'tags'\"\n (click)=\"setJsonView('tags')\">\n <i class=\"fas fa-tags\"></i>\n Tags\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"getJsonData()\"\n language=\"json\"\n [readonly]=\"true\"\n [toolbar]=\"jsonToolbar\"\n [lineWrapping]=\"true\">\n </mj-code-editor>\n </div>\n </div>\n </div>\n }\n\n <!-- Configuration Tab -->\n @if (activeTab === 'config') {\n <div class=\"config-tab\">\n <!-- Details -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-pen-to-square\"></i> Details</h3>\n <p class=\"edit-section-sub\">Edit any field \u2014 changes are saved with the bar at the bottom.</p>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-name\">Name <span class=\"required\">*</span></label>\n <input\n id=\"test-name\"\n type=\"text\"\n class=\"config-input\"\n placeholder=\"e.g., Agent Response Quality Test\"\n [(ngModel)]=\"record.Name\"\n />\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-description\">Description</label>\n <textarea\n id=\"test-description\"\n class=\"config-input config-textarea\"\n rows=\"3\"\n placeholder=\"What does this test evaluate?\"\n [ngModel]=\"record.Description\"\n (ngModelChange)=\"record.Description = $event || null\"\n ></textarea>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-status\">Status</label>\n <div class=\"select-wrapper\">\n <select\n id=\"test-status\"\n class=\"config-input\"\n [(ngModel)]=\"record.Status\"\n >\n @for (opt of statusOptions; track opt) {\n <option [ngValue]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-rubric\">Rubric</label>\n <select\n id=\"test-rubric\"\n class=\"config-input\"\n [ngModel]=\"record.RubricID\"\n (ngModelChange)=\"record.RubricID = $event || null\"\n >\n <option [ngValue]=\"null\">\u2014 None \u2014</option>\n @for (rubric of RubricOptions; track rubric.id) {\n <option [ngValue]=\"rubric.id\">{{ rubric.name }}</option>\n }\n </select>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-type\">Test Type</label>\n <select\n id=\"test-type\"\n class=\"config-input\"\n [(ngModel)]=\"record.TypeID\"\n >\n @for (t of testTypeOptions; track t.ID) {\n <option [ngValue]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-tags\">Tags</label>\n <div class=\"tag-editor\" (click)=\"tagInput.focus()\">\n @for (tag of tags; track tag) {\n <span class=\"tag-chip-editable\">\n {{ tag }}\n <button type=\"button\" class=\"tag-remove\" (click)=\"removeTag(tag); $event.stopPropagation()\" [attr.aria-label]=\"'Remove tag ' + tag\">\n <i class=\"fas fa-times\"></i>\n </button>\n </span>\n }\n <input\n #tagInput\n id=\"test-tags\"\n type=\"text\"\n class=\"tag-input-inline\"\n [placeholder]=\"tags.length === 0 ? 'Add tags, press Enter or comma...' : ''\"\n [(ngModel)]=\"tagDraft\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTagFromDraft()\"\n />\n </div>\n <span class=\"config-hint\">Press Enter or comma to add a tag. Backspace on empty input removes the last tag.</span>\n </div>\n </div>\n </section>\n\n <!-- Execution Settings -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-cogs\"></i> Execution Settings</h3>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field\">\n <label for=\"test-priority\">Priority</label>\n <input\n id=\"test-priority\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0 (lower runs first)\"\n [ngModel]=\"record.Priority\"\n (ngModelChange)=\"record.Priority = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Lower numbers run first.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-repeat\">Repeat Count</label>\n <input\n id=\"test-repeat\"\n type=\"number\"\n class=\"config-input\"\n min=\"1\"\n placeholder=\"1\"\n [ngModel]=\"record.RepeatCount\"\n (ngModelChange)=\"record.RepeatCount = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Number of times to repeat for statistical analysis.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-duration\">Estimated Duration (seconds)</label>\n <input\n id=\"test-duration\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0\"\n [ngModel]=\"record.EstimatedDurationSeconds\"\n (ngModelChange)=\"record.EstimatedDurationSeconds = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field\">\n <label for=\"test-cost\">Estimated Cost (USD)</label>\n <input\n id=\"test-cost\"\n type=\"number\"\n step=\"0.000001\"\n class=\"config-input\"\n placeholder=\"0.00\"\n [ngModel]=\"record.EstimatedCostUSD\"\n (ngModelChange)=\"record.EstimatedCostUSD = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-timeout\">Max Execution Time (ms)</label>\n <input\n id=\"test-timeout\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"Default: 300000 (5 min)\"\n [ngModel]=\"record.MaxExecutionTimeMS\"\n (ngModelChange)=\"record.MaxExecutionTimeMS = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Leave empty for the default 5 minute timeout. Currently: {{ formatTimeout(record.MaxExecutionTimeMS) }}</span>\n </div>\n </div>\n </section>\n\n <!-- JSON editors (preserved from original layout) -->\n <div class=\"config-section\">\n <h3><i class=\"fas fa-sign-in-alt\"></i> Input Definition (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.InputDefinition || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.InputDefinition = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-check-double\"></i> Expected Outcomes (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.ExpectedOutcomes || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.ExpectedOutcomes = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-cog\"></i> Configuration (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.Configuration || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.Configuration = $event\">\n </mj-code-editor>\n </div>\n </div>\n\n <!-- Metadata (read-only) -->\n <section class=\"meta-section\">\n <div class=\"meta-grid\">\n <div class=\"meta-item\">\n <div class=\"meta-label\">Created</div>\n <div class=\"meta-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Last updated</div>\n <div class=\"meta-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Test ID</div>\n <div class=\"meta-value meta-mono\">{{ record.ID }}</div>\n </div>\n </div>\n </section>\n </div>\n }\n\n <!-- Test Runs Tab -->\n @if (activeTab === 'runs') {\n <div class=\"runs-tab\">\n <!-- Loading State -->\n @if (loadingRuns) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3,4,5]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Runs List -->\n @if (!loadingRuns && testRuns.length > 0) {\n <div class=\"runs-list\">\n @for (run of testRuns; track run) {\n <div class=\"run-item\" (click)=\"openTestRun(run.ID)\">\n <div class=\"run-icon\" [style.background-color]=\"getRunStatusColor(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-stopwatch]=\"run.Status === 'Timeout'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n </div>\n <div class=\"run-content\">\n <div class=\"run-header\">\n <span class=\"run-id\">Run #{{ run.ID.substring(0, 8) }}</span>\n <span class=\"run-status\" [style.color]=\"getRunStatusColor(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-meta\">\n <span><i class=\"fas fa-calendar\"></i> {{ getRelativeTime(run.StartedAt) }}</span>\n @if (run.DurationSeconds) {\n <span><i class=\"fas fa-clock\"></i> {{ formatDuration(run.DurationSeconds) }}</span>\n }\n @if (run.CostUSD) {\n <span><i class=\"fas fa-dollar-sign\"></i> {{ formatCost(run.CostUSD) }}</span>\n }\n @if (run.TargetLogEntityID && run.TargetLogID) {\n <mj-entity-link-pill\n [entityName]=\"run.TargetLogEntity\"\n [recordId]=\"run.TargetLogID\">\n </mj-entity-link-pill>\n }\n </div>\n <!-- Evaluation indicators -->\n <div class=\"run-eval-stack\">\n <!-- Status indicator -->\n @if (evalPreferences.showExecution) {\n <span class=\"eval-pill status-pill\"\n [ngClass]=\"'status-' + run.Status.toLowerCase()\"\n [title]=\"getStatusTooltip(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-hourglass-end]=\"run.Status === 'Timeout'\"\n [class.fa-forward]=\"run.Status === 'Skipped'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n <span>{{ run.Status }}</span>\n </span>\n }\n <!-- Human feedback indicator -->\n @if (evalPreferences.showHuman) {\n @if (!getFeedbackForRun(run.ID)?.Rating) {\n <span class=\"eval-pill human-pill no-feedback\"\n title=\"Human Review: No rating submitted yet\">\n <i class=\"fas fa-user-slash\"></i>\n </span>\n }\n @if (getFeedbackForRun(run.ID)?.Rating; as rating) {\n <span class=\"eval-pill human-pill has-feedback\"\n [class.rating-low]=\"rating <= 4\"\n [class.rating-medium]=\"rating >= 5 && rating <= 6\"\n [class.rating-good]=\"rating >= 7 && rating <= 8\"\n [class.rating-excellent]=\"rating >= 9\"\n [title]=\"getHumanTooltip(rating, getFeedbackForRun(run.ID)?.CorrectionSummary || getFeedbackForRun(run.ID)?.Comments || null)\">\n <i class=\"fas fa-user\"></i>\n <span>{{ rating }}</span>\n </span>\n }\n }\n <!-- Auto score indicator -->\n @if (evalPreferences.showAuto) {\n @if (run.Score == null) {\n <span class=\"eval-pill auto-pill no-score\"\n title=\"Auto Score: No automated score available\">\n <i class=\"fas fa-robot\"></i>\n </span>\n }\n @if (run.Score != null) {\n <span class=\"eval-pill auto-pill has-score\"\n [class.score-low]=\"run.Score < 0.5\"\n [class.score-medium]=\"run.Score >= 0.5 && run.Score < 0.7\"\n [class.score-good]=\"run.Score >= 0.7 && run.Score < 0.85\"\n [class.score-excellent]=\"run.Score >= 0.85\"\n [title]=\"'Auto Score: ' + (run.Score * 100).toFixed(0) + '% automated evaluation'\">\n <i class=\"fas fa-robot\"></i>\n <span>{{ (run.Score * 100).toFixed(0) }}%</span>\n </span>\n }\n }\n </div>\n @if (getRunTags(run).length > 0) {\n <div class=\"run-tags\">\n @for (tag of getRunTags(run).slice(0, 3); track tag) {\n <span class=\"run-tag\">{{ tag }}</span>\n }\n @if (getRunTags(run).length > 3) {\n <span class=\"run-tag-more\">+{{ getRunTags(run).length - 3 }}</span>\n }\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (testRunsLoaded && !loadingRuns && testRuns.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-circle-play\"\n Title=\"No Test Runs Yet\"\n Message=\"Run this test to see execution history and results here.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n\n <!-- Test Suites Tab -->\n @if (activeTab === 'suites') {\n <div class=\"suites-tab\">\n <!-- Loading State -->\n @if (loadingSuites) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Suites List -->\n @if (!loadingSuites && suiteTests.length > 0) {\n <div class=\"suites-list\">\n @for (suiteTest of suiteTests; track suiteTest) {\n <div class=\"suite-item\" (click)=\"openTestSuite(suiteTest.SuiteID)\">\n <div class=\"suite-icon\">\n <i class=\"fas fa-layer-group\"></i>\n </div>\n <div class=\"suite-content\">\n <div class=\"suite-name\">{{ suiteTest.Suite }}</div>\n <div class=\"suite-meta\">\n <span><i class=\"fas fa-sort-numeric-up\"></i> Sequence: {{ suiteTest.Sequence }}</span>\n @if (suiteTest.Status) {\n <span><i class=\"fas fa-info-circle\"></i> {{ suiteTest.Status }}</span>\n }\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (suiteTestsLoaded && !loadingSuites && suiteTests.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-folder-open\"\n Title=\"Not Part of Any Suite\"\n Message=\"This test is not included in any test suites. Add it to a suite to run it with other tests.\" />\n }\n </div>\n }\n\n <!-- Analytics Tab -->\n @if (activeTab === 'analytics') {\n <div class=\"history-tab\">\n <!-- Loading State -->\n @if (loadingHistory) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading history...\"></mj-loading>\n </div>\n }\n <!-- History Content -->\n @if (!loadingHistory && historyLoaded) {\n <div class=\"history-content\">\n <!-- Filters -->\n <div class=\"history-filters\">\n <div class=\"time-range-filters\">\n <span class=\"filter-label\">Time Range:</span>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '7d'\"\n (click)=\"setHistoryTimeRange('7d')\">7 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '30d'\"\n (click)=\"setHistoryTimeRange('30d')\">30 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === '90d'\"\n (click)=\"setHistoryTimeRange('90d')\">90 Days</button>\n <button class=\"filter-btn\"\n [class.active]=\"historyTimeRange === 'all'\"\n (click)=\"setHistoryTimeRange('all')\">All Time</button>\n </div>\n <div class=\"history-actions\">\n <button mjButton (click)=\"exportHistoryToCSV()\" [disabled]=\"historyData.length === 0\">\n <i class=\"fas fa-download\"></i> Export CSV\n </button>\n </div>\n </div>\n <!-- KPI Cards -->\n @if (historyData.length > 0) {\n <div class=\"history-kpi-cards\">\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-play-circle\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ getTotalRuns() }}</div>\n <div class=\"kpi-label\">Total Runs</div>\n </div>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon pass-rate\">\n <i class=\"fas fa-percentage\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">\n {{ getOverallPassRate().toFixed(1) }}%\n <i class=\"fas trend-icon\"\n [class.fa-arrow-up]=\"getPassRateTrend() === 'up'\"\n [class.fa-arrow-down]=\"getPassRateTrend() === 'down'\"\n [class.fa-minus]=\"getPassRateTrend() === 'stable'\"\n [class.trend-up]=\"getPassRateTrend() === 'up'\"\n [class.trend-down]=\"getPassRateTrend() === 'down'\"></i>\n </div>\n <div class=\"kpi-label\">Pass Rate</div>\n </div>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-star\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ (getOverallAvgScore() * 100).toFixed(1) }}%</div>\n <div class=\"kpi-label\">Avg Score</div>\n </div>\n </div>\n }\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-clock\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatDuration(getOverallAvgDuration()) }}</div>\n <div class=\"kpi-label\">Avg Duration</div>\n </div>\n </div>\n <div class=\"kpi-card\">\n <div class=\"kpi-icon\">\n <i class=\"fas fa-dollar-sign\"></i>\n </div>\n <div class=\"kpi-content\">\n <div class=\"kpi-value\">{{ formatCost(getOverallAvgCost()) }}</div>\n <div class=\"kpi-label\">Avg Cost</div>\n </div>\n </div>\n </div>\n }\n <!-- Daily History Table -->\n @if (historyData.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-calendar-alt\"></i> Daily Performance</h3>\n <div class=\"history-table-container\">\n <table class=\"history-table\">\n <thead>\n <tr>\n <th>Date</th>\n <th>Runs</th>\n @if (evalPreferences.showExecution) {\n <th>Passed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Failed</th>\n }\n @if (evalPreferences.showExecution) {\n <th>Pass Rate</th>\n }\n @if (evalPreferences.showAuto) {\n <th>Avg Score</th>\n }\n <th>Avg Duration</th>\n <th>Avg Cost</th>\n </tr>\n </thead>\n <tbody>\n @for (day of historyData; track day) {\n <tr>\n <td class=\"date-cell\">{{ day.date | date:'mediumDate' }}</td>\n <td class=\"runs-cell\">{{ day.runCount }}</td>\n @if (evalPreferences.showExecution) {\n <td class=\"passed-cell\">{{ day.passCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"failed-cell\">{{ day.failCount }}</td>\n }\n @if (evalPreferences.showExecution) {\n <td class=\"pass-rate-cell\">\n <div class=\"pass-rate-bar\">\n <div class=\"pass-rate-fill\" [style.width.%]=\"day.passRate\"></div>\n <span class=\"pass-rate-text\">{{ day.passRate.toFixed(1) }}%</span>\n </div>\n </td>\n }\n @if (evalPreferences.showAuto) {\n <td class=\"score-cell\">{{ (day.avgScore * 100).toFixed(1) }}%</td>\n }\n <td class=\"duration-cell\">{{ formatDuration(day.avgDuration) }}</td>\n <td class=\"cost-cell\">{{ formatCost(day.avgCost) }}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n <!-- Suite Performance -->\n @if (suitePerformance.length > 0) {\n <div class=\"history-section\">\n <h3><i class=\"fas fa-layer-group\"></i> Performance by Suite</h3>\n <div class=\"suite-performance-list\">\n @for (suite of suitePerformance; track suite) {\n <div class=\"suite-perf-card\" (click)=\"openSuiteFromHistory(suite.suiteId)\">\n <div class=\"suite-perf-header\">\n <div class=\"suite-perf-name\">{{ suite.suiteName }}</div>\n @if (suite.tags.length > 0) {\n <div class=\"suite-perf-tags\">\n @for (tag of suite.tags.slice(0, 3); track tag) {\n <span class=\"tag-mini\">{{ tag }}</span>\n }\n @if (suite.tags.length > 3) {\n <span class=\"tag-more\">+{{ suite.tags.length - 3 }}</span>\n }\n </div>\n }\n </div>\n <div class=\"suite-perf-stats\">\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ suite.totalRuns }}</span>\n <span class=\"stat-label\">Runs</span>\n </div>\n @if (evalPreferences.showExecution) {\n <div class=\"suite-stat\">\n <span class=\"stat-value pass-rate\" [class.high]=\"suite.passRate >= 80\" [class.low]=\"suite.passRate < 50\">\n {{ suite.passRate.toFixed(1) }}%\n </span>\n <span class=\"stat-label\">Pass Rate</span>\n </div>\n }\n @if (evalPreferences.showAuto) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ (suite.avgScore * 100).toFixed(1) }}%</span>\n <span class=\"stat-label\">Avg Score</span>\n </div>\n }\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatDuration(suite.avgDuration) }}</span>\n <span class=\"stat-label\">Avg Duration</span>\n </div>\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ formatCost(suite.avgCost) }}</span>\n <span class=\"stat-label\">Avg Cost</span>\n </div>\n @if (suite.lastRun) {\n <div class=\"suite-stat\">\n <span class=\"stat-value\">{{ getRelativeTime(suite.lastRun) }}</span>\n <span class=\"stat-label\">Last Run</span>\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right suite-perf-arrow\"></i>\n </div>\n }\n </div>\n </div>\n }\n <!-- Empty State -->\n @if (historyData.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-chart-line\"\n Title=\"No History Available\"\n Message=\"Run this test to start building history and analytics data.\"\n ActionText=\"Run Test Now\"\n ActionIcon=\"fa-solid fa-play\"\n (Action)=\"runTest()\" />\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Keyboard Shortcuts Toggle Button -->\n <button class=\"shortcuts-toggle\" (click)=\"toggleShortcuts()\" [title]=\"showShortcuts ? 'Hide keyboard shortcuts' : 'Show keyboard shortcuts'\">\n <i class=\"fas fa-keyboard\"></i>\n </button>\n\n <!-- Keyboard Shortcuts Hint (Desktop Only) -->\n @if (showShortcuts) {\n <div class=\"keyboard-shortcuts\">\n <div class=\"shortcuts-header\">\n <i class=\"fas fa-keyboard\"></i>\n Shortcuts\n <button class=\"shortcuts-close\" (click)=\"toggleShortcuts()\" title=\"Hide shortcuts\">\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n <div class=\"shortcut-list\">\n <div class=\"shortcut-item\">\n <span>Save changes</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>S</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Refresh</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>R</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Run Test</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>Enter</kbd></span>\n </div>\n <div class=\"shortcut-item\">\n <span>Switch Tabs</span>\n <span class=\"shortcut-keys\"><kbd>1</kbd>-<kbd>5</kbd></span>\n </div>\n </div>\n </div>\n }\n\n <!-- Slide Panel for Test Execution -->\n @if (testingDialogService.IsPanelOpen) {\n <mj-slide-panel\n Mode=\"slide\"\n [Title]=\"testingDialogService.PanelOptions?.testId ? 'Test Execution' : 'Run Test'\"\n [Resizable]=\"true\"\n (Closed)=\"OnPanelClosed()\">\n <app-test-run-dialog\n [PanelMode]=\"true\"\n [selectedTestId]=\"testingDialogService.PanelOptions?.testId ?? null\"\n [selectedSuiteId]=\"testingDialogService.PanelOptions?.suiteId ?? null\"\n [runMode]=\"testingDialogService.PanelOptions?.mode ?? 'test'\"\n (PanelClose)=\"OnPanelClosed()\">\n </app-test-run-dialog>\n </mj-slide-panel>\n }\n\n <!-- Sticky Save Bar \u2014 always in the DOM so CSS transitions can fire reliably.\n Visibility is controlled by the .save-bar--visible class, driven by isDirty. -->\n <div\n class=\"save-bar\"\n [class.save-bar--visible]=\"isDirty\"\n [attr.aria-hidden]=\"!isDirty\"\n role=\"region\"\n aria-label=\"Unsaved changes\"\n >\n <div class=\"save-bar-message\">\n <span class=\"save-bar-dot\" aria-hidden=\"true\">\u25CF</span>\n <span class=\"save-bar-text\">\n <strong>Unsaved changes</strong>\n <span class=\"save-bar-fields\">\n @if (dirtyFieldNames.length === 1) {\n {{ dirtyFieldNames[0] }} edited\n } @else if (dirtyFieldNames.length > 1) {\n {{ dirtyFieldNames.length }} fields edited\n }\n </span>\n </span>\n </div>\n <div class=\"save-bar-actions\">\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--primary\"\n (click)=\"saveChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Save changes (\u2318S)\"\n >\n @if (isSaving) {\n <i class=\"fas fa-spinner fa-spin\"></i> Saving\u2026\n } @else {\n <i class=\"fas fa-check\"></i> Save changes\n <span class=\"save-bar-kbd\"><kbd>\u2318</kbd><kbd>S</kbd></span>\n }\n </button>\n <button\n type=\"button\"\n class=\"save-bar-btn save-bar-btn--ghost\"\n (click)=\"discardChanges()\"\n [disabled]=\"isSaving || !isDirty\"\n [attr.tabindex]=\"isDirty ? 0 : -1\"\n title=\"Discard changes\"\n >\n <i class=\"fas fa-undo\"></i> Discard\n </button>\n </div>\n </div>\n</div>\n", styles: ["/* ===========================\n Test Form - World-Class UX\n Premium Test Definition Styles\n =========================== */\n\n/* CSS Custom Properties for Theming - using :host for Angular encapsulation */\n:host {\n --test-primary: var(--mj-brand-primary);\n --test-primary-light: var(--mj-brand-primary);\n --test-primary-dark: var(--mj-brand-primary-hover);\n --test-success: var(--mj-status-success);\n --test-success-light: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n --test-error: var(--mj-status-error);\n --test-error-light: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n --test-warning: var(--mj-status-warning);\n --test-warning-light: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n --test-disabled: var(--mj-text-muted);\n --test-bg: var(--mj-bg-surface-card);\n --test-surface: var(--mj-bg-surface);\n --test-border: var(--mj-border-default);\n --test-text: var(--mj-text-primary);\n --test-text-secondary: var(--mj-text-muted);\n --test-text-muted: var(--mj-text-disabled);\n --test-radius-sm: 6px;\n --test-radius-md: 10px;\n --test-radius-lg: 16px;\n --test-shadow-sm: var(--mj-shadow-sm);\n --test-shadow-md: var(--mj-shadow-md);\n --test-shadow-lg: var(--mj-shadow-lg);\n --test-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n display: block;\n height: 100%;\n}\n\n/* Breadcrumb */\n.breadcrumb {\n margin-bottom: 16px;\n}\n\n.breadcrumb ol {\n display: flex;\n align-items: center;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n font-size: 13px;\n}\n\n.breadcrumb li {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.breadcrumb a {\n color: var(--test-primary);\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border-radius: 6px;\n transition: background 0.15s;\n}\n\n.breadcrumb a:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n text-decoration: none;\n}\n\n.breadcrumb .separator {\n font-size: 10px;\n color: var(--test-text-muted);\n margin: 0 4px;\n}\n\n.breadcrumb .current {\n color: var(--test-text-secondary);\n font-weight: 500;\n}\n\n.breadcrumb-text {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Base Container */\n.test-form {\n position: relative;\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--test-bg);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* ===========================\n Header Section\n =========================== */\n.test-header {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n padding: 20px;\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 16px;\n gap: 16px;\n}\n\n.header-left {\n display: flex;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n/* Test Icon */\n.test-icon {\n width: 56px;\n height: 56px;\n border-radius: var(--test-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-inverse);\n font-size: 24px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-md);\n transition: var(--test-transition);\n}\n\n.test-icon:hover {\n transform: scale(1.05);\n}\n\n/* Test Info */\n.test-info {\n flex: 1;\n min-width: 0;\n}\n\n.test-info h1 {\n margin: 0 0 8px 0;\n font-size: clamp(18px, 4vw, 24px);\n font-weight: 700;\n color: var(--test-text);\n line-height: 1.2;\n word-wrap: break-word;\n}\n\n.test-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* Status Badge */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border-radius: 20px;\n color: var(--mj-text-inverse);\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.status-badge.status-active { background: var(--mj-status-success); }\n.status-badge.status-disabled { background: var(--mj-text-secondary); }\n.status-badge.status-pending { background: var(--mj-status-warning); }\n\n.status-badge-inline {\n display: inline-flex;\n align-items: center;\n padding: 2px 10px;\n border-radius: 10px;\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n}\n\n.status-badge-inline.status-active { background: var(--test-success); }\n.status-badge-inline.status-disabled { background: var(--test-disabled); }\n.status-badge-inline.status-pending { background: var(--test-warning); }\n\n.test-type {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-size: 14px;\n color: var(--test-text-secondary);\n padding: 4px 10px;\n background: var(--test-bg);\n border-radius: var(--test-radius-sm);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.header-actions button {\n white-space: nowrap;\n}\n\n/* Test Description */\n.test-description {\n padding: 16px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n margin-bottom: 16px;\n border: 1px solid var(--test-border);\n}\n\n.test-description p {\n margin: 0;\n color: var(--test-text-secondary);\n line-height: 1.6;\n font-size: 14px;\n}\n\n/* ===========================\n Metrics Bar\n =========================== */\n.metrics-bar {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n}\n\n.metric-card {\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 14px;\n text-align: center;\n transition: var(--test-transition);\n}\n\n.metric-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.metric-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n margin-bottom: 6px;\n}\n\n.metric-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n/* Progress bar in metric card */\n.metric-progress {\n margin-top: 8px;\n height: 4px;\n background: var(--test-border);\n border-radius: 2px;\n overflow: hidden;\n}\n\n.metric-progress-fill {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.5s ease-out;\n}\n\n/* ===========================\n Tabs Navigation\n =========================== */\n.tabs-container {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.tabs {\n display: flex;\n padding: 0 20px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.tabs::-webkit-scrollbar {\n display: none;\n}\n\n.tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 14px 18px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: var(--test-text-secondary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n white-space: nowrap;\n}\n\n.tab:hover {\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.tab.active {\n color: var(--test-primary);\n border-bottom-color: var(--test-primary);\n font-weight: 600;\n}\n\n.tab i {\n font-size: 15px;\n}\n\n.tab-badge {\n background: var(--test-border);\n color: var(--test-text-secondary);\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.tab.active .tab-badge {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--test-primary);\n}\n\n.tab-shortcut {\n font-size: 10px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 600;\n margin-left: 4px;\n}\n\n/* ===========================\n Tab Content Area\n =========================== */\n.tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n/* ===========================\n Overview Tab\n =========================== */\n.overview-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n/* Info Section */\n.info-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.info-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.info-section h3 i {\n color: var(--test-primary);\n}\n\n.info-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n}\n\n.info-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.info-label {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.info-value {\n font-size: 14px;\n color: var(--test-text);\n word-wrap: break-word;\n font-weight: 500;\n}\n\n/* JSON Section */\n.json-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-section h3 {\n margin: 0 0 16px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.json-section h3 i {\n color: var(--test-primary);\n}\n\n.json-tabs {\n display: flex;\n gap: 4px;\n margin-bottom: 16px;\n background: var(--test-bg);\n border-radius: var(--test-radius-md);\n padding: 4px;\n flex-wrap: wrap;\n}\n\n.json-tab {\n flex: 1;\n min-width: 100px;\n padding: 10px 14px;\n border: none;\n background: transparent;\n color: var(--test-text-secondary);\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n border-radius: var(--test-radius-sm);\n transition: var(--test-transition);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n}\n\n.json-tab:hover {\n color: var(--test-text);\n background: var(--mj-bg-overlay);\n}\n\n.json-tab.active {\n background: var(--test-surface);\n color: var(--test-primary);\n font-weight: 600;\n box-shadow: var(--test-shadow-sm);\n}\n\n.json-tab i {\n font-size: 12px;\n}\n\n.code-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n max-height: 400px;\n}\n\n/* ===========================\n Configuration Tab\n =========================== */\n.config-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: fadeIn 0.3s ease-out;\n}\n\n.config-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.config-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.config-section h3 i {\n color: var(--test-primary);\n}\n\n.config-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 20px;\n}\n\n.config-item {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.config-item.full-width {\n grid-column: 1 / -1;\n}\n\n.config-item label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.config-input {\n padding: 10px 14px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n font-size: 14px;\n transition: var(--test-transition);\n background: var(--test-surface);\n}\n\n.config-input:focus {\n outline: none;\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.config-input::placeholder {\n color: var(--test-text-muted);\n}\n\n.config-hint {\n font-size: 11px;\n color: var(--test-text-muted);\n margin-top: 4px;\n}\n\n.config-editor-container {\n border-radius: var(--test-radius-md);\n overflow: hidden;\n border: 1px solid var(--test-border);\n min-height: 200px;\n}\n\n.config-editor-container.small {\n min-height: 100px;\n max-height: 150px;\n}\n\n/* ===========================\n Runs Tab\n =========================== */\n.runs-tab,\n.suites-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n/* Loading States & Skeletons */\n.loading-state {\n padding: 0;\n}\n\n.skeleton-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.skeleton-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n border: 1px solid var(--test-border);\n}\n\n.skeleton-icon {\n width: 44px;\n height: 44px;\n border-radius: var(--test-radius-md);\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n flex-shrink: 0;\n}\n\n.skeleton-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.skeleton-line {\n height: 14px;\n border-radius: 4px;\n background: linear-gradient(90deg, var(--mj-border-default) 25%, var(--mj-bg-surface-sunken) 50%, var(--mj-border-default) 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n}\n\n.skeleton-line.wide { width: 70%; }\n.skeleton-line.narrow { width: 40%; }\n\n@keyframes shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Runs List */\n.runs-list,\n.suites-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.run-item,\n.suite-item {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 16px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.run-item:hover,\n.suite-item:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n box-shadow: var(--test-shadow-sm);\n}\n\n.run-icon,\n.suite-icon {\n width: 44px;\n height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 18px;\n flex-shrink: 0;\n box-shadow: var(--test-shadow-sm);\n}\n\n.suite-icon {\n background: var(--mj-status-warning);\n}\n\n.run-content,\n.suite-content {\n flex: 1;\n min-width: 0;\n}\n\n.run-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-id {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.run-status {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.suite-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 4px;\n}\n\n.run-meta,\n.suite-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--test-text-secondary);\n flex-wrap: wrap;\n}\n\n.run-meta span,\n.suite-meta span {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-meta span i,\n.suite-meta span i {\n color: var(--test-text-muted);\n font-size: 11px;\n}\n\n.run-item > i.fa-chevron-right,\n.suite-item > i.fa-chevron-right {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.run-item:hover > i.fa-chevron-right,\n.suite-item:hover > i.fa-chevron-right {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* Run Evaluation Stack */\n.run-eval-stack {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n/* Evaluation Pills */\n.eval-pill {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n transition: var(--test-transition);\n}\n\n.eval-pill i {\n font-size: 10px;\n}\n\n/* Status pill colors */\n.eval-pill.status-pill.status-passed {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.status-pill.status-failed {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.status-pill.status-error {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-timeout {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.status-pill.status-skipped,\n.eval-pill.status-pill.status-pending {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.eval-pill.status-pill.status-running {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n/* Human feedback pills */\n.eval-pill.human-pill.no-feedback {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.human-pill.has-feedback.rating-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.human-pill.has-feedback.rating-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.human-pill.has-feedback.rating-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.human-pill.has-feedback.rating-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Auto score pills */\n.eval-pill.auto-pill.no-score {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-disabled);\n padding: 4px 8px;\n}\n\n.eval-pill.auto-pill.has-score.score-low {\n background: color-mix(in srgb, var(--mj-status-error) 15%, var(--mj-bg-surface));\n color: var(--mj-status-error);\n}\n\n.eval-pill.auto-pill.has-score.score-medium {\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning);\n}\n\n.eval-pill.auto-pill.has-score.score-good {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n.eval-pill.auto-pill.has-score.score-excellent {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n/* Run Tags */\n.run-tags {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n.run-tag {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n.run-tag-more {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 500;\n}\n\n/* ===========================\n Keyboard Shortcuts Popup\n =========================== */\n/* Keyboard shortcuts toggle button */\n.shortcuts-toggle {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n box-shadow: var(--test-shadow-md);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--test-text-secondary);\n font-size: 14px;\n z-index: 99;\n transition: var(--test-transition);\n opacity: 0.7;\n}\n\n.shortcuts-toggle:hover {\n opacity: 1;\n transform: scale(1.1);\n color: var(--test-primary);\n border-color: var(--test-primary);\n}\n\n.keyboard-shortcuts {\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: var(--test-surface);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n padding: 12px 16px;\n box-shadow: var(--test-shadow-lg);\n font-size: 12px;\n color: var(--test-text-secondary);\n z-index: 100;\n max-width: 260px;\n}\n\n.shortcuts-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--test-border);\n font-weight: 600;\n color: var(--test-text);\n}\n\n.shortcuts-close {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--test-text-muted);\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 4px;\n transition: var(--test-transition);\n}\n\n.shortcuts-close:hover {\n color: var(--test-text);\n background: var(--test-border);\n}\n\n.shortcut-list {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.shortcut-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.shortcut-keys {\n display: flex;\n gap: 4px;\n}\n\n.shortcut-keys kbd {\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: 4px;\n padding: 2px 6px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 11px;\n color: var(--test-text);\n}\n\n/* ===========================\n Responsive Design - Tablet\n =========================== */\n@media (max-width: 1024px) {\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .config-grid {\n grid-template-columns: 1fr;\n }\n\n .keyboard-shortcuts, .shortcuts-toggle {\n display: none;\n }\n}\n\n/* ===========================\n Responsive Design - Mobile\n =========================== */\n@media (max-width: 768px) {\n .test-form {\n height: auto;\n min-height: 100%;\n }\n\n .test-header {\n padding: 16px;\n }\n\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-left {\n width: 100%;\n }\n\n .test-icon {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .test-info h1 {\n font-size: 18px;\n }\n\n .test-meta {\n gap: 8px;\n }\n\n .status-badge {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .header-actions {\n width: 100%;\n justify-content: stretch;\n }\n\n .header-actions button {\n flex: 1;\n }\n\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .metric-card {\n padding: 12px;\n }\n\n .metric-value {\n font-size: 16px;\n }\n\n .tabs {\n padding: 0 12px;\n }\n\n .tab {\n padding: 12px 14px;\n font-size: 13px;\n gap: 6px;\n }\n\n .tab i {\n font-size: 14px;\n }\n\n .tab-shortcut {\n display: none;\n }\n\n .tab-content {\n padding: 16px;\n }\n\n .info-section,\n .json-section,\n .config-section {\n padding: 18px;\n }\n\n .info-grid {\n grid-template-columns: 1fr;\n }\n\n .json-tabs {\n flex-direction: column;\n }\n\n .json-tab {\n min-width: 0;\n justify-content: flex-start;\n }\n\n .run-item,\n .suite-item {\n padding: 14px;\n }\n\n .run-icon,\n .suite-icon {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .run-meta,\n .suite-meta {\n flex-direction: column;\n gap: 4px;\n }\n\n}\n\n/* ===========================\n Responsive Design - Small Mobile\n =========================== */\n@media (max-width: 480px) {\n .test-header {\n padding: 12px;\n }\n\n .header-left {\n gap: 12px;\n }\n\n .test-icon {\n width: 40px;\n height: 40px;\n font-size: 18px;\n border-radius: 8px;\n }\n\n .test-info h1 {\n font-size: 16px;\n }\n\n .metrics-bar {\n grid-template-columns: 1fr 1fr;\n }\n\n .tabs {\n padding: 0 8px;\n }\n\n .tab {\n padding: 10px 12px;\n font-size: 12px;\n }\n\n .tab-badge {\n display: none;\n }\n\n .tab-content {\n padding: 12px;\n }\n\n .run-header {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n}\n\n/* ===========================\n Touch Device Optimizations\n =========================== */\n@media (hover: none) and (pointer: coarse) {\n .tab,\n .json-tab,\n .run-item,\n .suite-item {\n -webkit-tap-highlight-color: transparent;\n }\n\n .run-item:active,\n .suite-item:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n transform: scale(0.98);\n }\n\n .tab:active,\n .json-tab:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n /* Larger touch targets */\n .tab {\n min-height: 48px;\n }\n\n .run-item,\n .suite-item {\n min-height: 64px;\n }\n}\n\n/* ===========================\n Reduced Motion\n =========================== */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n .skeleton-icon,\n .skeleton-line {\n animation: none;\n background: var(--mj-border-default);\n }\n}\n\n/* ===========================\n History Tab\n =========================== */\n.history-tab {\n animation: fadeIn 0.3s ease-out;\n}\n\n.history-content {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n/* History Filters */\n.history-filters {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n padding: 16px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n}\n\n.time-range-filters {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-label {\n font-size: 13px;\n font-weight: 600;\n color: var(--test-text-secondary);\n margin-right: 4px;\n}\n\n.filter-btn {\n padding: 8px 16px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n color: var(--test-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.filter-btn:hover {\n border-color: var(--test-primary-light);\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.filter-btn.active {\n background: var(--test-primary);\n color: var(--mj-text-inverse);\n border-color: var(--test-primary);\n}\n\n.history-actions {\n display: flex;\n gap: 8px;\n}\n\n/* KPI Cards */\n.history-kpi-cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n}\n\n.kpi-card {\n display: flex;\n align-items: center;\n gap: 14px;\n padding: 18px;\n background: var(--test-surface);\n border-radius: var(--test-radius-md);\n box-shadow: var(--test-shadow-sm);\n transition: var(--test-transition);\n}\n\n.kpi-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.kpi-icon {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-brand-primary);\n border-radius: var(--test-radius-md);\n color: var(--mj-text-inverse);\n font-size: 20px;\n flex-shrink: 0;\n}\n\n.kpi-icon.pass-rate {\n background: var(--mj-status-success);\n}\n\n.kpi-content {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value {\n font-size: 22px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.kpi-label {\n font-size: 12px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.trend-icon {\n font-size: 14px;\n}\n\n.trend-icon.trend-up {\n color: var(--test-success);\n}\n\n.trend-icon.trend-down {\n color: var(--test-error);\n}\n\n/* History Section */\n.history-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.history-section h3 {\n margin: 0 0 20px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.history-section h3 i {\n color: var(--test-primary);\n}\n\n/* History Table */\n.history-table-container {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.history-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 14px;\n}\n\n.history-table th,\n.history-table td {\n padding: 12px 16px;\n text-align: left;\n border-bottom: 1px solid var(--test-border);\n}\n\n.history-table th {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n background: var(--test-bg);\n}\n\n.history-table tbody tr:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, transparent);\n}\n\n.date-cell {\n font-weight: 600;\n color: var(--test-text);\n}\n\n.passed-cell {\n color: var(--test-success);\n font-weight: 600;\n}\n\n.failed-cell {\n color: var(--test-error);\n font-weight: 600;\n}\n\n.pass-rate-cell {\n min-width: 120px;\n}\n\n.pass-rate-bar {\n position: relative;\n height: 24px;\n background: var(--test-bg);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.pass-rate-fill {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 12px;\n transition: width 0.5s ease-out;\n}\n\n.pass-rate-text {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n font-size: 11px;\n font-weight: 700;\n color: var(--test-text);\n z-index: 1;\n}\n\n/* Suite Performance List */\n.suite-performance-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.suite-perf-card {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 18px;\n background: var(--test-bg);\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-md);\n cursor: pointer;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n border-color: var(--test-primary-light);\n transform: translateX(4px);\n}\n\n.suite-perf-header {\n flex: 1;\n min-width: 0;\n}\n\n.suite-perf-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 6px;\n}\n\n.suite-perf-tags {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.tag-mini {\n display: inline-flex;\n padding: 2px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--test-primary);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.tag-more {\n display: inline-flex;\n padding: 2px 8px;\n background: var(--test-border);\n color: var(--test-text-muted);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.suite-perf-stats {\n display: flex;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.suite-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n}\n\n.suite-stat .stat-value {\n font-size: 16px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n.suite-stat .stat-value.pass-rate.high {\n color: var(--test-success);\n}\n\n.suite-stat .stat-value.pass-rate.low {\n color: var(--test-error);\n}\n\n.suite-stat .stat-label {\n font-size: 10px;\n color: var(--test-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.suite-perf-arrow {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.suite-perf-card:hover .suite-perf-arrow {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n/* ===========================\n Print Styles\n =========================== */\n@media print {\n .test-form {\n background: var(--mj-bg-surface);\n height: auto;\n }\n\n .header-actions,\n .tabs-container,\n .keyboard-shortcuts {\n display: none !important;\n }\n\n .tab-content {\n overflow: visible;\n padding: 0;\n }\n\n .info-section,\n .json-section,\n .config-section {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}\n\n/* ===========================\n Editable Form Sections (Config tab)\n =========================== */\n\n.edit-section {\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n padding: 24px;\n box-shadow: var(--test-shadow-sm);\n}\n\n.edit-section-header {\n margin: 0 0 18px 0;\n}\n\n.edit-section-header h3 {\n margin: 0 0 4px 0;\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.edit-section-header h3 i {\n color: var(--test-primary);\n}\n\n.edit-section-sub {\n margin: 0;\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.edit-grid {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: 18px;\n}\n\n@media (max-width: 720px) {\n .edit-grid {\n grid-template-columns: 1fr;\n }\n}\n\n.edit-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.edit-field--full {\n grid-column: 1 / -1;\n}\n\n.edit-field label {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.edit-field .required {\n color: var(--mj-status-error);\n margin-left: 2px;\n}\n\n.config-textarea {\n resize: vertical;\n min-height: 72px;\n font-family: inherit;\n line-height: 1.5;\n}\n\n.select-wrapper {\n position: relative;\n}\n\n.select-wrapper select.config-input {\n padding-right: 36px;\n appearance: none;\n background-color: var(--test-surface);\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%2364748b' d='M1.41 0L6 4.59 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 14px center;\n background-size: 10px 7px;\n}\n\n/* Tag editor (chips + inline input) */\n.tag-editor {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 10px;\n border: 1px solid var(--test-border);\n border-radius: var(--test-radius-sm);\n background: var(--test-surface);\n transition: var(--test-transition);\n cursor: text;\n min-height: 42px;\n align-items: center;\n}\n\n.tag-editor:focus-within {\n border-color: var(--test-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.tag-chip-editable {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 3px 4px 3px 10px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary-hover);\n border-radius: 999px;\n font-size: 12px;\n font-weight: 600;\n line-height: 1;\n border: 1px solid color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n}\n\n.tag-chip-editable .tag-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n cursor: pointer;\n font-size: 10px;\n transition: background 0.15s;\n}\n\n.tag-chip-editable .tag-remove:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 25%, transparent);\n color: var(--mj-brand-primary-hover);\n}\n\n.tag-input-inline {\n flex: 1;\n min-width: 140px;\n border: none;\n background: transparent;\n outline: none;\n font-size: 13px;\n color: var(--test-text);\n padding: 4px 2px;\n}\n\n.tag-input-inline::placeholder {\n color: var(--test-text-muted);\n}\n\n/* Read-only metadata block at bottom of Config tab */\n.meta-section {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--test-radius-md);\n padding: 14px 18px;\n border: 1px solid var(--test-border);\n}\n\n.meta-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n}\n\n.meta-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.meta-label {\n font-size: 10px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--test-text-muted);\n}\n\n.meta-value {\n font-size: 12px;\n color: var(--test-text-secondary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.meta-mono {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n font-size: 11px;\n}\n\n/* Dirty indicator next to the title */\n.dirty-indicator {\n display: inline-block;\n margin-left: 8px;\n font-size: 14px;\n color: var(--mj-status-warning);\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n vertical-align: middle;\n}\n\n@keyframes pulseDot {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.85); }\n}\n\n.unsaved-pill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 15%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 30%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.unsaved-pill i {\n font-size: 6px;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n/* Pad the bottom of the tab content when the save bar is visible\n so the bar doesn't cover the last form field. */\n.tab-content.has-savebar {\n padding-bottom: 84px;\n}\n\n/* ===========================\n Sticky Save Bar\n =========================== */\n\n.save-bar {\n position: absolute;\n left: 16px;\n right: 96px; /* leaves room for the bottom-right chat launcher */\n bottom: 16px;\n z-index: 50;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 12px 16px 12px 20px;\n background: var(--mj-bg-surface-elevated, var(--test-surface));\n border: 1px solid color-mix(in srgb, var(--mj-status-warning) 25%, var(--test-border));\n border-radius: 14px;\n box-shadow: 0 12px 32px color-mix(in srgb, var(--mj-status-warning) 10%, rgba(0, 0, 0, 0.18));\n backdrop-filter: blur(8px);\n /* Hidden / off-screen state by default. The .save-bar--visible class\n animates it up into view. Using `transition` (not `animation`)\n guarantees the change runs every time isDirty toggles. */\n opacity: 0;\n transform: translateY(calc(100% + 32px));\n pointer-events: none;\n transition:\n transform 420ms cubic-bezier(0.16, 1, 0.3, 1),\n opacity 260ms cubic-bezier(0.16, 1, 0.3, 1);\n will-change: transform, opacity;\n}\n\n.save-bar--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .save-bar {\n transition: opacity 180ms ease-out;\n transform: none;\n }\n .save-bar--visible {\n transform: none;\n }\n}\n\n.save-bar-message {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.save-bar-dot {\n color: var(--mj-status-warning);\n font-size: 12px;\n line-height: 1;\n animation: pulseDot 1.8s ease-in-out infinite;\n}\n\n.save-bar-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.save-bar-text strong {\n font-size: 14px;\n color: var(--test-text);\n font-weight: 700;\n}\n\n.save-bar-fields {\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.save-bar-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.save-bar-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 9px 16px;\n font-size: 13px;\n font-weight: 600;\n border-radius: 8px;\n border: 1px solid transparent;\n cursor: pointer;\n transition: var(--test-transition);\n font-family: inherit;\n}\n\n.save-bar-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.save-bar-btn--primary {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse, white);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 35%, transparent);\n}\n\n.save-bar-btn--primary:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover, var(--mj-brand-primary));\n transform: translateY(-1px);\n box-shadow: 0 4px 12px color-mix(in srgb, var(--mj-brand-primary) 45%, transparent);\n}\n\n.save-bar-btn--primary:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.save-bar-btn--ghost {\n background: transparent;\n color: var(--test-text-secondary);\n border-color: var(--test-border);\n}\n\n.save-bar-btn--ghost:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover, var(--mj-bg-surface-card));\n color: var(--test-text);\n border-color: var(--test-text-muted);\n}\n\n.save-bar-kbd {\n display: inline-flex;\n gap: 3px;\n margin-left: 6px;\n opacity: 0.85;\n}\n\n.save-bar-kbd kbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 4px;\n font-size: 10px;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n background: color-mix(in srgb, white 18%, transparent);\n border: 1px solid color-mix(in srgb, white 35%, transparent);\n border-radius: 4px;\n color: inherit;\n}\n\n@media (max-width: 640px) {\n .save-bar {\n left: 8px;\n right: 8px;\n bottom: 88px; /* push above the chat launcher on small screens */\n flex-direction: column;\n align-items: stretch;\n padding: 12px;\n }\n .save-bar-actions {\n justify-content: space-between;\n }\n .save-bar-kbd {\n display: none;\n }\n}\n\n"] }]
2732
2773
  }], null, { handleKeyboardShortcut: [{
2733
2774
  type: HostListener,
2734
2775
  args: ['document:keydown', ['$event']]
@@ -2736,5 +2777,5 @@ export { MJTestFormComponentExtended };
2736
2777
  type: HostListener,
2737
2778
  args: ['window:beforeunload', ['$event']]
2738
2779
  }] }); })();
2739
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTestFormComponentExtended, { className: "MJTestFormComponentExtended", filePath: "src/lib/custom/Tests/test-form.component.ts", lineNumber: 63 }); })();
2780
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTestFormComponentExtended, { className: "MJTestFormComponentExtended", filePath: "src/lib/custom/Tests/test-form.component.ts", lineNumber: 64 }); })();
2740
2781
  //# sourceMappingURL=test-form.component.js.map