@memberjunction/ng-core-entity-forms 6.2.0 → 6.3.0-edge.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -6
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-header.panel.js +3 -3
- package/dist/lib/custom/AIAgentCategories/ai-agent-category-header.panel.js.map +1 -1
- package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.d.ts +12 -0
- package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.js +293 -230
- package/dist/lib/custom/AIAgentSessions/ai-agent-session-form.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/add-action-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/agent-prompt-advanced-settings-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts +11 -0
- package/dist/lib/custom/AIAgents/ai-agent-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js +862 -812
- package/dist/lib/custom/AIAgents/ai-agent-form.component.js.map +1 -1
- package/dist/lib/custom/AIAgents/create-prompt-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/create-sub-agent-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/new-agent-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/prompt-selector-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/sub-agent-advanced-settings-dialog.component.js +2 -2
- package/dist/lib/custom/AIAgents/sub-agent-selector-dialog.component.js +2 -2
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts +12 -0
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js +821 -763
- package/dist/lib/custom/AIPromptRuns/ai-prompt-run-form.component.js.map +1 -1
- package/dist/lib/custom/AIPromptRuns/chat-message-viewer.component.js +2 -2
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts +10 -0
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.d.ts.map +1 -1
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js +700 -605
- package/dist/lib/custom/AIPrompts/ai-prompt-form.component.js.map +1 -1
- package/dist/lib/custom/Actions/action-execution-log-form.component.d.ts +10 -0
- package/dist/lib/custom/Actions/action-execution-log-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Actions/action-execution-log-form.component.js +223 -175
- package/dist/lib/custom/Actions/action-execution-log-form.component.js.map +1 -1
- package/dist/lib/custom/Actions/action-form.component.d.ts +10 -0
- package/dist/lib/custom/Actions/action-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Actions/action-form.component.js +502 -453
- package/dist/lib/custom/Actions/action-form.component.js.map +1 -1
- package/dist/lib/custom/Companies/company-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Companies/company-header.panel.js +3 -3
- package/dist/lib/custom/Companies/company-header.panel.js.map +1 -1
- package/dist/lib/custom/Conversations/conversation-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Conversations/conversation-header.panel.js +3 -3
- package/dist/lib/custom/Conversations/conversation-header.panel.js.map +1 -1
- package/dist/lib/custom/Employees/employee-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Employees/employee-header.panel.js +3 -3
- package/dist/lib/custom/Employees/employee-header.panel.js.map +1 -1
- package/dist/lib/custom/Entities/entity-form.component.d.ts +15 -0
- package/dist/lib/custom/Entities/entity-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Entities/entity-form.component.js +836 -801
- package/dist/lib/custom/Entities/entity-form.component.js.map +1 -1
- package/dist/lib/custom/EntityActions/entityaction.form.component.js +2 -2
- package/dist/lib/custom/Files/file-form.component.js +2 -2
- package/dist/lib/custom/Lists/list-form.component.d.ts +5 -0
- package/dist/lib/custom/Lists/list-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Lists/list-form.component.js +355 -338
- package/dist/lib/custom/Lists/list-form.component.js.map +1 -1
- package/dist/lib/custom/MLModels/ml-model-form.component.js +3 -3
- package/dist/lib/custom/MLModels/ml-model-form.component.js.map +1 -1
- package/dist/lib/custom/MLModels/ml-model-view-models.d.ts +17 -35
- package/dist/lib/custom/MLModels/ml-model-view-models.d.ts.map +1 -1
- package/dist/lib/custom/MLModels/ml-model-view-models.js +55 -54
- package/dist/lib/custom/MLModels/ml-model-view-models.js.map +1 -1
- package/dist/lib/custom/MLModels/ps-model-detail.component.d.ts +7 -99
- package/dist/lib/custom/MLModels/ps-model-detail.component.d.ts.map +1 -1
- package/dist/lib/custom/MLModels/ps-model-detail.component.js +124 -303
- package/dist/lib/custom/MLModels/ps-model-detail.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.d.ts +9 -0
- package/dist/lib/custom/Queries/query-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Queries/query-form.component.js +493 -444
- package/dist/lib/custom/Queries/query-form.component.js.map +1 -1
- package/dist/lib/custom/Queries/query-run-dialog.component.js +2 -2
- package/dist/lib/custom/Templates/template-param-dialog.component.js +2 -2
- package/dist/lib/custom/Templates/templates-form.component.d.ts +9 -0
- package/dist/lib/custom/Templates/templates-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Templates/templates-form.component.js +118 -74
- package/dist/lib/custom/Templates/templates-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.d.ts +5 -0
- package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +471 -451
- package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.d.ts +5 -0
- package/dist/lib/custom/Tests/test-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.js +312 -289
- package/dist/lib/custom/Tests/test-run-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts +5 -0
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.js +697 -677
- package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-run-form.component.d.ts +5 -0
- package/dist/lib/custom/Tests/test-suite-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-run-form.component.js +453 -433
- package/dist/lib/custom/Tests/test-suite-run-form.component.js.map +1 -1
- package/dist/lib/custom/Users/user-header.panel.d.ts.map +1 -1
- package/dist/lib/custom/Users/user-header.panel.js +3 -3
- package/dist/lib/custom/Users/user-header.panel.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/agent-run-cost-split.d.ts +2 -2
- package/dist/lib/custom/ai-agent-run/agent-run-cost-split.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/agent-run-cost-split.js +30 -13
- package/dist/lib/custom/ai-agent-run/agent-run-cost-split.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts +23 -0
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +276 -216
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
- package/dist/lib/custom/custom-forms.module.d.ts +1 -1
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +7 -1
- package/dist/lib/custom/custom-forms.module.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js +32 -14
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js +119 -95
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJComment/mjcomment.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJComment/mjcomment.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJComment/mjcomment.form.component.js +124 -0
- package/dist/lib/generated/Entities/MJComment/mjcomment.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJCommentType/mjcommenttype.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJCommentType/mjcommenttype.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJCommentType/mjcommenttype.form.component.js +99 -0
- package/dist/lib/generated/Entities/MJCommentType/mjcommenttype.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.js +2 -2
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversationType/mjconversationtype.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJConversationType/mjconversationtype.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJConversationType/mjconversationtype.form.component.js +95 -0
- package/dist/lib/generated/Entities/MJConversationType/mjconversationtype.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJDocumentSequenceCounter/mjdocumentsequencecounter.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJDocumentSequenceCounter/mjdocumentsequencecounter.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJDocumentSequenceCounter/mjdocumentsequencecounter.form.component.js +60 -0
- package/dist/lib/generated/Entities/MJDocumentSequenceCounter/mjdocumentsequencecounter.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js +124 -106
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityFieldValue/mjentityfieldvalue.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEntityFieldValue/mjentityfieldvalue.form.component.js +12 -4
- package/dist/lib/generated/Entities/MJEntityFieldValue/mjentityfieldvalue.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityOrganicKey/mjentityorganickey.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJEntityOrganicKey/mjentityorganickey.form.component.js +19 -11
- package/dist/lib/generated/Entities/MJEntityOrganicKey/mjentityorganickey.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityUniqueKey/mjentityuniquekey.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJEntityUniqueKey/mjentityuniquekey.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJEntityUniqueKey/mjentityuniquekey.form.component.js +62 -0
- package/dist/lib/generated/Entities/MJEntityUniqueKey/mjentityuniquekey.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJFeatureValue/mjfeaturevalue.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJFeatureValue/mjfeaturevalue.form.component.js +26 -12
- package/dist/lib/generated/Entities/MJFeatureValue/mjfeaturevalue.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFieldSuggestion/mjfieldsuggestion.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJFieldSuggestion/mjfieldsuggestion.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJFieldSuggestion/mjfieldsuggestion.form.component.js +140 -0
- package/dist/lib/generated/Entities/MJFieldSuggestion/mjfieldsuggestion.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJFile/mjfile.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJFile/mjfile.form.component.js +69 -15
- package/dist/lib/generated/Entities/MJFile/mjfile.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFileStorageProvider/mjfilestorageprovider.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJFileStorageProvider/mjfilestorageprovider.form.component.js +31 -13
- package/dist/lib/generated/Entities/MJFileStorageProvider/mjfilestorageprovider.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJMLEvaluationProtocol/mjmlevaluationprotocol.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLEvaluationProtocol/mjmlevaluationprotocol.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLEvaluationProtocol/mjmlevaluationprotocol.form.component.js +205 -0
- package/dist/lib/generated/Entities/MJMLEvaluationProtocol/mjmlevaluationprotocol.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLModel/mjmlmodel.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJMLModel/mjmlmodel.form.component.js +24 -6
- package/dist/lib/generated/Entities/MJMLModel/mjmlmodel.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJMLPredictionUnit/mjmlpredictionunit.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLPredictionUnit/mjmlpredictionunit.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLPredictionUnit/mjmlpredictionunit.form.component.js +173 -0
- package/dist/lib/generated/Entities/MJMLPredictionUnit/mjmlpredictionunit.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJMLTrainingPipeline/mjmltrainingpipeline.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJMLTrainingPipeline/mjmltrainingpipeline.form.component.js +46 -24
- package/dist/lib/generated/Entities/MJMLTrainingPipeline/mjmltrainingpipeline.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJMLTrainingRun/mjmltrainingrun.form.component.js +22 -14
- package/dist/lib/generated/Entities/MJMLTrainingRun/mjmltrainingrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJMLTrainingSnapshot/mjmltrainingsnapshot.form.component.d.ts +10 -0
- package/dist/lib/generated/Entities/MJMLTrainingSnapshot/mjmltrainingsnapshot.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/MJMLTrainingSnapshot/mjmltrainingsnapshot.form.component.js +175 -0
- package/dist/lib/generated/Entities/MJMLTrainingSnapshot/mjmltrainingsnapshot.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/MJQueryField/mjqueryfield.form.component.js +8 -6
- package/dist/lib/generated/Entities/MJQueryField/mjqueryfield.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.js +44 -36
- package/dist/lib/generated/Entities/MJRecordProcess/mjrecordprocess.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTask/mjtask.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJTask/mjtask.form.component.js +54 -32
- package/dist/lib/generated/Entities/MJTask/mjtask.form.component.js.map +1 -1
- package/dist/lib/generated/generated-forms.module.d.ts +452 -443
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
- package/dist/lib/generated/generated-forms.module.js +27 -0
- package/dist/lib/generated/generated-forms.module.js.map +1 -1
- package/dist/lib/panels/feature-values/feature-values.panel.js +1 -1
- package/dist/lib/panels/feature-values/feature-values.panel.js.map +1 -1
- package/dist/lib/panels/model-predictions/model-prediction.logic.d.ts +1 -1
- package/dist/lib/panels/model-predictions/model-prediction.logic.d.ts.map +1 -1
- package/dist/lib/panels/model-predictions/model-prediction.logic.js.map +1 -1
- package/dist/lib/shared/components/template-editor.component.js +2 -2
- package/dist/lib/shared/phone-hero.d.ts +17 -0
- package/dist/lib/shared/phone-hero.d.ts.map +1 -0
- package/dist/lib/shared/phone-hero.js +30 -0
- package/dist/lib/shared/phone-hero.js.map +1 -0
- package/dist/lib/shared/phone-sections-state.d.ts +28 -0
- package/dist/lib/shared/phone-sections-state.d.ts.map +1 -0
- package/dist/lib/shared/phone-sections-state.js +38 -0
- package/dist/lib/shared/phone-sections-state.js.map +1 -0
- package/package.json +50 -50
|
@@ -36,7 +36,7 @@ function MJTestFormComponentExtended_Conditional_21_Template(rf, ctx) { if (rf &
|
|
|
36
36
|
} }
|
|
37
37
|
function MJTestFormComponentExtended_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
38
38
|
i0.ɵɵelementStart(0, "span", 18);
|
|
39
|
-
i0.ɵɵelement(1, "i",
|
|
39
|
+
i0.ɵɵelement(1, "i", 55);
|
|
40
40
|
i0.ɵɵtext(2);
|
|
41
41
|
i0.ɵɵelementEnd();
|
|
42
42
|
} if (rf & 2) {
|
|
@@ -46,7 +46,7 @@ function MJTestFormComponentExtended_Conditional_26_Template(rf, ctx) { if (rf &
|
|
|
46
46
|
} }
|
|
47
47
|
function MJTestFormComponentExtended_Conditional_27_Template(rf, ctx) { if (rf & 1) {
|
|
48
48
|
i0.ɵɵelementStart(0, "span", 19);
|
|
49
|
-
i0.ɵɵelement(1, "i",
|
|
49
|
+
i0.ɵɵelement(1, "i", 56);
|
|
50
50
|
i0.ɵɵtext(2, " Unsaved ");
|
|
51
51
|
i0.ɵɵelementEnd();
|
|
52
52
|
} }
|
|
@@ -60,31 +60,31 @@ function MJTestFormComponentExtended_Conditional_36_Template(rf, ctx) { if (rf &
|
|
|
60
60
|
i0.ɵɵtextInterpolate(ctx_r0.record.Description);
|
|
61
61
|
} }
|
|
62
62
|
function MJTestFormComponentExtended_Conditional_37_Template(rf, ctx) { if (rf & 1) {
|
|
63
|
-
i0.ɵɵelementStart(0, "div", 25)(1, "div",
|
|
63
|
+
i0.ɵɵelementStart(0, "div", 25)(1, "div", 57)(2, "div", 58);
|
|
64
64
|
i0.ɵɵtext(3, "Total Runs");
|
|
65
65
|
i0.ɵɵelementEnd();
|
|
66
|
-
i0.ɵɵelementStart(4, "div",
|
|
66
|
+
i0.ɵɵelementStart(4, "div", 59);
|
|
67
67
|
i0.ɵɵtext(5);
|
|
68
68
|
i0.ɵɵelementEnd()();
|
|
69
|
-
i0.ɵɵelementStart(6, "div",
|
|
69
|
+
i0.ɵɵelementStart(6, "div", 57)(7, "div", 58);
|
|
70
70
|
i0.ɵɵtext(8, "Pass Rate");
|
|
71
71
|
i0.ɵɵelementEnd();
|
|
72
|
-
i0.ɵɵelementStart(9, "div",
|
|
72
|
+
i0.ɵɵelementStart(9, "div", 59);
|
|
73
73
|
i0.ɵɵtext(10);
|
|
74
74
|
i0.ɵɵelementEnd();
|
|
75
|
-
i0.ɵɵelementStart(11, "div",
|
|
76
|
-
i0.ɵɵelement(12, "div",
|
|
75
|
+
i0.ɵɵelementStart(11, "div", 60);
|
|
76
|
+
i0.ɵɵelement(12, "div", 61);
|
|
77
77
|
i0.ɵɵelementEnd()();
|
|
78
|
-
i0.ɵɵelementStart(13, "div",
|
|
78
|
+
i0.ɵɵelementStart(13, "div", 57)(14, "div", 58);
|
|
79
79
|
i0.ɵɵtext(15, "Avg Cost");
|
|
80
80
|
i0.ɵɵelementEnd();
|
|
81
|
-
i0.ɵɵelementStart(16, "div",
|
|
81
|
+
i0.ɵɵelementStart(16, "div", 59);
|
|
82
82
|
i0.ɵɵtext(17);
|
|
83
83
|
i0.ɵɵelementEnd()();
|
|
84
|
-
i0.ɵɵelementStart(18, "div",
|
|
84
|
+
i0.ɵɵelementStart(18, "div", 57)(19, "div", 58);
|
|
85
85
|
i0.ɵɵtext(20, "Avg Duration");
|
|
86
86
|
i0.ɵɵelementEnd();
|
|
87
|
-
i0.ɵɵelementStart(21, "div",
|
|
87
|
+
i0.ɵɵelementStart(21, "div", 59);
|
|
88
88
|
i0.ɵɵtext(22);
|
|
89
89
|
i0.ɵɵelementEnd()()();
|
|
90
90
|
} if (rf & 2) {
|
|
@@ -100,8 +100,8 @@ function MJTestFormComponentExtended_Conditional_37_Template(rf, ctx) { if (rf &
|
|
|
100
100
|
i0.ɵɵadvance(5);
|
|
101
101
|
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(ctx_r0.getAverageDuration()));
|
|
102
102
|
} }
|
|
103
|
-
function
|
|
104
|
-
i0.ɵɵelementStart(0, "span",
|
|
103
|
+
function MJTestFormComponentExtended_Conditional_53_Template(rf, ctx) { if (rf & 1) {
|
|
104
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
105
105
|
i0.ɵɵtext(1);
|
|
106
106
|
i0.ɵɵelementEnd();
|
|
107
107
|
} if (rf & 2) {
|
|
@@ -109,8 +109,8 @@ function MJTestFormComponentExtended_Conditional_52_Template(rf, ctx) { if (rf &
|
|
|
109
109
|
i0.ɵɵadvance();
|
|
110
110
|
i0.ɵɵtextInterpolate(ctx_r0.testRuns.length);
|
|
111
111
|
} }
|
|
112
|
-
function
|
|
113
|
-
i0.ɵɵelementStart(0, "span",
|
|
112
|
+
function MJTestFormComponentExtended_Conditional_58_Template(rf, ctx) { if (rf & 1) {
|
|
113
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
114
114
|
i0.ɵɵtext(1);
|
|
115
115
|
i0.ɵɵelementEnd();
|
|
116
116
|
} if (rf & 2) {
|
|
@@ -118,100 +118,100 @@ function MJTestFormComponentExtended_Conditional_57_Template(rf, ctx) { if (rf &
|
|
|
118
118
|
i0.ɵɵadvance();
|
|
119
119
|
i0.ɵɵtextInterpolate(ctx_r0.suiteTests.length);
|
|
120
120
|
} }
|
|
121
|
-
function
|
|
121
|
+
function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf & 1) {
|
|
122
122
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
123
|
-
i0.ɵɵelementStart(0, "div",
|
|
124
|
-
i0.ɵɵelement(3, "i",
|
|
123
|
+
i0.ɵɵelementStart(0, "div", 37)(1, "div", 62)(2, "h3");
|
|
124
|
+
i0.ɵɵelement(3, "i", 63);
|
|
125
125
|
i0.ɵɵtext(4, " Test Information");
|
|
126
126
|
i0.ɵɵelementEnd();
|
|
127
|
-
i0.ɵɵelementStart(5, "div",
|
|
127
|
+
i0.ɵɵelementStart(5, "div", 64)(6, "div", 65)(7, "div", 66);
|
|
128
128
|
i0.ɵɵtext(8, "Name");
|
|
129
129
|
i0.ɵɵelementEnd();
|
|
130
|
-
i0.ɵɵelementStart(9, "div",
|
|
130
|
+
i0.ɵɵelementStart(9, "div", 67);
|
|
131
131
|
i0.ɵɵtext(10);
|
|
132
132
|
i0.ɵɵelementEnd()();
|
|
133
|
-
i0.ɵɵelementStart(11, "div",
|
|
133
|
+
i0.ɵɵelementStart(11, "div", 65)(12, "div", 66);
|
|
134
134
|
i0.ɵɵtext(13, "Type");
|
|
135
135
|
i0.ɵɵelementEnd();
|
|
136
|
-
i0.ɵɵelementStart(14, "div",
|
|
136
|
+
i0.ɵɵelementStart(14, "div", 67);
|
|
137
137
|
i0.ɵɵtext(15);
|
|
138
138
|
i0.ɵɵelementEnd()();
|
|
139
|
-
i0.ɵɵelementStart(16, "div",
|
|
139
|
+
i0.ɵɵelementStart(16, "div", 65)(17, "div", 66);
|
|
140
140
|
i0.ɵɵtext(18, "Status");
|
|
141
141
|
i0.ɵɵelementEnd();
|
|
142
|
-
i0.ɵɵelementStart(19, "div",
|
|
142
|
+
i0.ɵɵelementStart(19, "div", 67)(20, "span", 68);
|
|
143
143
|
i0.ɵɵtext(21);
|
|
144
144
|
i0.ɵɵelementEnd()()();
|
|
145
|
-
i0.ɵɵelementStart(22, "div",
|
|
145
|
+
i0.ɵɵelementStart(22, "div", 65)(23, "div", 66);
|
|
146
146
|
i0.ɵɵtext(24, "Priority");
|
|
147
147
|
i0.ɵɵelementEnd();
|
|
148
|
-
i0.ɵɵelementStart(25, "div",
|
|
148
|
+
i0.ɵɵelementStart(25, "div", 67);
|
|
149
149
|
i0.ɵɵtext(26);
|
|
150
150
|
i0.ɵɵelementEnd()();
|
|
151
|
-
i0.ɵɵelementStart(27, "div",
|
|
151
|
+
i0.ɵɵelementStart(27, "div", 65)(28, "div", 66);
|
|
152
152
|
i0.ɵɵtext(29, "Estimated Duration");
|
|
153
153
|
i0.ɵɵelementEnd();
|
|
154
|
-
i0.ɵɵelementStart(30, "div",
|
|
154
|
+
i0.ɵɵelementStart(30, "div", 67);
|
|
155
155
|
i0.ɵɵtext(31);
|
|
156
156
|
i0.ɵɵelementEnd()();
|
|
157
|
-
i0.ɵɵelementStart(32, "div",
|
|
157
|
+
i0.ɵɵelementStart(32, "div", 65)(33, "div", 66);
|
|
158
158
|
i0.ɵɵtext(34, "Estimated Cost");
|
|
159
159
|
i0.ɵɵelementEnd();
|
|
160
|
-
i0.ɵɵelementStart(35, "div",
|
|
160
|
+
i0.ɵɵelementStart(35, "div", 67);
|
|
161
161
|
i0.ɵɵtext(36);
|
|
162
162
|
i0.ɵɵelementEnd()();
|
|
163
|
-
i0.ɵɵelementStart(37, "div",
|
|
163
|
+
i0.ɵɵelementStart(37, "div", 65)(38, "div", 66);
|
|
164
164
|
i0.ɵɵtext(39, "Repeat Count");
|
|
165
165
|
i0.ɵɵelementEnd();
|
|
166
|
-
i0.ɵɵelementStart(40, "div",
|
|
166
|
+
i0.ɵɵelementStart(40, "div", 67);
|
|
167
167
|
i0.ɵɵtext(41);
|
|
168
168
|
i0.ɵɵelementEnd()();
|
|
169
|
-
i0.ɵɵelementStart(42, "div",
|
|
169
|
+
i0.ɵɵelementStart(42, "div", 65)(43, "div", 66);
|
|
170
170
|
i0.ɵɵtext(44, "Max Execution Time");
|
|
171
171
|
i0.ɵɵelementEnd();
|
|
172
|
-
i0.ɵɵelementStart(45, "div",
|
|
172
|
+
i0.ɵɵelementStart(45, "div", 67);
|
|
173
173
|
i0.ɵɵtext(46);
|
|
174
174
|
i0.ɵɵelementEnd()();
|
|
175
|
-
i0.ɵɵelementStart(47, "div",
|
|
175
|
+
i0.ɵɵelementStart(47, "div", 65)(48, "div", 66);
|
|
176
176
|
i0.ɵɵtext(49, "Created");
|
|
177
177
|
i0.ɵɵelementEnd();
|
|
178
|
-
i0.ɵɵelementStart(50, "div",
|
|
178
|
+
i0.ɵɵelementStart(50, "div", 67);
|
|
179
179
|
i0.ɵɵtext(51);
|
|
180
180
|
i0.ɵɵpipe(52, "date");
|
|
181
181
|
i0.ɵɵelementEnd()();
|
|
182
|
-
i0.ɵɵelementStart(53, "div",
|
|
182
|
+
i0.ɵɵelementStart(53, "div", 65)(54, "div", 66);
|
|
183
183
|
i0.ɵɵtext(55, "Updated");
|
|
184
184
|
i0.ɵɵelementEnd();
|
|
185
|
-
i0.ɵɵelementStart(56, "div",
|
|
185
|
+
i0.ɵɵelementStart(56, "div", 67);
|
|
186
186
|
i0.ɵɵtext(57);
|
|
187
187
|
i0.ɵɵpipe(58, "date");
|
|
188
188
|
i0.ɵɵelementEnd()()()();
|
|
189
|
-
i0.ɵɵelementStart(59, "div",
|
|
190
|
-
i0.ɵɵelement(61, "i",
|
|
189
|
+
i0.ɵɵelementStart(59, "div", 69)(60, "h3");
|
|
190
|
+
i0.ɵɵelement(61, "i", 70);
|
|
191
191
|
i0.ɵɵtext(62, " Test Definition");
|
|
192
192
|
i0.ɵɵelementEnd();
|
|
193
|
-
i0.ɵɵelementStart(63, "div",
|
|
194
|
-
i0.ɵɵlistener("click", function
|
|
195
|
-
i0.ɵɵelement(65, "i",
|
|
193
|
+
i0.ɵɵelementStart(63, "div", 71)(64, "button", 72);
|
|
194
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_button_click_64_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("input")); });
|
|
195
|
+
i0.ɵɵelement(65, "i", 73);
|
|
196
196
|
i0.ɵɵtext(66, " Input Definition ");
|
|
197
197
|
i0.ɵɵelementEnd();
|
|
198
|
-
i0.ɵɵelementStart(67, "button",
|
|
199
|
-
i0.ɵɵlistener("click", function
|
|
200
|
-
i0.ɵɵelement(68, "i",
|
|
198
|
+
i0.ɵɵelementStart(67, "button", 72);
|
|
199
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_button_click_67_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("expected")); });
|
|
200
|
+
i0.ɵɵelement(68, "i", 74);
|
|
201
201
|
i0.ɵɵtext(69, " Expected Outcomes ");
|
|
202
202
|
i0.ɵɵelementEnd();
|
|
203
|
-
i0.ɵɵelementStart(70, "button",
|
|
204
|
-
i0.ɵɵlistener("click", function
|
|
205
|
-
i0.ɵɵelement(71, "i",
|
|
203
|
+
i0.ɵɵelementStart(70, "button", 72);
|
|
204
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_button_click_70_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("config")); });
|
|
205
|
+
i0.ɵɵelement(71, "i", 75);
|
|
206
206
|
i0.ɵɵtext(72, " Configuration ");
|
|
207
207
|
i0.ɵɵelementEnd();
|
|
208
|
-
i0.ɵɵelementStart(73, "button",
|
|
209
|
-
i0.ɵɵlistener("click", function
|
|
210
|
-
i0.ɵɵelement(74, "i",
|
|
208
|
+
i0.ɵɵelementStart(73, "button", 72);
|
|
209
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_button_click_73_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("tags")); });
|
|
210
|
+
i0.ɵɵelement(74, "i", 76);
|
|
211
211
|
i0.ɵɵtext(75, " Tags ");
|
|
212
212
|
i0.ɵɵelementEnd()();
|
|
213
|
-
i0.ɵɵelementStart(76, "div",
|
|
214
|
-
i0.ɵɵelement(77, "mj-code-editor",
|
|
213
|
+
i0.ɵɵelementStart(76, "div", 77);
|
|
214
|
+
i0.ɵɵelement(77, "mj-code-editor", 78);
|
|
215
215
|
i0.ɵɵelementEnd()()();
|
|
216
216
|
} if (rf & 2) {
|
|
217
217
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -248,8 +248,8 @@ function MJTestFormComponentExtended_Conditional_63_Template(rf, ctx) { if (rf &
|
|
|
248
248
|
i0.ɵɵadvance(4);
|
|
249
249
|
i0.ɵɵproperty("value", ctx_r0.getJsonData())("readonly", true)("toolbar", ctx_r0.jsonToolbar)("lineWrapping", true);
|
|
250
250
|
} }
|
|
251
|
-
function
|
|
252
|
-
i0.ɵɵelementStart(0, "option",
|
|
251
|
+
function MJTestFormComponentExtended_Conditional_65_For_25_Template(rf, ctx) { if (rf & 1) {
|
|
252
|
+
i0.ɵɵelementStart(0, "option", 94);
|
|
253
253
|
i0.ɵɵtext(1);
|
|
254
254
|
i0.ɵɵelementEnd();
|
|
255
255
|
} if (rf & 2) {
|
|
@@ -258,8 +258,8 @@ function MJTestFormComponentExtended_Conditional_64_For_25_Template(rf, ctx) { i
|
|
|
258
258
|
i0.ɵɵadvance();
|
|
259
259
|
i0.ɵɵtextInterpolate(opt_r4);
|
|
260
260
|
} }
|
|
261
|
-
function
|
|
262
|
-
i0.ɵɵelementStart(0, "option",
|
|
261
|
+
function MJTestFormComponentExtended_Conditional_65_For_33_Template(rf, ctx) { if (rf & 1) {
|
|
262
|
+
i0.ɵɵelementStart(0, "option", 94);
|
|
263
263
|
i0.ɵɵtext(1);
|
|
264
264
|
i0.ɵɵelementEnd();
|
|
265
265
|
} if (rf & 2) {
|
|
@@ -268,8 +268,8 @@ function MJTestFormComponentExtended_Conditional_64_For_33_Template(rf, ctx) { i
|
|
|
268
268
|
i0.ɵɵadvance();
|
|
269
269
|
i0.ɵɵtextInterpolate(rubric_r5.name);
|
|
270
270
|
} }
|
|
271
|
-
function
|
|
272
|
-
i0.ɵɵelementStart(0, "option",
|
|
271
|
+
function MJTestFormComponentExtended_Conditional_65_For_39_Template(rf, ctx) { if (rf & 1) {
|
|
272
|
+
i0.ɵɵelementStart(0, "option", 94);
|
|
273
273
|
i0.ɵɵtext(1);
|
|
274
274
|
i0.ɵɵelementEnd();
|
|
275
275
|
} if (rf & 2) {
|
|
@@ -278,13 +278,13 @@ function MJTestFormComponentExtended_Conditional_64_For_39_Template(rf, ctx) { i
|
|
|
278
278
|
i0.ɵɵadvance();
|
|
279
279
|
i0.ɵɵtextInterpolate(t_r6.Name);
|
|
280
280
|
} }
|
|
281
|
-
function
|
|
281
|
+
function MJTestFormComponentExtended_Conditional_65_For_45_Template(rf, ctx) { if (rf & 1) {
|
|
282
282
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
283
|
-
i0.ɵɵelementStart(0, "span",
|
|
283
|
+
i0.ɵɵelementStart(0, "span", 101);
|
|
284
284
|
i0.ɵɵtext(1);
|
|
285
|
-
i0.ɵɵelementStart(2, "button",
|
|
286
|
-
i0.ɵɵlistener("click", function
|
|
287
|
-
i0.ɵɵelement(3, "i",
|
|
285
|
+
i0.ɵɵelementStart(2, "button", 124);
|
|
286
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_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", 125);
|
|
288
288
|
i0.ɵɵelementEnd()();
|
|
289
289
|
} if (rf & 2) {
|
|
290
290
|
const tag_r9 = ctx.$implicit;
|
|
@@ -293,148 +293,148 @@ function MJTestFormComponentExtended_Conditional_64_For_45_Template(rf, ctx) { i
|
|
|
293
293
|
i0.ɵɵadvance();
|
|
294
294
|
i0.ɵɵattribute("aria-label", "Remove tag " + tag_r9);
|
|
295
295
|
} }
|
|
296
|
-
function
|
|
296
|
+
function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf & 1) {
|
|
297
297
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
298
|
-
i0.ɵɵelementStart(0, "div",
|
|
299
|
-
i0.ɵɵelement(4, "i",
|
|
298
|
+
i0.ɵɵelementStart(0, "div", 38)(1, "section", 79)(2, "header", 80)(3, "h3");
|
|
299
|
+
i0.ɵɵelement(4, "i", 81);
|
|
300
300
|
i0.ɵɵtext(5, " Details");
|
|
301
301
|
i0.ɵɵelementEnd();
|
|
302
|
-
i0.ɵɵelementStart(6, "p",
|
|
302
|
+
i0.ɵɵelementStart(6, "p", 82);
|
|
303
303
|
i0.ɵɵtext(7, "Edit any field \u2014 changes are saved with the bar at the bottom.");
|
|
304
304
|
i0.ɵɵelementEnd()();
|
|
305
|
-
i0.ɵɵelementStart(8, "div",
|
|
305
|
+
i0.ɵɵelementStart(8, "div", 83)(9, "div", 84)(10, "label", 85);
|
|
306
306
|
i0.ɵɵtext(11, "Name ");
|
|
307
|
-
i0.ɵɵelementStart(12, "span",
|
|
307
|
+
i0.ɵɵelementStart(12, "span", 86);
|
|
308
308
|
i0.ɵɵtext(13, "*");
|
|
309
309
|
i0.ɵɵelementEnd()();
|
|
310
|
-
i0.ɵɵelementStart(14, "input",
|
|
311
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
310
|
+
i0.ɵɵelementStart(14, "input", 87);
|
|
311
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_Template_input_ngModelChange_14_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.Name, $event) || (ctx_r0.record.Name = $event); return i0.ɵɵresetView($event); });
|
|
312
312
|
i0.ɵɵelementEnd()();
|
|
313
|
-
i0.ɵɵelementStart(15, "div",
|
|
313
|
+
i0.ɵɵelementStart(15, "div", 84)(16, "label", 88);
|
|
314
314
|
i0.ɵɵtext(17, "Description");
|
|
315
315
|
i0.ɵɵelementEnd();
|
|
316
|
-
i0.ɵɵelementStart(18, "textarea",
|
|
317
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
316
|
+
i0.ɵɵelementStart(18, "textarea", 89);
|
|
317
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_Template_textarea_ngModelChange_18_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Description = $event || null); });
|
|
318
318
|
i0.ɵɵelementEnd()();
|
|
319
|
-
i0.ɵɵelementStart(19, "div",
|
|
319
|
+
i0.ɵɵelementStart(19, "div", 90)(20, "label", 91);
|
|
320
320
|
i0.ɵɵtext(21, "Status");
|
|
321
321
|
i0.ɵɵelementEnd();
|
|
322
|
-
i0.ɵɵelementStart(22, "div",
|
|
323
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
324
|
-
i0.ɵɵrepeaterCreate(24,
|
|
322
|
+
i0.ɵɵelementStart(22, "div", 92)(23, "select", 93);
|
|
323
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_Template_select_ngModelChange_23_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.Status, $event) || (ctx_r0.record.Status = $event); return i0.ɵɵresetView($event); });
|
|
324
|
+
i0.ɵɵrepeaterCreate(24, MJTestFormComponentExtended_Conditional_65_For_25_Template, 2, 2, "option", 94, i0.ɵɵrepeaterTrackByIdentity);
|
|
325
325
|
i0.ɵɵelementEnd()()();
|
|
326
|
-
i0.ɵɵelementStart(26, "div",
|
|
326
|
+
i0.ɵɵelementStart(26, "div", 90)(27, "label", 95);
|
|
327
327
|
i0.ɵɵtext(28, "Rubric");
|
|
328
328
|
i0.ɵɵelementEnd();
|
|
329
|
-
i0.ɵɵelementStart(29, "select",
|
|
330
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
331
|
-
i0.ɵɵelementStart(30, "option",
|
|
329
|
+
i0.ɵɵelementStart(29, "select", 96);
|
|
330
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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", 94);
|
|
332
332
|
i0.ɵɵtext(31, "\u2014 None \u2014");
|
|
333
333
|
i0.ɵɵelementEnd();
|
|
334
|
-
i0.ɵɵrepeaterCreate(32,
|
|
334
|
+
i0.ɵɵrepeaterCreate(32, MJTestFormComponentExtended_Conditional_65_For_33_Template, 2, 2, "option", 94, _forTrack0);
|
|
335
335
|
i0.ɵɵelementEnd()();
|
|
336
|
-
i0.ɵɵelementStart(34, "div",
|
|
336
|
+
i0.ɵɵelementStart(34, "div", 90)(35, "label", 97);
|
|
337
337
|
i0.ɵɵtext(36, "Test Type");
|
|
338
338
|
i0.ɵɵelementEnd();
|
|
339
|
-
i0.ɵɵelementStart(37, "select",
|
|
340
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
341
|
-
i0.ɵɵrepeaterCreate(38,
|
|
339
|
+
i0.ɵɵelementStart(37, "select", 98);
|
|
340
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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_65_For_39_Template, 2, 2, "option", 94, _forTrack1);
|
|
342
342
|
i0.ɵɵelementEnd()();
|
|
343
|
-
i0.ɵɵelementStart(40, "div",
|
|
343
|
+
i0.ɵɵelementStart(40, "div", 84)(41, "label", 99);
|
|
344
344
|
i0.ɵɵtext(42, "Tags");
|
|
345
345
|
i0.ɵɵelementEnd();
|
|
346
|
-
i0.ɵɵelementStart(43, "div",
|
|
347
|
-
i0.ɵɵlistener("click", function
|
|
348
|
-
i0.ɵɵrepeaterCreate(44,
|
|
349
|
-
i0.ɵɵelementStart(46, "input",
|
|
350
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
351
|
-
i0.ɵɵlistener("keydown", function
|
|
346
|
+
i0.ɵɵelementStart(43, "div", 100);
|
|
347
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_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_65_For_45_Template, 4, 2, "span", 101, i0.ɵɵrepeaterTrackByIdentity);
|
|
349
|
+
i0.ɵɵelementStart(46, "input", 102, 0);
|
|
350
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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_65_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_65_Template_input_blur_46_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.addTagFromDraft()); });
|
|
352
352
|
i0.ɵɵelementEnd()();
|
|
353
|
-
i0.ɵɵelementStart(48, "span",
|
|
353
|
+
i0.ɵɵelementStart(48, "span", 103);
|
|
354
354
|
i0.ɵɵtext(49, "Press Enter or comma to add a tag. Backspace on empty input removes the last tag.");
|
|
355
355
|
i0.ɵɵelementEnd()()()();
|
|
356
|
-
i0.ɵɵelementStart(50, "section",
|
|
357
|
-
i0.ɵɵelement(53, "i",
|
|
356
|
+
i0.ɵɵelementStart(50, "section", 79)(51, "header", 80)(52, "h3");
|
|
357
|
+
i0.ɵɵelement(53, "i", 104);
|
|
358
358
|
i0.ɵɵtext(54, " Execution Settings");
|
|
359
359
|
i0.ɵɵelementEnd()();
|
|
360
|
-
i0.ɵɵelementStart(55, "div",
|
|
360
|
+
i0.ɵɵelementStart(55, "div", 83)(56, "div", 90)(57, "label", 105);
|
|
361
361
|
i0.ɵɵtext(58, "Priority");
|
|
362
362
|
i0.ɵɵelementEnd();
|
|
363
|
-
i0.ɵɵelementStart(59, "input",
|
|
364
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
363
|
+
i0.ɵɵelementStart(59, "input", 106);
|
|
364
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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); });
|
|
365
365
|
i0.ɵɵelementEnd();
|
|
366
|
-
i0.ɵɵelementStart(60, "span",
|
|
366
|
+
i0.ɵɵelementStart(60, "span", 103);
|
|
367
367
|
i0.ɵɵtext(61, "Lower numbers run first.");
|
|
368
368
|
i0.ɵɵelementEnd()();
|
|
369
|
-
i0.ɵɵelementStart(62, "div",
|
|
369
|
+
i0.ɵɵelementStart(62, "div", 90)(63, "label", 107);
|
|
370
370
|
i0.ɵɵtext(64, "Repeat Count");
|
|
371
371
|
i0.ɵɵelementEnd();
|
|
372
|
-
i0.ɵɵelementStart(65, "input",
|
|
373
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
372
|
+
i0.ɵɵelementStart(65, "input", 108);
|
|
373
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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); });
|
|
374
374
|
i0.ɵɵelementEnd();
|
|
375
|
-
i0.ɵɵelementStart(66, "span",
|
|
375
|
+
i0.ɵɵelementStart(66, "span", 103);
|
|
376
376
|
i0.ɵɵtext(67, "Number of times to repeat for statistical analysis.");
|
|
377
377
|
i0.ɵɵelementEnd()();
|
|
378
|
-
i0.ɵɵelementStart(68, "div",
|
|
378
|
+
i0.ɵɵelementStart(68, "div", 90)(69, "label", 109);
|
|
379
379
|
i0.ɵɵtext(70, "Estimated Duration (seconds)");
|
|
380
380
|
i0.ɵɵelementEnd();
|
|
381
|
-
i0.ɵɵelementStart(71, "input",
|
|
382
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
381
|
+
i0.ɵɵelementStart(71, "input", 110);
|
|
382
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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); });
|
|
383
383
|
i0.ɵɵelementEnd()();
|
|
384
|
-
i0.ɵɵelementStart(72, "div",
|
|
384
|
+
i0.ɵɵelementStart(72, "div", 90)(73, "label", 111);
|
|
385
385
|
i0.ɵɵtext(74, "Estimated Cost (USD)");
|
|
386
386
|
i0.ɵɵelementEnd();
|
|
387
|
-
i0.ɵɵelementStart(75, "input",
|
|
388
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
387
|
+
i0.ɵɵelementStart(75, "input", 112);
|
|
388
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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); });
|
|
389
389
|
i0.ɵɵelementEnd()();
|
|
390
|
-
i0.ɵɵelementStart(76, "div",
|
|
390
|
+
i0.ɵɵelementStart(76, "div", 84)(77, "label", 113);
|
|
391
391
|
i0.ɵɵtext(78, "Max Execution Time (ms)");
|
|
392
392
|
i0.ɵɵelementEnd();
|
|
393
|
-
i0.ɵɵelementStart(79, "input",
|
|
394
|
-
i0.ɵɵlistener("ngModelChange", function
|
|
393
|
+
i0.ɵɵelementStart(79, "input", 114);
|
|
394
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_65_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); });
|
|
395
395
|
i0.ɵɵelementEnd();
|
|
396
|
-
i0.ɵɵelementStart(80, "span",
|
|
396
|
+
i0.ɵɵelementStart(80, "span", 103);
|
|
397
397
|
i0.ɵɵtext(81);
|
|
398
398
|
i0.ɵɵelementEnd()()()();
|
|
399
|
-
i0.ɵɵelementStart(82, "div",
|
|
400
|
-
i0.ɵɵelement(84, "i",
|
|
399
|
+
i0.ɵɵelementStart(82, "div", 115)(83, "h3");
|
|
400
|
+
i0.ɵɵelement(84, "i", 73);
|
|
401
401
|
i0.ɵɵtext(85, " Input Definition (JSON)");
|
|
402
402
|
i0.ɵɵelementEnd();
|
|
403
|
-
i0.ɵɵelementStart(86, "div",
|
|
404
|
-
i0.ɵɵlistener("change", function
|
|
403
|
+
i0.ɵɵelementStart(86, "div", 116)(87, "mj-code-editor", 117);
|
|
404
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_65_Template_mj_code_editor_change_87_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.InputDefinition = $event); });
|
|
405
405
|
i0.ɵɵelementEnd()()();
|
|
406
|
-
i0.ɵɵelementStart(88, "div",
|
|
407
|
-
i0.ɵɵelement(90, "i",
|
|
406
|
+
i0.ɵɵelementStart(88, "div", 115)(89, "h3");
|
|
407
|
+
i0.ɵɵelement(90, "i", 74);
|
|
408
408
|
i0.ɵɵtext(91, " Expected Outcomes (JSON)");
|
|
409
409
|
i0.ɵɵelementEnd();
|
|
410
|
-
i0.ɵɵelementStart(92, "div",
|
|
411
|
-
i0.ɵɵlistener("change", function
|
|
410
|
+
i0.ɵɵelementStart(92, "div", 116)(93, "mj-code-editor", 117);
|
|
411
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_65_Template_mj_code_editor_change_93_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.ExpectedOutcomes = $event); });
|
|
412
412
|
i0.ɵɵelementEnd()()();
|
|
413
|
-
i0.ɵɵelementStart(94, "div",
|
|
414
|
-
i0.ɵɵelement(96, "i",
|
|
413
|
+
i0.ɵɵelementStart(94, "div", 115)(95, "h3");
|
|
414
|
+
i0.ɵɵelement(96, "i", 75);
|
|
415
415
|
i0.ɵɵtext(97, " Configuration (JSON)");
|
|
416
416
|
i0.ɵɵelementEnd();
|
|
417
|
-
i0.ɵɵelementStart(98, "div",
|
|
418
|
-
i0.ɵɵlistener("change", function
|
|
417
|
+
i0.ɵɵelementStart(98, "div", 116)(99, "mj-code-editor", 117);
|
|
418
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_65_Template_mj_code_editor_change_99_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Configuration = $event); });
|
|
419
419
|
i0.ɵɵelementEnd()()();
|
|
420
|
-
i0.ɵɵelementStart(100, "section",
|
|
420
|
+
i0.ɵɵelementStart(100, "section", 118)(101, "div", 119)(102, "div", 120)(103, "div", 121);
|
|
421
421
|
i0.ɵɵtext(104, "Created");
|
|
422
422
|
i0.ɵɵelementEnd();
|
|
423
|
-
i0.ɵɵelementStart(105, "div",
|
|
423
|
+
i0.ɵɵelementStart(105, "div", 122);
|
|
424
424
|
i0.ɵɵtext(106);
|
|
425
425
|
i0.ɵɵpipe(107, "date");
|
|
426
426
|
i0.ɵɵelementEnd()();
|
|
427
|
-
i0.ɵɵelementStart(108, "div",
|
|
427
|
+
i0.ɵɵelementStart(108, "div", 120)(109, "div", 121);
|
|
428
428
|
i0.ɵɵtext(110, "Last updated");
|
|
429
429
|
i0.ɵɵelementEnd();
|
|
430
|
-
i0.ɵɵelementStart(111, "div",
|
|
430
|
+
i0.ɵɵelementStart(111, "div", 122);
|
|
431
431
|
i0.ɵɵtext(112);
|
|
432
432
|
i0.ɵɵpipe(113, "date");
|
|
433
433
|
i0.ɵɵelementEnd()();
|
|
434
|
-
i0.ɵɵelementStart(114, "div",
|
|
434
|
+
i0.ɵɵelementStart(114, "div", 120)(115, "div", 121);
|
|
435
435
|
i0.ɵɵtext(116, "Test ID");
|
|
436
436
|
i0.ɵɵelementEnd();
|
|
437
|
-
i0.ɵɵelementStart(117, "div",
|
|
437
|
+
i0.ɵɵelementStart(117, "div", 123);
|
|
438
438
|
i0.ɵɵtext(118);
|
|
439
439
|
i0.ɵɵelementEnd()()()()();
|
|
440
440
|
} if (rf & 2) {
|
|
@@ -487,24 +487,24 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
|
|
|
487
487
|
i0.ɵɵadvance(6);
|
|
488
488
|
i0.ɵɵtextInterpolate(ctx_r0.record.ID);
|
|
489
489
|
} }
|
|
490
|
-
function
|
|
491
|
-
i0.ɵɵelementStart(0, "div",
|
|
492
|
-
i0.ɵɵelement(1, "div",
|
|
493
|
-
i0.ɵɵelementStart(2, "div",
|
|
494
|
-
i0.ɵɵelement(3, "div",
|
|
490
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
491
|
+
i0.ɵɵelementStart(0, "div", 130);
|
|
492
|
+
i0.ɵɵelement(1, "div", 131);
|
|
493
|
+
i0.ɵɵelementStart(2, "div", 132);
|
|
494
|
+
i0.ɵɵelement(3, "div", 133)(4, "div", 134);
|
|
495
495
|
i0.ɵɵelementEnd()();
|
|
496
496
|
} }
|
|
497
|
-
function
|
|
498
|
-
i0.ɵɵelementStart(0, "div",
|
|
499
|
-
i0.ɵɵrepeaterCreate(2,
|
|
497
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
498
|
+
i0.ɵɵelementStart(0, "div", 126)(1, "div", 129);
|
|
499
|
+
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template, 5, 0, "div", 130, i0.ɵɵrepeaterTrackByIdentity);
|
|
500
500
|
i0.ɵɵelementEnd()();
|
|
501
501
|
} if (rf & 2) {
|
|
502
502
|
i0.ɵɵadvance(2);
|
|
503
503
|
i0.ɵɵrepeater(i0.ɵɵpureFunction0(0, _c0));
|
|
504
504
|
} }
|
|
505
|
-
function
|
|
505
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
506
506
|
i0.ɵɵelementStart(0, "span");
|
|
507
|
-
i0.ɵɵelement(1, "i",
|
|
507
|
+
i0.ɵɵelement(1, "i", 150);
|
|
508
508
|
i0.ɵɵtext(2);
|
|
509
509
|
i0.ɵɵelementEnd();
|
|
510
510
|
} if (rf & 2) {
|
|
@@ -513,9 +513,9 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
513
513
|
i0.ɵɵadvance(2);
|
|
514
514
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(run_r11.DurationSeconds));
|
|
515
515
|
} }
|
|
516
|
-
function
|
|
516
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
517
517
|
i0.ɵɵelementStart(0, "span");
|
|
518
|
-
i0.ɵɵelement(1, "i",
|
|
518
|
+
i0.ɵɵelement(1, "i", 151);
|
|
519
519
|
i0.ɵɵtext(2);
|
|
520
520
|
i0.ɵɵelementEnd();
|
|
521
521
|
} if (rf & 2) {
|
|
@@ -524,15 +524,15 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
524
524
|
i0.ɵɵadvance(2);
|
|
525
525
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(run_r11.CostUSD));
|
|
526
526
|
} }
|
|
527
|
-
function
|
|
528
|
-
i0.ɵɵelement(0, "mj-entity-link-pill",
|
|
527
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
528
|
+
i0.ɵɵelement(0, "mj-entity-link-pill", 145);
|
|
529
529
|
} if (rf & 2) {
|
|
530
530
|
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
531
531
|
i0.ɵɵproperty("entityName", run_r11.TargetLogEntity)("recordId", run_r11.TargetLogID);
|
|
532
532
|
} }
|
|
533
|
-
function
|
|
534
|
-
i0.ɵɵelementStart(0, "span",
|
|
535
|
-
i0.ɵɵelement(1, "i",
|
|
533
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
534
|
+
i0.ɵɵelementStart(0, "span", 147);
|
|
535
|
+
i0.ɵɵelement(1, "i", 138);
|
|
536
536
|
i0.ɵɵelementStart(2, "span");
|
|
537
537
|
i0.ɵɵtext(3);
|
|
538
538
|
i0.ɵɵelementEnd()();
|
|
@@ -545,14 +545,14 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
545
545
|
i0.ɵɵadvance(2);
|
|
546
546
|
i0.ɵɵtextInterpolate(run_r11.Status);
|
|
547
547
|
} }
|
|
548
|
-
function
|
|
549
|
-
i0.ɵɵelementStart(0, "span",
|
|
550
|
-
i0.ɵɵelement(1, "i",
|
|
548
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
549
|
+
i0.ɵɵelementStart(0, "span", 152);
|
|
550
|
+
i0.ɵɵelement(1, "i", 154);
|
|
551
551
|
i0.ɵɵelementEnd();
|
|
552
552
|
} }
|
|
553
|
-
function
|
|
554
|
-
i0.ɵɵelementStart(0, "span",
|
|
555
|
-
i0.ɵɵelement(1, "i",
|
|
553
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_18_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
554
|
+
i0.ɵɵelementStart(0, "span", 155);
|
|
555
|
+
i0.ɵɵelement(1, "i", 156);
|
|
556
556
|
i0.ɵɵelementStart(2, "span");
|
|
557
557
|
i0.ɵɵtext(3);
|
|
558
558
|
i0.ɵɵelementEnd()();
|
|
@@ -566,9 +566,9 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
566
566
|
i0.ɵɵadvance(3);
|
|
567
567
|
i0.ɵɵtextInterpolate(rating_r12);
|
|
568
568
|
} }
|
|
569
|
-
function
|
|
570
|
-
i0.ɵɵconditionalCreate(0,
|
|
571
|
-
i0.ɵɵconditionalCreate(1,
|
|
569
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
570
|
+
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_18_Conditional_0_Template, 2, 0, "span", 152);
|
|
571
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_18_Conditional_1_Template, 4, 10, "span", 153);
|
|
572
572
|
} if (rf & 2) {
|
|
573
573
|
let tmp_13_0;
|
|
574
574
|
let tmp_14_0;
|
|
@@ -578,14 +578,14 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
578
578
|
i0.ɵɵadvance();
|
|
579
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);
|
|
580
580
|
} }
|
|
581
|
-
function
|
|
582
|
-
i0.ɵɵelementStart(0, "span",
|
|
583
|
-
i0.ɵɵelement(1, "i",
|
|
581
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_19_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
582
|
+
i0.ɵɵelementStart(0, "span", 157);
|
|
583
|
+
i0.ɵɵelement(1, "i", 159);
|
|
584
584
|
i0.ɵɵelementEnd();
|
|
585
585
|
} }
|
|
586
|
-
function
|
|
587
|
-
i0.ɵɵelementStart(0, "span",
|
|
588
|
-
i0.ɵɵelement(1, "i",
|
|
586
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_19_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
587
|
+
i0.ɵɵelementStart(0, "span", 160);
|
|
588
|
+
i0.ɵɵelement(1, "i", 159);
|
|
589
589
|
i0.ɵɵelementStart(2, "span");
|
|
590
590
|
i0.ɵɵtext(3);
|
|
591
591
|
i0.ɵɵelementEnd()();
|
|
@@ -596,17 +596,17 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
596
596
|
i0.ɵɵadvance(3);
|
|
597
597
|
i0.ɵɵtextInterpolate1("", (run_r11.Score * 100).toFixed(0), "%");
|
|
598
598
|
} }
|
|
599
|
-
function
|
|
600
|
-
i0.ɵɵconditionalCreate(0,
|
|
601
|
-
i0.ɵɵconditionalCreate(1,
|
|
599
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
600
|
+
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_19_Conditional_0_Template, 2, 0, "span", 157);
|
|
601
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_19_Conditional_1_Template, 4, 10, "span", 158);
|
|
602
602
|
} if (rf & 2) {
|
|
603
603
|
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
604
604
|
i0.ɵɵconditional(run_r11.Score == null ? 0 : -1);
|
|
605
605
|
i0.ɵɵadvance();
|
|
606
606
|
i0.ɵɵconditional(run_r11.Score != null ? 1 : -1);
|
|
607
607
|
} }
|
|
608
|
-
function
|
|
609
|
-
i0.ɵɵelementStart(0, "span",
|
|
608
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
609
|
+
i0.ɵɵelementStart(0, "span", 161);
|
|
610
610
|
i0.ɵɵtext(1);
|
|
611
611
|
i0.ɵɵelementEnd();
|
|
612
612
|
} if (rf & 2) {
|
|
@@ -614,8 +614,8 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
614
614
|
i0.ɵɵadvance();
|
|
615
615
|
i0.ɵɵtextInterpolate(tag_r13);
|
|
616
616
|
} }
|
|
617
|
-
function
|
|
618
|
-
i0.ɵɵelementStart(0, "span",
|
|
617
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_20_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
618
|
+
i0.ɵɵelementStart(0, "span", 162);
|
|
619
619
|
i0.ɵɵtext(1);
|
|
620
620
|
i0.ɵɵelementEnd();
|
|
621
621
|
} if (rf & 2) {
|
|
@@ -624,10 +624,10 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
624
624
|
i0.ɵɵadvance();
|
|
625
625
|
i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(run_r11).length - 3);
|
|
626
626
|
} }
|
|
627
|
-
function
|
|
628
|
-
i0.ɵɵelementStart(0, "div",
|
|
629
|
-
i0.ɵɵrepeaterCreate(1,
|
|
630
|
-
i0.ɵɵconditionalCreate(3,
|
|
627
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
628
|
+
i0.ɵɵelementStart(0, "div", 148);
|
|
629
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_20_For_2_Template, 2, 1, "span", 161, i0.ɵɵrepeaterTrackByIdentity);
|
|
630
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_20_Conditional_3_Template, 2, 1, "span", 162);
|
|
631
631
|
i0.ɵɵelementEnd();
|
|
632
632
|
} if (rf & 2) {
|
|
633
633
|
const run_r11 = i0.ɵɵnextContext().$implicit;
|
|
@@ -637,35 +637,35 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditio
|
|
|
637
637
|
i0.ɵɵadvance(2);
|
|
638
638
|
i0.ɵɵconditional(ctx_r0.getRunTags(run_r11).length > 3 ? 3 : -1);
|
|
639
639
|
} }
|
|
640
|
-
function
|
|
640
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
641
641
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
642
|
-
i0.ɵɵelementStart(0, "div",
|
|
643
|
-
i0.ɵɵlistener("click", function
|
|
644
|
-
i0.ɵɵelementStart(1, "div",
|
|
645
|
-
i0.ɵɵelement(2, "i",
|
|
642
|
+
i0.ɵɵelementStart(0, "div", 136);
|
|
643
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_66_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", 137);
|
|
645
|
+
i0.ɵɵelement(2, "i", 138);
|
|
646
646
|
i0.ɵɵelementEnd();
|
|
647
|
-
i0.ɵɵelementStart(3, "div",
|
|
647
|
+
i0.ɵɵelementStart(3, "div", 139)(4, "div", 140)(5, "span", 141);
|
|
648
648
|
i0.ɵɵtext(6);
|
|
649
649
|
i0.ɵɵelementEnd();
|
|
650
|
-
i0.ɵɵelementStart(7, "span",
|
|
650
|
+
i0.ɵɵelementStart(7, "span", 142);
|
|
651
651
|
i0.ɵɵtext(8);
|
|
652
652
|
i0.ɵɵelementEnd()();
|
|
653
|
-
i0.ɵɵelementStart(9, "div",
|
|
654
|
-
i0.ɵɵelement(11, "i",
|
|
653
|
+
i0.ɵɵelementStart(9, "div", 143)(10, "span");
|
|
654
|
+
i0.ɵɵelement(11, "i", 144);
|
|
655
655
|
i0.ɵɵtext(12);
|
|
656
656
|
i0.ɵɵelementEnd();
|
|
657
|
-
i0.ɵɵconditionalCreate(13,
|
|
658
|
-
i0.ɵɵconditionalCreate(14,
|
|
659
|
-
i0.ɵɵconditionalCreate(15,
|
|
657
|
+
i0.ɵɵconditionalCreate(13, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_13_Template, 3, 1, "span");
|
|
658
|
+
i0.ɵɵconditionalCreate(14, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_14_Template, 3, 1, "span");
|
|
659
|
+
i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_15_Template, 1, 2, "mj-entity-link-pill", 145);
|
|
660
660
|
i0.ɵɵelementEnd();
|
|
661
|
-
i0.ɵɵelementStart(16, "div",
|
|
662
|
-
i0.ɵɵconditionalCreate(17,
|
|
663
|
-
i0.ɵɵconditionalCreate(18,
|
|
664
|
-
i0.ɵɵconditionalCreate(19,
|
|
661
|
+
i0.ɵɵelementStart(16, "div", 146);
|
|
662
|
+
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_17_Template, 4, 17, "span", 147);
|
|
663
|
+
i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_18_Template, 2, 2);
|
|
664
|
+
i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_19_Template, 2, 2);
|
|
665
665
|
i0.ɵɵelementEnd();
|
|
666
|
-
i0.ɵɵconditionalCreate(20,
|
|
666
|
+
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_20_Template, 4, 1, "div", 148);
|
|
667
667
|
i0.ɵɵelementEnd();
|
|
668
|
-
i0.ɵɵelement(21, "i",
|
|
668
|
+
i0.ɵɵelement(21, "i", 149);
|
|
669
669
|
i0.ɵɵelementEnd();
|
|
670
670
|
} if (rf & 2) {
|
|
671
671
|
const run_r11 = ctx.$implicit;
|
|
@@ -697,26 +697,26 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template
|
|
|
697
697
|
i0.ɵɵadvance();
|
|
698
698
|
i0.ɵɵconditional(ctx_r0.getRunTags(run_r11).length > 0 ? 20 : -1);
|
|
699
699
|
} }
|
|
700
|
-
function
|
|
701
|
-
i0.ɵɵelementStart(0, "div",
|
|
702
|
-
i0.ɵɵrepeaterCreate(1,
|
|
700
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
701
|
+
i0.ɵɵelementStart(0, "div", 127);
|
|
702
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template, 22, 26, "div", 135, i0.ɵɵrepeaterTrackByIdentity);
|
|
703
703
|
i0.ɵɵelementEnd();
|
|
704
704
|
} if (rf & 2) {
|
|
705
705
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
706
706
|
i0.ɵɵadvance();
|
|
707
707
|
i0.ɵɵrepeater(ctx_r0.testRuns);
|
|
708
708
|
} }
|
|
709
|
-
function
|
|
709
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
710
710
|
const _r14 = i0.ɵɵgetCurrentView();
|
|
711
|
-
i0.ɵɵelementStart(0, "mj-empty-state",
|
|
712
|
-
i0.ɵɵlistener("Action", function
|
|
711
|
+
i0.ɵɵelementStart(0, "mj-empty-state", 163);
|
|
712
|
+
i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_66_Conditional_3_Template_mj_empty_state_Action_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.runTest()); });
|
|
713
713
|
i0.ɵɵelementEnd();
|
|
714
714
|
} }
|
|
715
|
-
function
|
|
716
|
-
i0.ɵɵelementStart(0, "div",
|
|
717
|
-
i0.ɵɵconditionalCreate(1,
|
|
718
|
-
i0.ɵɵconditionalCreate(2,
|
|
719
|
-
i0.ɵɵconditionalCreate(3,
|
|
715
|
+
function MJTestFormComponentExtended_Conditional_66_Template(rf, ctx) { if (rf & 1) {
|
|
716
|
+
i0.ɵɵelementStart(0, "div", 39);
|
|
717
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_1_Template, 4, 1, "div", 126);
|
|
718
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_2_Template, 3, 0, "div", 127);
|
|
719
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_66_Conditional_3_Template, 1, 0, "mj-empty-state", 128);
|
|
720
720
|
i0.ɵɵelementEnd();
|
|
721
721
|
} if (rf & 2) {
|
|
722
722
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -727,24 +727,24 @@ function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf &
|
|
|
727
727
|
i0.ɵɵadvance();
|
|
728
728
|
i0.ɵɵconditional(ctx_r0.testRunsLoaded && !ctx_r0.loadingRuns && ctx_r0.testRuns.length === 0 ? 3 : -1);
|
|
729
729
|
} }
|
|
730
|
-
function
|
|
731
|
-
i0.ɵɵelementStart(0, "div",
|
|
732
|
-
i0.ɵɵelement(1, "div",
|
|
733
|
-
i0.ɵɵelementStart(2, "div",
|
|
734
|
-
i0.ɵɵelement(3, "div",
|
|
730
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
731
|
+
i0.ɵɵelementStart(0, "div", 130);
|
|
732
|
+
i0.ɵɵelement(1, "div", 131);
|
|
733
|
+
i0.ɵɵelementStart(2, "div", 132);
|
|
734
|
+
i0.ɵɵelement(3, "div", 133)(4, "div", 134);
|
|
735
735
|
i0.ɵɵelementEnd()();
|
|
736
736
|
} }
|
|
737
|
-
function
|
|
738
|
-
i0.ɵɵelementStart(0, "div",
|
|
739
|
-
i0.ɵɵrepeaterCreate(2,
|
|
737
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
738
|
+
i0.ɵɵelementStart(0, "div", 126)(1, "div", 129);
|
|
739
|
+
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_67_Conditional_1_For_3_Template, 5, 0, "div", 130, i0.ɵɵrepeaterTrackByIdentity);
|
|
740
740
|
i0.ɵɵelementEnd()();
|
|
741
741
|
} if (rf & 2) {
|
|
742
742
|
i0.ɵɵadvance(2);
|
|
743
743
|
i0.ɵɵrepeater(i0.ɵɵpureFunction0(0, _c1));
|
|
744
744
|
} }
|
|
745
|
-
function
|
|
745
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_For_2_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
746
746
|
i0.ɵɵelementStart(0, "span");
|
|
747
|
-
i0.ɵɵelement(1, "i",
|
|
747
|
+
i0.ɵɵelement(1, "i", 63);
|
|
748
748
|
i0.ɵɵtext(2);
|
|
749
749
|
i0.ɵɵelementEnd();
|
|
750
750
|
} if (rf & 2) {
|
|
@@ -752,23 +752,23 @@ function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditio
|
|
|
752
752
|
i0.ɵɵadvance(2);
|
|
753
753
|
i0.ɵɵtextInterpolate1(" ", suiteTest_r16.Status);
|
|
754
754
|
} }
|
|
755
|
-
function
|
|
755
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
756
756
|
const _r15 = i0.ɵɵgetCurrentView();
|
|
757
|
-
i0.ɵɵelementStart(0, "div",
|
|
758
|
-
i0.ɵɵlistener("click", function
|
|
759
|
-
i0.ɵɵelementStart(1, "div",
|
|
760
|
-
i0.ɵɵelement(2, "i",
|
|
757
|
+
i0.ɵɵelementStart(0, "div", 167);
|
|
758
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_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", 168);
|
|
760
|
+
i0.ɵɵelement(2, "i", 34);
|
|
761
761
|
i0.ɵɵelementEnd();
|
|
762
|
-
i0.ɵɵelementStart(3, "div",
|
|
762
|
+
i0.ɵɵelementStart(3, "div", 169)(4, "div", 170);
|
|
763
763
|
i0.ɵɵtext(5);
|
|
764
764
|
i0.ɵɵelementEnd();
|
|
765
|
-
i0.ɵɵelementStart(6, "div",
|
|
766
|
-
i0.ɵɵelement(8, "i",
|
|
765
|
+
i0.ɵɵelementStart(6, "div", 171)(7, "span");
|
|
766
|
+
i0.ɵɵelement(8, "i", 172);
|
|
767
767
|
i0.ɵɵtext(9);
|
|
768
768
|
i0.ɵɵelementEnd();
|
|
769
|
-
i0.ɵɵconditionalCreate(10,
|
|
769
|
+
i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_67_Conditional_2_For_2_Conditional_10_Template, 3, 1, "span");
|
|
770
770
|
i0.ɵɵelementEnd()();
|
|
771
|
-
i0.ɵɵelement(11, "i",
|
|
771
|
+
i0.ɵɵelement(11, "i", 149);
|
|
772
772
|
i0.ɵɵelementEnd();
|
|
773
773
|
} if (rf & 2) {
|
|
774
774
|
const suiteTest_r16 = ctx.$implicit;
|
|
@@ -779,23 +779,23 @@ function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template
|
|
|
779
779
|
i0.ɵɵadvance();
|
|
780
780
|
i0.ɵɵconditional(suiteTest_r16.Status ? 10 : -1);
|
|
781
781
|
} }
|
|
782
|
-
function
|
|
783
|
-
i0.ɵɵelementStart(0, "div",
|
|
784
|
-
i0.ɵɵrepeaterCreate(1,
|
|
782
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
783
|
+
i0.ɵɵelementStart(0, "div", 164);
|
|
784
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_2_For_2_Template, 12, 3, "div", 166, i0.ɵɵrepeaterTrackByIdentity);
|
|
785
785
|
i0.ɵɵelementEnd();
|
|
786
786
|
} if (rf & 2) {
|
|
787
787
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
788
788
|
i0.ɵɵadvance();
|
|
789
789
|
i0.ɵɵrepeater(ctx_r0.suiteTests);
|
|
790
790
|
} }
|
|
791
|
-
function
|
|
792
|
-
i0.ɵɵelement(0, "mj-empty-state",
|
|
791
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
792
|
+
i0.ɵɵelement(0, "mj-empty-state", 165);
|
|
793
793
|
} }
|
|
794
|
-
function
|
|
795
|
-
i0.ɵɵelementStart(0, "div",
|
|
796
|
-
i0.ɵɵconditionalCreate(1,
|
|
797
|
-
i0.ɵɵconditionalCreate(2,
|
|
798
|
-
i0.ɵɵconditionalCreate(3,
|
|
794
|
+
function MJTestFormComponentExtended_Conditional_67_Template(rf, ctx) { if (rf & 1) {
|
|
795
|
+
i0.ɵɵelementStart(0, "div", 40);
|
|
796
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_1_Template, 4, 1, "div", 126);
|
|
797
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_67_Conditional_2_Template, 3, 0, "div", 164);
|
|
798
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_67_Conditional_3_Template, 1, 0, "mj-empty-state", 165);
|
|
799
799
|
i0.ɵɵelementEnd();
|
|
800
800
|
} if (rf & 2) {
|
|
801
801
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -806,20 +806,20 @@ function MJTestFormComponentExtended_Conditional_66_Template(rf, ctx) { if (rf &
|
|
|
806
806
|
i0.ɵɵadvance();
|
|
807
807
|
i0.ɵɵconditional(ctx_r0.suiteTestsLoaded && !ctx_r0.loadingSuites && ctx_r0.suiteTests.length === 0 ? 3 : -1);
|
|
808
808
|
} }
|
|
809
|
-
function
|
|
810
|
-
i0.ɵɵelementStart(0, "div",
|
|
811
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
809
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
810
|
+
i0.ɵɵelementStart(0, "div", 126);
|
|
811
|
+
i0.ɵɵelement(1, "mj-loading", 174);
|
|
812
812
|
i0.ɵɵelementEnd();
|
|
813
813
|
} }
|
|
814
|
-
function
|
|
815
|
-
i0.ɵɵelementStart(0, "div",
|
|
816
|
-
i0.ɵɵelement(2, "i",
|
|
814
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_17_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
815
|
+
i0.ɵɵelementStart(0, "div", 184)(1, "div", 190);
|
|
816
|
+
i0.ɵɵelement(2, "i", 191);
|
|
817
817
|
i0.ɵɵelementEnd();
|
|
818
|
-
i0.ɵɵelementStart(3, "div",
|
|
818
|
+
i0.ɵɵelementStart(3, "div", 187)(4, "div", 188);
|
|
819
819
|
i0.ɵɵtext(5);
|
|
820
|
-
i0.ɵɵelement(6, "i",
|
|
820
|
+
i0.ɵɵelement(6, "i", 192);
|
|
821
821
|
i0.ɵɵelementEnd();
|
|
822
|
-
i0.ɵɵelementStart(7, "div",
|
|
822
|
+
i0.ɵɵelementStart(7, "div", 189);
|
|
823
823
|
i0.ɵɵtext(8, "Pass Rate");
|
|
824
824
|
i0.ɵɵelementEnd()()();
|
|
825
825
|
} if (rf & 2) {
|
|
@@ -829,14 +829,14 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17
|
|
|
829
829
|
i0.ɵɵadvance();
|
|
830
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");
|
|
831
831
|
} }
|
|
832
|
-
function
|
|
833
|
-
i0.ɵɵelementStart(0, "div",
|
|
834
|
-
i0.ɵɵelement(2, "i",
|
|
832
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_17_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
833
|
+
i0.ɵɵelementStart(0, "div", 184)(1, "div", 185);
|
|
834
|
+
i0.ɵɵelement(2, "i", 193);
|
|
835
835
|
i0.ɵɵelementEnd();
|
|
836
|
-
i0.ɵɵelementStart(3, "div",
|
|
836
|
+
i0.ɵɵelementStart(3, "div", 187)(4, "div", 188);
|
|
837
837
|
i0.ɵɵtext(5);
|
|
838
838
|
i0.ɵɵelementEnd();
|
|
839
|
-
i0.ɵɵelementStart(6, "div",
|
|
839
|
+
i0.ɵɵelementStart(6, "div", 189);
|
|
840
840
|
i0.ɵɵtext(7, "Avg Score");
|
|
841
841
|
i0.ɵɵelementEnd()()();
|
|
842
842
|
} if (rf & 2) {
|
|
@@ -844,34 +844,34 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17
|
|
|
844
844
|
i0.ɵɵadvance(5);
|
|
845
845
|
i0.ɵɵtextInterpolate1("", (ctx_r0.getOverallAvgScore() * 100).toFixed(1), "%");
|
|
846
846
|
} }
|
|
847
|
-
function
|
|
848
|
-
i0.ɵɵelementStart(0, "div",
|
|
849
|
-
i0.ɵɵelement(3, "i",
|
|
847
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
848
|
+
i0.ɵɵelementStart(0, "div", 181)(1, "div", 184)(2, "div", 185);
|
|
849
|
+
i0.ɵɵelement(3, "i", 186);
|
|
850
850
|
i0.ɵɵelementEnd();
|
|
851
|
-
i0.ɵɵelementStart(4, "div",
|
|
851
|
+
i0.ɵɵelementStart(4, "div", 187)(5, "div", 188);
|
|
852
852
|
i0.ɵɵtext(6);
|
|
853
853
|
i0.ɵɵelementEnd();
|
|
854
|
-
i0.ɵɵelementStart(7, "div",
|
|
854
|
+
i0.ɵɵelementStart(7, "div", 189);
|
|
855
855
|
i0.ɵɵtext(8, "Total Runs");
|
|
856
856
|
i0.ɵɵelementEnd()()();
|
|
857
|
-
i0.ɵɵconditionalCreate(9,
|
|
858
|
-
i0.ɵɵconditionalCreate(10,
|
|
859
|
-
i0.ɵɵelementStart(11, "div",
|
|
860
|
-
i0.ɵɵelement(13, "i",
|
|
857
|
+
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_17_Conditional_9_Template, 9, 11, "div", 184);
|
|
858
|
+
i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_17_Conditional_10_Template, 8, 1, "div", 184);
|
|
859
|
+
i0.ɵɵelementStart(11, "div", 184)(12, "div", 185);
|
|
860
|
+
i0.ɵɵelement(13, "i", 150);
|
|
861
861
|
i0.ɵɵelementEnd();
|
|
862
|
-
i0.ɵɵelementStart(14, "div",
|
|
862
|
+
i0.ɵɵelementStart(14, "div", 187)(15, "div", 188);
|
|
863
863
|
i0.ɵɵtext(16);
|
|
864
864
|
i0.ɵɵelementEnd();
|
|
865
|
-
i0.ɵɵelementStart(17, "div",
|
|
865
|
+
i0.ɵɵelementStart(17, "div", 189);
|
|
866
866
|
i0.ɵɵtext(18, "Avg Duration");
|
|
867
867
|
i0.ɵɵelementEnd()()();
|
|
868
|
-
i0.ɵɵelementStart(19, "div",
|
|
869
|
-
i0.ɵɵelement(21, "i",
|
|
868
|
+
i0.ɵɵelementStart(19, "div", 184)(20, "div", 185);
|
|
869
|
+
i0.ɵɵelement(21, "i", 151);
|
|
870
870
|
i0.ɵɵelementEnd();
|
|
871
|
-
i0.ɵɵelementStart(22, "div",
|
|
871
|
+
i0.ɵɵelementStart(22, "div", 187)(23, "div", 188);
|
|
872
872
|
i0.ɵɵtext(24);
|
|
873
873
|
i0.ɵɵelementEnd();
|
|
874
|
-
i0.ɵɵelementStart(25, "div",
|
|
874
|
+
i0.ɵɵelementStart(25, "div", 189);
|
|
875
875
|
i0.ɵɵtext(26, "Avg Cost");
|
|
876
876
|
i0.ɵɵelementEnd()()()();
|
|
877
877
|
} if (rf & 2) {
|
|
@@ -887,28 +887,28 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17
|
|
|
887
887
|
i0.ɵɵadvance(8);
|
|
888
888
|
i0.ɵɵtextInterpolate(ctx_r0.formatCost(ctx_r0.getOverallAvgCost()));
|
|
889
889
|
} }
|
|
890
|
-
function
|
|
890
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
891
891
|
i0.ɵɵelementStart(0, "th");
|
|
892
892
|
i0.ɵɵtext(1, "Passed");
|
|
893
893
|
i0.ɵɵelementEnd();
|
|
894
894
|
} }
|
|
895
|
-
function
|
|
895
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
896
896
|
i0.ɵɵelementStart(0, "th");
|
|
897
897
|
i0.ɵɵtext(1, "Failed");
|
|
898
898
|
i0.ɵɵelementEnd();
|
|
899
899
|
} }
|
|
900
|
-
function
|
|
900
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
901
901
|
i0.ɵɵelementStart(0, "th");
|
|
902
902
|
i0.ɵɵtext(1, "Pass Rate");
|
|
903
903
|
i0.ɵɵelementEnd();
|
|
904
904
|
} }
|
|
905
|
-
function
|
|
905
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
906
906
|
i0.ɵɵelementStart(0, "th");
|
|
907
907
|
i0.ɵɵtext(1, "Avg Score");
|
|
908
908
|
i0.ɵɵelementEnd();
|
|
909
909
|
} }
|
|
910
|
-
function
|
|
911
|
-
i0.ɵɵelementStart(0, "td",
|
|
910
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
911
|
+
i0.ɵɵelementStart(0, "td", 199);
|
|
912
912
|
i0.ɵɵtext(1);
|
|
913
913
|
i0.ɵɵelementEnd();
|
|
914
914
|
} if (rf & 2) {
|
|
@@ -916,8 +916,8 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
916
916
|
i0.ɵɵadvance();
|
|
917
917
|
i0.ɵɵtextInterpolate(day_r18.passCount);
|
|
918
918
|
} }
|
|
919
|
-
function
|
|
920
|
-
i0.ɵɵelementStart(0, "td",
|
|
919
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
920
|
+
i0.ɵɵelementStart(0, "td", 200);
|
|
921
921
|
i0.ɵɵtext(1);
|
|
922
922
|
i0.ɵɵelementEnd();
|
|
923
923
|
} if (rf & 2) {
|
|
@@ -925,10 +925,10 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
925
925
|
i0.ɵɵadvance();
|
|
926
926
|
i0.ɵɵtextInterpolate(day_r18.failCount);
|
|
927
927
|
} }
|
|
928
|
-
function
|
|
929
|
-
i0.ɵɵelementStart(0, "td",
|
|
930
|
-
i0.ɵɵelement(2, "div",
|
|
931
|
-
i0.ɵɵelementStart(3, "span",
|
|
928
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
929
|
+
i0.ɵɵelementStart(0, "td", 201)(1, "div", 205);
|
|
930
|
+
i0.ɵɵelement(2, "div", 206);
|
|
931
|
+
i0.ɵɵelementStart(3, "span", 207);
|
|
932
932
|
i0.ɵɵtext(4);
|
|
933
933
|
i0.ɵɵelementEnd()()();
|
|
934
934
|
} if (rf & 2) {
|
|
@@ -938,8 +938,8 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
938
938
|
i0.ɵɵadvance(2);
|
|
939
939
|
i0.ɵɵtextInterpolate1("", day_r18.passRate.toFixed(1), "%");
|
|
940
940
|
} }
|
|
941
|
-
function
|
|
942
|
-
i0.ɵɵelementStart(0, "td",
|
|
941
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
942
|
+
i0.ɵɵelementStart(0, "td", 202);
|
|
943
943
|
i0.ɵɵtext(1);
|
|
944
944
|
i0.ɵɵelementEnd();
|
|
945
945
|
} if (rf & 2) {
|
|
@@ -947,22 +947,22 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
947
947
|
i0.ɵɵadvance();
|
|
948
948
|
i0.ɵɵtextInterpolate1("", (day_r18.avgScore * 100).toFixed(1), "%");
|
|
949
949
|
} }
|
|
950
|
-
function
|
|
951
|
-
i0.ɵɵelementStart(0, "tr")(1, "td",
|
|
950
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Template(rf, ctx) { if (rf & 1) {
|
|
951
|
+
i0.ɵɵelementStart(0, "tr")(1, "td", 197);
|
|
952
952
|
i0.ɵɵtext(2);
|
|
953
953
|
i0.ɵɵpipe(3, "date");
|
|
954
954
|
i0.ɵɵelementEnd();
|
|
955
|
-
i0.ɵɵelementStart(4, "td",
|
|
955
|
+
i0.ɵɵelementStart(4, "td", 198);
|
|
956
956
|
i0.ɵɵtext(5);
|
|
957
957
|
i0.ɵɵelementEnd();
|
|
958
|
-
i0.ɵɵconditionalCreate(6,
|
|
959
|
-
i0.ɵɵconditionalCreate(7,
|
|
960
|
-
i0.ɵɵconditionalCreate(8,
|
|
961
|
-
i0.ɵɵconditionalCreate(9,
|
|
962
|
-
i0.ɵɵelementStart(10, "td",
|
|
958
|
+
i0.ɵɵconditionalCreate(6, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_6_Template, 2, 1, "td", 199);
|
|
959
|
+
i0.ɵɵconditionalCreate(7, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_7_Template, 2, 1, "td", 200);
|
|
960
|
+
i0.ɵɵconditionalCreate(8, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_8_Template, 5, 3, "td", 201);
|
|
961
|
+
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Conditional_9_Template, 2, 1, "td", 202);
|
|
962
|
+
i0.ɵɵelementStart(10, "td", 203);
|
|
963
963
|
i0.ɵɵtext(11);
|
|
964
964
|
i0.ɵɵelementEnd();
|
|
965
|
-
i0.ɵɵelementStart(12, "td",
|
|
965
|
+
i0.ɵɵelementStart(12, "td", 204);
|
|
966
966
|
i0.ɵɵtext(13);
|
|
967
967
|
i0.ɵɵelementEnd()();
|
|
968
968
|
} if (rf & 2) {
|
|
@@ -985,21 +985,21 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
985
985
|
i0.ɵɵadvance(2);
|
|
986
986
|
i0.ɵɵtextInterpolate(ctx_r0.formatCost(day_r18.avgCost));
|
|
987
987
|
} }
|
|
988
|
-
function
|
|
989
|
-
i0.ɵɵelementStart(0, "div",
|
|
990
|
-
i0.ɵɵelement(2, "i",
|
|
988
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
989
|
+
i0.ɵɵelementStart(0, "div", 182)(1, "h3");
|
|
990
|
+
i0.ɵɵelement(2, "i", 194);
|
|
991
991
|
i0.ɵɵtext(3, " Daily Performance");
|
|
992
992
|
i0.ɵɵelementEnd();
|
|
993
|
-
i0.ɵɵelementStart(4, "div",
|
|
993
|
+
i0.ɵɵelementStart(4, "div", 195)(5, "table", 196)(6, "thead")(7, "tr")(8, "th");
|
|
994
994
|
i0.ɵɵtext(9, "Date");
|
|
995
995
|
i0.ɵɵelementEnd();
|
|
996
996
|
i0.ɵɵelementStart(10, "th");
|
|
997
997
|
i0.ɵɵtext(11, "Runs");
|
|
998
998
|
i0.ɵɵelementEnd();
|
|
999
|
-
i0.ɵɵconditionalCreate(12,
|
|
1000
|
-
i0.ɵɵconditionalCreate(13,
|
|
1001
|
-
i0.ɵɵconditionalCreate(14,
|
|
1002
|
-
i0.ɵɵconditionalCreate(15,
|
|
999
|
+
i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_12_Template, 2, 0, "th");
|
|
1000
|
+
i0.ɵɵconditionalCreate(13, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_13_Template, 2, 0, "th");
|
|
1001
|
+
i0.ɵɵconditionalCreate(14, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_14_Template, 2, 0, "th");
|
|
1002
|
+
i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Conditional_15_Template, 2, 0, "th");
|
|
1003
1003
|
i0.ɵɵelementStart(16, "th");
|
|
1004
1004
|
i0.ɵɵtext(17, "Avg Duration");
|
|
1005
1005
|
i0.ɵɵelementEnd();
|
|
@@ -1007,7 +1007,7 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
1007
1007
|
i0.ɵɵtext(19, "Avg Cost");
|
|
1008
1008
|
i0.ɵɵelementEnd()()();
|
|
1009
1009
|
i0.ɵɵelementStart(20, "tbody");
|
|
1010
|
-
i0.ɵɵrepeaterCreate(21,
|
|
1010
|
+
i0.ɵɵrepeaterCreate(21, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_For_22_Template, 14, 11, "tr", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
1011
1011
|
i0.ɵɵelementEnd()()()();
|
|
1012
1012
|
} if (rf & 2) {
|
|
1013
1013
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
@@ -1022,8 +1022,8 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18
|
|
|
1022
1022
|
i0.ɵɵadvance(6);
|
|
1023
1023
|
i0.ɵɵrepeater(ctx_r0.historyData);
|
|
1024
1024
|
} }
|
|
1025
|
-
function
|
|
1026
|
-
i0.ɵɵelementStart(0, "span",
|
|
1025
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
1026
|
+
i0.ɵɵelementStart(0, "span", 219);
|
|
1027
1027
|
i0.ɵɵtext(1);
|
|
1028
1028
|
i0.ɵɵelementEnd();
|
|
1029
1029
|
} if (rf & 2) {
|
|
@@ -1031,8 +1031,8 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1031
1031
|
i0.ɵɵadvance();
|
|
1032
1032
|
i0.ɵɵtextInterpolate(tag_r21);
|
|
1033
1033
|
} }
|
|
1034
|
-
function
|
|
1035
|
-
i0.ɵɵelementStart(0, "span",
|
|
1034
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
1035
|
+
i0.ɵɵelementStart(0, "span", 220);
|
|
1036
1036
|
i0.ɵɵtext(1);
|
|
1037
1037
|
i0.ɵɵelementEnd();
|
|
1038
1038
|
} if (rf & 2) {
|
|
@@ -1040,10 +1040,10 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1040
1040
|
i0.ɵɵadvance();
|
|
1041
1041
|
i0.ɵɵtextInterpolate1("+", suite_r20.tags.length - 3);
|
|
1042
1042
|
} }
|
|
1043
|
-
function
|
|
1044
|
-
i0.ɵɵelementStart(0, "div",
|
|
1045
|
-
i0.ɵɵrepeaterCreate(1,
|
|
1046
|
-
i0.ɵɵconditionalCreate(3,
|
|
1043
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
1044
|
+
i0.ɵɵelementStart(0, "div", 213);
|
|
1045
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template, 2, 1, "span", 219, i0.ɵɵrepeaterTrackByIdentity);
|
|
1046
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template, 2, 1, "span", 220);
|
|
1047
1047
|
i0.ɵɵelementEnd();
|
|
1048
1048
|
} if (rf & 2) {
|
|
1049
1049
|
const suite_r20 = i0.ɵɵnextContext().$implicit;
|
|
@@ -1052,11 +1052,11 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1052
1052
|
i0.ɵɵadvance(2);
|
|
1053
1053
|
i0.ɵɵconditional(suite_r20.tags.length > 3 ? 3 : -1);
|
|
1054
1054
|
} }
|
|
1055
|
-
function
|
|
1056
|
-
i0.ɵɵelementStart(0, "div",
|
|
1055
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
1056
|
+
i0.ɵɵelementStart(0, "div", 215)(1, "span", 221);
|
|
1057
1057
|
i0.ɵɵtext(2);
|
|
1058
1058
|
i0.ɵɵelementEnd();
|
|
1059
|
-
i0.ɵɵelementStart(3, "span",
|
|
1059
|
+
i0.ɵɵelementStart(3, "span", 217);
|
|
1060
1060
|
i0.ɵɵtext(4, "Pass Rate");
|
|
1061
1061
|
i0.ɵɵelementEnd()();
|
|
1062
1062
|
} if (rf & 2) {
|
|
@@ -1066,11 +1066,11 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1066
1066
|
i0.ɵɵadvance();
|
|
1067
1067
|
i0.ɵɵtextInterpolate1(" ", suite_r20.passRate.toFixed(1), "% ");
|
|
1068
1068
|
} }
|
|
1069
|
-
function
|
|
1070
|
-
i0.ɵɵelementStart(0, "div",
|
|
1069
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
1070
|
+
i0.ɵɵelementStart(0, "div", 215)(1, "span", 216);
|
|
1071
1071
|
i0.ɵɵtext(2);
|
|
1072
1072
|
i0.ɵɵelementEnd();
|
|
1073
|
-
i0.ɵɵelementStart(3, "span",
|
|
1073
|
+
i0.ɵɵelementStart(3, "span", 217);
|
|
1074
1074
|
i0.ɵɵtext(4, "Avg Score");
|
|
1075
1075
|
i0.ɵɵelementEnd()();
|
|
1076
1076
|
} if (rf & 2) {
|
|
@@ -1078,11 +1078,11 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1078
1078
|
i0.ɵɵadvance(2);
|
|
1079
1079
|
i0.ɵɵtextInterpolate1("", (suite_r20.avgScore * 100).toFixed(1), "%");
|
|
1080
1080
|
} }
|
|
1081
|
-
function
|
|
1082
|
-
i0.ɵɵelementStart(0, "div",
|
|
1081
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
1082
|
+
i0.ɵɵelementStart(0, "div", 215)(1, "span", 216);
|
|
1083
1083
|
i0.ɵɵtext(2);
|
|
1084
1084
|
i0.ɵɵelementEnd();
|
|
1085
|
-
i0.ɵɵelementStart(3, "span",
|
|
1085
|
+
i0.ɵɵelementStart(3, "span", 217);
|
|
1086
1086
|
i0.ɵɵtext(4, "Last Run");
|
|
1087
1087
|
i0.ɵɵelementEnd()();
|
|
1088
1088
|
} if (rf & 2) {
|
|
@@ -1091,38 +1091,38 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1091
1091
|
i0.ɵɵadvance(2);
|
|
1092
1092
|
i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(suite_r20.lastRun));
|
|
1093
1093
|
} }
|
|
1094
|
-
function
|
|
1094
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Template(rf, ctx) { if (rf & 1) {
|
|
1095
1095
|
const _r19 = i0.ɵɵgetCurrentView();
|
|
1096
|
-
i0.ɵɵelementStart(0, "div",
|
|
1097
|
-
i0.ɵɵlistener("click", function
|
|
1098
|
-
i0.ɵɵelementStart(1, "div",
|
|
1096
|
+
i0.ɵɵelementStart(0, "div", 210);
|
|
1097
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_68_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", 211)(2, "div", 212);
|
|
1099
1099
|
i0.ɵɵtext(3);
|
|
1100
1100
|
i0.ɵɵelementEnd();
|
|
1101
|
-
i0.ɵɵconditionalCreate(4,
|
|
1101
|
+
i0.ɵɵconditionalCreate(4, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_4_Template, 4, 1, "div", 213);
|
|
1102
1102
|
i0.ɵɵelementEnd();
|
|
1103
|
-
i0.ɵɵelementStart(5, "div",
|
|
1103
|
+
i0.ɵɵelementStart(5, "div", 214)(6, "div", 215)(7, "span", 216);
|
|
1104
1104
|
i0.ɵɵtext(8);
|
|
1105
1105
|
i0.ɵɵelementEnd();
|
|
1106
|
-
i0.ɵɵelementStart(9, "span",
|
|
1106
|
+
i0.ɵɵelementStart(9, "span", 217);
|
|
1107
1107
|
i0.ɵɵtext(10, "Runs");
|
|
1108
1108
|
i0.ɵɵelementEnd()();
|
|
1109
|
-
i0.ɵɵconditionalCreate(11,
|
|
1110
|
-
i0.ɵɵconditionalCreate(12,
|
|
1111
|
-
i0.ɵɵelementStart(13, "div",
|
|
1109
|
+
i0.ɵɵconditionalCreate(11, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_11_Template, 5, 5, "div", 215);
|
|
1110
|
+
i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_12_Template, 5, 1, "div", 215);
|
|
1111
|
+
i0.ɵɵelementStart(13, "div", 215)(14, "span", 216);
|
|
1112
1112
|
i0.ɵɵtext(15);
|
|
1113
1113
|
i0.ɵɵelementEnd();
|
|
1114
|
-
i0.ɵɵelementStart(16, "span",
|
|
1114
|
+
i0.ɵɵelementStart(16, "span", 217);
|
|
1115
1115
|
i0.ɵɵtext(17, "Avg Duration");
|
|
1116
1116
|
i0.ɵɵelementEnd()();
|
|
1117
|
-
i0.ɵɵelementStart(18, "div",
|
|
1117
|
+
i0.ɵɵelementStart(18, "div", 215)(19, "span", 216);
|
|
1118
1118
|
i0.ɵɵtext(20);
|
|
1119
1119
|
i0.ɵɵelementEnd();
|
|
1120
|
-
i0.ɵɵelementStart(21, "span",
|
|
1120
|
+
i0.ɵɵelementStart(21, "span", 217);
|
|
1121
1121
|
i0.ɵɵtext(22, "Avg Cost");
|
|
1122
1122
|
i0.ɵɵelementEnd()();
|
|
1123
|
-
i0.ɵɵconditionalCreate(23,
|
|
1123
|
+
i0.ɵɵconditionalCreate(23, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Conditional_23_Template, 5, 1, "div", 215);
|
|
1124
1124
|
i0.ɵɵelementEnd();
|
|
1125
|
-
i0.ɵɵelement(24, "i",
|
|
1125
|
+
i0.ɵɵelement(24, "i", 218);
|
|
1126
1126
|
i0.ɵɵelementEnd();
|
|
1127
1127
|
} if (rf & 2) {
|
|
1128
1128
|
const suite_r20 = ctx.$implicit;
|
|
@@ -1144,55 +1144,55 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19
|
|
|
1144
1144
|
i0.ɵɵadvance(3);
|
|
1145
1145
|
i0.ɵɵconditional(suite_r20.lastRun ? 23 : -1);
|
|
1146
1146
|
} }
|
|
1147
|
-
function
|
|
1148
|
-
i0.ɵɵelementStart(0, "div",
|
|
1149
|
-
i0.ɵɵelement(2, "i",
|
|
1147
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
1148
|
+
i0.ɵɵelementStart(0, "div", 182)(1, "h3");
|
|
1149
|
+
i0.ɵɵelement(2, "i", 34);
|
|
1150
1150
|
i0.ɵɵtext(3, " Performance by Suite");
|
|
1151
1151
|
i0.ɵɵelementEnd();
|
|
1152
|
-
i0.ɵɵelementStart(4, "div",
|
|
1153
|
-
i0.ɵɵrepeaterCreate(5,
|
|
1152
|
+
i0.ɵɵelementStart(4, "div", 208);
|
|
1153
|
+
i0.ɵɵrepeaterCreate(5, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_For_6_Template, 25, 8, "div", 209, i0.ɵɵrepeaterTrackByIdentity);
|
|
1154
1154
|
i0.ɵɵelementEnd()();
|
|
1155
1155
|
} if (rf & 2) {
|
|
1156
1156
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
1157
1157
|
i0.ɵɵadvance(5);
|
|
1158
1158
|
i0.ɵɵrepeater(ctx_r0.suitePerformance);
|
|
1159
1159
|
} }
|
|
1160
|
-
function
|
|
1160
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
1161
1161
|
const _r22 = i0.ɵɵgetCurrentView();
|
|
1162
|
-
i0.ɵɵelementStart(0, "mj-empty-state",
|
|
1163
|
-
i0.ɵɵlistener("Action", function
|
|
1162
|
+
i0.ɵɵelementStart(0, "mj-empty-state", 222);
|
|
1163
|
+
i0.ɵɵlistener("Action", function MJTestFormComponentExtended_Conditional_68_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()); });
|
|
1164
1164
|
i0.ɵɵelementEnd();
|
|
1165
1165
|
} }
|
|
1166
|
-
function
|
|
1166
|
+
function MJTestFormComponentExtended_Conditional_68_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
1167
1167
|
const _r17 = i0.ɵɵgetCurrentView();
|
|
1168
|
-
i0.ɵɵelementStart(0, "div",
|
|
1168
|
+
i0.ɵɵelementStart(0, "div", 173)(1, "div", 175)(2, "div", 176)(3, "span", 177);
|
|
1169
1169
|
i0.ɵɵtext(4, "Time Range:");
|
|
1170
1170
|
i0.ɵɵelementEnd();
|
|
1171
|
-
i0.ɵɵelementStart(5, "button",
|
|
1172
|
-
i0.ɵɵlistener("click", function
|
|
1171
|
+
i0.ɵɵelementStart(5, "button", 178);
|
|
1172
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_68_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("7d")); });
|
|
1173
1173
|
i0.ɵɵtext(6, "7 Days");
|
|
1174
1174
|
i0.ɵɵelementEnd();
|
|
1175
|
-
i0.ɵɵelementStart(7, "button",
|
|
1176
|
-
i0.ɵɵlistener("click", function
|
|
1175
|
+
i0.ɵɵelementStart(7, "button", 178);
|
|
1176
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_68_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("30d")); });
|
|
1177
1177
|
i0.ɵɵtext(8, "30 Days");
|
|
1178
1178
|
i0.ɵɵelementEnd();
|
|
1179
|
-
i0.ɵɵelementStart(9, "button",
|
|
1180
|
-
i0.ɵɵlistener("click", function
|
|
1179
|
+
i0.ɵɵelementStart(9, "button", 178);
|
|
1180
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_68_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("90d")); });
|
|
1181
1181
|
i0.ɵɵtext(10, "90 Days");
|
|
1182
1182
|
i0.ɵɵelementEnd();
|
|
1183
|
-
i0.ɵɵelementStart(11, "button",
|
|
1184
|
-
i0.ɵɵlistener("click", function
|
|
1183
|
+
i0.ɵɵelementStart(11, "button", 178);
|
|
1184
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_68_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r17); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("all")); });
|
|
1185
1185
|
i0.ɵɵtext(12, "All Time");
|
|
1186
1186
|
i0.ɵɵelementEnd()();
|
|
1187
|
-
i0.ɵɵelementStart(13, "div",
|
|
1188
|
-
i0.ɵɵlistener("click", function
|
|
1189
|
-
i0.ɵɵelement(15, "i",
|
|
1187
|
+
i0.ɵɵelementStart(13, "div", 179)(14, "button", 23);
|
|
1188
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_68_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", 180);
|
|
1190
1190
|
i0.ɵɵtext(16, " Export CSV ");
|
|
1191
1191
|
i0.ɵɵelementEnd()()();
|
|
1192
|
-
i0.ɵɵconditionalCreate(17,
|
|
1193
|
-
i0.ɵɵconditionalCreate(18,
|
|
1194
|
-
i0.ɵɵconditionalCreate(19,
|
|
1195
|
-
i0.ɵɵconditionalCreate(20,
|
|
1192
|
+
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_17_Template, 27, 5, "div", 181);
|
|
1193
|
+
i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_18_Template, 23, 4, "div", 182);
|
|
1194
|
+
i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_19_Template, 7, 0, "div", 182);
|
|
1195
|
+
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_68_Conditional_2_Conditional_20_Template, 1, 0, "mj-empty-state", 183);
|
|
1196
1196
|
i0.ɵɵelementEnd();
|
|
1197
1197
|
} if (rf & 2) {
|
|
1198
1198
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -1215,10 +1215,10 @@ function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template(rf, c
|
|
|
1215
1215
|
i0.ɵɵadvance();
|
|
1216
1216
|
i0.ɵɵconditional(ctx_r0.historyData.length === 0 ? 20 : -1);
|
|
1217
1217
|
} }
|
|
1218
|
-
function
|
|
1219
|
-
i0.ɵɵelementStart(0, "div",
|
|
1220
|
-
i0.ɵɵconditionalCreate(1,
|
|
1221
|
-
i0.ɵɵconditionalCreate(2,
|
|
1218
|
+
function MJTestFormComponentExtended_Conditional_68_Template(rf, ctx) { if (rf & 1) {
|
|
1219
|
+
i0.ɵɵelementStart(0, "div", 41);
|
|
1220
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_68_Conditional_1_Template, 2, 0, "div", 126);
|
|
1221
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_68_Conditional_2_Template, 21, 13, "div", 173);
|
|
1222
1222
|
i0.ɵɵelementEnd();
|
|
1223
1223
|
} if (rf & 2) {
|
|
1224
1224
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -1227,46 +1227,46 @@ function MJTestFormComponentExtended_Conditional_67_Template(rf, ctx) { if (rf &
|
|
|
1227
1227
|
i0.ɵɵadvance();
|
|
1228
1228
|
i0.ɵɵconditional(!ctx_r0.loadingHistory && ctx_r0.historyLoaded ? 2 : -1);
|
|
1229
1229
|
} }
|
|
1230
|
-
function
|
|
1230
|
+
function MJTestFormComponentExtended_Conditional_71_Template(rf, ctx) { if (rf & 1) {
|
|
1231
1231
|
const _r23 = i0.ɵɵgetCurrentView();
|
|
1232
|
-
i0.ɵɵelementStart(0, "div",
|
|
1233
|
-
i0.ɵɵelement(2, "i",
|
|
1232
|
+
i0.ɵɵelementStart(0, "div", 44)(1, "div", 223);
|
|
1233
|
+
i0.ɵɵelement(2, "i", 43);
|
|
1234
1234
|
i0.ɵɵtext(3, " Shortcuts ");
|
|
1235
|
-
i0.ɵɵelementStart(4, "button",
|
|
1236
|
-
i0.ɵɵlistener("click", function
|
|
1237
|
-
i0.ɵɵelement(5, "i",
|
|
1235
|
+
i0.ɵɵelementStart(4, "button", 224);
|
|
1236
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_71_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r23); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleShortcuts()); });
|
|
1237
|
+
i0.ɵɵelement(5, "i", 125);
|
|
1238
1238
|
i0.ɵɵelementEnd()();
|
|
1239
|
-
i0.ɵɵelementStart(6, "div",
|
|
1239
|
+
i0.ɵɵelementStart(6, "div", 225)(7, "div", 226)(8, "span");
|
|
1240
1240
|
i0.ɵɵtext(9, "Save changes");
|
|
1241
1241
|
i0.ɵɵelementEnd();
|
|
1242
|
-
i0.ɵɵelementStart(10, "span",
|
|
1242
|
+
i0.ɵɵelementStart(10, "span", 227)(11, "kbd");
|
|
1243
1243
|
i0.ɵɵtext(12, "Cmd");
|
|
1244
1244
|
i0.ɵɵelementEnd();
|
|
1245
1245
|
i0.ɵɵelementStart(13, "kbd");
|
|
1246
1246
|
i0.ɵɵtext(14, "S");
|
|
1247
1247
|
i0.ɵɵelementEnd()()();
|
|
1248
|
-
i0.ɵɵelementStart(15, "div",
|
|
1248
|
+
i0.ɵɵelementStart(15, "div", 226)(16, "span");
|
|
1249
1249
|
i0.ɵɵtext(17, "Refresh");
|
|
1250
1250
|
i0.ɵɵelementEnd();
|
|
1251
|
-
i0.ɵɵelementStart(18, "span",
|
|
1251
|
+
i0.ɵɵelementStart(18, "span", 227)(19, "kbd");
|
|
1252
1252
|
i0.ɵɵtext(20, "Cmd");
|
|
1253
1253
|
i0.ɵɵelementEnd();
|
|
1254
1254
|
i0.ɵɵelementStart(21, "kbd");
|
|
1255
1255
|
i0.ɵɵtext(22, "R");
|
|
1256
1256
|
i0.ɵɵelementEnd()()();
|
|
1257
|
-
i0.ɵɵelementStart(23, "div",
|
|
1257
|
+
i0.ɵɵelementStart(23, "div", 226)(24, "span");
|
|
1258
1258
|
i0.ɵɵtext(25, "Run Test");
|
|
1259
1259
|
i0.ɵɵelementEnd();
|
|
1260
|
-
i0.ɵɵelementStart(26, "span",
|
|
1260
|
+
i0.ɵɵelementStart(26, "span", 227)(27, "kbd");
|
|
1261
1261
|
i0.ɵɵtext(28, "Cmd");
|
|
1262
1262
|
i0.ɵɵelementEnd();
|
|
1263
1263
|
i0.ɵɵelementStart(29, "kbd");
|
|
1264
1264
|
i0.ɵɵtext(30, "Enter");
|
|
1265
1265
|
i0.ɵɵelementEnd()()();
|
|
1266
|
-
i0.ɵɵelementStart(31, "div",
|
|
1266
|
+
i0.ɵɵelementStart(31, "div", 226)(32, "span");
|
|
1267
1267
|
i0.ɵɵtext(33, "Switch Tabs");
|
|
1268
1268
|
i0.ɵɵelementEnd();
|
|
1269
|
-
i0.ɵɵelementStart(34, "span",
|
|
1269
|
+
i0.ɵɵelementStart(34, "span", 227)(35, "kbd");
|
|
1270
1270
|
i0.ɵɵtext(36, "1");
|
|
1271
1271
|
i0.ɵɵelementEnd();
|
|
1272
1272
|
i0.ɵɵtext(37, "-");
|
|
@@ -1274,12 +1274,12 @@ function MJTestFormComponentExtended_Conditional_70_Template(rf, ctx) { if (rf &
|
|
|
1274
1274
|
i0.ɵɵtext(39, "5");
|
|
1275
1275
|
i0.ɵɵelementEnd()()()()();
|
|
1276
1276
|
} }
|
|
1277
|
-
function
|
|
1277
|
+
function MJTestFormComponentExtended_Conditional_72_Template(rf, ctx) { if (rf & 1) {
|
|
1278
1278
|
const _r24 = i0.ɵɵgetCurrentView();
|
|
1279
|
-
i0.ɵɵelementStart(0, "mj-slide-panel",
|
|
1280
|
-
i0.ɵɵlistener("Closed", function
|
|
1281
|
-
i0.ɵɵelementStart(1, "app-test-run-dialog",
|
|
1282
|
-
i0.ɵɵlistener("PanelClose", function
|
|
1279
|
+
i0.ɵɵelementStart(0, "mj-slide-panel", 228);
|
|
1280
|
+
i0.ɵɵlistener("Closed", function MJTestFormComponentExtended_Conditional_72_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", 229);
|
|
1282
|
+
i0.ɵɵlistener("PanelClose", function MJTestFormComponentExtended_Conditional_72_Template_app_test_run_dialog_PanelClose_1_listener() { i0.ɵɵrestoreView(_r24); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
|
|
1283
1283
|
i0.ɵɵelementEnd()();
|
|
1284
1284
|
} if (rf & 2) {
|
|
1285
1285
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -1287,26 +1287,26 @@ function MJTestFormComponentExtended_Conditional_71_Template(rf, ctx) { if (rf &
|
|
|
1287
1287
|
i0.ɵɵadvance();
|
|
1288
1288
|
i0.ɵɵproperty("PanelMode", true)("selectedTestId", (ctx_r0.testingDialogService.PanelOptions == null ? null : ctx_r0.testingDialogService.PanelOptions.testId) ?? null)("selectedSuiteId", (ctx_r0.testingDialogService.PanelOptions == null ? null : ctx_r0.testingDialogService.PanelOptions.suiteId) ?? null)("runMode", (ctx_r0.testingDialogService.PanelOptions == null ? null : ctx_r0.testingDialogService.PanelOptions.mode) ?? "test");
|
|
1289
1289
|
} }
|
|
1290
|
-
function
|
|
1290
|
+
function MJTestFormComponentExtended_Conditional_81_Template(rf, ctx) { if (rf & 1) {
|
|
1291
1291
|
i0.ɵɵtext(0);
|
|
1292
1292
|
} if (rf & 2) {
|
|
1293
1293
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
1294
1294
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.dirtyFieldNames[0], " edited ");
|
|
1295
1295
|
} }
|
|
1296
|
-
function
|
|
1296
|
+
function MJTestFormComponentExtended_Conditional_82_Template(rf, ctx) { if (rf & 1) {
|
|
1297
1297
|
i0.ɵɵtext(0);
|
|
1298
1298
|
} if (rf & 2) {
|
|
1299
1299
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
1300
1300
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.dirtyFieldNames.length, " fields edited ");
|
|
1301
1301
|
} }
|
|
1302
|
-
function MJTestFormComponentExtended_Conditional_84_Template(rf, ctx) { if (rf & 1) {
|
|
1303
|
-
i0.ɵɵelement(0, "i", 229);
|
|
1304
|
-
i0.ɵɵtext(1, " Saving\u2026 ");
|
|
1305
|
-
} }
|
|
1306
1302
|
function MJTestFormComponentExtended_Conditional_85_Template(rf, ctx) { if (rf & 1) {
|
|
1307
1303
|
i0.ɵɵelement(0, "i", 230);
|
|
1304
|
+
i0.ɵɵtext(1, " Saving\u2026 ");
|
|
1305
|
+
} }
|
|
1306
|
+
function MJTestFormComponentExtended_Conditional_86_Template(rf, ctx) { if (rf & 1) {
|
|
1307
|
+
i0.ɵɵelement(0, "i", 231);
|
|
1308
1308
|
i0.ɵɵtext(1, " Save changes ");
|
|
1309
|
-
i0.ɵɵelementStart(2, "span",
|
|
1309
|
+
i0.ɵɵelementStart(2, "span", 232)(3, "kbd");
|
|
1310
1310
|
i0.ɵɵtext(4, "\u2318");
|
|
1311
1311
|
i0.ɵɵelementEnd();
|
|
1312
1312
|
i0.ɵɵelementStart(5, "kbd");
|
|
@@ -1817,6 +1817,21 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1817
1817
|
console.error('Error parsing JSON fields:', error);
|
|
1818
1818
|
}
|
|
1819
1819
|
}
|
|
1820
|
+
/** The tab strip as `mj-section-picker` items: strip order, a count once that tab's data has loaded. */
|
|
1821
|
+
get SectionPickerItems() {
|
|
1822
|
+
return [
|
|
1823
|
+
{ Key: 'overview', Title: 'Overview', Icon: 'fas fa-th-large' },
|
|
1824
|
+
{ Key: 'config', Title: 'Configuration', Icon: 'fas fa-sliders-h' },
|
|
1825
|
+
{ Key: 'runs', Title: 'Runs', Icon: 'fas fa-history', Count: this.TestRunsLoaded ? this.TestRuns.length : null },
|
|
1826
|
+
{ Key: 'suites', Title: 'Test Suites', Icon: 'fas fa-layer-group', Count: this.SuiteTestsLoaded ? this.SuiteTests.length : null },
|
|
1827
|
+
{ Key: 'analytics', Title: 'Analytics', Icon: 'fas fa-chart-line' },
|
|
1828
|
+
];
|
|
1829
|
+
}
|
|
1830
|
+
/** A pick from the phone section sheet; goes through ChangeTab so lazy loads fire. An unknown key is ignored. */
|
|
1831
|
+
OnSectionPicked(key) {
|
|
1832
|
+
if (this.SectionPickerItems.some((i) => i.Key === key))
|
|
1833
|
+
this.ChangeTab(key);
|
|
1834
|
+
}
|
|
1820
1835
|
ChangeTab(tab) {
|
|
1821
1836
|
this.ActiveTab = tab;
|
|
1822
1837
|
// Lazy load tabs
|
|
@@ -2577,7 +2592,7 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
2577
2592
|
static { this.ɵfac = /*@__PURE__*/ (() => { let ɵMJTestFormComponentExtended_BaseFactory; return function MJTestFormComponentExtended_Factory(__ngFactoryType__) { return (ɵMJTestFormComponentExtended_BaseFactory || (ɵMJTestFormComponentExtended_BaseFactory = i0.ɵɵgetInheritedFactory(MJTestFormComponentExtended)))(__ngFactoryType__ || MJTestFormComponentExtended); }; })(); }
|
|
2578
2593
|
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTestFormComponentExtended, selectors: [["mj-test-form"]], hostBindings: function MJTestFormComponentExtended_HostBindings(rf, ctx) { if (rf & 1) {
|
|
2579
2594
|
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);
|
|
2580
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
2595
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 90, vars: 53, 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"], [1, "phone-section-picker", 3, "ActiveKeyChange", "Items", "ActiveKey"], ["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) {
|
|
2581
2596
|
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "nav", 3)(3, "ol")(4, "li")(5, "a", 4);
|
|
2582
2597
|
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_a_click_5_listener() { return ctx.navigateToTestingDashboard(); });
|
|
2583
2598
|
i0.ɵɵelement(6, "i", 5);
|
|
@@ -2618,70 +2633,73 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
2618
2633
|
i0.ɵɵconditionalCreate(36, MJTestFormComponentExtended_Conditional_36_Template, 3, 1, "div", 24);
|
|
2619
2634
|
i0.ɵɵconditionalCreate(37, MJTestFormComponentExtended_Conditional_37_Template, 23, 6, "div", 25);
|
|
2620
2635
|
i0.ɵɵelementEnd();
|
|
2621
|
-
i0.ɵɵelementStart(38, "div", 26)(39, "
|
|
2622
|
-
i0.ɵɵlistener("
|
|
2623
|
-
i0.ɵɵ
|
|
2624
|
-
i0.ɵɵelementStart(
|
|
2625
|
-
i0.ɵɵ
|
|
2636
|
+
i0.ɵɵelementStart(38, "div", 26)(39, "mj-section-picker", 27);
|
|
2637
|
+
i0.ɵɵlistener("ActiveKeyChange", function MJTestFormComponentExtended_Template_mj_section_picker_ActiveKeyChange_39_listener($event) { return ctx.OnSectionPicked($event); });
|
|
2638
|
+
i0.ɵɵelementEnd();
|
|
2639
|
+
i0.ɵɵelementStart(40, "div", 28)(41, "button", 29);
|
|
2640
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_41_listener() { return ctx.changeTab("overview"); });
|
|
2641
|
+
i0.ɵɵelement(42, "i", 30);
|
|
2642
|
+
i0.ɵɵelementStart(43, "span");
|
|
2643
|
+
i0.ɵɵtext(44, "Overview");
|
|
2626
2644
|
i0.ɵɵelementEnd()();
|
|
2627
|
-
i0.ɵɵelementStart(
|
|
2628
|
-
i0.ɵɵlistener("click", function
|
|
2629
|
-
i0.ɵɵelement(
|
|
2630
|
-
i0.ɵɵelementStart(
|
|
2631
|
-
i0.ɵɵtext(
|
|
2645
|
+
i0.ɵɵelementStart(45, "button", 29);
|
|
2646
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_45_listener() { return ctx.changeTab("config"); });
|
|
2647
|
+
i0.ɵɵelement(46, "i", 31);
|
|
2648
|
+
i0.ɵɵelementStart(47, "span");
|
|
2649
|
+
i0.ɵɵtext(48, "Configuration");
|
|
2632
2650
|
i0.ɵɵelementEnd()();
|
|
2633
|
-
i0.ɵɵelementStart(
|
|
2634
|
-
i0.ɵɵlistener("click", function
|
|
2635
|
-
i0.ɵɵelement(
|
|
2636
|
-
i0.ɵɵelementStart(
|
|
2637
|
-
i0.ɵɵtext(
|
|
2651
|
+
i0.ɵɵelementStart(49, "button", 29);
|
|
2652
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_49_listener() { return ctx.changeTab("runs"); });
|
|
2653
|
+
i0.ɵɵelement(50, "i", 32);
|
|
2654
|
+
i0.ɵɵelementStart(51, "span");
|
|
2655
|
+
i0.ɵɵtext(52, "Runs");
|
|
2638
2656
|
i0.ɵɵelementEnd();
|
|
2639
|
-
i0.ɵɵconditionalCreate(
|
|
2657
|
+
i0.ɵɵconditionalCreate(53, MJTestFormComponentExtended_Conditional_53_Template, 2, 1, "span", 33);
|
|
2640
2658
|
i0.ɵɵelementEnd();
|
|
2641
|
-
i0.ɵɵelementStart(
|
|
2642
|
-
i0.ɵɵlistener("click", function
|
|
2643
|
-
i0.ɵɵelement(
|
|
2644
|
-
i0.ɵɵelementStart(
|
|
2645
|
-
i0.ɵɵtext(
|
|
2659
|
+
i0.ɵɵelementStart(54, "button", 29);
|
|
2660
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_54_listener() { return ctx.changeTab("suites"); });
|
|
2661
|
+
i0.ɵɵelement(55, "i", 34);
|
|
2662
|
+
i0.ɵɵelementStart(56, "span");
|
|
2663
|
+
i0.ɵɵtext(57, "Test Suites");
|
|
2646
2664
|
i0.ɵɵelementEnd();
|
|
2647
|
-
i0.ɵɵconditionalCreate(
|
|
2665
|
+
i0.ɵɵconditionalCreate(58, MJTestFormComponentExtended_Conditional_58_Template, 2, 1, "span", 33);
|
|
2648
2666
|
i0.ɵɵelementEnd();
|
|
2649
|
-
i0.ɵɵelementStart(
|
|
2650
|
-
i0.ɵɵlistener("click", function
|
|
2651
|
-
i0.ɵɵelement(
|
|
2652
|
-
i0.ɵɵelementStart(
|
|
2653
|
-
i0.ɵɵtext(
|
|
2667
|
+
i0.ɵɵelementStart(59, "button", 29);
|
|
2668
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_59_listener() { return ctx.changeTab("analytics"); });
|
|
2669
|
+
i0.ɵɵelement(60, "i", 35);
|
|
2670
|
+
i0.ɵɵelementStart(61, "span");
|
|
2671
|
+
i0.ɵɵtext(62, "Analytics");
|
|
2654
2672
|
i0.ɵɵelementEnd()()()();
|
|
2655
|
-
i0.ɵɵelementStart(
|
|
2656
|
-
i0.ɵɵconditionalCreate(
|
|
2657
|
-
i0.ɵɵconditionalCreate(
|
|
2658
|
-
i0.ɵɵconditionalCreate(65, MJTestFormComponentExtended_Conditional_65_Template, 4, 3, "div", 38);
|
|
2673
|
+
i0.ɵɵelementStart(63, "div", 36);
|
|
2674
|
+
i0.ɵɵconditionalCreate(64, MJTestFormComponentExtended_Conditional_64_Template, 78, 29, "div", 37);
|
|
2675
|
+
i0.ɵɵconditionalCreate(65, MJTestFormComponentExtended_Conditional_65_Template, 119, 32, "div", 38);
|
|
2659
2676
|
i0.ɵɵconditionalCreate(66, MJTestFormComponentExtended_Conditional_66_Template, 4, 3, "div", 39);
|
|
2660
|
-
i0.ɵɵconditionalCreate(67, MJTestFormComponentExtended_Conditional_67_Template,
|
|
2677
|
+
i0.ɵɵconditionalCreate(67, MJTestFormComponentExtended_Conditional_67_Template, 4, 3, "div", 40);
|
|
2678
|
+
i0.ɵɵconditionalCreate(68, MJTestFormComponentExtended_Conditional_68_Template, 3, 2, "div", 41);
|
|
2661
2679
|
i0.ɵɵelementEnd();
|
|
2662
|
-
i0.ɵɵelementStart(
|
|
2663
|
-
i0.ɵɵlistener("click", function
|
|
2664
|
-
i0.ɵɵelement(
|
|
2680
|
+
i0.ɵɵelementStart(69, "button", 42);
|
|
2681
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_69_listener() { return ctx.toggleShortcuts(); });
|
|
2682
|
+
i0.ɵɵelement(70, "i", 43);
|
|
2665
2683
|
i0.ɵɵelementEnd();
|
|
2666
|
-
i0.ɵɵconditionalCreate(
|
|
2667
|
-
i0.ɵɵconditionalCreate(
|
|
2668
|
-
i0.ɵɵelementStart(
|
|
2669
|
-
i0.ɵɵtext(
|
|
2684
|
+
i0.ɵɵconditionalCreate(71, MJTestFormComponentExtended_Conditional_71_Template, 40, 0, "div", 44);
|
|
2685
|
+
i0.ɵɵconditionalCreate(72, MJTestFormComponentExtended_Conditional_72_Template, 2, 6, "mj-slide-panel", 45);
|
|
2686
|
+
i0.ɵɵelementStart(73, "div", 46)(74, "div", 47)(75, "span", 48);
|
|
2687
|
+
i0.ɵɵtext(76, "\u25CF");
|
|
2670
2688
|
i0.ɵɵelementEnd();
|
|
2671
|
-
i0.ɵɵelementStart(
|
|
2672
|
-
i0.ɵɵtext(
|
|
2689
|
+
i0.ɵɵelementStart(77, "span", 49)(78, "strong");
|
|
2690
|
+
i0.ɵɵtext(79, "Unsaved changes");
|
|
2673
2691
|
i0.ɵɵelementEnd();
|
|
2674
|
-
i0.ɵɵelementStart(
|
|
2675
|
-
i0.ɵɵconditionalCreate(
|
|
2692
|
+
i0.ɵɵelementStart(80, "span", 50);
|
|
2693
|
+
i0.ɵɵconditionalCreate(81, MJTestFormComponentExtended_Conditional_81_Template, 1, 1)(82, MJTestFormComponentExtended_Conditional_82_Template, 1, 1);
|
|
2676
2694
|
i0.ɵɵelementEnd()()();
|
|
2677
|
-
i0.ɵɵelementStart(
|
|
2678
|
-
i0.ɵɵlistener("click", function
|
|
2679
|
-
i0.ɵɵconditionalCreate(
|
|
2695
|
+
i0.ɵɵelementStart(83, "div", 51)(84, "button", 52);
|
|
2696
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_84_listener() { return ctx.saveChanges(); });
|
|
2697
|
+
i0.ɵɵconditionalCreate(85, MJTestFormComponentExtended_Conditional_85_Template, 2, 0)(86, MJTestFormComponentExtended_Conditional_86_Template, 7, 0);
|
|
2680
2698
|
i0.ɵɵelementEnd();
|
|
2681
|
-
i0.ɵɵelementStart(
|
|
2682
|
-
i0.ɵɵlistener("click", function
|
|
2683
|
-
i0.ɵɵelement(
|
|
2684
|
-
i0.ɵɵtext(
|
|
2699
|
+
i0.ɵɵelementStart(87, "button", 53);
|
|
2700
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_87_listener() { return ctx.discardChanges(); });
|
|
2701
|
+
i0.ɵɵelement(88, "i", 54);
|
|
2702
|
+
i0.ɵɵtext(89, " Discard ");
|
|
2685
2703
|
i0.ɵɵelementEnd()()()();
|
|
2686
2704
|
} if (rf & 2) {
|
|
2687
2705
|
i0.ɵɵadvance(13);
|
|
@@ -2712,7 +2730,9 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
2712
2730
|
i0.ɵɵconditional(ctx.record.Description ? 36 : -1);
|
|
2713
2731
|
i0.ɵɵadvance();
|
|
2714
2732
|
i0.ɵɵconditional(ctx.testRunsLoaded && ctx.testRuns.length > 0 ? 37 : -1);
|
|
2715
|
-
i0.ɵɵadvance(
|
|
2733
|
+
i0.ɵɵadvance(2);
|
|
2734
|
+
i0.ɵɵproperty("Items", ctx.SectionPickerItems)("ActiveKey", ctx.ActiveTab);
|
|
2735
|
+
i0.ɵɵadvance(2);
|
|
2716
2736
|
i0.ɵɵclassProp("active", ctx.activeTab === "overview");
|
|
2717
2737
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "overview");
|
|
2718
2738
|
i0.ɵɵadvance(4);
|
|
@@ -2722,47 +2742,47 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
2722
2742
|
i0.ɵɵclassProp("active", ctx.activeTab === "runs");
|
|
2723
2743
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "runs");
|
|
2724
2744
|
i0.ɵɵadvance(4);
|
|
2725
|
-
i0.ɵɵconditional(ctx.testRunsLoaded ?
|
|
2745
|
+
i0.ɵɵconditional(ctx.testRunsLoaded ? 53 : -1);
|
|
2726
2746
|
i0.ɵɵadvance();
|
|
2727
2747
|
i0.ɵɵclassProp("active", ctx.activeTab === "suites");
|
|
2728
2748
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "suites");
|
|
2729
2749
|
i0.ɵɵadvance(4);
|
|
2730
|
-
i0.ɵɵconditional(ctx.suiteTestsLoaded ?
|
|
2750
|
+
i0.ɵɵconditional(ctx.suiteTestsLoaded ? 58 : -1);
|
|
2731
2751
|
i0.ɵɵadvance();
|
|
2732
2752
|
i0.ɵɵclassProp("active", ctx.activeTab === "analytics");
|
|
2733
2753
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "analytics");
|
|
2734
2754
|
i0.ɵɵadvance(4);
|
|
2735
2755
|
i0.ɵɵclassProp("has-savebar", ctx.isDirty);
|
|
2736
2756
|
i0.ɵɵadvance();
|
|
2737
|
-
i0.ɵɵconditional(ctx.activeTab === "overview" ?
|
|
2757
|
+
i0.ɵɵconditional(ctx.activeTab === "overview" ? 64 : -1);
|
|
2738
2758
|
i0.ɵɵadvance();
|
|
2739
|
-
i0.ɵɵconditional(ctx.activeTab === "config" ?
|
|
2759
|
+
i0.ɵɵconditional(ctx.activeTab === "config" ? 65 : -1);
|
|
2740
2760
|
i0.ɵɵadvance();
|
|
2741
|
-
i0.ɵɵconditional(ctx.activeTab === "runs" ?
|
|
2761
|
+
i0.ɵɵconditional(ctx.activeTab === "runs" ? 66 : -1);
|
|
2742
2762
|
i0.ɵɵadvance();
|
|
2743
|
-
i0.ɵɵconditional(ctx.activeTab === "suites" ?
|
|
2763
|
+
i0.ɵɵconditional(ctx.activeTab === "suites" ? 67 : -1);
|
|
2744
2764
|
i0.ɵɵadvance();
|
|
2745
|
-
i0.ɵɵconditional(ctx.activeTab === "analytics" ?
|
|
2765
|
+
i0.ɵɵconditional(ctx.activeTab === "analytics" ? 68 : -1);
|
|
2746
2766
|
i0.ɵɵadvance();
|
|
2747
2767
|
i0.ɵɵproperty("title", ctx.showShortcuts ? "Hide keyboard shortcuts" : "Show keyboard shortcuts");
|
|
2748
2768
|
i0.ɵɵadvance(2);
|
|
2749
|
-
i0.ɵɵconditional(ctx.showShortcuts ?
|
|
2769
|
+
i0.ɵɵconditional(ctx.showShortcuts ? 71 : -1);
|
|
2750
2770
|
i0.ɵɵadvance();
|
|
2751
|
-
i0.ɵɵconditional(ctx.testingDialogService.IsPanelOpen ?
|
|
2771
|
+
i0.ɵɵconditional(ctx.testingDialogService.IsPanelOpen ? 72 : -1);
|
|
2752
2772
|
i0.ɵɵadvance();
|
|
2753
2773
|
i0.ɵɵclassProp("save-bar--visible", ctx.isDirty);
|
|
2754
2774
|
i0.ɵɵattribute("aria-hidden", !ctx.isDirty);
|
|
2755
2775
|
i0.ɵɵadvance(8);
|
|
2756
|
-
i0.ɵɵconditional(ctx.dirtyFieldNames.length === 1 ?
|
|
2776
|
+
i0.ɵɵconditional(ctx.dirtyFieldNames.length === 1 ? 81 : ctx.dirtyFieldNames.length > 1 ? 82 : -1);
|
|
2757
2777
|
i0.ɵɵadvance(3);
|
|
2758
2778
|
i0.ɵɵproperty("disabled", ctx.isSaving || !ctx.isDirty);
|
|
2759
2779
|
i0.ɵɵattribute("tabindex", ctx.isDirty ? 0 : -1);
|
|
2760
2780
|
i0.ɵɵadvance();
|
|
2761
|
-
i0.ɵɵconditional(ctx.isSaving ?
|
|
2781
|
+
i0.ɵɵconditional(ctx.isSaving ? 85 : 86);
|
|
2762
2782
|
i0.ɵɵadvance(2);
|
|
2763
2783
|
i0.ɵɵproperty("disabled", ctx.isSaving || !ctx.isDirty);
|
|
2764
2784
|
i0.ɵɵattribute("tabindex", ctx.isDirty ? 0 : -1);
|
|
2765
|
-
} }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.NgModel, i3.MJEmptyStateComponent, i3.MJButtonDirective, i4.CodeEditorComponent, i5.TestRunDialogComponent, i5.EvaluationModeToggleComponent, i6.LoadingComponent, i3.MjSlidePanelComponent, i7.EntityLinkPillComponent, i1.DatePipe], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\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\n.breadcrumb[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n}\n\n.breadcrumb[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.breadcrumb[_ngcontent-%COMP%] a[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] a[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n text-decoration: none;\n}\n\n.breadcrumb[_ngcontent-%COMP%] .separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--test-text-muted);\n margin: 0 4px;\n}\n\n.breadcrumb[_ngcontent-%COMP%] .current[_ngcontent-%COMP%] {\n color: var(--test-text-secondary);\n font-weight: 500;\n}\n\n.breadcrumb-text[_ngcontent-%COMP%] {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n.test-form[_ngcontent-%COMP%] {\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\n\n.test-header[_ngcontent-%COMP%] {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n padding: 20px;\n}\n\n.header-content[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n\n.test-icon[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n.test-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n\n.status-badge[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.status-badge.status-disabled[_ngcontent-%COMP%] { background: var(--mj-text-secondary); }\n.status-badge.status-pending[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n\n.status-badge-inline[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] { background: var(--test-success); }\n.status-badge-inline.status-disabled[_ngcontent-%COMP%] { background: var(--test-disabled); }\n.status-badge-inline.status-pending[_ngcontent-%COMP%] { background: var(--test-warning); }\n\n.test-type[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n white-space: nowrap;\n}\n\n\n.test-description[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--test-text-secondary);\n line-height: 1.6;\n font-size: 14px;\n}\n\n\n\n\n.metrics-bar[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n}\n\n.metric-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.metric-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n\n.metric-progress[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.5s ease-out;\n}\n\n\n\n\n.tabs-container[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]::-webkit-scrollbar {\n display: none;\n}\n\n.tab[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.tab.active[_ngcontent-%COMP%] {\n color: var(--test-primary);\n border-bottom-color: var(--test-primary);\n font-weight: 600;\n}\n\n.tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 15px;\n}\n\n.tab-badge[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .tab-badge[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--test-primary);\n}\n\n.tab-shortcut[_ngcontent-%COMP%] {\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\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n\n\n\n.overview-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n.info-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.info-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n}\n\n.info-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.info-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--test-text);\n word-wrap: break-word;\n font-weight: 500;\n}\n\n\n.json-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.json-tabs[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-text);\n background: var(--mj-bg-overlay);\n}\n\n.json-tab.active[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.code-editor-container[_ngcontent-%COMP%] {\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\n\n.config-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n.config-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.config-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 20px;\n}\n\n.config-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.config-item.full-width[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.config-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%]::placeholder {\n color: var(--test-text-muted);\n}\n\n.config-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--test-text-muted);\n margin-top: 4px;\n}\n\n.config-editor-container[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n min-height: 100px;\n max-height: 150px;\n}\n\n\n\n\n.runs-tab[_ngcontent-%COMP%], \n.suites-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n\n.loading-state[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n.skeleton-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.skeleton-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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: _ngcontent-%COMP%_shimmer 1.5s infinite;\n flex-shrink: 0;\n}\n\n.skeleton-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.skeleton-line[_ngcontent-%COMP%] {\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: _ngcontent-%COMP%_shimmer 1.5s infinite;\n}\n\n.skeleton-line.wide[_ngcontent-%COMP%] { width: 70%; }\n.skeleton-line.narrow[_ngcontent-%COMP%] { width: 40%; }\n\n@keyframes _ngcontent-%COMP%_shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n\n.runs-list[_ngcontent-%COMP%], \n.suites-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.run-item[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover, \n.suite-item[_ngcontent-%COMP%]: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[_ngcontent-%COMP%], \n.suite-icon[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n}\n\n.run-content[_ngcontent-%COMP%], \n.suite-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.run-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-id[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.run-status[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.suite-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 4px;\n}\n\n.run-meta[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] span[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 11px;\n}\n\n.run-item[_ngcontent-%COMP%] > i.fa-chevron-right[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] > i.fa-chevron-right[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.run-item[_ngcontent-%COMP%]:hover > i.fa-chevron-right[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%]:hover > i.fa-chevron-right[_ngcontent-%COMP%] {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n\n.run-eval-stack[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n\n.eval-pill[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n.eval-pill.status-pill.status-passed[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%], \n.eval-pill.status-pill.status-pending[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.eval-pill.status-pill.status-running[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n\n.eval-pill.human-pill.no-feedback[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n\n.eval-pill.auto-pill.no-score[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n\n.run-tags[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n.run-tag[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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\n\n\n.shortcuts-toggle[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-text);\n background: var(--test-border);\n}\n\n.shortcut-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.shortcut-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.shortcut-keys[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.shortcut-keys[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\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\n\n@media (max-width: 1024px) {\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .config-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .keyboard-shortcuts[_ngcontent-%COMP%], .shortcuts-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n@media (max-width: 768px) {\n .test-form[_ngcontent-%COMP%] {\n height: auto;\n min-height: 100%;\n }\n\n .test-header[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .header-content[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-left[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .test-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .test-meta[_ngcontent-%COMP%] {\n gap: 8px;\n }\n\n .status-badge[_ngcontent-%COMP%] {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .header-actions[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: stretch;\n }\n\n .header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .metric-card[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .metric-value[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 12px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 12px 14px;\n font-size: 13px;\n gap: 6px;\n }\n\n .tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n\n .tab-shortcut[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .info-section[_ngcontent-%COMP%], \n .json-section[_ngcontent-%COMP%], \n .config-section[_ngcontent-%COMP%] {\n padding: 18px;\n }\n\n .info-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .json-tabs[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .json-tab[_ngcontent-%COMP%] {\n min-width: 0;\n justify-content: flex-start;\n }\n\n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n padding: 14px;\n }\n\n .run-icon[_ngcontent-%COMP%], \n .suite-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .run-meta[_ngcontent-%COMP%], \n .suite-meta[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 4px;\n }\n\n}\n\n\n\n\n@media (max-width: 480px) {\n .test-header[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .header-left[_ngcontent-%COMP%] {\n gap: 12px;\n }\n\n .test-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 18px;\n border-radius: 8px;\n }\n\n .test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 8px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 10px 12px;\n font-size: 12px;\n }\n\n .tab-badge[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .run-header[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n}\n\n\n\n\n@media (hover: none) and (pointer: coarse) {\n .tab[_ngcontent-%COMP%], \n .json-tab[_ngcontent-%COMP%], \n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n -webkit-tap-highlight-color: transparent;\n }\n\n .run-item[_ngcontent-%COMP%]:active, \n .suite-item[_ngcontent-%COMP%]:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n transform: scale(0.98);\n }\n\n .tab[_ngcontent-%COMP%]:active, \n .json-tab[_ngcontent-%COMP%]:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n \n .tab[_ngcontent-%COMP%] {\n min-height: 48px;\n }\n\n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n min-height: 64px;\n }\n}\n\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n .skeleton-icon[_ngcontent-%COMP%], \n .skeleton-line[_ngcontent-%COMP%] {\n animation: none;\n background: var(--mj-border-default);\n }\n}\n\n\n\n\n.history-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n.history-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n\n.history-filters[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--test-text-secondary);\n margin-right: 4px;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\n background: var(--test-primary);\n color: var(--mj-text-inverse);\n border-color: var(--test-primary);\n}\n\n.history-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n\n.history-kpi-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.kpi-icon[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n.kpi-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.trend-icon.trend-up[_ngcontent-%COMP%] {\n color: var(--test-success);\n}\n\n.trend-icon.trend-down[_ngcontent-%COMP%] {\n color: var(--test-error);\n}\n\n\n.history-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n\n.history-table-container[_ngcontent-%COMP%] {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.history-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: 14px;\n}\n\n.history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%], \n.history-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px 16px;\n text-align: left;\n border-bottom: 1px solid var(--test-border);\n}\n\n.history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, transparent);\n}\n\n.date-cell[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--test-text);\n}\n\n.passed-cell[_ngcontent-%COMP%] {\n color: var(--test-success);\n font-weight: 600;\n}\n\n.failed-cell[_ngcontent-%COMP%] {\n color: var(--test-error);\n font-weight: 600;\n}\n\n.pass-rate-cell[_ngcontent-%COMP%] {\n min-width: 120px;\n}\n\n.pass-rate-bar[_ngcontent-%COMP%] {\n position: relative;\n height: 24px;\n background: var(--test-bg);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.pass-rate-fill[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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\n.suite-performance-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.suite-perf-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.suite-perf-name[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 6px;\n}\n\n.suite-perf-tags[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.tag-mini[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.suite-stat[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value.pass-rate.high[_ngcontent-%COMP%] {\n color: var(--test-success);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value.pass-rate.low[_ngcontent-%COMP%] {\n color: var(--test-error);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.suite-perf-card[_ngcontent-%COMP%]:hover .suite-perf-arrow[_ngcontent-%COMP%] {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n\n\n\n@media print {\n .test-form[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n height: auto;\n }\n\n .header-actions[_ngcontent-%COMP%], \n .tabs-container[_ngcontent-%COMP%], \n .keyboard-shortcuts[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n overflow: visible;\n padding: 0;\n }\n\n .info-section[_ngcontent-%COMP%], \n .json-section[_ngcontent-%COMP%], \n .config-section[_ngcontent-%COMP%] {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}\n\n\n\n\n\n.edit-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n margin: 0 0 18px 0;\n}\n\n.edit-section-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.edit-section-sub[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.edit-grid[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n}\n\n.edit-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.edit-field--full[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.edit-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .required[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n margin-left: 2px;\n}\n\n.config-textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 72px;\n font-family: inherit;\n line-height: 1.5;\n}\n\n.select-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.select-wrapper[_ngcontent-%COMP%] select.config-input[_ngcontent-%COMP%] {\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\n.tag-editor[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .tag-remove[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .tag-remove[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]::placeholder {\n color: var(--test-text-muted);\n}\n\n\n.meta-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n}\n\n.meta-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.meta-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n font-size: 11px;\n}\n\n\n.dirty-indicator[_ngcontent-%COMP%] {\n display: inline-block;\n margin-left: 8px;\n font-size: 14px;\n color: var(--mj-status-warning);\n line-height: 1;\n animation: _ngcontent-%COMP%_pulseDot 1.8s ease-in-out infinite;\n vertical-align: middle;\n}\n\n@keyframes _ngcontent-%COMP%_pulseDot {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.85); }\n}\n\n.unsaved-pill[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 6px;\n animation: _ngcontent-%COMP%_pulseDot 1.8s ease-in-out infinite;\n}\n\n\n\n.tab-content.has-savebar[_ngcontent-%COMP%] {\n padding-bottom: 84px;\n}\n\n\n\n\n\n.save-bar[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n right: 96px; \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 \n\n\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[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .save-bar[_ngcontent-%COMP%] {\n transition: opacity 180ms ease-out;\n transform: none;\n }\n .save-bar--visible[_ngcontent-%COMP%] {\n transform: none;\n }\n}\n\n.save-bar-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.save-bar-dot[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 12px;\n line-height: 1;\n animation: _ngcontent-%COMP%_pulseDot 1.8s ease-in-out infinite;\n}\n\n.save-bar-text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.save-bar-text[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--test-text);\n font-weight: 700;\n}\n\n.save-bar-fields[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.save-bar-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.save-bar-btn[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.save-bar-btn--primary[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.save-bar-btn--ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--test-text-secondary);\n border-color: var(--test-border);\n}\n\n.save-bar-btn--ghost[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\n display: inline-flex;\n gap: 3px;\n margin-left: 6px;\n opacity: 0.85;\n}\n\n.save-bar-kbd[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n left: 8px;\n right: 8px;\n bottom: 88px; \n flex-direction: column;\n align-items: stretch;\n padding: 12px;\n }\n .save-bar-actions[_ngcontent-%COMP%] {\n justify-content: space-between;\n }\n .save-bar-kbd[_ngcontent-%COMP%] {\n display: none;\n }\n}"], changeDetection: 0 }); }
|
|
2785
|
+
} }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.NgModel, i3.MJEmptyStateComponent, i3.MJSectionPickerComponent, i3.MJButtonDirective, i4.CodeEditorComponent, i5.TestRunDialogComponent, i5.EvaluationModeToggleComponent, i6.LoadingComponent, i3.MjSlidePanelComponent, i7.EntityLinkPillComponent, i1.DatePipe], styles: ["\n\n\n\n\n\n[_nghost-%COMP%] {\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\n.breadcrumb[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n}\n\n.breadcrumb[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.breadcrumb[_ngcontent-%COMP%] a[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] a[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n text-decoration: none;\n}\n\n.breadcrumb[_ngcontent-%COMP%] .separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--test-text-muted);\n margin: 0 4px;\n}\n\n.breadcrumb[_ngcontent-%COMP%] .current[_ngcontent-%COMP%] {\n color: var(--test-text-secondary);\n font-weight: 500;\n}\n\n.breadcrumb-text[_ngcontent-%COMP%] {\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n.test-form[_ngcontent-%COMP%] {\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\n\n.test-header[_ngcontent-%COMP%] {\n background: var(--test-surface);\n border-bottom: 1px solid var(--test-border);\n padding: 20px;\n}\n\n.header-content[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n flex: 1;\n min-width: 0;\n}\n\n\n.test-icon[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n.test-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n\n.status-badge[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] { background: var(--mj-status-success); }\n.status-badge.status-disabled[_ngcontent-%COMP%] { background: var(--mj-text-secondary); }\n.status-badge.status-pending[_ngcontent-%COMP%] { background: var(--mj-status-warning); }\n\n.status-badge-inline[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] { background: var(--test-success); }\n.status-badge-inline.status-disabled[_ngcontent-%COMP%] { background: var(--test-disabled); }\n.status-badge-inline.status-pending[_ngcontent-%COMP%] { background: var(--test-warning); }\n\n.test-type[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n white-space: nowrap;\n}\n\n\n.test-description[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n color: var(--test-text-secondary);\n line-height: 1.6;\n font-size: 14px;\n}\n\n\n\n\n.metrics-bar[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n}\n\n.metric-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.metric-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n\n.metric-progress[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n height: 100%;\n background: var(--mj-status-success);\n border-radius: 2px;\n transition: width 0.5s ease-out;\n}\n\n\n\n\n.tabs-container[_ngcontent-%COMP%] {\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\n.phone-section-picker[_ngcontent-%COMP%] {\n display: none;\n}\n\n.tabs[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]::-webkit-scrollbar {\n display: none;\n}\n\n.tab[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, transparent);\n}\n\n.tab.active[_ngcontent-%COMP%] {\n color: var(--test-primary);\n border-bottom-color: var(--test-primary);\n font-weight: 600;\n}\n\n.tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 15px;\n}\n\n.tab-badge[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .tab-badge[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n color: var(--test-primary);\n}\n\n.tab-shortcut[_ngcontent-%COMP%] {\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\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n scroll-behavior: smooth;\n}\n\n\n\n\n.overview-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; transform: translateY(10px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n\n.info-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.info-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n}\n\n.info-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.info-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--test-text);\n word-wrap: break-word;\n font-weight: 500;\n}\n\n\n.json-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.json-tabs[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-text);\n background: var(--mj-bg-overlay);\n}\n\n.json-tab.active[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.code-editor-container[_ngcontent-%COMP%] {\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\n\n.config-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n.config-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.config-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 20px;\n}\n\n.config-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.config-item.full-width[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.config-item[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%]::placeholder {\n color: var(--test-text-muted);\n}\n\n.config-hint[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--test-text-muted);\n margin-top: 4px;\n}\n\n.config-editor-container[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n min-height: 100px;\n max-height: 150px;\n}\n\n\n\n\n.runs-tab[_ngcontent-%COMP%], \n.suites-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n\n.loading-state[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n.skeleton-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.skeleton-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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: _ngcontent-%COMP%_shimmer 1.5s infinite;\n flex-shrink: 0;\n}\n\n.skeleton-content[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.skeleton-line[_ngcontent-%COMP%] {\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: _ngcontent-%COMP%_shimmer 1.5s infinite;\n}\n\n.skeleton-line.wide[_ngcontent-%COMP%] { width: 70%; }\n.skeleton-line.narrow[_ngcontent-%COMP%] { width: 40%; }\n\n@keyframes _ngcontent-%COMP%_shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n\n.runs-list[_ngcontent-%COMP%], \n.suites-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.run-item[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover, \n.suite-item[_ngcontent-%COMP%]: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[_ngcontent-%COMP%], \n.suite-icon[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: var(--mj-status-warning);\n}\n\n.run-content[_ngcontent-%COMP%], \n.suite-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.run-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-id[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.run-status[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.suite-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 4px;\n}\n\n.run-meta[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] span[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.suite-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 11px;\n}\n\n.run-item[_ngcontent-%COMP%] > i.fa-chevron-right[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%] > i.fa-chevron-right[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.run-item[_ngcontent-%COMP%]:hover > i.fa-chevron-right[_ngcontent-%COMP%], \n.suite-item[_ngcontent-%COMP%]:hover > i.fa-chevron-right[_ngcontent-%COMP%] {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n\n.run-eval-stack[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n\n.eval-pill[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n.eval-pill.status-pill.status-passed[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%], \n.eval-pill.status-pill.status-pending[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.eval-pill.status-pill.status-running[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n\n.eval-pill.human-pill.no-feedback[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n\n.eval-pill.auto-pill.no-score[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-status-success) 15%, var(--mj-bg-surface));\n color: var(--mj-status-success);\n}\n\n\n.run-tags[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 8px;\n flex-wrap: wrap;\n}\n\n.run-tag[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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\n\n\n.shortcuts-toggle[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n color: var(--test-text);\n background: var(--test-border);\n}\n\n.shortcut-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.shortcut-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.shortcut-keys[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\n.shortcut-keys[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\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\n\n@media (max-width: 1024px) {\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .info-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .config-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .keyboard-shortcuts[_ngcontent-%COMP%], .shortcuts-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n@media (max-width: 768px) {\n \n .tabs[_ngcontent-%COMP%] {\n display: none;\n }\n\n .phone-section-picker[_ngcontent-%COMP%] {\n display: block;\n padding: 4px 8px;\n }\n\n .test-form[_ngcontent-%COMP%] {\n height: auto;\n min-height: 100%;\n }\n\n .test-header[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .header-content[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .header-left[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .test-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .test-meta[_ngcontent-%COMP%] {\n gap: 8px;\n }\n\n .status-badge[_ngcontent-%COMP%] {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .header-actions[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: stretch;\n }\n\n .header-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 10px;\n }\n\n .metric-card[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .metric-value[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 12px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 12px 14px;\n font-size: 13px;\n gap: 6px;\n }\n\n .tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n\n .tab-shortcut[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .info-section[_ngcontent-%COMP%], \n .json-section[_ngcontent-%COMP%], \n .config-section[_ngcontent-%COMP%] {\n padding: 18px;\n }\n\n .info-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .json-tabs[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .json-tab[_ngcontent-%COMP%] {\n min-width: 0;\n justify-content: flex-start;\n }\n\n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n padding: 14px;\n }\n\n .run-icon[_ngcontent-%COMP%], \n .suite-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .run-meta[_ngcontent-%COMP%], \n .suite-meta[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 4px;\n }\n\n}\n\n\n\n\n@media (max-width: 480px) {\n .test-header[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .header-left[_ngcontent-%COMP%] {\n gap: 12px;\n }\n\n .test-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 18px;\n border-radius: 8px;\n }\n\n .test-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 8px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 10px 12px;\n font-size: 12px;\n }\n\n .tab-badge[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .run-header[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n }\n}\n\n\n\n\n@media (hover: none) and (pointer: coarse) {\n .tab[_ngcontent-%COMP%], \n .json-tab[_ngcontent-%COMP%], \n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n -webkit-tap-highlight-color: transparent;\n }\n\n .run-item[_ngcontent-%COMP%]:active, \n .suite-item[_ngcontent-%COMP%]:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n transform: scale(0.98);\n }\n\n .tab[_ngcontent-%COMP%]:active, \n .json-tab[_ngcontent-%COMP%]:active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n }\n\n \n .tab[_ngcontent-%COMP%] {\n min-height: 48px;\n }\n\n .run-item[_ngcontent-%COMP%], \n .suite-item[_ngcontent-%COMP%] {\n min-height: 64px;\n }\n}\n\n\n\n\n@media (prefers-reduced-motion: reduce) {\n *[_ngcontent-%COMP%], \n *[_ngcontent-%COMP%]::before, \n *[_ngcontent-%COMP%]::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n\n .skeleton-icon[_ngcontent-%COMP%], \n .skeleton-line[_ngcontent-%COMP%] {\n animation: none;\n background: var(--mj-border-default);\n }\n}\n\n\n\n\n.history-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\n\n.history-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n\n.history-filters[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--test-text-secondary);\n margin-right: 4px;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\n background: var(--test-primary);\n color: var(--mj-text-inverse);\n border-color: var(--test-primary);\n}\n\n.history-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n\n.history-kpi-cards[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 16px;\n}\n\n.kpi-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--test-shadow-md);\n}\n\n.kpi-icon[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n}\n\n.kpi-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.kpi-value[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.trend-icon.trend-up[_ngcontent-%COMP%] {\n color: var(--test-success);\n}\n\n.trend-icon.trend-down[_ngcontent-%COMP%] {\n color: var(--test-error);\n}\n\n\n.history-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n\n.history-table-container[_ngcontent-%COMP%] {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.history-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: 14px;\n}\n\n.history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%], \n.history-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px 16px;\n text-align: left;\n border-bottom: 1px solid var(--test-border);\n}\n\n.history-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, transparent);\n}\n\n.date-cell[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--test-text);\n}\n\n.passed-cell[_ngcontent-%COMP%] {\n color: var(--test-success);\n font-weight: 600;\n}\n\n.failed-cell[_ngcontent-%COMP%] {\n color: var(--test-error);\n font-weight: 600;\n}\n\n.pass-rate-cell[_ngcontent-%COMP%] {\n min-width: 120px;\n}\n\n.pass-rate-bar[_ngcontent-%COMP%] {\n position: relative;\n height: 24px;\n background: var(--test-bg);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.pass-rate-fill[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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\n.suite-performance-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.suite-perf-card[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.suite-perf-name[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n color: var(--test-text);\n margin-bottom: 6px;\n}\n\n.suite-perf-tags[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.tag-mini[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: flex;\n gap: 24px;\n flex-wrap: wrap;\n}\n\n.suite-stat[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 16px;\n font-weight: 700;\n color: var(--test-text);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value.pass-rate.high[_ngcontent-%COMP%] {\n color: var(--test-success);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-value.pass-rate.low[_ngcontent-%COMP%] {\n color: var(--test-error);\n}\n\n.suite-stat[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n color: var(--test-text-muted);\n font-size: 14px;\n transition: var(--test-transition);\n}\n\n.suite-perf-card[_ngcontent-%COMP%]:hover .suite-perf-arrow[_ngcontent-%COMP%] {\n color: var(--test-primary);\n transform: translateX(2px);\n}\n\n\n\n\n@media print {\n .test-form[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n height: auto;\n }\n\n .header-actions[_ngcontent-%COMP%], \n .tabs-container[_ngcontent-%COMP%], \n .keyboard-shortcuts[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n overflow: visible;\n padding: 0;\n }\n\n .info-section[_ngcontent-%COMP%], \n .json-section[_ngcontent-%COMP%], \n .config-section[_ngcontent-%COMP%] {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}\n\n\n\n\n\n.edit-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n margin: 0 0 18px 0;\n}\n\n.edit-section-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--test-primary);\n}\n\n.edit-section-sub[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.edit-grid[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n}\n\n.edit-field[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 0;\n}\n\n.edit-field--full[_ngcontent-%COMP%] {\n grid-column: 1 / -1;\n}\n\n.edit-field[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .required[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n margin-left: 2px;\n}\n\n.config-textarea[_ngcontent-%COMP%] {\n resize: vertical;\n min-height: 72px;\n font-family: inherit;\n line-height: 1.5;\n}\n\n.select-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.select-wrapper[_ngcontent-%COMP%] select.config-input[_ngcontent-%COMP%] {\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\n.tag-editor[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .tag-remove[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] .tag-remove[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]::placeholder {\n color: var(--test-text-muted);\n}\n\n\n.meta-section[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 14px;\n}\n\n.meta-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.meta-label[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;\n font-size: 11px;\n}\n\n\n.dirty-indicator[_ngcontent-%COMP%] {\n display: inline-block;\n margin-left: 8px;\n font-size: 14px;\n color: var(--mj-status-warning);\n line-height: 1;\n animation: _ngcontent-%COMP%_pulseDot 1.8s ease-in-out infinite;\n vertical-align: middle;\n}\n\n@keyframes _ngcontent-%COMP%_pulseDot {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.5; transform: scale(0.85); }\n}\n\n.unsaved-pill[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 6px;\n animation: _ngcontent-%COMP%_pulseDot 1.8s ease-in-out infinite;\n}\n\n\n\n.tab-content.has-savebar[_ngcontent-%COMP%] {\n padding-bottom: 84px;\n}\n\n\n\n\n\n.save-bar[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n right: 96px; \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 \n\n\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[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .save-bar[_ngcontent-%COMP%] {\n transition: opacity 180ms ease-out;\n transform: none;\n }\n .save-bar--visible[_ngcontent-%COMP%] {\n transform: none;\n }\n}\n\n.save-bar-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.save-bar-dot[_ngcontent-%COMP%] {\n color: var(--mj-status-warning);\n font-size: 12px;\n line-height: 1;\n animation: _ngcontent-%COMP%_pulseDot 1.8s ease-in-out infinite;\n}\n\n.save-bar-text[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.save-bar-text[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--test-text);\n font-weight: 700;\n}\n\n.save-bar-fields[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--test-text-muted);\n}\n\n.save-bar-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n}\n\n.save-bar-btn[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.save-bar-btn--primary[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%]: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[_ngcontent-%COMP%]:active:not(:disabled) {\n transform: translateY(0);\n}\n\n.save-bar-btn--ghost[_ngcontent-%COMP%] {\n background: transparent;\n color: var(--test-text-secondary);\n border-color: var(--test-border);\n}\n\n.save-bar-btn--ghost[_ngcontent-%COMP%]: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[_ngcontent-%COMP%] {\n display: inline-flex;\n gap: 3px;\n margin-left: 6px;\n opacity: 0.85;\n}\n\n.save-bar-kbd[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\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[_ngcontent-%COMP%] {\n left: 8px;\n right: 8px;\n bottom: 88px; \n flex-direction: column;\n align-items: stretch;\n padding: 12px;\n }\n .save-bar-actions[_ngcontent-%COMP%] {\n justify-content: space-between;\n }\n .save-bar-kbd[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n@media (max-width: 768px) {\n .header-actions[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .header-actions[_ngcontent-%COMP%] app-evaluation-mode-toggle[_ngcontent-%COMP%] {\n flex-basis: 100%;\n }\n\n .breadcrumb[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .breadcrumb[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n min-width: 0;\n }\n}"], changeDetection: 0 }); }
|
|
2766
2786
|
};
|
|
2767
2787
|
MJTestFormComponentExtended = __decorate([
|
|
2768
2788
|
RegisterClass(BaseFormComponent, 'MJ: Tests')
|
|
@@ -2770,7 +2790,7 @@ MJTestFormComponentExtended = __decorate([
|
|
|
2770
2790
|
export { MJTestFormComponentExtended };
|
|
2771
2791
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJTestFormComponentExtended, [{
|
|
2772
2792
|
type: Component,
|
|
2773
|
-
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"] }]
|
|
2793
|
+
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 <!-- Phone: the strip becomes one button that opens the Sections sheet -->\n <mj-section-picker class=\"phone-section-picker\"\n [Items]=\"SectionPickerItems\"\n [ActiveKey]=\"ActiveTab\"\n (ActiveKeyChange)=\"OnSectionPicked($event)\"></mj-section-picker>\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/* Phone section picker: hidden until the 768px rule swaps it in for the strip */\n.phone-section-picker {\n display: none;\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 /* The tab strip becomes one section-picker button (same pattern as the standard record form). */\n .tabs {\n display: none;\n }\n\n .phone-section-picker {\n display: block;\n padding: 4px 8px;\n }\n\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/* Phone (375px): the action row wraps instead of running past the edge, the SHOW\n toggle takes its own line, and the breadcrumb wraps. (The tab strip is\n hidden on phones; the section picker replaces it.) */\n@media (max-width: 768px) {\n .header-actions {\n flex-wrap: wrap;\n }\n\n .header-actions app-evaluation-mode-toggle {\n flex-basis: 100%;\n }\n\n .breadcrumb ol {\n flex-wrap: wrap;\n }\n\n .breadcrumb li {\n min-width: 0;\n }\n}\n"] }]
|
|
2774
2794
|
}], null, { handleKeyboardShortcut: [{
|
|
2775
2795
|
type: HostListener,
|
|
2776
2796
|
args: ['document:keydown', ['$event']]
|