@memberjunction/ng-core-entity-forms 5.34.0 → 5.35.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/dist/lib/custom/Tests/test-form.component.d.ts +25 -1
- package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +898 -547
- package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts +56 -1
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.js +1647 -788
- package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
- package/dist/lib/custom/custom-forms.module.d.ts +25 -24
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +4 -0
- package/dist/lib/custom/custom-forms.module.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js +215 -213
- package/dist/lib/generated/Entities/MJAIAgent/mjaiagent.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js +23 -23
- package/dist/lib/generated/Entities/MJAIAgentRun/mjaiagentrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIConfiguration/mjaiconfiguration.form.component.js +12 -12
- package/dist/lib/generated/Entities/MJAIConfiguration/mjaiconfiguration.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIModality/mjaimodality.form.component.js +17 -17
- package/dist/lib/generated/Entities/MJAIModality/mjaimodality.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIModel/mjaimodel.form.component.js +51 -51
- package/dist/lib/generated/Entities/MJAIModel/mjaimodel.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js +31 -31
- package/dist/lib/generated/Entities/MJAIPrompt/mjaiprompt.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJAIPromptRun/mjaipromptrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAIVendor/mjaivendor.form.component.js +25 -25
- package/dist/lib/generated/Entities/MJAIVendor/mjaivendor.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAPIKey/mjapikey.form.component.js +13 -13
- package/dist/lib/generated/Entities/MJAPIKey/mjapikey.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAPIScope/mjapiscope.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJAPIScope/mjapiscope.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js +19 -19
- package/dist/lib/generated/Entities/MJAction/mjaction.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJApplication/mjapplication.form.component.js +17 -17
- package/dist/lib/generated/Entities/MJApplication/mjapplication.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJArtifactType/mjartifacttype.form.component.js +53 -47
- package/dist/lib/generated/Entities/MJArtifactType/mjartifacttype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJArtifactVersion/mjartifactversion.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/MJArtifactVersion/mjartifactversion.form.component.js +53 -33
- package/dist/lib/generated/Entities/MJArtifactVersion/mjartifactversion.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAuditLogType/mjauditlogtype.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJAuditLogType/mjauditlogtype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJAuthorization/mjauthorization.form.component.js +20 -20
- package/dist/lib/generated/Entities/MJAuthorization/mjauthorization.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCommunicationProvider/mjcommunicationprovider.form.component.js +19 -19
- package/dist/lib/generated/Entities/MJCommunicationProvider/mjcommunicationprovider.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCompany/mjcompany.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJCompany/mjcompany.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCompanyIntegration/mjcompanyintegration.form.component.js +17 -17
- package/dist/lib/generated/Entities/MJCompanyIntegration/mjcompanyintegration.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJCompanyIntegrationRun/mjcompanyintegrationrun.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJCompanyIntegrationRun/mjcompanyintegrationrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJConversation/mjconversation.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversationDetail/mjconversationdetail.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJConversationDetail/mjconversationdetail.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJConversationDetailAttachment/mjconversationdetailattachment.form.component.js +7 -5
- package/dist/lib/generated/Entities/MJConversationDetailAttachment/mjconversationdetailattachment.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJDashboard/mjdashboard.form.component.js +17 -17
- package/dist/lib/generated/Entities/MJDashboard/mjdashboard.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJDashboardCategory/mjdashboardcategory.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJDashboardCategory/mjdashboardcategory.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEmployee/mjemployee.form.component.js +15 -15
- package/dist/lib/generated/Entities/MJEmployee/mjemployee.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js +208 -208
- package/dist/lib/generated/Entities/MJEntity/mjentity.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJEntityAction/mjentityaction.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJEntityAction/mjentityaction.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFileCategory/mjfilecategory.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJFileCategory/mjfilecategory.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJFileStorageAccount/mjfilestorageaccount.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJFileStorageAccount/mjfilestorageaccount.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJIntegration/mjintegration.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJIntegration/mjintegration.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJList/mjlist.form.component.js +17 -17
- package/dist/lib/generated/Entities/MJList/mjlist.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJMCPServerConnection/mjmcpserverconnection.form.component.js +12 -12
- package/dist/lib/generated/Entities/MJMCPServerConnection/mjmcpserverconnection.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.js +30 -30
- package/dist/lib/generated/Entities/MJQuery/mjquery.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJQueryCategory/mjquerycategory.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJQueryCategory/mjquerycategory.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJRecordChange/mjrecordchange.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRecordMergeLog/mjrecordmergelog.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJRecordMergeLog/mjrecordmergelog.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJRole/mjrole.form.component.js +34 -34
- package/dist/lib/generated/Entities/MJRole/mjrole.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJSearchScope/mjsearchscope.form.component.js +19 -19
- package/dist/lib/generated/Entities/MJSearchScope/mjsearchscope.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTag/mjtag.form.component.js +16 -16
- package/dist/lib/generated/Entities/MJTag/mjtag.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTemplate/mjtemplate.form.component.js +16 -16
- package/dist/lib/generated/Entities/MJTemplate/mjtemplate.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJTemplateCategory/mjtemplatecategory.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJTemplateCategory/mjtemplatecategory.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js +330 -330
- package/dist/lib/generated/Entities/MJUser/mjuser.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJUserView/mjuserview.form.component.js +13 -13
- package/dist/lib/generated/Entities/MJUserView/mjuserview.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJVectorDatabase/mjvectordatabase.form.component.js +10 -10
- package/dist/lib/generated/Entities/MJVectorDatabase/mjvectordatabase.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/MJVectorIndex/mjvectorindex.form.component.js +9 -9
- package/dist/lib/generated/Entities/MJVectorIndex/mjvectorindex.form.component.js.map +1 -1
- package/package.json +37 -36
|
@@ -27,9 +27,15 @@ import * as i7 from "@memberjunction/ng-versions";
|
|
|
27
27
|
import * as i8 from "./entity-link-pill.component";
|
|
28
28
|
const _c0 = () => [1, 2, 3, 4, 5];
|
|
29
29
|
const _c1 = () => [1, 2, 3];
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
i0.ɵɵ
|
|
30
|
+
const _forTrack0 = ($index, $item) => $item.ID;
|
|
31
|
+
function MJTestFormComponentExtended_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
32
|
+
i0.ɵɵelementStart(0, "span", 14);
|
|
33
|
+
i0.ɵɵtext(1, "\u25CF");
|
|
34
|
+
i0.ɵɵelementEnd();
|
|
35
|
+
} }
|
|
36
|
+
function MJTestFormComponentExtended_Conditional_26_Template(rf, ctx) { if (rf & 1) {
|
|
37
|
+
i0.ɵɵelementStart(0, "span", 18);
|
|
38
|
+
i0.ɵɵelement(1, "i", 54);
|
|
33
39
|
i0.ɵɵtext(2);
|
|
34
40
|
i0.ɵɵelementEnd();
|
|
35
41
|
} if (rf & 2) {
|
|
@@ -37,8 +43,14 @@ function MJTestFormComponentExtended_Conditional_25_Template(rf, ctx) { if (rf &
|
|
|
37
43
|
i0.ɵɵadvance(2);
|
|
38
44
|
i0.ɵɵtextInterpolate1(" ", ctx_r0.record.Type, " ");
|
|
39
45
|
} }
|
|
40
|
-
function
|
|
41
|
-
i0.ɵɵelementStart(0, "
|
|
46
|
+
function MJTestFormComponentExtended_Conditional_27_Template(rf, ctx) { if (rf & 1) {
|
|
47
|
+
i0.ɵɵelementStart(0, "span", 19);
|
|
48
|
+
i0.ɵɵelement(1, "i", 55);
|
|
49
|
+
i0.ɵɵtext(2, " Unsaved ");
|
|
50
|
+
i0.ɵɵelementEnd();
|
|
51
|
+
} }
|
|
52
|
+
function MJTestFormComponentExtended_Conditional_36_Template(rf, ctx) { if (rf & 1) {
|
|
53
|
+
i0.ɵɵelementStart(0, "div", 24)(1, "p");
|
|
42
54
|
i0.ɵɵtext(2);
|
|
43
55
|
i0.ɵɵelementEnd()();
|
|
44
56
|
} if (rf & 2) {
|
|
@@ -46,32 +58,32 @@ function MJTestFormComponentExtended_Conditional_34_Template(rf, ctx) { if (rf &
|
|
|
46
58
|
i0.ɵɵadvance(2);
|
|
47
59
|
i0.ɵɵtextInterpolate(ctx_r0.record.Description);
|
|
48
60
|
} }
|
|
49
|
-
function
|
|
50
|
-
i0.ɵɵelementStart(0, "div",
|
|
61
|
+
function MJTestFormComponentExtended_Conditional_37_Template(rf, ctx) { if (rf & 1) {
|
|
62
|
+
i0.ɵɵelementStart(0, "div", 25)(1, "div", 56)(2, "div", 57);
|
|
51
63
|
i0.ɵɵtext(3, "Total Runs");
|
|
52
64
|
i0.ɵɵelementEnd();
|
|
53
|
-
i0.ɵɵelementStart(4, "div",
|
|
65
|
+
i0.ɵɵelementStart(4, "div", 58);
|
|
54
66
|
i0.ɵɵtext(5);
|
|
55
67
|
i0.ɵɵelementEnd()();
|
|
56
|
-
i0.ɵɵelementStart(6, "div",
|
|
68
|
+
i0.ɵɵelementStart(6, "div", 56)(7, "div", 57);
|
|
57
69
|
i0.ɵɵtext(8, "Pass Rate");
|
|
58
70
|
i0.ɵɵelementEnd();
|
|
59
|
-
i0.ɵɵelementStart(9, "div",
|
|
71
|
+
i0.ɵɵelementStart(9, "div", 58);
|
|
60
72
|
i0.ɵɵtext(10);
|
|
61
73
|
i0.ɵɵelementEnd();
|
|
62
|
-
i0.ɵɵelementStart(11, "div",
|
|
63
|
-
i0.ɵɵelement(12, "div",
|
|
74
|
+
i0.ɵɵelementStart(11, "div", 59);
|
|
75
|
+
i0.ɵɵelement(12, "div", 60);
|
|
64
76
|
i0.ɵɵelementEnd()();
|
|
65
|
-
i0.ɵɵelementStart(13, "div",
|
|
77
|
+
i0.ɵɵelementStart(13, "div", 56)(14, "div", 57);
|
|
66
78
|
i0.ɵɵtext(15, "Avg Cost");
|
|
67
79
|
i0.ɵɵelementEnd();
|
|
68
|
-
i0.ɵɵelementStart(16, "div",
|
|
80
|
+
i0.ɵɵelementStart(16, "div", 58);
|
|
69
81
|
i0.ɵɵtext(17);
|
|
70
82
|
i0.ɵɵelementEnd()();
|
|
71
|
-
i0.ɵɵelementStart(18, "div",
|
|
83
|
+
i0.ɵɵelementStart(18, "div", 56)(19, "div", 57);
|
|
72
84
|
i0.ɵɵtext(20, "Avg Duration");
|
|
73
85
|
i0.ɵɵelementEnd();
|
|
74
|
-
i0.ɵɵelementStart(21, "div",
|
|
86
|
+
i0.ɵɵelementStart(21, "div", 58);
|
|
75
87
|
i0.ɵɵtext(22);
|
|
76
88
|
i0.ɵɵelementEnd()()();
|
|
77
89
|
} if (rf & 2) {
|
|
@@ -87,8 +99,8 @@ function MJTestFormComponentExtended_Conditional_35_Template(rf, ctx) { if (rf &
|
|
|
87
99
|
i0.ɵɵadvance(5);
|
|
88
100
|
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(ctx_r0.getAverageDuration()));
|
|
89
101
|
} }
|
|
90
|
-
function
|
|
91
|
-
i0.ɵɵelementStart(0, "span",
|
|
102
|
+
function MJTestFormComponentExtended_Conditional_52_Template(rf, ctx) { if (rf & 1) {
|
|
103
|
+
i0.ɵɵelementStart(0, "span", 32);
|
|
92
104
|
i0.ɵɵtext(1);
|
|
93
105
|
i0.ɵɵelementEnd();
|
|
94
106
|
} if (rf & 2) {
|
|
@@ -96,8 +108,8 @@ function MJTestFormComponentExtended_Conditional_50_Template(rf, ctx) { if (rf &
|
|
|
96
108
|
i0.ɵɵadvance();
|
|
97
109
|
i0.ɵɵtextInterpolate(ctx_r0.testRuns.length);
|
|
98
110
|
} }
|
|
99
|
-
function
|
|
100
|
-
i0.ɵɵelementStart(0, "span",
|
|
111
|
+
function MJTestFormComponentExtended_Conditional_57_Template(rf, ctx) { if (rf & 1) {
|
|
112
|
+
i0.ɵɵelementStart(0, "span", 32);
|
|
101
113
|
i0.ɵɵtext(1);
|
|
102
114
|
i0.ɵɵelementEnd();
|
|
103
115
|
} if (rf & 2) {
|
|
@@ -105,100 +117,100 @@ function MJTestFormComponentExtended_Conditional_55_Template(rf, ctx) { if (rf &
|
|
|
105
117
|
i0.ɵɵadvance();
|
|
106
118
|
i0.ɵɵtextInterpolate(ctx_r0.suiteTests.length);
|
|
107
119
|
} }
|
|
108
|
-
function
|
|
120
|
+
function MJTestFormComponentExtended_Conditional_63_Template(rf, ctx) { if (rf & 1) {
|
|
109
121
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
110
|
-
i0.ɵɵelementStart(0, "div",
|
|
111
|
-
i0.ɵɵelement(3, "i",
|
|
122
|
+
i0.ɵɵelementStart(0, "div", 36)(1, "div", 61)(2, "h3");
|
|
123
|
+
i0.ɵɵelement(3, "i", 62);
|
|
112
124
|
i0.ɵɵtext(4, " Test Information");
|
|
113
125
|
i0.ɵɵelementEnd();
|
|
114
|
-
i0.ɵɵelementStart(5, "div",
|
|
126
|
+
i0.ɵɵelementStart(5, "div", 63)(6, "div", 64)(7, "div", 65);
|
|
115
127
|
i0.ɵɵtext(8, "Name");
|
|
116
128
|
i0.ɵɵelementEnd();
|
|
117
|
-
i0.ɵɵelementStart(9, "div",
|
|
129
|
+
i0.ɵɵelementStart(9, "div", 66);
|
|
118
130
|
i0.ɵɵtext(10);
|
|
119
131
|
i0.ɵɵelementEnd()();
|
|
120
|
-
i0.ɵɵelementStart(11, "div",
|
|
132
|
+
i0.ɵɵelementStart(11, "div", 64)(12, "div", 65);
|
|
121
133
|
i0.ɵɵtext(13, "Type");
|
|
122
134
|
i0.ɵɵelementEnd();
|
|
123
|
-
i0.ɵɵelementStart(14, "div",
|
|
135
|
+
i0.ɵɵelementStart(14, "div", 66);
|
|
124
136
|
i0.ɵɵtext(15);
|
|
125
137
|
i0.ɵɵelementEnd()();
|
|
126
|
-
i0.ɵɵelementStart(16, "div",
|
|
138
|
+
i0.ɵɵelementStart(16, "div", 64)(17, "div", 65);
|
|
127
139
|
i0.ɵɵtext(18, "Status");
|
|
128
140
|
i0.ɵɵelementEnd();
|
|
129
|
-
i0.ɵɵelementStart(19, "div",
|
|
141
|
+
i0.ɵɵelementStart(19, "div", 66)(20, "span", 67);
|
|
130
142
|
i0.ɵɵtext(21);
|
|
131
143
|
i0.ɵɵelementEnd()()();
|
|
132
|
-
i0.ɵɵelementStart(22, "div",
|
|
144
|
+
i0.ɵɵelementStart(22, "div", 64)(23, "div", 65);
|
|
133
145
|
i0.ɵɵtext(24, "Priority");
|
|
134
146
|
i0.ɵɵelementEnd();
|
|
135
|
-
i0.ɵɵelementStart(25, "div",
|
|
147
|
+
i0.ɵɵelementStart(25, "div", 66);
|
|
136
148
|
i0.ɵɵtext(26);
|
|
137
149
|
i0.ɵɵelementEnd()();
|
|
138
|
-
i0.ɵɵelementStart(27, "div",
|
|
150
|
+
i0.ɵɵelementStart(27, "div", 64)(28, "div", 65);
|
|
139
151
|
i0.ɵɵtext(29, "Estimated Duration");
|
|
140
152
|
i0.ɵɵelementEnd();
|
|
141
|
-
i0.ɵɵelementStart(30, "div",
|
|
153
|
+
i0.ɵɵelementStart(30, "div", 66);
|
|
142
154
|
i0.ɵɵtext(31);
|
|
143
155
|
i0.ɵɵelementEnd()();
|
|
144
|
-
i0.ɵɵelementStart(32, "div",
|
|
156
|
+
i0.ɵɵelementStart(32, "div", 64)(33, "div", 65);
|
|
145
157
|
i0.ɵɵtext(34, "Estimated Cost");
|
|
146
158
|
i0.ɵɵelementEnd();
|
|
147
|
-
i0.ɵɵelementStart(35, "div",
|
|
159
|
+
i0.ɵɵelementStart(35, "div", 66);
|
|
148
160
|
i0.ɵɵtext(36);
|
|
149
161
|
i0.ɵɵelementEnd()();
|
|
150
|
-
i0.ɵɵelementStart(37, "div",
|
|
162
|
+
i0.ɵɵelementStart(37, "div", 64)(38, "div", 65);
|
|
151
163
|
i0.ɵɵtext(39, "Repeat Count");
|
|
152
164
|
i0.ɵɵelementEnd();
|
|
153
|
-
i0.ɵɵelementStart(40, "div",
|
|
165
|
+
i0.ɵɵelementStart(40, "div", 66);
|
|
154
166
|
i0.ɵɵtext(41);
|
|
155
167
|
i0.ɵɵelementEnd()();
|
|
156
|
-
i0.ɵɵelementStart(42, "div",
|
|
168
|
+
i0.ɵɵelementStart(42, "div", 64)(43, "div", 65);
|
|
157
169
|
i0.ɵɵtext(44, "Max Execution Time");
|
|
158
170
|
i0.ɵɵelementEnd();
|
|
159
|
-
i0.ɵɵelementStart(45, "div",
|
|
171
|
+
i0.ɵɵelementStart(45, "div", 66);
|
|
160
172
|
i0.ɵɵtext(46);
|
|
161
173
|
i0.ɵɵelementEnd()();
|
|
162
|
-
i0.ɵɵelementStart(47, "div",
|
|
174
|
+
i0.ɵɵelementStart(47, "div", 64)(48, "div", 65);
|
|
163
175
|
i0.ɵɵtext(49, "Created");
|
|
164
176
|
i0.ɵɵelementEnd();
|
|
165
|
-
i0.ɵɵelementStart(50, "div",
|
|
177
|
+
i0.ɵɵelementStart(50, "div", 66);
|
|
166
178
|
i0.ɵɵtext(51);
|
|
167
179
|
i0.ɵɵpipe(52, "date");
|
|
168
180
|
i0.ɵɵelementEnd()();
|
|
169
|
-
i0.ɵɵelementStart(53, "div",
|
|
181
|
+
i0.ɵɵelementStart(53, "div", 64)(54, "div", 65);
|
|
170
182
|
i0.ɵɵtext(55, "Updated");
|
|
171
183
|
i0.ɵɵelementEnd();
|
|
172
|
-
i0.ɵɵelementStart(56, "div",
|
|
184
|
+
i0.ɵɵelementStart(56, "div", 66);
|
|
173
185
|
i0.ɵɵtext(57);
|
|
174
186
|
i0.ɵɵpipe(58, "date");
|
|
175
187
|
i0.ɵɵelementEnd()()()();
|
|
176
|
-
i0.ɵɵelementStart(59, "div",
|
|
177
|
-
i0.ɵɵelement(61, "i",
|
|
188
|
+
i0.ɵɵelementStart(59, "div", 68)(60, "h3");
|
|
189
|
+
i0.ɵɵelement(61, "i", 69);
|
|
178
190
|
i0.ɵɵtext(62, " Test Definition");
|
|
179
191
|
i0.ɵɵelementEnd();
|
|
180
|
-
i0.ɵɵelementStart(63, "div",
|
|
181
|
-
i0.ɵɵlistener("click", function
|
|
182
|
-
i0.ɵɵelement(65, "i",
|
|
192
|
+
i0.ɵɵelementStart(63, "div", 70)(64, "button", 71);
|
|
193
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_63_Template_button_click_64_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("input")); });
|
|
194
|
+
i0.ɵɵelement(65, "i", 72);
|
|
183
195
|
i0.ɵɵtext(66, " Input Definition ");
|
|
184
196
|
i0.ɵɵelementEnd();
|
|
185
|
-
i0.ɵɵelementStart(67, "button",
|
|
186
|
-
i0.ɵɵlistener("click", function
|
|
187
|
-
i0.ɵɵelement(68, "i",
|
|
197
|
+
i0.ɵɵelementStart(67, "button", 71);
|
|
198
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_63_Template_button_click_67_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("expected")); });
|
|
199
|
+
i0.ɵɵelement(68, "i", 73);
|
|
188
200
|
i0.ɵɵtext(69, " Expected Outcomes ");
|
|
189
201
|
i0.ɵɵelementEnd();
|
|
190
|
-
i0.ɵɵelementStart(70, "button",
|
|
191
|
-
i0.ɵɵlistener("click", function
|
|
192
|
-
i0.ɵɵelement(71, "i",
|
|
202
|
+
i0.ɵɵelementStart(70, "button", 71);
|
|
203
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_63_Template_button_click_70_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("config")); });
|
|
204
|
+
i0.ɵɵelement(71, "i", 74);
|
|
193
205
|
i0.ɵɵtext(72, " Configuration ");
|
|
194
206
|
i0.ɵɵelementEnd();
|
|
195
|
-
i0.ɵɵelementStart(73, "button",
|
|
196
|
-
i0.ɵɵlistener("click", function
|
|
197
|
-
i0.ɵɵelement(74, "i",
|
|
207
|
+
i0.ɵɵelementStart(73, "button", 71);
|
|
208
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_63_Template_button_click_73_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.setJsonView("tags")); });
|
|
209
|
+
i0.ɵɵelement(74, "i", 75);
|
|
198
210
|
i0.ɵɵtext(75, " Tags ");
|
|
199
211
|
i0.ɵɵelementEnd()();
|
|
200
|
-
i0.ɵɵelementStart(76, "div",
|
|
201
|
-
i0.ɵɵelement(77, "mj-code-editor",
|
|
212
|
+
i0.ɵɵelementStart(76, "div", 76);
|
|
213
|
+
i0.ɵɵelement(77, "mj-code-editor", 77);
|
|
202
214
|
i0.ɵɵelementEnd()()();
|
|
203
215
|
} if (rf & 2) {
|
|
204
216
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -235,295 +247,420 @@ function MJTestFormComponentExtended_Conditional_61_Template(rf, ctx) { if (rf &
|
|
|
235
247
|
i0.ɵɵadvance(4);
|
|
236
248
|
i0.ɵɵproperty("value", ctx_r0.getJsonData())("readonly", true)("toolbar", ctx_r0.jsonToolbar)("lineWrapping", true);
|
|
237
249
|
} }
|
|
238
|
-
function
|
|
250
|
+
function MJTestFormComponentExtended_Conditional_64_For_25_Template(rf, ctx) { if (rf & 1) {
|
|
251
|
+
i0.ɵɵelementStart(0, "option", 93);
|
|
252
|
+
i0.ɵɵtext(1);
|
|
253
|
+
i0.ɵɵelementEnd();
|
|
254
|
+
} if (rf & 2) {
|
|
255
|
+
const opt_r4 = ctx.$implicit;
|
|
256
|
+
i0.ɵɵproperty("ngValue", opt_r4);
|
|
257
|
+
i0.ɵɵadvance();
|
|
258
|
+
i0.ɵɵtextInterpolate(opt_r4);
|
|
259
|
+
} }
|
|
260
|
+
function MJTestFormComponentExtended_Conditional_64_For_31_Template(rf, ctx) { if (rf & 1) {
|
|
261
|
+
i0.ɵɵelementStart(0, "option", 93);
|
|
262
|
+
i0.ɵɵtext(1);
|
|
263
|
+
i0.ɵɵelementEnd();
|
|
264
|
+
} if (rf & 2) {
|
|
265
|
+
const t_r5 = ctx.$implicit;
|
|
266
|
+
i0.ɵɵproperty("ngValue", t_r5.ID);
|
|
267
|
+
i0.ɵɵadvance();
|
|
268
|
+
i0.ɵɵtextInterpolate(t_r5.Name);
|
|
269
|
+
} }
|
|
270
|
+
function MJTestFormComponentExtended_Conditional_64_For_37_Template(rf, ctx) { if (rf & 1) {
|
|
271
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
272
|
+
i0.ɵɵelementStart(0, "span", 98);
|
|
273
|
+
i0.ɵɵtext(1);
|
|
274
|
+
i0.ɵɵelementStart(2, "button", 121);
|
|
275
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_For_37_Template_button_click_2_listener($event) { const tag_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); ctx_r0.removeTag(tag_r8); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
276
|
+
i0.ɵɵelement(3, "i", 122);
|
|
277
|
+
i0.ɵɵelementEnd()();
|
|
278
|
+
} if (rf & 2) {
|
|
279
|
+
const tag_r8 = ctx.$implicit;
|
|
280
|
+
i0.ɵɵadvance();
|
|
281
|
+
i0.ɵɵtextInterpolate1(" ", tag_r8, " ");
|
|
282
|
+
i0.ɵɵadvance();
|
|
283
|
+
i0.ɵɵattribute("aria-label", "Remove tag " + tag_r8);
|
|
284
|
+
} }
|
|
285
|
+
function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf & 1) {
|
|
239
286
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
240
|
-
i0.ɵɵelementStart(0, "div",
|
|
241
|
-
i0.ɵɵelement(
|
|
242
|
-
i0.ɵɵtext(
|
|
287
|
+
i0.ɵɵelementStart(0, "div", 37)(1, "section", 78)(2, "header", 79)(3, "h3");
|
|
288
|
+
i0.ɵɵelement(4, "i", 80);
|
|
289
|
+
i0.ɵɵtext(5, " Details");
|
|
243
290
|
i0.ɵɵelementEnd();
|
|
244
|
-
i0.ɵɵelementStart(
|
|
245
|
-
i0.ɵɵtext(
|
|
291
|
+
i0.ɵɵelementStart(6, "p", 81);
|
|
292
|
+
i0.ɵɵtext(7, "Edit any field \u2014 changes are saved with the bar at the bottom.");
|
|
293
|
+
i0.ɵɵelementEnd()();
|
|
294
|
+
i0.ɵɵelementStart(8, "div", 82)(9, "div", 83)(10, "label", 84);
|
|
295
|
+
i0.ɵɵtext(11, "Name ");
|
|
296
|
+
i0.ɵɵelementStart(12, "span", 85);
|
|
297
|
+
i0.ɵɵtext(13, "*");
|
|
298
|
+
i0.ɵɵelementEnd()();
|
|
299
|
+
i0.ɵɵelementStart(14, "input", 86);
|
|
300
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_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); });
|
|
301
|
+
i0.ɵɵelementEnd()();
|
|
302
|
+
i0.ɵɵelementStart(15, "div", 83)(16, "label", 87);
|
|
303
|
+
i0.ɵɵtext(17, "Description");
|
|
246
304
|
i0.ɵɵelementEnd();
|
|
247
|
-
i0.ɵɵelementStart(
|
|
248
|
-
i0.ɵɵ
|
|
305
|
+
i0.ɵɵelementStart(18, "textarea", 88);
|
|
306
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_textarea_ngModelChange_18_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Description = $event || null); });
|
|
249
307
|
i0.ɵɵelementEnd()();
|
|
250
|
-
i0.ɵɵelementStart(
|
|
251
|
-
i0.ɵɵtext(
|
|
308
|
+
i0.ɵɵelementStart(19, "div", 89)(20, "label", 90);
|
|
309
|
+
i0.ɵɵtext(21, "Status");
|
|
310
|
+
i0.ɵɵelementEnd();
|
|
311
|
+
i0.ɵɵelementStart(22, "div", 91)(23, "select", 92);
|
|
312
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_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); });
|
|
313
|
+
i0.ɵɵrepeaterCreate(24, MJTestFormComponentExtended_Conditional_64_For_25_Template, 2, 2, "option", 93, i0.ɵɵrepeaterTrackByIdentity);
|
|
314
|
+
i0.ɵɵelementEnd()()();
|
|
315
|
+
i0.ɵɵelementStart(26, "div", 89)(27, "label", 94);
|
|
316
|
+
i0.ɵɵtext(28, "Test Type");
|
|
252
317
|
i0.ɵɵelementEnd();
|
|
253
|
-
i0.ɵɵelementStart(
|
|
254
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
318
|
+
i0.ɵɵelementStart(29, "select", 95);
|
|
319
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_select_ngModelChange_29_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.record.TypeID, $event) || (ctx_r0.record.TypeID = $event); return i0.ɵɵresetView($event); });
|
|
320
|
+
i0.ɵɵrepeaterCreate(30, MJTestFormComponentExtended_Conditional_64_For_31_Template, 2, 2, "option", 93, _forTrack0);
|
|
255
321
|
i0.ɵɵelementEnd()();
|
|
256
|
-
i0.ɵɵelementStart(
|
|
257
|
-
i0.ɵɵtext(
|
|
322
|
+
i0.ɵɵelementStart(32, "div", 83)(33, "label", 96);
|
|
323
|
+
i0.ɵɵtext(34, "Tags");
|
|
324
|
+
i0.ɵɵelementEnd();
|
|
325
|
+
i0.ɵɵelementStart(35, "div", 97);
|
|
326
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_64_Template_div_click_35_listener() { i0.ɵɵrestoreView(_r3); const tagInput_r6 = i0.ɵɵreference(39); return i0.ɵɵresetView(tagInput_r6.focus()); });
|
|
327
|
+
i0.ɵɵrepeaterCreate(36, MJTestFormComponentExtended_Conditional_64_For_37_Template, 4, 2, "span", 98, i0.ɵɵrepeaterTrackByIdentity);
|
|
328
|
+
i0.ɵɵelementStart(38, "input", 99, 0);
|
|
329
|
+
i0.ɵɵtwoWayListener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_38_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r0.tagDraft, $event) || (ctx_r0.tagDraft = $event); return i0.ɵɵresetView($event); });
|
|
330
|
+
i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_Conditional_64_Template_input_keydown_38_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onTagInputKeydown($event)); })("blur", function MJTestFormComponentExtended_Conditional_64_Template_input_blur_38_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.addTagFromDraft()); });
|
|
331
|
+
i0.ɵɵelementEnd()();
|
|
332
|
+
i0.ɵɵelementStart(40, "span", 100);
|
|
333
|
+
i0.ɵɵtext(41, "Press Enter or comma to add a tag. Backspace on empty input removes the last tag.");
|
|
334
|
+
i0.ɵɵelementEnd()()()();
|
|
335
|
+
i0.ɵɵelementStart(42, "section", 78)(43, "header", 79)(44, "h3");
|
|
336
|
+
i0.ɵɵelement(45, "i", 101);
|
|
337
|
+
i0.ɵɵtext(46, " Execution Settings");
|
|
338
|
+
i0.ɵɵelementEnd()();
|
|
339
|
+
i0.ɵɵelementStart(47, "div", 82)(48, "div", 89)(49, "label", 102);
|
|
340
|
+
i0.ɵɵtext(50, "Priority");
|
|
341
|
+
i0.ɵɵelementEnd();
|
|
342
|
+
i0.ɵɵelementStart(51, "input", 103);
|
|
343
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_51_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Priority = $event === "" || $event === null ? null : +$event); });
|
|
258
344
|
i0.ɵɵelementEnd();
|
|
259
|
-
i0.ɵɵelementStart(
|
|
260
|
-
i0.ɵɵ
|
|
345
|
+
i0.ɵɵelementStart(52, "span", 100);
|
|
346
|
+
i0.ɵɵtext(53, "Lower numbers run first.");
|
|
261
347
|
i0.ɵɵelementEnd()();
|
|
262
|
-
i0.ɵɵelementStart(
|
|
263
|
-
i0.ɵɵtext(
|
|
348
|
+
i0.ɵɵelementStart(54, "div", 89)(55, "label", 104);
|
|
349
|
+
i0.ɵɵtext(56, "Repeat Count");
|
|
350
|
+
i0.ɵɵelementEnd();
|
|
351
|
+
i0.ɵɵelementStart(57, "input", 105);
|
|
352
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_57_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.RepeatCount = $event === "" || $event === null ? null : +$event); });
|
|
264
353
|
i0.ɵɵelementEnd();
|
|
265
|
-
i0.ɵɵelementStart(
|
|
266
|
-
i0.ɵɵ
|
|
354
|
+
i0.ɵɵelementStart(58, "span", 100);
|
|
355
|
+
i0.ɵɵtext(59, "Number of times to repeat for statistical analysis.");
|
|
267
356
|
i0.ɵɵelementEnd()();
|
|
268
|
-
i0.ɵɵelementStart(
|
|
269
|
-
i0.ɵɵtext(
|
|
357
|
+
i0.ɵɵelementStart(60, "div", 89)(61, "label", 106);
|
|
358
|
+
i0.ɵɵtext(62, "Estimated Duration (seconds)");
|
|
270
359
|
i0.ɵɵelementEnd();
|
|
271
|
-
i0.ɵɵelementStart(
|
|
272
|
-
i0.ɵɵ
|
|
360
|
+
i0.ɵɵelementStart(63, "input", 107);
|
|
361
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_63_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedDurationSeconds = $event === "" || $event === null ? null : +$event); });
|
|
362
|
+
i0.ɵɵelementEnd()();
|
|
363
|
+
i0.ɵɵelementStart(64, "div", 89)(65, "label", 108);
|
|
364
|
+
i0.ɵɵtext(66, "Estimated Cost (USD)");
|
|
273
365
|
i0.ɵɵelementEnd();
|
|
274
|
-
i0.ɵɵelementStart(
|
|
275
|
-
i0.ɵɵ
|
|
366
|
+
i0.ɵɵelementStart(67, "input", 109);
|
|
367
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_67_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.EstimatedCostUSD = $event === "" || $event === null ? null : +$event); });
|
|
368
|
+
i0.ɵɵelementEnd()();
|
|
369
|
+
i0.ɵɵelementStart(68, "div", 83)(69, "label", 110);
|
|
370
|
+
i0.ɵɵtext(70, "Max Execution Time (ms)");
|
|
371
|
+
i0.ɵɵelementEnd();
|
|
372
|
+
i0.ɵɵelementStart(71, "input", 111);
|
|
373
|
+
i0.ɵɵlistener("ngModelChange", function MJTestFormComponentExtended_Conditional_64_Template_input_ngModelChange_71_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.MaxExecutionTimeMS = $event === "" || $event === null ? null : +$event); });
|
|
374
|
+
i0.ɵɵelementEnd();
|
|
375
|
+
i0.ɵɵelementStart(72, "span", 100);
|
|
376
|
+
i0.ɵɵtext(73);
|
|
276
377
|
i0.ɵɵelementEnd()()()();
|
|
277
|
-
i0.ɵɵelementStart(
|
|
278
|
-
i0.ɵɵelement(
|
|
279
|
-
i0.ɵɵtext(
|
|
378
|
+
i0.ɵɵelementStart(74, "div", 112)(75, "h3");
|
|
379
|
+
i0.ɵɵelement(76, "i", 72);
|
|
380
|
+
i0.ɵɵtext(77, " Input Definition (JSON)");
|
|
280
381
|
i0.ɵɵelementEnd();
|
|
281
|
-
i0.ɵɵelementStart(
|
|
282
|
-
i0.ɵɵlistener("change", function
|
|
382
|
+
i0.ɵɵelementStart(78, "div", 113)(79, "mj-code-editor", 114);
|
|
383
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_79_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.InputDefinition = $event); });
|
|
283
384
|
i0.ɵɵelementEnd()()();
|
|
284
|
-
i0.ɵɵelementStart(
|
|
285
|
-
i0.ɵɵelement(
|
|
286
|
-
i0.ɵɵtext(
|
|
385
|
+
i0.ɵɵelementStart(80, "div", 112)(81, "h3");
|
|
386
|
+
i0.ɵɵelement(82, "i", 73);
|
|
387
|
+
i0.ɵɵtext(83, " Expected Outcomes (JSON)");
|
|
287
388
|
i0.ɵɵelementEnd();
|
|
288
|
-
i0.ɵɵelementStart(
|
|
289
|
-
i0.ɵɵlistener("change", function
|
|
389
|
+
i0.ɵɵelementStart(84, "div", 113)(85, "mj-code-editor", 114);
|
|
390
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_85_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.ExpectedOutcomes = $event); });
|
|
290
391
|
i0.ɵɵelementEnd()()();
|
|
291
|
-
i0.ɵɵelementStart(
|
|
292
|
-
i0.ɵɵelement(
|
|
293
|
-
i0.ɵɵtext(
|
|
392
|
+
i0.ɵɵelementStart(86, "div", 112)(87, "h3");
|
|
393
|
+
i0.ɵɵelement(88, "i", 74);
|
|
394
|
+
i0.ɵɵtext(89, " Configuration (JSON)");
|
|
294
395
|
i0.ɵɵelementEnd();
|
|
295
|
-
i0.ɵɵelementStart(
|
|
296
|
-
i0.ɵɵlistener("change", function
|
|
396
|
+
i0.ɵɵelementStart(90, "div", 113)(91, "mj-code-editor", 114);
|
|
397
|
+
i0.ɵɵlistener("change", function MJTestFormComponentExtended_Conditional_64_Template_mj_code_editor_change_91_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.record.Configuration = $event); });
|
|
297
398
|
i0.ɵɵelementEnd()()();
|
|
298
|
-
i0.ɵɵelementStart(
|
|
299
|
-
i0.ɵɵ
|
|
300
|
-
i0.ɵɵtext(49, " Tags (JSON Array)");
|
|
399
|
+
i0.ɵɵelementStart(92, "section", 115)(93, "div", 116)(94, "div", 117)(95, "div", 118);
|
|
400
|
+
i0.ɵɵtext(96, "Created");
|
|
301
401
|
i0.ɵɵelementEnd();
|
|
302
|
-
i0.ɵɵelementStart(
|
|
303
|
-
i0.ɵɵ
|
|
304
|
-
i0.ɵɵ
|
|
402
|
+
i0.ɵɵelementStart(97, "div", 119);
|
|
403
|
+
i0.ɵɵtext(98);
|
|
404
|
+
i0.ɵɵpipe(99, "date");
|
|
405
|
+
i0.ɵɵelementEnd()();
|
|
406
|
+
i0.ɵɵelementStart(100, "div", 117)(101, "div", 118);
|
|
407
|
+
i0.ɵɵtext(102, "Last updated");
|
|
408
|
+
i0.ɵɵelementEnd();
|
|
409
|
+
i0.ɵɵelementStart(103, "div", 119);
|
|
410
|
+
i0.ɵɵtext(104);
|
|
411
|
+
i0.ɵɵpipe(105, "date");
|
|
412
|
+
i0.ɵɵelementEnd()();
|
|
413
|
+
i0.ɵɵelementStart(106, "div", 117)(107, "div", 118);
|
|
414
|
+
i0.ɵɵtext(108, "Test ID");
|
|
415
|
+
i0.ɵɵelementEnd();
|
|
416
|
+
i0.ɵɵelementStart(109, "div", 120);
|
|
417
|
+
i0.ɵɵtext(110);
|
|
418
|
+
i0.ɵɵelementEnd()()()()();
|
|
305
419
|
} if (rf & 2) {
|
|
306
420
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
307
|
-
i0.ɵɵadvance(
|
|
308
|
-
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.
|
|
309
|
-
i0.ɵɵadvance(4);
|
|
310
|
-
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.RepeatCount);
|
|
421
|
+
i0.ɵɵadvance(14);
|
|
422
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.Name);
|
|
311
423
|
i0.ɵɵadvance(4);
|
|
312
|
-
i0.ɵɵ
|
|
424
|
+
i0.ɵɵproperty("ngModel", ctx_r0.record.Description);
|
|
425
|
+
i0.ɵɵadvance(5);
|
|
426
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.Status);
|
|
427
|
+
i0.ɵɵadvance();
|
|
428
|
+
i0.ɵɵrepeater(ctx_r0.statusOptions);
|
|
429
|
+
i0.ɵɵadvance(5);
|
|
430
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.record.TypeID);
|
|
431
|
+
i0.ɵɵadvance();
|
|
432
|
+
i0.ɵɵrepeater(ctx_r0.testTypeOptions);
|
|
433
|
+
i0.ɵɵadvance(6);
|
|
434
|
+
i0.ɵɵrepeater(ctx_r0.tags);
|
|
435
|
+
i0.ɵɵadvance(2);
|
|
436
|
+
i0.ɵɵproperty("placeholder", ctx_r0.tags.length === 0 ? "Add tags, press Enter or comma..." : "");
|
|
437
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r0.tagDraft);
|
|
438
|
+
i0.ɵɵadvance(13);
|
|
439
|
+
i0.ɵɵproperty("ngModel", ctx_r0.record.Priority);
|
|
440
|
+
i0.ɵɵadvance(6);
|
|
441
|
+
i0.ɵɵproperty("ngModel", ctx_r0.record.RepeatCount);
|
|
442
|
+
i0.ɵɵadvance(6);
|
|
443
|
+
i0.ɵɵproperty("ngModel", ctx_r0.record.EstimatedDurationSeconds);
|
|
313
444
|
i0.ɵɵadvance(4);
|
|
314
|
-
i0.ɵɵ
|
|
445
|
+
i0.ɵɵproperty("ngModel", ctx_r0.record.EstimatedCostUSD);
|
|
315
446
|
i0.ɵɵadvance(4);
|
|
316
|
-
i0.ɵɵ
|
|
317
|
-
i0.ɵɵadvance(
|
|
447
|
+
i0.ɵɵproperty("ngModel", ctx_r0.record.MaxExecutionTimeMS);
|
|
448
|
+
i0.ɵɵadvance(2);
|
|
449
|
+
i0.ɵɵtextInterpolate1("Leave empty for the default 5 minute timeout. Currently: ", ctx_r0.formatTimeout(ctx_r0.record.MaxExecutionTimeMS));
|
|
450
|
+
i0.ɵɵadvance(6);
|
|
318
451
|
i0.ɵɵproperty("value", ctx_r0.record.InputDefinition || "")("readonly", false)("lineWrapping", true);
|
|
319
452
|
i0.ɵɵadvance(6);
|
|
320
453
|
i0.ɵɵproperty("value", ctx_r0.record.ExpectedOutcomes || "")("readonly", false)("lineWrapping", true);
|
|
321
454
|
i0.ɵɵadvance(6);
|
|
322
455
|
i0.ɵɵproperty("value", ctx_r0.record.Configuration || "")("readonly", false)("lineWrapping", true);
|
|
456
|
+
i0.ɵɵadvance(7);
|
|
457
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(99, 24, ctx_r0.record.__mj_CreatedAt, "medium"));
|
|
323
458
|
i0.ɵɵadvance(6);
|
|
324
|
-
i0.ɵɵ
|
|
459
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(105, 27, ctx_r0.record.__mj_UpdatedAt, "medium"));
|
|
460
|
+
i0.ɵɵadvance(6);
|
|
461
|
+
i0.ɵɵtextInterpolate(ctx_r0.record.ID);
|
|
325
462
|
} }
|
|
326
|
-
function
|
|
327
|
-
i0.ɵɵelementStart(0, "div",
|
|
328
|
-
i0.ɵɵelement(1, "div",
|
|
329
|
-
i0.ɵɵelementStart(2, "div",
|
|
330
|
-
i0.ɵɵelement(3, "div",
|
|
463
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
464
|
+
i0.ɵɵelementStart(0, "div", 127);
|
|
465
|
+
i0.ɵɵelement(1, "div", 128);
|
|
466
|
+
i0.ɵɵelementStart(2, "div", 129);
|
|
467
|
+
i0.ɵɵelement(3, "div", 130)(4, "div", 131);
|
|
331
468
|
i0.ɵɵelementEnd()();
|
|
332
469
|
} }
|
|
333
|
-
function
|
|
334
|
-
i0.ɵɵelementStart(0, "div",
|
|
335
|
-
i0.ɵɵrepeaterCreate(2,
|
|
470
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
471
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "div", 126);
|
|
472
|
+
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_1_For_3_Template, 5, 0, "div", 127, i0.ɵɵrepeaterTrackByIdentity);
|
|
336
473
|
i0.ɵɵelementEnd()();
|
|
337
474
|
} if (rf & 2) {
|
|
338
475
|
i0.ɵɵadvance(2);
|
|
339
476
|
i0.ɵɵrepeater(i0.ɵɵpureFunction0(0, _c0));
|
|
340
477
|
} }
|
|
341
|
-
function
|
|
478
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
342
479
|
i0.ɵɵelementStart(0, "span");
|
|
343
|
-
i0.ɵɵelement(1, "i",
|
|
480
|
+
i0.ɵɵelement(1, "i", 147);
|
|
344
481
|
i0.ɵɵtext(2);
|
|
345
482
|
i0.ɵɵelementEnd();
|
|
346
483
|
} if (rf & 2) {
|
|
347
|
-
const
|
|
484
|
+
const run_r10 = i0.ɵɵnextContext().$implicit;
|
|
348
485
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
349
486
|
i0.ɵɵadvance(2);
|
|
350
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(
|
|
487
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatDuration(run_r10.DurationSeconds));
|
|
351
488
|
} }
|
|
352
|
-
function
|
|
489
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
353
490
|
i0.ɵɵelementStart(0, "span");
|
|
354
|
-
i0.ɵɵelement(1, "i",
|
|
491
|
+
i0.ɵɵelement(1, "i", 148);
|
|
355
492
|
i0.ɵɵtext(2);
|
|
356
493
|
i0.ɵɵelementEnd();
|
|
357
494
|
} if (rf & 2) {
|
|
358
|
-
const
|
|
495
|
+
const run_r10 = i0.ɵɵnextContext().$implicit;
|
|
359
496
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
360
497
|
i0.ɵɵadvance(2);
|
|
361
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(
|
|
498
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.formatCost(run_r10.CostUSD));
|
|
362
499
|
} }
|
|
363
|
-
function
|
|
364
|
-
i0.ɵɵelement(0, "mj-entity-link-pill",
|
|
500
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
501
|
+
i0.ɵɵelement(0, "mj-entity-link-pill", 142);
|
|
365
502
|
} if (rf & 2) {
|
|
366
|
-
const
|
|
367
|
-
i0.ɵɵproperty("entityName",
|
|
503
|
+
const run_r10 = i0.ɵɵnextContext().$implicit;
|
|
504
|
+
i0.ɵɵproperty("entityName", run_r10.TargetLogEntity)("recordId", run_r10.TargetLogID);
|
|
368
505
|
} }
|
|
369
|
-
function
|
|
370
|
-
i0.ɵɵelementStart(0, "span",
|
|
371
|
-
i0.ɵɵelement(1, "i",
|
|
506
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
507
|
+
i0.ɵɵelementStart(0, "span", 144);
|
|
508
|
+
i0.ɵɵelement(1, "i", 135);
|
|
372
509
|
i0.ɵɵelementStart(2, "span");
|
|
373
510
|
i0.ɵɵtext(3);
|
|
374
511
|
i0.ɵɵelementEnd()();
|
|
375
512
|
} if (rf & 2) {
|
|
376
|
-
const
|
|
513
|
+
const run_r10 = i0.ɵɵnextContext().$implicit;
|
|
377
514
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
378
|
-
i0.ɵɵproperty("ngClass", "status-" +
|
|
515
|
+
i0.ɵɵproperty("ngClass", "status-" + run_r10.Status.toLowerCase())("title", ctx_r0.getStatusTooltip(run_r10.Status));
|
|
379
516
|
i0.ɵɵadvance();
|
|
380
|
-
i0.ɵɵclassProp("fa-check",
|
|
517
|
+
i0.ɵɵclassProp("fa-check", run_r10.Status === "Passed")("fa-times", run_r10.Status === "Failed")("fa-exclamation", run_r10.Status === "Error")("fa-hourglass-end", run_r10.Status === "Timeout")("fa-forward", run_r10.Status === "Skipped")("fa-spinner", run_r10.Status === "Running")("fa-clock", run_r10.Status === "Pending");
|
|
381
518
|
i0.ɵɵadvance(2);
|
|
382
|
-
i0.ɵɵtextInterpolate(
|
|
519
|
+
i0.ɵɵtextInterpolate(run_r10.Status);
|
|
383
520
|
} }
|
|
384
|
-
function
|
|
385
|
-
i0.ɵɵelementStart(0, "span",
|
|
386
|
-
i0.ɵɵelement(1, "i",
|
|
521
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
522
|
+
i0.ɵɵelementStart(0, "span", 149);
|
|
523
|
+
i0.ɵɵelement(1, "i", 151);
|
|
387
524
|
i0.ɵɵelementEnd();
|
|
388
525
|
} }
|
|
389
|
-
function
|
|
390
|
-
i0.ɵɵelementStart(0, "span",
|
|
391
|
-
i0.ɵɵelement(1, "i",
|
|
526
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
527
|
+
i0.ɵɵelementStart(0, "span", 152);
|
|
528
|
+
i0.ɵɵelement(1, "i", 153);
|
|
392
529
|
i0.ɵɵelementStart(2, "span");
|
|
393
530
|
i0.ɵɵtext(3);
|
|
394
531
|
i0.ɵɵelementEnd()();
|
|
395
532
|
} if (rf & 2) {
|
|
396
533
|
let tmp_19_0;
|
|
397
|
-
const
|
|
398
|
-
const
|
|
534
|
+
const rating_r11 = ctx;
|
|
535
|
+
const run_r10 = i0.ɵɵnextContext(2).$implicit;
|
|
399
536
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
400
|
-
i0.ɵɵclassProp("rating-low",
|
|
401
|
-
i0.ɵɵproperty("title", ctx_r0.getHumanTooltip(
|
|
537
|
+
i0.ɵɵclassProp("rating-low", rating_r11 <= 4)("rating-medium", rating_r11 >= 5 && rating_r11 <= 6)("rating-good", rating_r11 >= 7 && rating_r11 <= 8)("rating-excellent", rating_r11 >= 9);
|
|
538
|
+
i0.ɵɵproperty("title", ctx_r0.getHumanTooltip(rating_r11, ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_19_0.CorrectionSummary) || ((tmp_19_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_19_0.Comments) || null));
|
|
402
539
|
i0.ɵɵadvance(3);
|
|
403
|
-
i0.ɵɵtextInterpolate(
|
|
540
|
+
i0.ɵɵtextInterpolate(rating_r11);
|
|
404
541
|
} }
|
|
405
|
-
function
|
|
406
|
-
i0.ɵɵconditionalCreate(0,
|
|
407
|
-
i0.ɵɵconditionalCreate(1,
|
|
542
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
543
|
+
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_0_Template, 2, 0, "span", 149);
|
|
544
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Conditional_1_Template, 4, 10, "span", 150);
|
|
408
545
|
} if (rf & 2) {
|
|
409
546
|
let tmp_13_0;
|
|
410
547
|
let tmp_14_0;
|
|
411
|
-
const
|
|
548
|
+
const run_r10 = i0.ɵɵnextContext().$implicit;
|
|
412
549
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
413
|
-
i0.ɵɵconditional(!((tmp_13_0 = ctx_r0.getFeedbackForRun(
|
|
550
|
+
i0.ɵɵconditional(!((tmp_13_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_13_0.Rating) ? 0 : -1);
|
|
414
551
|
i0.ɵɵadvance();
|
|
415
|
-
i0.ɵɵconditional((tmp_14_0 = (tmp_14_0 = ctx_r0.getFeedbackForRun(
|
|
552
|
+
i0.ɵɵconditional((tmp_14_0 = (tmp_14_0 = ctx_r0.getFeedbackForRun(run_r10.ID)) == null ? null : tmp_14_0.Rating) ? 1 : -1, tmp_14_0);
|
|
416
553
|
} }
|
|
417
|
-
function
|
|
418
|
-
i0.ɵɵelementStart(0, "span",
|
|
419
|
-
i0.ɵɵelement(1, "i",
|
|
554
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
555
|
+
i0.ɵɵelementStart(0, "span", 154);
|
|
556
|
+
i0.ɵɵelement(1, "i", 156);
|
|
420
557
|
i0.ɵɵelementEnd();
|
|
421
558
|
} }
|
|
422
|
-
function
|
|
423
|
-
i0.ɵɵelementStart(0, "span",
|
|
424
|
-
i0.ɵɵelement(1, "i",
|
|
559
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
560
|
+
i0.ɵɵelementStart(0, "span", 157);
|
|
561
|
+
i0.ɵɵelement(1, "i", 156);
|
|
425
562
|
i0.ɵɵelementStart(2, "span");
|
|
426
563
|
i0.ɵɵtext(3);
|
|
427
564
|
i0.ɵɵelementEnd()();
|
|
428
565
|
} if (rf & 2) {
|
|
429
|
-
const
|
|
430
|
-
i0.ɵɵclassProp("score-low",
|
|
431
|
-
i0.ɵɵproperty("title", "Auto Score: " + (
|
|
566
|
+
const run_r10 = i0.ɵɵnextContext(2).$implicit;
|
|
567
|
+
i0.ɵɵclassProp("score-low", run_r10.Score < 0.5)("score-medium", run_r10.Score >= 0.5 && run_r10.Score < 0.7)("score-good", run_r10.Score >= 0.7 && run_r10.Score < 0.85)("score-excellent", run_r10.Score >= 0.85);
|
|
568
|
+
i0.ɵɵproperty("title", "Auto Score: " + (run_r10.Score * 100).toFixed(0) + "% automated evaluation");
|
|
432
569
|
i0.ɵɵadvance(3);
|
|
433
|
-
i0.ɵɵtextInterpolate1("", (
|
|
570
|
+
i0.ɵɵtextInterpolate1("", (run_r10.Score * 100).toFixed(0), "%");
|
|
434
571
|
} }
|
|
435
|
-
function
|
|
436
|
-
i0.ɵɵconditionalCreate(0,
|
|
437
|
-
i0.ɵɵconditionalCreate(1,
|
|
572
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
573
|
+
i0.ɵɵconditionalCreate(0, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_0_Template, 2, 0, "span", 154);
|
|
574
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Conditional_1_Template, 4, 10, "span", 155);
|
|
438
575
|
} if (rf & 2) {
|
|
439
|
-
const
|
|
440
|
-
i0.ɵɵconditional(
|
|
576
|
+
const run_r10 = i0.ɵɵnextContext().$implicit;
|
|
577
|
+
i0.ɵɵconditional(run_r10.Score == null ? 0 : -1);
|
|
441
578
|
i0.ɵɵadvance();
|
|
442
|
-
i0.ɵɵconditional(
|
|
579
|
+
i0.ɵɵconditional(run_r10.Score != null ? 1 : -1);
|
|
443
580
|
} }
|
|
444
|
-
function
|
|
445
|
-
i0.ɵɵelementStart(0, "span",
|
|
581
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
582
|
+
i0.ɵɵelementStart(0, "span", 158);
|
|
446
583
|
i0.ɵɵtext(1);
|
|
447
584
|
i0.ɵɵelementEnd();
|
|
448
585
|
} if (rf & 2) {
|
|
449
|
-
const
|
|
586
|
+
const tag_r12 = ctx.$implicit;
|
|
450
587
|
i0.ɵɵadvance();
|
|
451
|
-
i0.ɵɵtextInterpolate(
|
|
588
|
+
i0.ɵɵtextInterpolate(tag_r12);
|
|
452
589
|
} }
|
|
453
|
-
function
|
|
454
|
-
i0.ɵɵelementStart(0, "span",
|
|
590
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
591
|
+
i0.ɵɵelementStart(0, "span", 159);
|
|
455
592
|
i0.ɵɵtext(1);
|
|
456
593
|
i0.ɵɵelementEnd();
|
|
457
594
|
} if (rf & 2) {
|
|
458
|
-
const
|
|
595
|
+
const run_r10 = i0.ɵɵnextContext(2).$implicit;
|
|
459
596
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
460
597
|
i0.ɵɵadvance();
|
|
461
|
-
i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(
|
|
598
|
+
i0.ɵɵtextInterpolate1("+", ctx_r0.getRunTags(run_r10).length - 3);
|
|
462
599
|
} }
|
|
463
|
-
function
|
|
464
|
-
i0.ɵɵelementStart(0, "div",
|
|
465
|
-
i0.ɵɵrepeaterCreate(1,
|
|
466
|
-
i0.ɵɵconditionalCreate(3,
|
|
600
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
601
|
+
i0.ɵɵelementStart(0, "div", 145);
|
|
602
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_For_2_Template, 2, 1, "span", 158, i0.ɵɵrepeaterTrackByIdentity);
|
|
603
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Conditional_3_Template, 2, 1, "span", 159);
|
|
467
604
|
i0.ɵɵelementEnd();
|
|
468
605
|
} if (rf & 2) {
|
|
469
|
-
const
|
|
606
|
+
const run_r10 = i0.ɵɵnextContext().$implicit;
|
|
470
607
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
471
608
|
i0.ɵɵadvance();
|
|
472
|
-
i0.ɵɵrepeater(ctx_r0.getRunTags(
|
|
609
|
+
i0.ɵɵrepeater(ctx_r0.getRunTags(run_r10).slice(0, 3));
|
|
473
610
|
i0.ɵɵadvance(2);
|
|
474
|
-
i0.ɵɵconditional(ctx_r0.getRunTags(
|
|
611
|
+
i0.ɵɵconditional(ctx_r0.getRunTags(run_r10).length > 3 ? 3 : -1);
|
|
475
612
|
} }
|
|
476
|
-
function
|
|
477
|
-
const
|
|
478
|
-
i0.ɵɵelementStart(0, "div",
|
|
479
|
-
i0.ɵɵlistener("click", function
|
|
480
|
-
i0.ɵɵelementStart(1, "div",
|
|
481
|
-
i0.ɵɵelement(2, "i",
|
|
613
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
614
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
615
|
+
i0.ɵɵelementStart(0, "div", 133);
|
|
616
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template_div_click_0_listener() { const run_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestRun(run_r10.ID)); });
|
|
617
|
+
i0.ɵɵelementStart(1, "div", 134);
|
|
618
|
+
i0.ɵɵelement(2, "i", 135);
|
|
482
619
|
i0.ɵɵelementEnd();
|
|
483
|
-
i0.ɵɵelementStart(3, "div",
|
|
620
|
+
i0.ɵɵelementStart(3, "div", 136)(4, "div", 137)(5, "span", 138);
|
|
484
621
|
i0.ɵɵtext(6);
|
|
485
622
|
i0.ɵɵelementEnd();
|
|
486
|
-
i0.ɵɵelementStart(7, "span",
|
|
623
|
+
i0.ɵɵelementStart(7, "span", 139);
|
|
487
624
|
i0.ɵɵtext(8);
|
|
488
625
|
i0.ɵɵelementEnd()();
|
|
489
|
-
i0.ɵɵelementStart(9, "div",
|
|
490
|
-
i0.ɵɵelement(11, "i",
|
|
626
|
+
i0.ɵɵelementStart(9, "div", 140)(10, "span");
|
|
627
|
+
i0.ɵɵelement(11, "i", 141);
|
|
491
628
|
i0.ɵɵtext(12);
|
|
492
629
|
i0.ɵɵelementEnd();
|
|
493
|
-
i0.ɵɵconditionalCreate(13,
|
|
494
|
-
i0.ɵɵconditionalCreate(14,
|
|
495
|
-
i0.ɵɵconditionalCreate(15,
|
|
630
|
+
i0.ɵɵconditionalCreate(13, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_13_Template, 3, 1, "span");
|
|
631
|
+
i0.ɵɵconditionalCreate(14, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_14_Template, 3, 1, "span");
|
|
632
|
+
i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_15_Template, 1, 2, "mj-entity-link-pill", 142);
|
|
496
633
|
i0.ɵɵelementEnd();
|
|
497
|
-
i0.ɵɵelementStart(16, "div",
|
|
498
|
-
i0.ɵɵconditionalCreate(17,
|
|
499
|
-
i0.ɵɵconditionalCreate(18,
|
|
500
|
-
i0.ɵɵconditionalCreate(19,
|
|
634
|
+
i0.ɵɵelementStart(16, "div", 143);
|
|
635
|
+
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_17_Template, 4, 17, "span", 144);
|
|
636
|
+
i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_18_Template, 2, 2);
|
|
637
|
+
i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_19_Template, 2, 2);
|
|
501
638
|
i0.ɵɵelementEnd();
|
|
502
|
-
i0.ɵɵconditionalCreate(20,
|
|
639
|
+
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Conditional_20_Template, 4, 1, "div", 145);
|
|
503
640
|
i0.ɵɵelementEnd();
|
|
504
|
-
i0.ɵɵelement(21, "i",
|
|
641
|
+
i0.ɵɵelement(21, "i", 146);
|
|
505
642
|
i0.ɵɵelementEnd();
|
|
506
643
|
} if (rf & 2) {
|
|
507
|
-
const
|
|
644
|
+
const run_r10 = ctx.$implicit;
|
|
508
645
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
509
646
|
i0.ɵɵadvance();
|
|
510
|
-
i0.ɵɵstyleProp("background-color", ctx_r0.getRunStatusColor(
|
|
647
|
+
i0.ɵɵstyleProp("background-color", ctx_r0.getRunStatusColor(run_r10.Status));
|
|
511
648
|
i0.ɵɵadvance();
|
|
512
|
-
i0.ɵɵclassProp("fa-check",
|
|
649
|
+
i0.ɵɵclassProp("fa-check", run_r10.Status === "Passed")("fa-times", run_r10.Status === "Failed")("fa-exclamation", run_r10.Status === "Error")("fa-stopwatch", run_r10.Status === "Timeout")("fa-spinner", run_r10.Status === "Running")("fa-clock", run_r10.Status === "Pending");
|
|
513
650
|
i0.ɵɵadvance(4);
|
|
514
|
-
i0.ɵɵtextInterpolate1("Run #",
|
|
651
|
+
i0.ɵɵtextInterpolate1("Run #", run_r10.ID.substring(0, 8));
|
|
515
652
|
i0.ɵɵadvance();
|
|
516
|
-
i0.ɵɵstyleProp("color", ctx_r0.getRunStatusColor(
|
|
653
|
+
i0.ɵɵstyleProp("color", ctx_r0.getRunStatusColor(run_r10.Status));
|
|
517
654
|
i0.ɵɵadvance();
|
|
518
|
-
i0.ɵɵtextInterpolate(
|
|
655
|
+
i0.ɵɵtextInterpolate(run_r10.Status);
|
|
519
656
|
i0.ɵɵadvance(4);
|
|
520
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r0.getRelativeTime(
|
|
657
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.getRelativeTime(run_r10.StartedAt));
|
|
521
658
|
i0.ɵɵadvance();
|
|
522
|
-
i0.ɵɵconditional(
|
|
659
|
+
i0.ɵɵconditional(run_r10.DurationSeconds ? 13 : -1);
|
|
523
660
|
i0.ɵɵadvance();
|
|
524
|
-
i0.ɵɵconditional(
|
|
661
|
+
i0.ɵɵconditional(run_r10.CostUSD ? 14 : -1);
|
|
525
662
|
i0.ɵɵadvance();
|
|
526
|
-
i0.ɵɵconditional(
|
|
663
|
+
i0.ɵɵconditional(run_r10.TargetLogEntityID && run_r10.TargetLogID ? 15 : -1);
|
|
527
664
|
i0.ɵɵadvance(2);
|
|
528
665
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 17 : -1);
|
|
529
666
|
i0.ɵɵadvance();
|
|
@@ -531,21 +668,21 @@ function MJTestFormComponentExtended_Conditional_63_Conditional_2_For_2_Template
|
|
|
531
668
|
i0.ɵɵadvance();
|
|
532
669
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 19 : -1);
|
|
533
670
|
i0.ɵɵadvance();
|
|
534
|
-
i0.ɵɵconditional(ctx_r0.getRunTags(
|
|
671
|
+
i0.ɵɵconditional(ctx_r0.getRunTags(run_r10).length > 0 ? 20 : -1);
|
|
535
672
|
} }
|
|
536
|
-
function
|
|
537
|
-
i0.ɵɵelementStart(0, "div",
|
|
538
|
-
i0.ɵɵrepeaterCreate(1,
|
|
673
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
674
|
+
i0.ɵɵelementStart(0, "div", 124);
|
|
675
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_2_For_2_Template, 22, 26, "div", 132, i0.ɵɵrepeaterTrackByIdentity);
|
|
539
676
|
i0.ɵɵelementEnd();
|
|
540
677
|
} if (rf & 2) {
|
|
541
678
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
542
679
|
i0.ɵɵadvance();
|
|
543
680
|
i0.ɵɵrepeater(ctx_r0.testRuns);
|
|
544
681
|
} }
|
|
545
|
-
function
|
|
546
|
-
const
|
|
547
|
-
i0.ɵɵelementStart(0, "div",
|
|
548
|
-
i0.ɵɵelement(2, "i",
|
|
682
|
+
function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
683
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
684
|
+
i0.ɵɵelementStart(0, "div", 125)(1, "div", 160);
|
|
685
|
+
i0.ɵɵelement(2, "i", 161);
|
|
549
686
|
i0.ɵɵelementEnd();
|
|
550
687
|
i0.ɵɵelementStart(3, "h4");
|
|
551
688
|
i0.ɵɵtext(4, "No Test Runs Yet");
|
|
@@ -553,17 +690,17 @@ function MJTestFormComponentExtended_Conditional_63_Conditional_3_Template(rf, c
|
|
|
553
690
|
i0.ɵɵelementStart(5, "p");
|
|
554
691
|
i0.ɵɵtext(6, "Run this test to see execution history and results here.");
|
|
555
692
|
i0.ɵɵelementEnd();
|
|
556
|
-
i0.ɵɵelementStart(7, "button",
|
|
557
|
-
i0.ɵɵlistener("click", function
|
|
558
|
-
i0.ɵɵelement(8, "i",
|
|
693
|
+
i0.ɵɵelementStart(7, "button", 21);
|
|
694
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_65_Conditional_3_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r13); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.runTest()); });
|
|
695
|
+
i0.ɵɵelement(8, "i", 22);
|
|
559
696
|
i0.ɵɵtext(9, " Run Test Now ");
|
|
560
697
|
i0.ɵɵelementEnd()();
|
|
561
698
|
} }
|
|
562
|
-
function
|
|
563
|
-
i0.ɵɵelementStart(0, "div",
|
|
564
|
-
i0.ɵɵconditionalCreate(1,
|
|
565
|
-
i0.ɵɵconditionalCreate(2,
|
|
566
|
-
i0.ɵɵconditionalCreate(3,
|
|
699
|
+
function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf & 1) {
|
|
700
|
+
i0.ɵɵelementStart(0, "div", 38);
|
|
701
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_65_Conditional_1_Template, 4, 1, "div", 123);
|
|
702
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_65_Conditional_2_Template, 3, 0, "div", 124);
|
|
703
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_65_Conditional_3_Template, 10, 0, "div", 125);
|
|
567
704
|
i0.ɵɵelementEnd();
|
|
568
705
|
} if (rf & 2) {
|
|
569
706
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -574,70 +711,70 @@ function MJTestFormComponentExtended_Conditional_63_Template(rf, ctx) { if (rf &
|
|
|
574
711
|
i0.ɵɵadvance();
|
|
575
712
|
i0.ɵɵconditional(ctx_r0.testRunsLoaded && !ctx_r0.loadingRuns && ctx_r0.testRuns.length === 0 ? 3 : -1);
|
|
576
713
|
} }
|
|
577
|
-
function
|
|
578
|
-
i0.ɵɵelementStart(0, "div",
|
|
579
|
-
i0.ɵɵelement(1, "div",
|
|
580
|
-
i0.ɵɵelementStart(2, "div",
|
|
581
|
-
i0.ɵɵelement(3, "div",
|
|
714
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
715
|
+
i0.ɵɵelementStart(0, "div", 127);
|
|
716
|
+
i0.ɵɵelement(1, "div", 128);
|
|
717
|
+
i0.ɵɵelementStart(2, "div", 129);
|
|
718
|
+
i0.ɵɵelement(3, "div", 130)(4, "div", 131);
|
|
582
719
|
i0.ɵɵelementEnd()();
|
|
583
720
|
} }
|
|
584
|
-
function
|
|
585
|
-
i0.ɵɵelementStart(0, "div",
|
|
586
|
-
i0.ɵɵrepeaterCreate(2,
|
|
721
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
722
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "div", 126);
|
|
723
|
+
i0.ɵɵrepeaterCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_1_For_3_Template, 5, 0, "div", 127, i0.ɵɵrepeaterTrackByIdentity);
|
|
587
724
|
i0.ɵɵelementEnd()();
|
|
588
725
|
} if (rf & 2) {
|
|
589
726
|
i0.ɵɵadvance(2);
|
|
590
727
|
i0.ɵɵrepeater(i0.ɵɵpureFunction0(0, _c1));
|
|
591
728
|
} }
|
|
592
|
-
function
|
|
729
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
593
730
|
i0.ɵɵelementStart(0, "span");
|
|
594
|
-
i0.ɵɵelement(1, "i",
|
|
731
|
+
i0.ɵɵelement(1, "i", 62);
|
|
595
732
|
i0.ɵɵtext(2);
|
|
596
733
|
i0.ɵɵelementEnd();
|
|
597
734
|
} if (rf & 2) {
|
|
598
|
-
const
|
|
735
|
+
const suiteTest_r15 = i0.ɵɵnextContext().$implicit;
|
|
599
736
|
i0.ɵɵadvance(2);
|
|
600
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
737
|
+
i0.ɵɵtextInterpolate1(" ", suiteTest_r15.Status);
|
|
601
738
|
} }
|
|
602
|
-
function
|
|
603
|
-
const
|
|
604
|
-
i0.ɵɵelementStart(0, "div",
|
|
605
|
-
i0.ɵɵlistener("click", function
|
|
606
|
-
i0.ɵɵelementStart(1, "div",
|
|
607
|
-
i0.ɵɵelement(2, "i",
|
|
608
|
-
i0.ɵɵelementEnd();
|
|
609
|
-
i0.ɵɵelementStart(3, "div",
|
|
739
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
740
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
741
|
+
i0.ɵɵelementStart(0, "div", 164);
|
|
742
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template_div_click_0_listener() { const suiteTest_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.openTestSuite(suiteTest_r15.SuiteID)); });
|
|
743
|
+
i0.ɵɵelementStart(1, "div", 165);
|
|
744
|
+
i0.ɵɵelement(2, "i", 33);
|
|
745
|
+
i0.ɵɵelementEnd();
|
|
746
|
+
i0.ɵɵelementStart(3, "div", 166)(4, "div", 167);
|
|
610
747
|
i0.ɵɵtext(5);
|
|
611
748
|
i0.ɵɵelementEnd();
|
|
612
|
-
i0.ɵɵelementStart(6, "div",
|
|
613
|
-
i0.ɵɵelement(8, "i",
|
|
749
|
+
i0.ɵɵelementStart(6, "div", 168)(7, "span");
|
|
750
|
+
i0.ɵɵelement(8, "i", 169);
|
|
614
751
|
i0.ɵɵtext(9);
|
|
615
752
|
i0.ɵɵelementEnd();
|
|
616
|
-
i0.ɵɵconditionalCreate(10,
|
|
753
|
+
i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Conditional_10_Template, 3, 1, "span");
|
|
617
754
|
i0.ɵɵelementEnd()();
|
|
618
|
-
i0.ɵɵelement(11, "i",
|
|
755
|
+
i0.ɵɵelement(11, "i", 146);
|
|
619
756
|
i0.ɵɵelementEnd();
|
|
620
757
|
} if (rf & 2) {
|
|
621
|
-
const
|
|
758
|
+
const suiteTest_r15 = ctx.$implicit;
|
|
622
759
|
i0.ɵɵadvance(5);
|
|
623
|
-
i0.ɵɵtextInterpolate(
|
|
760
|
+
i0.ɵɵtextInterpolate(suiteTest_r15.Suite);
|
|
624
761
|
i0.ɵɵadvance(4);
|
|
625
|
-
i0.ɵɵtextInterpolate1(" Sequence: ",
|
|
762
|
+
i0.ɵɵtextInterpolate1(" Sequence: ", suiteTest_r15.Sequence);
|
|
626
763
|
i0.ɵɵadvance();
|
|
627
|
-
i0.ɵɵconditional(
|
|
764
|
+
i0.ɵɵconditional(suiteTest_r15.Status ? 10 : -1);
|
|
628
765
|
} }
|
|
629
|
-
function
|
|
630
|
-
i0.ɵɵelementStart(0, "div",
|
|
631
|
-
i0.ɵɵrepeaterCreate(1,
|
|
766
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
767
|
+
i0.ɵɵelementStart(0, "div", 162);
|
|
768
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_2_For_2_Template, 12, 3, "div", 163, i0.ɵɵrepeaterTrackByIdentity);
|
|
632
769
|
i0.ɵɵelementEnd();
|
|
633
770
|
} if (rf & 2) {
|
|
634
771
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
635
772
|
i0.ɵɵadvance();
|
|
636
773
|
i0.ɵɵrepeater(ctx_r0.suiteTests);
|
|
637
774
|
} }
|
|
638
|
-
function
|
|
639
|
-
i0.ɵɵelementStart(0, "div",
|
|
640
|
-
i0.ɵɵelement(2, "i",
|
|
775
|
+
function MJTestFormComponentExtended_Conditional_66_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
776
|
+
i0.ɵɵelementStart(0, "div", 125)(1, "div", 160);
|
|
777
|
+
i0.ɵɵelement(2, "i", 170);
|
|
641
778
|
i0.ɵɵelementEnd();
|
|
642
779
|
i0.ɵɵelementStart(3, "h4");
|
|
643
780
|
i0.ɵɵtext(4, "Not Part of Any Suite");
|
|
@@ -646,11 +783,11 @@ function MJTestFormComponentExtended_Conditional_64_Conditional_3_Template(rf, c
|
|
|
646
783
|
i0.ɵɵtext(6, "This test is not included in any test suites. Add it to a suite to run it with other tests.");
|
|
647
784
|
i0.ɵɵelementEnd()();
|
|
648
785
|
} }
|
|
649
|
-
function
|
|
650
|
-
i0.ɵɵelementStart(0, "div",
|
|
651
|
-
i0.ɵɵconditionalCreate(1,
|
|
652
|
-
i0.ɵɵconditionalCreate(2,
|
|
653
|
-
i0.ɵɵconditionalCreate(3,
|
|
786
|
+
function MJTestFormComponentExtended_Conditional_66_Template(rf, ctx) { if (rf & 1) {
|
|
787
|
+
i0.ɵɵelementStart(0, "div", 39);
|
|
788
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_66_Conditional_1_Template, 4, 1, "div", 123);
|
|
789
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_66_Conditional_2_Template, 3, 0, "div", 162);
|
|
790
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_66_Conditional_3_Template, 7, 0, "div", 125);
|
|
654
791
|
i0.ɵɵelementEnd();
|
|
655
792
|
} if (rf & 2) {
|
|
656
793
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -661,20 +798,20 @@ function MJTestFormComponentExtended_Conditional_64_Template(rf, ctx) { if (rf &
|
|
|
661
798
|
i0.ɵɵadvance();
|
|
662
799
|
i0.ɵɵconditional(ctx_r0.suiteTestsLoaded && !ctx_r0.loadingSuites && ctx_r0.suiteTests.length === 0 ? 3 : -1);
|
|
663
800
|
} }
|
|
664
|
-
function
|
|
665
|
-
i0.ɵɵelementStart(0, "div",
|
|
666
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
801
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
802
|
+
i0.ɵɵelementStart(0, "div", 123);
|
|
803
|
+
i0.ɵɵelement(1, "mj-loading", 172);
|
|
667
804
|
i0.ɵɵelementEnd();
|
|
668
805
|
} }
|
|
669
|
-
function
|
|
670
|
-
i0.ɵɵelementStart(0, "div",
|
|
671
|
-
i0.ɵɵelement(2, "i",
|
|
806
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
807
|
+
i0.ɵɵelementStart(0, "div", 181)(1, "div", 186);
|
|
808
|
+
i0.ɵɵelement(2, "i", 187);
|
|
672
809
|
i0.ɵɵelementEnd();
|
|
673
|
-
i0.ɵɵelementStart(3, "div",
|
|
810
|
+
i0.ɵɵelementStart(3, "div", 183)(4, "div", 184);
|
|
674
811
|
i0.ɵɵtext(5);
|
|
675
|
-
i0.ɵɵelement(6, "i",
|
|
812
|
+
i0.ɵɵelement(6, "i", 188);
|
|
676
813
|
i0.ɵɵelementEnd();
|
|
677
|
-
i0.ɵɵelementStart(7, "div",
|
|
814
|
+
i0.ɵɵelementStart(7, "div", 185);
|
|
678
815
|
i0.ɵɵtext(8, "Pass Rate");
|
|
679
816
|
i0.ɵɵelementEnd()()();
|
|
680
817
|
} if (rf & 2) {
|
|
@@ -684,14 +821,14 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Conditional_17
|
|
|
684
821
|
i0.ɵɵadvance();
|
|
685
822
|
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");
|
|
686
823
|
} }
|
|
687
|
-
function
|
|
688
|
-
i0.ɵɵelementStart(0, "div",
|
|
689
|
-
i0.ɵɵelement(2, "i",
|
|
824
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
825
|
+
i0.ɵɵelementStart(0, "div", 181)(1, "div", 182);
|
|
826
|
+
i0.ɵɵelement(2, "i", 189);
|
|
690
827
|
i0.ɵɵelementEnd();
|
|
691
|
-
i0.ɵɵelementStart(3, "div",
|
|
828
|
+
i0.ɵɵelementStart(3, "div", 183)(4, "div", 184);
|
|
692
829
|
i0.ɵɵtext(5);
|
|
693
830
|
i0.ɵɵelementEnd();
|
|
694
|
-
i0.ɵɵelementStart(6, "div",
|
|
831
|
+
i0.ɵɵelementStart(6, "div", 185);
|
|
695
832
|
i0.ɵɵtext(7, "Avg Score");
|
|
696
833
|
i0.ɵɵelementEnd()()();
|
|
697
834
|
} if (rf & 2) {
|
|
@@ -699,34 +836,34 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Conditional_17
|
|
|
699
836
|
i0.ɵɵadvance(5);
|
|
700
837
|
i0.ɵɵtextInterpolate1("", (ctx_r0.getOverallAvgScore() * 100).toFixed(1), "%");
|
|
701
838
|
} }
|
|
702
|
-
function
|
|
703
|
-
i0.ɵɵelementStart(0, "div",
|
|
704
|
-
i0.ɵɵelement(3, "i",
|
|
839
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
840
|
+
i0.ɵɵelementStart(0, "div", 179)(1, "div", 181)(2, "div", 182);
|
|
841
|
+
i0.ɵɵelement(3, "i", 161);
|
|
705
842
|
i0.ɵɵelementEnd();
|
|
706
|
-
i0.ɵɵelementStart(4, "div",
|
|
843
|
+
i0.ɵɵelementStart(4, "div", 183)(5, "div", 184);
|
|
707
844
|
i0.ɵɵtext(6);
|
|
708
845
|
i0.ɵɵelementEnd();
|
|
709
|
-
i0.ɵɵelementStart(7, "div",
|
|
846
|
+
i0.ɵɵelementStart(7, "div", 185);
|
|
710
847
|
i0.ɵɵtext(8, "Total Runs");
|
|
711
848
|
i0.ɵɵelementEnd()()();
|
|
712
|
-
i0.ɵɵconditionalCreate(9,
|
|
713
|
-
i0.ɵɵconditionalCreate(10,
|
|
714
|
-
i0.ɵɵelementStart(11, "div",
|
|
715
|
-
i0.ɵɵelement(13, "i",
|
|
849
|
+
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_9_Template, 9, 11, "div", 181);
|
|
850
|
+
i0.ɵɵconditionalCreate(10, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Conditional_10_Template, 8, 1, "div", 181);
|
|
851
|
+
i0.ɵɵelementStart(11, "div", 181)(12, "div", 182);
|
|
852
|
+
i0.ɵɵelement(13, "i", 147);
|
|
716
853
|
i0.ɵɵelementEnd();
|
|
717
|
-
i0.ɵɵelementStart(14, "div",
|
|
854
|
+
i0.ɵɵelementStart(14, "div", 183)(15, "div", 184);
|
|
718
855
|
i0.ɵɵtext(16);
|
|
719
856
|
i0.ɵɵelementEnd();
|
|
720
|
-
i0.ɵɵelementStart(17, "div",
|
|
857
|
+
i0.ɵɵelementStart(17, "div", 185);
|
|
721
858
|
i0.ɵɵtext(18, "Avg Duration");
|
|
722
859
|
i0.ɵɵelementEnd()()();
|
|
723
|
-
i0.ɵɵelementStart(19, "div",
|
|
724
|
-
i0.ɵɵelement(21, "i",
|
|
860
|
+
i0.ɵɵelementStart(19, "div", 181)(20, "div", 182);
|
|
861
|
+
i0.ɵɵelement(21, "i", 148);
|
|
725
862
|
i0.ɵɵelementEnd();
|
|
726
|
-
i0.ɵɵelementStart(22, "div",
|
|
863
|
+
i0.ɵɵelementStart(22, "div", 183)(23, "div", 184);
|
|
727
864
|
i0.ɵɵtext(24);
|
|
728
865
|
i0.ɵɵelementEnd();
|
|
729
|
-
i0.ɵɵelementStart(25, "div",
|
|
866
|
+
i0.ɵɵelementStart(25, "div", 185);
|
|
730
867
|
i0.ɵɵtext(26, "Avg Cost");
|
|
731
868
|
i0.ɵɵelementEnd()()()();
|
|
732
869
|
} if (rf & 2) {
|
|
@@ -742,91 +879,91 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Conditional_17
|
|
|
742
879
|
i0.ɵɵadvance(8);
|
|
743
880
|
i0.ɵɵtextInterpolate(ctx_r0.formatCost(ctx_r0.getOverallAvgCost()));
|
|
744
881
|
} }
|
|
745
|
-
function
|
|
882
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
746
883
|
i0.ɵɵelementStart(0, "th");
|
|
747
884
|
i0.ɵɵtext(1, "Passed");
|
|
748
885
|
i0.ɵɵelementEnd();
|
|
749
886
|
} }
|
|
750
|
-
function
|
|
887
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
751
888
|
i0.ɵɵelementStart(0, "th");
|
|
752
889
|
i0.ɵɵtext(1, "Failed");
|
|
753
890
|
i0.ɵɵelementEnd();
|
|
754
891
|
} }
|
|
755
|
-
function
|
|
892
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
756
893
|
i0.ɵɵelementStart(0, "th");
|
|
757
894
|
i0.ɵɵtext(1, "Pass Rate");
|
|
758
895
|
i0.ɵɵelementEnd();
|
|
759
896
|
} }
|
|
760
|
-
function
|
|
897
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
761
898
|
i0.ɵɵelementStart(0, "th");
|
|
762
899
|
i0.ɵɵtext(1, "Avg Score");
|
|
763
900
|
i0.ɵɵelementEnd();
|
|
764
901
|
} }
|
|
765
|
-
function
|
|
766
|
-
i0.ɵɵelementStart(0, "td",
|
|
902
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
903
|
+
i0.ɵɵelementStart(0, "td", 195);
|
|
767
904
|
i0.ɵɵtext(1);
|
|
768
905
|
i0.ɵɵelementEnd();
|
|
769
906
|
} if (rf & 2) {
|
|
770
|
-
const
|
|
907
|
+
const day_r17 = i0.ɵɵnextContext().$implicit;
|
|
771
908
|
i0.ɵɵadvance();
|
|
772
|
-
i0.ɵɵtextInterpolate(
|
|
909
|
+
i0.ɵɵtextInterpolate(day_r17.passCount);
|
|
773
910
|
} }
|
|
774
|
-
function
|
|
775
|
-
i0.ɵɵelementStart(0, "td",
|
|
911
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
912
|
+
i0.ɵɵelementStart(0, "td", 196);
|
|
776
913
|
i0.ɵɵtext(1);
|
|
777
914
|
i0.ɵɵelementEnd();
|
|
778
915
|
} if (rf & 2) {
|
|
779
|
-
const
|
|
916
|
+
const day_r17 = i0.ɵɵnextContext().$implicit;
|
|
780
917
|
i0.ɵɵadvance();
|
|
781
|
-
i0.ɵɵtextInterpolate(
|
|
918
|
+
i0.ɵɵtextInterpolate(day_r17.failCount);
|
|
782
919
|
} }
|
|
783
|
-
function
|
|
784
|
-
i0.ɵɵelementStart(0, "td",
|
|
785
|
-
i0.ɵɵelement(2, "div",
|
|
786
|
-
i0.ɵɵelementStart(3, "span",
|
|
920
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
921
|
+
i0.ɵɵelementStart(0, "td", 197)(1, "div", 201);
|
|
922
|
+
i0.ɵɵelement(2, "div", 202);
|
|
923
|
+
i0.ɵɵelementStart(3, "span", 203);
|
|
787
924
|
i0.ɵɵtext(4);
|
|
788
925
|
i0.ɵɵelementEnd()()();
|
|
789
926
|
} if (rf & 2) {
|
|
790
|
-
const
|
|
927
|
+
const day_r17 = i0.ɵɵnextContext().$implicit;
|
|
791
928
|
i0.ɵɵadvance(2);
|
|
792
|
-
i0.ɵɵstyleProp("width",
|
|
929
|
+
i0.ɵɵstyleProp("width", day_r17.passRate, "%");
|
|
793
930
|
i0.ɵɵadvance(2);
|
|
794
|
-
i0.ɵɵtextInterpolate1("",
|
|
931
|
+
i0.ɵɵtextInterpolate1("", day_r17.passRate.toFixed(1), "%");
|
|
795
932
|
} }
|
|
796
|
-
function
|
|
797
|
-
i0.ɵɵelementStart(0, "td",
|
|
933
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
934
|
+
i0.ɵɵelementStart(0, "td", 198);
|
|
798
935
|
i0.ɵɵtext(1);
|
|
799
936
|
i0.ɵɵelementEnd();
|
|
800
937
|
} if (rf & 2) {
|
|
801
|
-
const
|
|
938
|
+
const day_r17 = i0.ɵɵnextContext().$implicit;
|
|
802
939
|
i0.ɵɵadvance();
|
|
803
|
-
i0.ɵɵtextInterpolate1("", (
|
|
940
|
+
i0.ɵɵtextInterpolate1("", (day_r17.avgScore * 100).toFixed(1), "%");
|
|
804
941
|
} }
|
|
805
|
-
function
|
|
806
|
-
i0.ɵɵelementStart(0, "tr")(1, "td",
|
|
942
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Template(rf, ctx) { if (rf & 1) {
|
|
943
|
+
i0.ɵɵelementStart(0, "tr")(1, "td", 193);
|
|
807
944
|
i0.ɵɵtext(2);
|
|
808
945
|
i0.ɵɵpipe(3, "date");
|
|
809
946
|
i0.ɵɵelementEnd();
|
|
810
|
-
i0.ɵɵelementStart(4, "td",
|
|
947
|
+
i0.ɵɵelementStart(4, "td", 194);
|
|
811
948
|
i0.ɵɵtext(5);
|
|
812
949
|
i0.ɵɵelementEnd();
|
|
813
|
-
i0.ɵɵconditionalCreate(6,
|
|
814
|
-
i0.ɵɵconditionalCreate(7,
|
|
815
|
-
i0.ɵɵconditionalCreate(8,
|
|
816
|
-
i0.ɵɵconditionalCreate(9,
|
|
817
|
-
i0.ɵɵelementStart(10, "td",
|
|
950
|
+
i0.ɵɵconditionalCreate(6, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_6_Template, 2, 1, "td", 195);
|
|
951
|
+
i0.ɵɵconditionalCreate(7, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_7_Template, 2, 1, "td", 196);
|
|
952
|
+
i0.ɵɵconditionalCreate(8, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_8_Template, 5, 3, "td", 197);
|
|
953
|
+
i0.ɵɵconditionalCreate(9, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Conditional_9_Template, 2, 1, "td", 198);
|
|
954
|
+
i0.ɵɵelementStart(10, "td", 199);
|
|
818
955
|
i0.ɵɵtext(11);
|
|
819
956
|
i0.ɵɵelementEnd();
|
|
820
|
-
i0.ɵɵelementStart(12, "td",
|
|
957
|
+
i0.ɵɵelementStart(12, "td", 200);
|
|
821
958
|
i0.ɵɵtext(13);
|
|
822
959
|
i0.ɵɵelementEnd()();
|
|
823
960
|
} if (rf & 2) {
|
|
824
|
-
const
|
|
961
|
+
const day_r17 = ctx.$implicit;
|
|
825
962
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
826
963
|
i0.ɵɵadvance(2);
|
|
827
|
-
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 8,
|
|
964
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 8, day_r17.date, "mediumDate"));
|
|
828
965
|
i0.ɵɵadvance(3);
|
|
829
|
-
i0.ɵɵtextInterpolate(
|
|
966
|
+
i0.ɵɵtextInterpolate(day_r17.runCount);
|
|
830
967
|
i0.ɵɵadvance();
|
|
831
968
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 6 : -1);
|
|
832
969
|
i0.ɵɵadvance();
|
|
@@ -836,25 +973,25 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Conditional_18
|
|
|
836
973
|
i0.ɵɵadvance();
|
|
837
974
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 9 : -1);
|
|
838
975
|
i0.ɵɵadvance(2);
|
|
839
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(
|
|
976
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(day_r17.avgDuration));
|
|
840
977
|
i0.ɵɵadvance(2);
|
|
841
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatCost(
|
|
978
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatCost(day_r17.avgCost));
|
|
842
979
|
} }
|
|
843
|
-
function
|
|
844
|
-
i0.ɵɵelementStart(0, "div",
|
|
845
|
-
i0.ɵɵelement(2, "i",
|
|
980
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
981
|
+
i0.ɵɵelementStart(0, "div", 180)(1, "h3");
|
|
982
|
+
i0.ɵɵelement(2, "i", 190);
|
|
846
983
|
i0.ɵɵtext(3, " Daily Performance");
|
|
847
984
|
i0.ɵɵelementEnd();
|
|
848
|
-
i0.ɵɵelementStart(4, "div",
|
|
985
|
+
i0.ɵɵelementStart(4, "div", 191)(5, "table", 192)(6, "thead")(7, "tr")(8, "th");
|
|
849
986
|
i0.ɵɵtext(9, "Date");
|
|
850
987
|
i0.ɵɵelementEnd();
|
|
851
988
|
i0.ɵɵelementStart(10, "th");
|
|
852
989
|
i0.ɵɵtext(11, "Runs");
|
|
853
990
|
i0.ɵɵelementEnd();
|
|
854
|
-
i0.ɵɵconditionalCreate(12,
|
|
855
|
-
i0.ɵɵconditionalCreate(13,
|
|
856
|
-
i0.ɵɵconditionalCreate(14,
|
|
857
|
-
i0.ɵɵconditionalCreate(15,
|
|
991
|
+
i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_12_Template, 2, 0, "th");
|
|
992
|
+
i0.ɵɵconditionalCreate(13, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_13_Template, 2, 0, "th");
|
|
993
|
+
i0.ɵɵconditionalCreate(14, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_14_Template, 2, 0, "th");
|
|
994
|
+
i0.ɵɵconditionalCreate(15, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Conditional_15_Template, 2, 0, "th");
|
|
858
995
|
i0.ɵɵelementStart(16, "th");
|
|
859
996
|
i0.ɵɵtext(17, "Avg Duration");
|
|
860
997
|
i0.ɵɵelementEnd();
|
|
@@ -862,7 +999,7 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Conditional_18
|
|
|
862
999
|
i0.ɵɵtext(19, "Avg Cost");
|
|
863
1000
|
i0.ɵɵelementEnd()()();
|
|
864
1001
|
i0.ɵɵelementStart(20, "tbody");
|
|
865
|
-
i0.ɵɵrepeaterCreate(21,
|
|
1002
|
+
i0.ɵɵrepeaterCreate(21, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_For_22_Template, 14, 11, "tr", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
866
1003
|
i0.ɵɵelementEnd()()()();
|
|
867
1004
|
} if (rf & 2) {
|
|
868
1005
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
@@ -877,145 +1014,145 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Conditional_18
|
|
|
877
1014
|
i0.ɵɵadvance(6);
|
|
878
1015
|
i0.ɵɵrepeater(ctx_r0.historyData);
|
|
879
1016
|
} }
|
|
880
|
-
function
|
|
881
|
-
i0.ɵɵelementStart(0, "span",
|
|
1017
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
1018
|
+
i0.ɵɵelementStart(0, "span", 215);
|
|
882
1019
|
i0.ɵɵtext(1);
|
|
883
1020
|
i0.ɵɵelementEnd();
|
|
884
1021
|
} if (rf & 2) {
|
|
885
|
-
const
|
|
1022
|
+
const tag_r20 = ctx.$implicit;
|
|
886
1023
|
i0.ɵɵadvance();
|
|
887
|
-
i0.ɵɵtextInterpolate(
|
|
1024
|
+
i0.ɵɵtextInterpolate(tag_r20);
|
|
888
1025
|
} }
|
|
889
|
-
function
|
|
890
|
-
i0.ɵɵelementStart(0, "span",
|
|
1026
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
1027
|
+
i0.ɵɵelementStart(0, "span", 216);
|
|
891
1028
|
i0.ɵɵtext(1);
|
|
892
1029
|
i0.ɵɵelementEnd();
|
|
893
1030
|
} if (rf & 2) {
|
|
894
|
-
const
|
|
1031
|
+
const suite_r19 = i0.ɵɵnextContext(2).$implicit;
|
|
895
1032
|
i0.ɵɵadvance();
|
|
896
|
-
i0.ɵɵtextInterpolate1("+",
|
|
1033
|
+
i0.ɵɵtextInterpolate1("+", suite_r19.tags.length - 3);
|
|
897
1034
|
} }
|
|
898
|
-
function
|
|
899
|
-
i0.ɵɵelementStart(0, "div",
|
|
900
|
-
i0.ɵɵrepeaterCreate(1,
|
|
901
|
-
i0.ɵɵconditionalCreate(3,
|
|
1035
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
1036
|
+
i0.ɵɵelementStart(0, "div", 209);
|
|
1037
|
+
i0.ɵɵrepeaterCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_For_2_Template, 2, 1, "span", 215, i0.ɵɵrepeaterTrackByIdentity);
|
|
1038
|
+
i0.ɵɵconditionalCreate(3, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Conditional_3_Template, 2, 1, "span", 216);
|
|
902
1039
|
i0.ɵɵelementEnd();
|
|
903
1040
|
} if (rf & 2) {
|
|
904
|
-
const
|
|
1041
|
+
const suite_r19 = i0.ɵɵnextContext().$implicit;
|
|
905
1042
|
i0.ɵɵadvance();
|
|
906
|
-
i0.ɵɵrepeater(
|
|
1043
|
+
i0.ɵɵrepeater(suite_r19.tags.slice(0, 3));
|
|
907
1044
|
i0.ɵɵadvance(2);
|
|
908
|
-
i0.ɵɵconditional(
|
|
1045
|
+
i0.ɵɵconditional(suite_r19.tags.length > 3 ? 3 : -1);
|
|
909
1046
|
} }
|
|
910
|
-
function
|
|
911
|
-
i0.ɵɵelementStart(0, "div",
|
|
1047
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
1048
|
+
i0.ɵɵelementStart(0, "div", 211)(1, "span", 217);
|
|
912
1049
|
i0.ɵɵtext(2);
|
|
913
1050
|
i0.ɵɵelementEnd();
|
|
914
|
-
i0.ɵɵelementStart(3, "span",
|
|
1051
|
+
i0.ɵɵelementStart(3, "span", 213);
|
|
915
1052
|
i0.ɵɵtext(4, "Pass Rate");
|
|
916
1053
|
i0.ɵɵelementEnd()();
|
|
917
1054
|
} if (rf & 2) {
|
|
918
|
-
const
|
|
1055
|
+
const suite_r19 = i0.ɵɵnextContext().$implicit;
|
|
919
1056
|
i0.ɵɵadvance();
|
|
920
|
-
i0.ɵɵclassProp("high",
|
|
1057
|
+
i0.ɵɵclassProp("high", suite_r19.passRate >= 80)("low", suite_r19.passRate < 50);
|
|
921
1058
|
i0.ɵɵadvance();
|
|
922
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
1059
|
+
i0.ɵɵtextInterpolate1(" ", suite_r19.passRate.toFixed(1), "% ");
|
|
923
1060
|
} }
|
|
924
|
-
function
|
|
925
|
-
i0.ɵɵelementStart(0, "div",
|
|
1061
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
1062
|
+
i0.ɵɵelementStart(0, "div", 211)(1, "span", 212);
|
|
926
1063
|
i0.ɵɵtext(2);
|
|
927
1064
|
i0.ɵɵelementEnd();
|
|
928
|
-
i0.ɵɵelementStart(3, "span",
|
|
1065
|
+
i0.ɵɵelementStart(3, "span", 213);
|
|
929
1066
|
i0.ɵɵtext(4, "Avg Score");
|
|
930
1067
|
i0.ɵɵelementEnd()();
|
|
931
1068
|
} if (rf & 2) {
|
|
932
|
-
const
|
|
1069
|
+
const suite_r19 = i0.ɵɵnextContext().$implicit;
|
|
933
1070
|
i0.ɵɵadvance(2);
|
|
934
|
-
i0.ɵɵtextInterpolate1("", (
|
|
1071
|
+
i0.ɵɵtextInterpolate1("", (suite_r19.avgScore * 100).toFixed(1), "%");
|
|
935
1072
|
} }
|
|
936
|
-
function
|
|
937
|
-
i0.ɵɵelementStart(0, "div",
|
|
1073
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
1074
|
+
i0.ɵɵelementStart(0, "div", 211)(1, "span", 212);
|
|
938
1075
|
i0.ɵɵtext(2);
|
|
939
1076
|
i0.ɵɵelementEnd();
|
|
940
|
-
i0.ɵɵelementStart(3, "span",
|
|
1077
|
+
i0.ɵɵelementStart(3, "span", 213);
|
|
941
1078
|
i0.ɵɵtext(4, "Last Run");
|
|
942
1079
|
i0.ɵɵelementEnd()();
|
|
943
1080
|
} if (rf & 2) {
|
|
944
|
-
const
|
|
1081
|
+
const suite_r19 = i0.ɵɵnextContext().$implicit;
|
|
945
1082
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
946
1083
|
i0.ɵɵadvance(2);
|
|
947
|
-
i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(
|
|
1084
|
+
i0.ɵɵtextInterpolate(ctx_r0.getRelativeTime(suite_r19.lastRun));
|
|
948
1085
|
} }
|
|
949
|
-
function
|
|
950
|
-
const
|
|
951
|
-
i0.ɵɵelementStart(0, "div",
|
|
952
|
-
i0.ɵɵlistener("click", function
|
|
953
|
-
i0.ɵɵelementStart(1, "div",
|
|
1086
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template(rf, ctx) { if (rf & 1) {
|
|
1087
|
+
const _r18 = i0.ɵɵgetCurrentView();
|
|
1088
|
+
i0.ɵɵelementStart(0, "div", 206);
|
|
1089
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template_div_click_0_listener() { const suite_r19 = i0.ɵɵrestoreView(_r18).$implicit; const ctx_r0 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r0.openSuiteFromHistory(suite_r19.suiteId)); });
|
|
1090
|
+
i0.ɵɵelementStart(1, "div", 207)(2, "div", 208);
|
|
954
1091
|
i0.ɵɵtext(3);
|
|
955
1092
|
i0.ɵɵelementEnd();
|
|
956
|
-
i0.ɵɵconditionalCreate(4,
|
|
1093
|
+
i0.ɵɵconditionalCreate(4, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_4_Template, 4, 1, "div", 209);
|
|
957
1094
|
i0.ɵɵelementEnd();
|
|
958
|
-
i0.ɵɵelementStart(5, "div",
|
|
1095
|
+
i0.ɵɵelementStart(5, "div", 210)(6, "div", 211)(7, "span", 212);
|
|
959
1096
|
i0.ɵɵtext(8);
|
|
960
1097
|
i0.ɵɵelementEnd();
|
|
961
|
-
i0.ɵɵelementStart(9, "span",
|
|
1098
|
+
i0.ɵɵelementStart(9, "span", 213);
|
|
962
1099
|
i0.ɵɵtext(10, "Runs");
|
|
963
1100
|
i0.ɵɵelementEnd()();
|
|
964
|
-
i0.ɵɵconditionalCreate(11,
|
|
965
|
-
i0.ɵɵconditionalCreate(12,
|
|
966
|
-
i0.ɵɵelementStart(13, "div",
|
|
1101
|
+
i0.ɵɵconditionalCreate(11, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_11_Template, 5, 5, "div", 211);
|
|
1102
|
+
i0.ɵɵconditionalCreate(12, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_12_Template, 5, 1, "div", 211);
|
|
1103
|
+
i0.ɵɵelementStart(13, "div", 211)(14, "span", 212);
|
|
967
1104
|
i0.ɵɵtext(15);
|
|
968
1105
|
i0.ɵɵelementEnd();
|
|
969
|
-
i0.ɵɵelementStart(16, "span",
|
|
1106
|
+
i0.ɵɵelementStart(16, "span", 213);
|
|
970
1107
|
i0.ɵɵtext(17, "Avg Duration");
|
|
971
1108
|
i0.ɵɵelementEnd()();
|
|
972
|
-
i0.ɵɵelementStart(18, "div",
|
|
1109
|
+
i0.ɵɵelementStart(18, "div", 211)(19, "span", 212);
|
|
973
1110
|
i0.ɵɵtext(20);
|
|
974
1111
|
i0.ɵɵelementEnd();
|
|
975
|
-
i0.ɵɵelementStart(21, "span",
|
|
1112
|
+
i0.ɵɵelementStart(21, "span", 213);
|
|
976
1113
|
i0.ɵɵtext(22, "Avg Cost");
|
|
977
1114
|
i0.ɵɵelementEnd()();
|
|
978
|
-
i0.ɵɵconditionalCreate(23,
|
|
1115
|
+
i0.ɵɵconditionalCreate(23, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Conditional_23_Template, 5, 1, "div", 211);
|
|
979
1116
|
i0.ɵɵelementEnd();
|
|
980
|
-
i0.ɵɵelement(24, "i",
|
|
1117
|
+
i0.ɵɵelement(24, "i", 214);
|
|
981
1118
|
i0.ɵɵelementEnd();
|
|
982
1119
|
} if (rf & 2) {
|
|
983
|
-
const
|
|
1120
|
+
const suite_r19 = ctx.$implicit;
|
|
984
1121
|
const ctx_r0 = i0.ɵɵnextContext(4);
|
|
985
1122
|
i0.ɵɵadvance(3);
|
|
986
|
-
i0.ɵɵtextInterpolate(
|
|
1123
|
+
i0.ɵɵtextInterpolate(suite_r19.suiteName);
|
|
987
1124
|
i0.ɵɵadvance();
|
|
988
|
-
i0.ɵɵconditional(
|
|
1125
|
+
i0.ɵɵconditional(suite_r19.tags.length > 0 ? 4 : -1);
|
|
989
1126
|
i0.ɵɵadvance(4);
|
|
990
|
-
i0.ɵɵtextInterpolate(
|
|
1127
|
+
i0.ɵɵtextInterpolate(suite_r19.totalRuns);
|
|
991
1128
|
i0.ɵɵadvance(3);
|
|
992
1129
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showExecution ? 11 : -1);
|
|
993
1130
|
i0.ɵɵadvance();
|
|
994
1131
|
i0.ɵɵconditional(ctx_r0.evalPreferences.showAuto ? 12 : -1);
|
|
995
1132
|
i0.ɵɵadvance(3);
|
|
996
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(
|
|
1133
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatDuration(suite_r19.avgDuration));
|
|
997
1134
|
i0.ɵɵadvance(5);
|
|
998
|
-
i0.ɵɵtextInterpolate(ctx_r0.formatCost(
|
|
1135
|
+
i0.ɵɵtextInterpolate(ctx_r0.formatCost(suite_r19.avgCost));
|
|
999
1136
|
i0.ɵɵadvance(3);
|
|
1000
|
-
i0.ɵɵconditional(
|
|
1137
|
+
i0.ɵɵconditional(suite_r19.lastRun ? 23 : -1);
|
|
1001
1138
|
} }
|
|
1002
|
-
function
|
|
1003
|
-
i0.ɵɵelementStart(0, "div",
|
|
1004
|
-
i0.ɵɵelement(2, "i",
|
|
1139
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
1140
|
+
i0.ɵɵelementStart(0, "div", 180)(1, "h3");
|
|
1141
|
+
i0.ɵɵelement(2, "i", 33);
|
|
1005
1142
|
i0.ɵɵtext(3, " Performance by Suite");
|
|
1006
1143
|
i0.ɵɵelementEnd();
|
|
1007
|
-
i0.ɵɵelementStart(4, "div",
|
|
1008
|
-
i0.ɵɵrepeaterCreate(5,
|
|
1144
|
+
i0.ɵɵelementStart(4, "div", 204);
|
|
1145
|
+
i0.ɵɵrepeaterCreate(5, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_For_6_Template, 25, 8, "div", 205, i0.ɵɵrepeaterTrackByIdentity);
|
|
1009
1146
|
i0.ɵɵelementEnd()();
|
|
1010
1147
|
} if (rf & 2) {
|
|
1011
1148
|
const ctx_r0 = i0.ɵɵnextContext(3);
|
|
1012
1149
|
i0.ɵɵadvance(5);
|
|
1013
1150
|
i0.ɵɵrepeater(ctx_r0.suitePerformance);
|
|
1014
1151
|
} }
|
|
1015
|
-
function
|
|
1016
|
-
const
|
|
1017
|
-
i0.ɵɵelementStart(0, "div",
|
|
1018
|
-
i0.ɵɵelement(2, "i",
|
|
1152
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
1153
|
+
const _r21 = i0.ɵɵgetCurrentView();
|
|
1154
|
+
i0.ɵɵelementStart(0, "div", 125)(1, "div", 160);
|
|
1155
|
+
i0.ɵɵelement(2, "i", 34);
|
|
1019
1156
|
i0.ɵɵelementEnd();
|
|
1020
1157
|
i0.ɵɵelementStart(3, "h4");
|
|
1021
1158
|
i0.ɵɵtext(4, "No History Available");
|
|
@@ -1023,42 +1160,42 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Conditional_20
|
|
|
1023
1160
|
i0.ɵɵelementStart(5, "p");
|
|
1024
1161
|
i0.ɵɵtext(6, "Run this test to start building history and analytics data.");
|
|
1025
1162
|
i0.ɵɵelementEnd();
|
|
1026
|
-
i0.ɵɵelementStart(7, "button",
|
|
1027
|
-
i0.ɵɵlistener("click", function
|
|
1028
|
-
i0.ɵɵelement(8, "i",
|
|
1163
|
+
i0.ɵɵelementStart(7, "button", 21);
|
|
1164
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r21); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.runTest()); });
|
|
1165
|
+
i0.ɵɵelement(8, "i", 22);
|
|
1029
1166
|
i0.ɵɵtext(9, " Run Test Now ");
|
|
1030
1167
|
i0.ɵɵelementEnd()();
|
|
1031
1168
|
} }
|
|
1032
|
-
function
|
|
1033
|
-
const
|
|
1034
|
-
i0.ɵɵelementStart(0, "div",
|
|
1169
|
+
function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
1170
|
+
const _r16 = i0.ɵɵgetCurrentView();
|
|
1171
|
+
i0.ɵɵelementStart(0, "div", 171)(1, "div", 173)(2, "div", 174)(3, "span", 175);
|
|
1035
1172
|
i0.ɵɵtext(4, "Time Range:");
|
|
1036
1173
|
i0.ɵɵelementEnd();
|
|
1037
|
-
i0.ɵɵelementStart(5, "button",
|
|
1038
|
-
i0.ɵɵlistener("click", function
|
|
1174
|
+
i0.ɵɵelementStart(5, "button", 176);
|
|
1175
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("7d")); });
|
|
1039
1176
|
i0.ɵɵtext(6, "7 Days");
|
|
1040
1177
|
i0.ɵɵelementEnd();
|
|
1041
|
-
i0.ɵɵelementStart(7, "button",
|
|
1042
|
-
i0.ɵɵlistener("click", function
|
|
1178
|
+
i0.ɵɵelementStart(7, "button", 176);
|
|
1179
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("30d")); });
|
|
1043
1180
|
i0.ɵɵtext(8, "30 Days");
|
|
1044
1181
|
i0.ɵɵelementEnd();
|
|
1045
|
-
i0.ɵɵelementStart(9, "button",
|
|
1046
|
-
i0.ɵɵlistener("click", function
|
|
1182
|
+
i0.ɵɵelementStart(9, "button", 176);
|
|
1183
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("90d")); });
|
|
1047
1184
|
i0.ɵɵtext(10, "90 Days");
|
|
1048
1185
|
i0.ɵɵelementEnd();
|
|
1049
|
-
i0.ɵɵelementStart(11, "button",
|
|
1050
|
-
i0.ɵɵlistener("click", function
|
|
1186
|
+
i0.ɵɵelementStart(11, "button", 176);
|
|
1187
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.setHistoryTimeRange("all")); });
|
|
1051
1188
|
i0.ɵɵtext(12, "All Time");
|
|
1052
1189
|
i0.ɵɵelementEnd()();
|
|
1053
|
-
i0.ɵɵelementStart(13, "div",
|
|
1054
|
-
i0.ɵɵlistener("click", function
|
|
1055
|
-
i0.ɵɵelement(15, "i",
|
|
1190
|
+
i0.ɵɵelementStart(13, "div", 177)(14, "button", 23);
|
|
1191
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_67_Conditional_2_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r16); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.exportHistoryToCSV()); });
|
|
1192
|
+
i0.ɵɵelement(15, "i", 178);
|
|
1056
1193
|
i0.ɵɵtext(16, " Export CSV ");
|
|
1057
1194
|
i0.ɵɵelementEnd()()();
|
|
1058
|
-
i0.ɵɵconditionalCreate(17,
|
|
1059
|
-
i0.ɵɵconditionalCreate(18,
|
|
1060
|
-
i0.ɵɵconditionalCreate(19,
|
|
1061
|
-
i0.ɵɵconditionalCreate(20,
|
|
1195
|
+
i0.ɵɵconditionalCreate(17, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_17_Template, 27, 5, "div", 179);
|
|
1196
|
+
i0.ɵɵconditionalCreate(18, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_18_Template, 23, 4, "div", 180);
|
|
1197
|
+
i0.ɵɵconditionalCreate(19, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_19_Template, 7, 0, "div", 180);
|
|
1198
|
+
i0.ɵɵconditionalCreate(20, MJTestFormComponentExtended_Conditional_67_Conditional_2_Conditional_20_Template, 10, 0, "div", 125);
|
|
1062
1199
|
i0.ɵɵelementEnd();
|
|
1063
1200
|
} if (rf & 2) {
|
|
1064
1201
|
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
@@ -1081,10 +1218,10 @@ function MJTestFormComponentExtended_Conditional_65_Conditional_2_Template(rf, c
|
|
|
1081
1218
|
i0.ɵɵadvance();
|
|
1082
1219
|
i0.ɵɵconditional(ctx_r0.historyData.length === 0 ? 20 : -1);
|
|
1083
1220
|
} }
|
|
1084
|
-
function
|
|
1085
|
-
i0.ɵɵelementStart(0, "div",
|
|
1086
|
-
i0.ɵɵconditionalCreate(1,
|
|
1087
|
-
i0.ɵɵconditionalCreate(2,
|
|
1221
|
+
function MJTestFormComponentExtended_Conditional_67_Template(rf, ctx) { if (rf & 1) {
|
|
1222
|
+
i0.ɵɵelementStart(0, "div", 40);
|
|
1223
|
+
i0.ɵɵconditionalCreate(1, MJTestFormComponentExtended_Conditional_67_Conditional_1_Template, 2, 0, "div", 123);
|
|
1224
|
+
i0.ɵɵconditionalCreate(2, MJTestFormComponentExtended_Conditional_67_Conditional_2_Template, 21, 13, "div", 171);
|
|
1088
1225
|
i0.ɵɵelementEnd();
|
|
1089
1226
|
} if (rf & 2) {
|
|
1090
1227
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -1093,50 +1230,59 @@ function MJTestFormComponentExtended_Conditional_65_Template(rf, ctx) { if (rf &
|
|
|
1093
1230
|
i0.ɵɵadvance();
|
|
1094
1231
|
i0.ɵɵconditional(!ctx_r0.loadingHistory && ctx_r0.historyLoaded ? 2 : -1);
|
|
1095
1232
|
} }
|
|
1096
|
-
function
|
|
1097
|
-
const
|
|
1098
|
-
i0.ɵɵelementStart(0, "div",
|
|
1099
|
-
i0.ɵɵelement(2, "i",
|
|
1233
|
+
function MJTestFormComponentExtended_Conditional_70_Template(rf, ctx) { if (rf & 1) {
|
|
1234
|
+
const _r22 = i0.ɵɵgetCurrentView();
|
|
1235
|
+
i0.ɵɵelementStart(0, "div", 43)(1, "div", 218);
|
|
1236
|
+
i0.ɵɵelement(2, "i", 42);
|
|
1100
1237
|
i0.ɵɵtext(3, " Shortcuts ");
|
|
1101
|
-
i0.ɵɵelementStart(4, "button",
|
|
1102
|
-
i0.ɵɵlistener("click", function
|
|
1103
|
-
i0.ɵɵelement(5, "i",
|
|
1238
|
+
i0.ɵɵelementStart(4, "button", 219);
|
|
1239
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Conditional_70_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r22); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleShortcuts()); });
|
|
1240
|
+
i0.ɵɵelement(5, "i", 122);
|
|
1104
1241
|
i0.ɵɵelementEnd()();
|
|
1105
|
-
i0.ɵɵelementStart(6, "div",
|
|
1106
|
-
i0.ɵɵtext(9, "
|
|
1242
|
+
i0.ɵɵelementStart(6, "div", 220)(7, "div", 221)(8, "span");
|
|
1243
|
+
i0.ɵɵtext(9, "Save changes");
|
|
1107
1244
|
i0.ɵɵelementEnd();
|
|
1108
|
-
i0.ɵɵelementStart(10, "span",
|
|
1245
|
+
i0.ɵɵelementStart(10, "span", 222)(11, "kbd");
|
|
1109
1246
|
i0.ɵɵtext(12, "Cmd");
|
|
1110
1247
|
i0.ɵɵelementEnd();
|
|
1111
1248
|
i0.ɵɵelementStart(13, "kbd");
|
|
1112
|
-
i0.ɵɵtext(14, "
|
|
1249
|
+
i0.ɵɵtext(14, "S");
|
|
1113
1250
|
i0.ɵɵelementEnd()()();
|
|
1114
|
-
i0.ɵɵelementStart(15, "div",
|
|
1115
|
-
i0.ɵɵtext(17, "
|
|
1251
|
+
i0.ɵɵelementStart(15, "div", 221)(16, "span");
|
|
1252
|
+
i0.ɵɵtext(17, "Refresh");
|
|
1116
1253
|
i0.ɵɵelementEnd();
|
|
1117
|
-
i0.ɵɵelementStart(18, "span",
|
|
1254
|
+
i0.ɵɵelementStart(18, "span", 222)(19, "kbd");
|
|
1118
1255
|
i0.ɵɵtext(20, "Cmd");
|
|
1119
1256
|
i0.ɵɵelementEnd();
|
|
1120
1257
|
i0.ɵɵelementStart(21, "kbd");
|
|
1121
|
-
i0.ɵɵtext(22, "
|
|
1258
|
+
i0.ɵɵtext(22, "R");
|
|
1259
|
+
i0.ɵɵelementEnd()()();
|
|
1260
|
+
i0.ɵɵelementStart(23, "div", 221)(24, "span");
|
|
1261
|
+
i0.ɵɵtext(25, "Run Test");
|
|
1262
|
+
i0.ɵɵelementEnd();
|
|
1263
|
+
i0.ɵɵelementStart(26, "span", 222)(27, "kbd");
|
|
1264
|
+
i0.ɵɵtext(28, "Cmd");
|
|
1265
|
+
i0.ɵɵelementEnd();
|
|
1266
|
+
i0.ɵɵelementStart(29, "kbd");
|
|
1267
|
+
i0.ɵɵtext(30, "Enter");
|
|
1122
1268
|
i0.ɵɵelementEnd()()();
|
|
1123
|
-
i0.ɵɵelementStart(
|
|
1124
|
-
i0.ɵɵtext(
|
|
1269
|
+
i0.ɵɵelementStart(31, "div", 221)(32, "span");
|
|
1270
|
+
i0.ɵɵtext(33, "Switch Tabs");
|
|
1125
1271
|
i0.ɵɵelementEnd();
|
|
1126
|
-
i0.ɵɵelementStart(
|
|
1127
|
-
i0.ɵɵtext(
|
|
1272
|
+
i0.ɵɵelementStart(34, "span", 222)(35, "kbd");
|
|
1273
|
+
i0.ɵɵtext(36, "1");
|
|
1128
1274
|
i0.ɵɵelementEnd();
|
|
1129
|
-
i0.ɵɵtext(
|
|
1130
|
-
i0.ɵɵelementStart(
|
|
1131
|
-
i0.ɵɵtext(
|
|
1275
|
+
i0.ɵɵtext(37, "-");
|
|
1276
|
+
i0.ɵɵelementStart(38, "kbd");
|
|
1277
|
+
i0.ɵɵtext(39, "5");
|
|
1132
1278
|
i0.ɵɵelementEnd()()()()();
|
|
1133
1279
|
} }
|
|
1134
|
-
function
|
|
1135
|
-
const
|
|
1136
|
-
i0.ɵɵelementStart(0, "mj-slide-panel",
|
|
1137
|
-
i0.ɵɵlistener("Closed", function
|
|
1138
|
-
i0.ɵɵelementStart(1, "app-test-run-dialog",
|
|
1139
|
-
i0.ɵɵlistener("PanelClose", function
|
|
1280
|
+
function MJTestFormComponentExtended_Conditional_71_Template(rf, ctx) { if (rf & 1) {
|
|
1281
|
+
const _r23 = i0.ɵɵgetCurrentView();
|
|
1282
|
+
i0.ɵɵelementStart(0, "mj-slide-panel", 223);
|
|
1283
|
+
i0.ɵɵlistener("Closed", function MJTestFormComponentExtended_Conditional_71_Template_mj_slide_panel_Closed_0_listener() { i0.ɵɵrestoreView(_r23); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
|
|
1284
|
+
i0.ɵɵelementStart(1, "app-test-run-dialog", 224);
|
|
1285
|
+
i0.ɵɵlistener("PanelClose", function MJTestFormComponentExtended_Conditional_71_Template_app_test_run_dialog_PanelClose_1_listener() { i0.ɵɵrestoreView(_r23); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnPanelClosed()); });
|
|
1140
1286
|
i0.ɵɵelementEnd()();
|
|
1141
1287
|
} if (rf & 2) {
|
|
1142
1288
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -1144,6 +1290,32 @@ function MJTestFormComponentExtended_Conditional_69_Template(rf, ctx) { if (rf &
|
|
|
1144
1290
|
i0.ɵɵadvance();
|
|
1145
1291
|
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");
|
|
1146
1292
|
} }
|
|
1293
|
+
function MJTestFormComponentExtended_Conditional_80_Template(rf, ctx) { if (rf & 1) {
|
|
1294
|
+
i0.ɵɵtext(0);
|
|
1295
|
+
} if (rf & 2) {
|
|
1296
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
1297
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.dirtyFieldNames[0], " edited ");
|
|
1298
|
+
} }
|
|
1299
|
+
function MJTestFormComponentExtended_Conditional_81_Template(rf, ctx) { if (rf & 1) {
|
|
1300
|
+
i0.ɵɵtext(0);
|
|
1301
|
+
} if (rf & 2) {
|
|
1302
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
1303
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r0.dirtyFieldNames.length, " fields edited ");
|
|
1304
|
+
} }
|
|
1305
|
+
function MJTestFormComponentExtended_Conditional_84_Template(rf, ctx) { if (rf & 1) {
|
|
1306
|
+
i0.ɵɵelement(0, "i", 225);
|
|
1307
|
+
i0.ɵɵtext(1, " Saving\u2026 ");
|
|
1308
|
+
} }
|
|
1309
|
+
function MJTestFormComponentExtended_Conditional_85_Template(rf, ctx) { if (rf & 1) {
|
|
1310
|
+
i0.ɵɵelement(0, "i", 226);
|
|
1311
|
+
i0.ɵɵtext(1, " Save changes ");
|
|
1312
|
+
i0.ɵɵelementStart(2, "span", 227)(3, "kbd");
|
|
1313
|
+
i0.ɵɵtext(4, "\u2318");
|
|
1314
|
+
i0.ɵɵelementEnd();
|
|
1315
|
+
i0.ɵɵelementStart(5, "kbd");
|
|
1316
|
+
i0.ɵɵtext(6, "S");
|
|
1317
|
+
i0.ɵɵelementEnd()();
|
|
1318
|
+
} }
|
|
1147
1319
|
/** Settings key for keyboard shortcuts visibility */
|
|
1148
1320
|
const SHORTCUTS_SETTINGS_KEY = '__mj.Testing.ShowKeyboardShortcuts';
|
|
1149
1321
|
let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTestFormComponent {
|
|
@@ -1190,11 +1362,18 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1190
1362
|
this.evalPrefsService = inject(EvaluationPreferencesService);
|
|
1191
1363
|
this.viewContainerRef = inject(ViewContainerRef);
|
|
1192
1364
|
this.appManager = inject(ApplicationManager);
|
|
1365
|
+
// Edit state
|
|
1366
|
+
this.isSaving = false;
|
|
1367
|
+
this.testTypeOptions = [];
|
|
1368
|
+
this.tagDraft = '';
|
|
1369
|
+
this.statusOptions = ['Active', 'Pending', 'Disabled'];
|
|
1193
1370
|
}
|
|
1194
1371
|
get metadata() { return this.ProviderToUse; }
|
|
1195
1372
|
async ngOnInit() {
|
|
1196
1373
|
await super.ngOnInit();
|
|
1197
1374
|
this.loadShortcutsSetting();
|
|
1375
|
+
// Fire-and-forget: test type list for the edit form
|
|
1376
|
+
this.loadTestTypeOptions();
|
|
1198
1377
|
// Subscribe to evaluation preferences
|
|
1199
1378
|
this.evalPrefsService.preferences$
|
|
1200
1379
|
.pipe(takeUntil(this.destroy$))
|
|
@@ -1220,6 +1399,14 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1220
1399
|
handleKeyboardShortcut(event) {
|
|
1221
1400
|
if (!this.keyboardShortcutsEnabled)
|
|
1222
1401
|
return;
|
|
1402
|
+
// Cmd/Ctrl + S: Save (if dirty)
|
|
1403
|
+
if ((event.metaKey || event.ctrlKey) && event.key === 's' && !event.shiftKey) {
|
|
1404
|
+
if (this.isDirty) {
|
|
1405
|
+
event.preventDefault();
|
|
1406
|
+
this.saveChanges();
|
|
1407
|
+
}
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1223
1410
|
// Cmd/Ctrl + R: Refresh
|
|
1224
1411
|
if ((event.metaKey || event.ctrlKey) && event.key === 'r' && !event.shiftKey) {
|
|
1225
1412
|
event.preventDefault();
|
|
@@ -1232,8 +1419,8 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1232
1419
|
this.runTest();
|
|
1233
1420
|
return;
|
|
1234
1421
|
}
|
|
1235
|
-
// Number keys for tabs (1-5)
|
|
1236
|
-
if (!event.metaKey && !event.ctrlKey && !event.altKey) {
|
|
1422
|
+
// Number keys for tabs (1-5) — skip when typing into form inputs
|
|
1423
|
+
if (!event.metaKey && !event.ctrlKey && !event.altKey && !this.isTextInputFocused()) {
|
|
1237
1424
|
switch (event.key) {
|
|
1238
1425
|
case '1':
|
|
1239
1426
|
this.changeTab('overview');
|
|
@@ -1253,6 +1440,20 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1253
1440
|
}
|
|
1254
1441
|
}
|
|
1255
1442
|
}
|
|
1443
|
+
// Warn before tab close / hard navigation when there are unsaved changes
|
|
1444
|
+
handleBeforeUnload(event) {
|
|
1445
|
+
if (this.isDirty) {
|
|
1446
|
+
event.preventDefault();
|
|
1447
|
+
event.returnValue = '';
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
isTextInputFocused() {
|
|
1451
|
+
const el = document.activeElement;
|
|
1452
|
+
if (!el)
|
|
1453
|
+
return false;
|
|
1454
|
+
const tag = el.tagName;
|
|
1455
|
+
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable;
|
|
1456
|
+
}
|
|
1256
1457
|
async loadTestRuns() {
|
|
1257
1458
|
if (this.testRunsLoaded)
|
|
1258
1459
|
return;
|
|
@@ -1871,103 +2072,233 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1871
2072
|
console.warn('Failed to save shortcuts setting:', error);
|
|
1872
2073
|
}
|
|
1873
2074
|
}
|
|
2075
|
+
// ==========================================
|
|
2076
|
+
// Edit / Save Methods
|
|
2077
|
+
// ==========================================
|
|
2078
|
+
/** True if the test record has any unsaved field changes. */
|
|
2079
|
+
get isDirty() {
|
|
2080
|
+
return this.record?.Dirty === true;
|
|
2081
|
+
}
|
|
2082
|
+
/** Names of fields with pending edits, used by the save bar. */
|
|
2083
|
+
get dirtyFieldNames() {
|
|
2084
|
+
if (!this.record?.Fields)
|
|
2085
|
+
return [];
|
|
2086
|
+
return this.record.Fields.filter(f => f.Dirty).map(f => f.Name);
|
|
2087
|
+
}
|
|
2088
|
+
/** Parsed tags as a plain array — derived from record.Tags JSON. */
|
|
2089
|
+
get tags() {
|
|
2090
|
+
return TagsHelper.parseTags(this.record?.Tags);
|
|
2091
|
+
}
|
|
2092
|
+
/** Load test types for the Type dropdown. */
|
|
2093
|
+
async loadTestTypeOptions() {
|
|
2094
|
+
try {
|
|
2095
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
2096
|
+
const result = await rv.RunView({
|
|
2097
|
+
EntityName: 'MJ: Test Types',
|
|
2098
|
+
OrderBy: 'Name',
|
|
2099
|
+
ResultType: 'entity_object'
|
|
2100
|
+
});
|
|
2101
|
+
if (result.Success) {
|
|
2102
|
+
this.testTypeOptions = result.Results || [];
|
|
2103
|
+
this.cdr.markForCheck();
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
catch (error) {
|
|
2107
|
+
console.warn('Failed to load test type options:', error);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
/** Save all pending changes on the test record. */
|
|
2111
|
+
async saveChanges() {
|
|
2112
|
+
if (!this.isDirty || this.isSaving)
|
|
2113
|
+
return;
|
|
2114
|
+
this.isSaving = true;
|
|
2115
|
+
this.cdr.markForCheck();
|
|
2116
|
+
try {
|
|
2117
|
+
const ok = await this.SaveRecord(false);
|
|
2118
|
+
if (ok) {
|
|
2119
|
+
SharedService.Instance.CreateSimpleNotification('Test saved', 'success', 2000);
|
|
2120
|
+
// Re-parse JSON fields since editor content may have changed
|
|
2121
|
+
this.parseJsonFields();
|
|
2122
|
+
}
|
|
2123
|
+
else {
|
|
2124
|
+
const detail = this.record?.LatestResult?.CompleteMessage || this.record?.LatestResult?.Message || 'Save failed';
|
|
2125
|
+
SharedService.Instance.CreateSimpleNotification(detail, 'error', 4000);
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
catch (err) {
|
|
2129
|
+
const msg = err instanceof Error ? err.message : 'Save failed';
|
|
2130
|
+
SharedService.Instance.CreateSimpleNotification(msg, 'error', 4000);
|
|
2131
|
+
}
|
|
2132
|
+
finally {
|
|
2133
|
+
this.isSaving = false;
|
|
2134
|
+
this.cdr.markForCheck();
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
/** Discard all pending field changes on the test. */
|
|
2138
|
+
discardChanges() {
|
|
2139
|
+
if (!this.isDirty)
|
|
2140
|
+
return;
|
|
2141
|
+
if (!confirm('Discard your unsaved changes?'))
|
|
2142
|
+
return;
|
|
2143
|
+
this.record.Revert();
|
|
2144
|
+
this.tagDraft = '';
|
|
2145
|
+
this.parseJsonFields();
|
|
2146
|
+
this.cdr.markForCheck();
|
|
2147
|
+
}
|
|
2148
|
+
/** Add a tag from tagDraft (called on Enter / comma / blur). */
|
|
2149
|
+
addTagFromDraft() {
|
|
2150
|
+
const raw = this.tagDraft.trim();
|
|
2151
|
+
if (!raw)
|
|
2152
|
+
return;
|
|
2153
|
+
const incoming = raw.split(',').map(t => t.trim()).filter(t => t.length > 0);
|
|
2154
|
+
const existing = this.tags;
|
|
2155
|
+
const merged = [...existing];
|
|
2156
|
+
for (const t of incoming) {
|
|
2157
|
+
if (!merged.includes(t))
|
|
2158
|
+
merged.push(t);
|
|
2159
|
+
}
|
|
2160
|
+
this.record.Tags = TagsHelper.toJson(merged);
|
|
2161
|
+
this.tagDraft = '';
|
|
2162
|
+
this.cdr.markForCheck();
|
|
2163
|
+
}
|
|
2164
|
+
/** Remove a single tag. */
|
|
2165
|
+
removeTag(tag) {
|
|
2166
|
+
this.record.Tags = TagsHelper.removeTag(this.record.Tags, tag);
|
|
2167
|
+
this.cdr.markForCheck();
|
|
2168
|
+
}
|
|
2169
|
+
/** Handle Enter / comma in the tag input to commit the draft tag. */
|
|
2170
|
+
onTagInputKeydown(event) {
|
|
2171
|
+
if (event.key === 'Enter' || event.key === ',') {
|
|
2172
|
+
event.preventDefault();
|
|
2173
|
+
this.addTagFromDraft();
|
|
2174
|
+
return;
|
|
2175
|
+
}
|
|
2176
|
+
if (event.key === 'Backspace' && !this.tagDraft) {
|
|
2177
|
+
const all = this.tags;
|
|
2178
|
+
if (all.length > 0) {
|
|
2179
|
+
event.preventDefault();
|
|
2180
|
+
this.removeTag(all[all.length - 1]);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
1874
2184
|
static { this.ɵfac = /*@__PURE__*/ (() => { let ɵMJTestFormComponentExtended_BaseFactory; return function MJTestFormComponentExtended_Factory(__ngFactoryType__) { return (ɵMJTestFormComponentExtended_BaseFactory || (ɵMJTestFormComponentExtended_BaseFactory = i0.ɵɵgetInheritedFactory(MJTestFormComponentExtended)))(__ngFactoryType__ || MJTestFormComponentExtended); }; })(); }
|
|
1875
2185
|
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MJTestFormComponentExtended, selectors: [["mj-test-form"]], hostBindings: function MJTestFormComponentExtended_HostBindings(rf, ctx) { if (rf & 1) {
|
|
1876
|
-
i0.ɵɵlistener("keydown", function MJTestFormComponentExtended_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, i0.ɵɵresolveDocument);
|
|
1877
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
1878
|
-
i0.ɵɵelementStart(0, "div",
|
|
2186
|
+
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);
|
|
2187
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 89, vars: 51, consts: [["tagInput", ""], [1, "test-form"], [1, "test-header"], ["aria-label", "Breadcrumb", 1, "breadcrumb"], ["href", "javascript:void(0)", 3, "click"], [1, "fas", "fa-vial"], [1, "breadcrumb-text"], [1, "current"], [1, "fas", "fa-chevron-right", "separator"], [1, "fas", "fa-flask"], [1, "header-content"], [1, "header-left"], [1, "test-icon"], [1, "test-info"], ["title", "You have unsaved changes", "aria-label", "Unsaved changes", 1, "dirty-indicator"], [1, "test-meta"], [1, "status-badge", 3, "ngClass"], [1, "fas", 3, "ngClass"], [1, "test-type"], ["title", "You have unsaved changes", 1, "unsaved-pill"], [1, "header-actions"], ["mjButton", "", "variant", "primary", 3, "click"], [1, "fas", "fa-play"], ["mjButton", "", 3, "click", "disabled"], [1, "test-description"], [1, "metrics-bar"], [1, "tabs-container"], ["role", "tablist", 1, "tabs"], ["role", "tab", 1, "tab", 3, "click"], [1, "fas", "fa-th-large"], [1, "fas", "fa-sliders-h"], [1, "fas", "fa-history"], [1, "tab-badge"], [1, "fas", "fa-layer-group"], [1, "fas", "fa-chart-line"], [1, "tab-content"], [1, "overview-tab"], [1, "config-tab"], [1, "runs-tab"], [1, "suites-tab"], [1, "history-tab"], [1, "shortcuts-toggle", 3, "click", "title"], [1, "fas", "fa-keyboard"], [1, "keyboard-shortcuts"], ["Mode", "slide", 3, "Title", "Resizable"], ["role", "region", "aria-label", "Unsaved changes", 1, "save-bar"], [1, "save-bar-message"], ["aria-hidden", "true", 1, "save-bar-dot"], [1, "save-bar-text"], [1, "save-bar-fields"], [1, "save-bar-actions"], ["type", "button", "title", "Save changes (\u2318S)", 1, "save-bar-btn", "save-bar-btn--primary", 3, "click", "disabled"], ["type", "button", "title", "Discard changes", 1, "save-bar-btn", "save-bar-btn--ghost", 3, "click", "disabled"], [1, "fas", "fa-undo"], [1, "fas", "fa-tag"], [1, "fas", "fa-circle"], [1, "metric-card"], [1, "metric-label"], [1, "metric-value"], [1, "metric-progress"], [1, "metric-progress-fill"], [1, "info-section"], [1, "fas", "fa-info-circle"], [1, "info-grid"], [1, "info-item"], [1, "info-label"], [1, "info-value"], [1, "status-badge-inline", 3, "ngClass"], [1, "json-section"], [1, "fas", "fa-code"], [1, "json-tabs"], [1, "json-tab", 3, "click"], [1, "fas", "fa-sign-in-alt"], [1, "fas", "fa-check-double"], [1, "fas", "fa-cog"], [1, "fas", "fa-tags"], [1, "code-editor-container"], ["language", "json", 3, "value", "readonly", "toolbar", "lineWrapping"], [1, "edit-section"], [1, "edit-section-header"], [1, "fas", "fa-pen-to-square"], [1, "edit-section-sub"], [1, "edit-grid"], [1, "edit-field", "edit-field--full"], ["for", "test-name"], [1, "required"], ["id", "test-name", "type", "text", "placeholder", "e.g., Agent Response Quality Test", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-description"], ["id", "test-description", "rows", "3", "placeholder", "What does this test evaluate?", 1, "config-input", "config-textarea", 3, "ngModelChange", "ngModel"], [1, "edit-field"], ["for", "test-status"], [1, "select-wrapper"], ["id", "test-status", 1, "config-input", 3, "ngModelChange", "ngModel"], [3, "ngValue"], ["for", "test-type"], ["id", "test-type", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-tags"], [1, "tag-editor", 3, "click"], [1, "tag-chip-editable"], ["id", "test-tags", "type", "text", 1, "tag-input-inline", 3, "ngModelChange", "keydown", "blur", "placeholder", "ngModel"], [1, "config-hint"], [1, "fas", "fa-cogs"], ["for", "test-priority"], ["id", "test-priority", "type", "number", "placeholder", "0 (lower runs first)", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-repeat"], ["id", "test-repeat", "type", "number", "min", "1", "placeholder", "1", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-duration"], ["id", "test-duration", "type", "number", "placeholder", "0", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-cost"], ["id", "test-cost", "type", "number", "step", "0.000001", "placeholder", "0.00", 1, "config-input", 3, "ngModelChange", "ngModel"], ["for", "test-timeout"], ["id", "test-timeout", "type", "number", "placeholder", "Default: 300000 (5 min)", 1, "config-input", 3, "ngModelChange", "ngModel"], [1, "config-section"], [1, "config-editor-container"], ["language", "json", 3, "change", "value", "readonly", "lineWrapping"], [1, "meta-section"], [1, "meta-grid"], [1, "meta-item"], [1, "meta-label"], [1, "meta-value"], [1, "meta-value", "meta-mono"], ["type", "button", 1, "tag-remove", 3, "click"], [1, "fas", "fa-times"], [1, "loading-state"], [1, "runs-list"], [1, "empty-state"], [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"], [1, "empty-icon"], [1, "fas", "fa-play-circle"], [1, "suites-list"], [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, "fas", "fa-folder-open"], [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"], [1, "kpi-card"], [1, "kpi-icon"], [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"], [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) {
|
|
2188
|
+
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "nav", 3)(3, "ol")(4, "li")(5, "a", 4);
|
|
1879
2189
|
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_a_click_5_listener() { return ctx.navigateToTestingDashboard(); });
|
|
1880
|
-
i0.ɵɵelement(6, "i",
|
|
1881
|
-
i0.ɵɵelementStart(7, "span",
|
|
2190
|
+
i0.ɵɵelement(6, "i", 5);
|
|
2191
|
+
i0.ɵɵelementStart(7, "span", 6);
|
|
1882
2192
|
i0.ɵɵtext(8, "Testing");
|
|
1883
2193
|
i0.ɵɵelementEnd()()();
|
|
1884
|
-
i0.ɵɵelementStart(9, "li",
|
|
1885
|
-
i0.ɵɵelement(10, "i",
|
|
2194
|
+
i0.ɵɵelementStart(9, "li", 7);
|
|
2195
|
+
i0.ɵɵelement(10, "i", 8)(11, "i", 9);
|
|
1886
2196
|
i0.ɵɵelementStart(12, "span");
|
|
1887
2197
|
i0.ɵɵtext(13);
|
|
1888
2198
|
i0.ɵɵelementEnd()()()();
|
|
1889
|
-
i0.ɵɵelementStart(14, "div",
|
|
1890
|
-
i0.ɵɵelement(17, "i",
|
|
2199
|
+
i0.ɵɵelementStart(14, "div", 10)(15, "div", 11)(16, "div", 12);
|
|
2200
|
+
i0.ɵɵelement(17, "i", 9);
|
|
1891
2201
|
i0.ɵɵelementEnd();
|
|
1892
|
-
i0.ɵɵelementStart(18, "div",
|
|
2202
|
+
i0.ɵɵelementStart(18, "div", 13)(19, "h1");
|
|
1893
2203
|
i0.ɵɵtext(20);
|
|
2204
|
+
i0.ɵɵconditionalCreate(21, MJTestFormComponentExtended_Conditional_21_Template, 2, 0, "span", 14);
|
|
1894
2205
|
i0.ɵɵelementEnd();
|
|
1895
|
-
i0.ɵɵelementStart(
|
|
1896
|
-
i0.ɵɵelement(
|
|
1897
|
-
i0.ɵɵtext(
|
|
2206
|
+
i0.ɵɵelementStart(22, "div", 15)(23, "span", 16);
|
|
2207
|
+
i0.ɵɵelement(24, "i", 17);
|
|
2208
|
+
i0.ɵɵtext(25);
|
|
1898
2209
|
i0.ɵɵelementEnd();
|
|
1899
|
-
i0.ɵɵconditionalCreate(
|
|
2210
|
+
i0.ɵɵconditionalCreate(26, MJTestFormComponentExtended_Conditional_26_Template, 3, 1, "span", 18);
|
|
2211
|
+
i0.ɵɵconditionalCreate(27, MJTestFormComponentExtended_Conditional_27_Template, 3, 0, "span", 19);
|
|
1900
2212
|
i0.ɵɵelementEnd()()();
|
|
1901
|
-
i0.ɵɵelementStart(
|
|
1902
|
-
i0.ɵɵelement(
|
|
1903
|
-
i0.ɵɵelementStart(
|
|
1904
|
-
i0.ɵɵlistener("click", function
|
|
1905
|
-
i0.ɵɵelement(
|
|
1906
|
-
i0.ɵɵtext(
|
|
2213
|
+
i0.ɵɵelementStart(28, "div", 20);
|
|
2214
|
+
i0.ɵɵelement(29, "app-evaluation-mode-toggle");
|
|
2215
|
+
i0.ɵɵelementStart(30, "button", 21);
|
|
2216
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_30_listener() { return ctx.runTest(); });
|
|
2217
|
+
i0.ɵɵelement(31, "i", 22);
|
|
2218
|
+
i0.ɵɵtext(32, " Run Test ");
|
|
1907
2219
|
i0.ɵɵelementEnd();
|
|
1908
|
-
i0.ɵɵelementStart(
|
|
1909
|
-
i0.ɵɵlistener("click", function
|
|
1910
|
-
i0.ɵɵelement(
|
|
1911
|
-
i0.ɵɵtext(
|
|
2220
|
+
i0.ɵɵelementStart(33, "button", 23);
|
|
2221
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_33_listener() { return ctx.refresh(); });
|
|
2222
|
+
i0.ɵɵelement(34, "i", 17);
|
|
2223
|
+
i0.ɵɵtext(35);
|
|
1912
2224
|
i0.ɵɵelementEnd()()();
|
|
1913
|
-
i0.ɵɵconditionalCreate(
|
|
1914
|
-
i0.ɵɵconditionalCreate(
|
|
2225
|
+
i0.ɵɵconditionalCreate(36, MJTestFormComponentExtended_Conditional_36_Template, 3, 1, "div", 24);
|
|
2226
|
+
i0.ɵɵconditionalCreate(37, MJTestFormComponentExtended_Conditional_37_Template, 23, 6, "div", 25);
|
|
1915
2227
|
i0.ɵɵelementEnd();
|
|
1916
|
-
i0.ɵɵelementStart(
|
|
1917
|
-
i0.ɵɵlistener("click", function
|
|
1918
|
-
i0.ɵɵelement(
|
|
1919
|
-
i0.ɵɵelementStart(
|
|
1920
|
-
i0.ɵɵtext(
|
|
2228
|
+
i0.ɵɵelementStart(38, "div", 26)(39, "div", 27)(40, "button", 28);
|
|
2229
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_40_listener() { return ctx.changeTab("overview"); });
|
|
2230
|
+
i0.ɵɵelement(41, "i", 29);
|
|
2231
|
+
i0.ɵɵelementStart(42, "span");
|
|
2232
|
+
i0.ɵɵtext(43, "Overview");
|
|
1921
2233
|
i0.ɵɵelementEnd()();
|
|
1922
|
-
i0.ɵɵelementStart(
|
|
1923
|
-
i0.ɵɵlistener("click", function
|
|
1924
|
-
i0.ɵɵelement(
|
|
1925
|
-
i0.ɵɵelementStart(
|
|
1926
|
-
i0.ɵɵtext(
|
|
2234
|
+
i0.ɵɵelementStart(44, "button", 28);
|
|
2235
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_44_listener() { return ctx.changeTab("config"); });
|
|
2236
|
+
i0.ɵɵelement(45, "i", 30);
|
|
2237
|
+
i0.ɵɵelementStart(46, "span");
|
|
2238
|
+
i0.ɵɵtext(47, "Configuration");
|
|
1927
2239
|
i0.ɵɵelementEnd()();
|
|
1928
|
-
i0.ɵɵelementStart(
|
|
1929
|
-
i0.ɵɵlistener("click", function
|
|
1930
|
-
i0.ɵɵelement(
|
|
1931
|
-
i0.ɵɵelementStart(
|
|
1932
|
-
i0.ɵɵtext(
|
|
2240
|
+
i0.ɵɵelementStart(48, "button", 28);
|
|
2241
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_48_listener() { return ctx.changeTab("runs"); });
|
|
2242
|
+
i0.ɵɵelement(49, "i", 31);
|
|
2243
|
+
i0.ɵɵelementStart(50, "span");
|
|
2244
|
+
i0.ɵɵtext(51, "Runs");
|
|
1933
2245
|
i0.ɵɵelementEnd();
|
|
1934
|
-
i0.ɵɵconditionalCreate(
|
|
2246
|
+
i0.ɵɵconditionalCreate(52, MJTestFormComponentExtended_Conditional_52_Template, 2, 1, "span", 32);
|
|
1935
2247
|
i0.ɵɵelementEnd();
|
|
1936
|
-
i0.ɵɵelementStart(
|
|
1937
|
-
i0.ɵɵlistener("click", function
|
|
1938
|
-
i0.ɵɵelement(
|
|
1939
|
-
i0.ɵɵelementStart(
|
|
1940
|
-
i0.ɵɵtext(
|
|
2248
|
+
i0.ɵɵelementStart(53, "button", 28);
|
|
2249
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_53_listener() { return ctx.changeTab("suites"); });
|
|
2250
|
+
i0.ɵɵelement(54, "i", 33);
|
|
2251
|
+
i0.ɵɵelementStart(55, "span");
|
|
2252
|
+
i0.ɵɵtext(56, "Test Suites");
|
|
1941
2253
|
i0.ɵɵelementEnd();
|
|
1942
|
-
i0.ɵɵconditionalCreate(
|
|
2254
|
+
i0.ɵɵconditionalCreate(57, MJTestFormComponentExtended_Conditional_57_Template, 2, 1, "span", 32);
|
|
1943
2255
|
i0.ɵɵelementEnd();
|
|
1944
|
-
i0.ɵɵelementStart(
|
|
1945
|
-
i0.ɵɵlistener("click", function
|
|
1946
|
-
i0.ɵɵelement(
|
|
1947
|
-
i0.ɵɵelementStart(
|
|
1948
|
-
i0.ɵɵtext(
|
|
2256
|
+
i0.ɵɵelementStart(58, "button", 28);
|
|
2257
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_58_listener() { return ctx.changeTab("analytics"); });
|
|
2258
|
+
i0.ɵɵelement(59, "i", 34);
|
|
2259
|
+
i0.ɵɵelementStart(60, "span");
|
|
2260
|
+
i0.ɵɵtext(61, "Analytics");
|
|
1949
2261
|
i0.ɵɵelementEnd()()()();
|
|
1950
|
-
i0.ɵɵelementStart(
|
|
1951
|
-
i0.ɵɵconditionalCreate(
|
|
1952
|
-
i0.ɵɵconditionalCreate(
|
|
1953
|
-
i0.ɵɵconditionalCreate(
|
|
1954
|
-
i0.ɵɵconditionalCreate(
|
|
1955
|
-
i0.ɵɵconditionalCreate(
|
|
2262
|
+
i0.ɵɵelementStart(62, "div", 35);
|
|
2263
|
+
i0.ɵɵconditionalCreate(63, MJTestFormComponentExtended_Conditional_63_Template, 78, 29, "div", 36);
|
|
2264
|
+
i0.ɵɵconditionalCreate(64, MJTestFormComponentExtended_Conditional_64_Template, 111, 30, "div", 37);
|
|
2265
|
+
i0.ɵɵconditionalCreate(65, MJTestFormComponentExtended_Conditional_65_Template, 4, 3, "div", 38);
|
|
2266
|
+
i0.ɵɵconditionalCreate(66, MJTestFormComponentExtended_Conditional_66_Template, 4, 3, "div", 39);
|
|
2267
|
+
i0.ɵɵconditionalCreate(67, MJTestFormComponentExtended_Conditional_67_Template, 3, 2, "div", 40);
|
|
2268
|
+
i0.ɵɵelementEnd();
|
|
2269
|
+
i0.ɵɵelementStart(68, "button", 41);
|
|
2270
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_68_listener() { return ctx.toggleShortcuts(); });
|
|
2271
|
+
i0.ɵɵelement(69, "i", 42);
|
|
1956
2272
|
i0.ɵɵelementEnd();
|
|
1957
|
-
i0.ɵɵ
|
|
1958
|
-
i0.ɵɵ
|
|
1959
|
-
i0.ɵɵ
|
|
2273
|
+
i0.ɵɵconditionalCreate(70, MJTestFormComponentExtended_Conditional_70_Template, 40, 0, "div", 43);
|
|
2274
|
+
i0.ɵɵconditionalCreate(71, MJTestFormComponentExtended_Conditional_71_Template, 2, 6, "mj-slide-panel", 44);
|
|
2275
|
+
i0.ɵɵelementStart(72, "div", 45)(73, "div", 46)(74, "span", 47);
|
|
2276
|
+
i0.ɵɵtext(75, "\u25CF");
|
|
1960
2277
|
i0.ɵɵelementEnd();
|
|
1961
|
-
i0.ɵɵ
|
|
1962
|
-
i0.ɵɵ
|
|
2278
|
+
i0.ɵɵelementStart(76, "span", 48)(77, "strong");
|
|
2279
|
+
i0.ɵɵtext(78, "Unsaved changes");
|
|
1963
2280
|
i0.ɵɵelementEnd();
|
|
2281
|
+
i0.ɵɵelementStart(79, "span", 49);
|
|
2282
|
+
i0.ɵɵconditionalCreate(80, MJTestFormComponentExtended_Conditional_80_Template, 1, 1)(81, MJTestFormComponentExtended_Conditional_81_Template, 1, 1);
|
|
2283
|
+
i0.ɵɵelementEnd()()();
|
|
2284
|
+
i0.ɵɵelementStart(82, "div", 50)(83, "button", 51);
|
|
2285
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_83_listener() { return ctx.saveChanges(); });
|
|
2286
|
+
i0.ɵɵconditionalCreate(84, MJTestFormComponentExtended_Conditional_84_Template, 2, 0)(85, MJTestFormComponentExtended_Conditional_85_Template, 7, 0);
|
|
2287
|
+
i0.ɵɵelementEnd();
|
|
2288
|
+
i0.ɵɵelementStart(86, "button", 52);
|
|
2289
|
+
i0.ɵɵlistener("click", function MJTestFormComponentExtended_Template_button_click_86_listener() { return ctx.discardChanges(); });
|
|
2290
|
+
i0.ɵɵelement(87, "i", 53);
|
|
2291
|
+
i0.ɵɵtext(88, " Discard ");
|
|
2292
|
+
i0.ɵɵelementEnd()()()();
|
|
1964
2293
|
} if (rf & 2) {
|
|
1965
2294
|
i0.ɵɵadvance(13);
|
|
1966
2295
|
i0.ɵɵtextInterpolate(ctx.record.Name);
|
|
1967
2296
|
i0.ɵɵadvance(3);
|
|
1968
2297
|
i0.ɵɵstyleProp("background-color", ctx.getStatusColor());
|
|
1969
2298
|
i0.ɵɵadvance(4);
|
|
1970
|
-
i0.ɵɵ
|
|
2299
|
+
i0.ɵɵtextInterpolate1(" ", ctx.record.Name, " ");
|
|
2300
|
+
i0.ɵɵadvance();
|
|
2301
|
+
i0.ɵɵconditional(ctx.isDirty ? 21 : -1);
|
|
1971
2302
|
i0.ɵɵadvance(2);
|
|
1972
2303
|
i0.ɵɵproperty("ngClass", ctx.getStatusClass());
|
|
1973
2304
|
i0.ɵɵadvance();
|
|
@@ -1975,7 +2306,9 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1975
2306
|
i0.ɵɵadvance();
|
|
1976
2307
|
i0.ɵɵtextInterpolate1(" ", ctx.record.Status, " ");
|
|
1977
2308
|
i0.ɵɵadvance();
|
|
1978
|
-
i0.ɵɵconditional(ctx.record.Type ?
|
|
2309
|
+
i0.ɵɵconditional(ctx.record.Type ? 26 : -1);
|
|
2310
|
+
i0.ɵɵadvance();
|
|
2311
|
+
i0.ɵɵconditional(ctx.isDirty ? 27 : -1);
|
|
1979
2312
|
i0.ɵɵadvance(6);
|
|
1980
2313
|
i0.ɵɵproperty("disabled", ctx.isRefreshing);
|
|
1981
2314
|
i0.ɵɵadvance();
|
|
@@ -1983,9 +2316,9 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1983
2316
|
i0.ɵɵadvance();
|
|
1984
2317
|
i0.ɵɵtextInterpolate1(" ", ctx.isRefreshing ? "Refreshing..." : "Refresh", " ");
|
|
1985
2318
|
i0.ɵɵadvance();
|
|
1986
|
-
i0.ɵɵconditional(ctx.record.Description ?
|
|
2319
|
+
i0.ɵɵconditional(ctx.record.Description ? 36 : -1);
|
|
1987
2320
|
i0.ɵɵadvance();
|
|
1988
|
-
i0.ɵɵconditional(ctx.testRunsLoaded && ctx.testRuns.length > 0 ?
|
|
2321
|
+
i0.ɵɵconditional(ctx.testRunsLoaded && ctx.testRuns.length > 0 ? 37 : -1);
|
|
1989
2322
|
i0.ɵɵadvance(3);
|
|
1990
2323
|
i0.ɵɵclassProp("active", ctx.activeTab === "overview");
|
|
1991
2324
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "overview");
|
|
@@ -1996,32 +2329,47 @@ let MJTestFormComponentExtended = class MJTestFormComponentExtended extends MJTe
|
|
|
1996
2329
|
i0.ɵɵclassProp("active", ctx.activeTab === "runs");
|
|
1997
2330
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "runs");
|
|
1998
2331
|
i0.ɵɵadvance(4);
|
|
1999
|
-
i0.ɵɵconditional(ctx.testRunsLoaded ?
|
|
2332
|
+
i0.ɵɵconditional(ctx.testRunsLoaded ? 52 : -1);
|
|
2000
2333
|
i0.ɵɵadvance();
|
|
2001
2334
|
i0.ɵɵclassProp("active", ctx.activeTab === "suites");
|
|
2002
2335
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "suites");
|
|
2003
2336
|
i0.ɵɵadvance(4);
|
|
2004
|
-
i0.ɵɵconditional(ctx.suiteTestsLoaded ?
|
|
2337
|
+
i0.ɵɵconditional(ctx.suiteTestsLoaded ? 57 : -1);
|
|
2005
2338
|
i0.ɵɵadvance();
|
|
2006
2339
|
i0.ɵɵclassProp("active", ctx.activeTab === "analytics");
|
|
2007
2340
|
i0.ɵɵattribute("aria-selected", ctx.activeTab === "analytics");
|
|
2008
|
-
i0.ɵɵadvance(
|
|
2009
|
-
i0.ɵɵ
|
|
2341
|
+
i0.ɵɵadvance(4);
|
|
2342
|
+
i0.ɵɵclassProp("has-savebar", ctx.isDirty);
|
|
2010
2343
|
i0.ɵɵadvance();
|
|
2011
|
-
i0.ɵɵconditional(ctx.activeTab === "
|
|
2344
|
+
i0.ɵɵconditional(ctx.activeTab === "overview" ? 63 : -1);
|
|
2012
2345
|
i0.ɵɵadvance();
|
|
2013
|
-
i0.ɵɵconditional(ctx.activeTab === "
|
|
2346
|
+
i0.ɵɵconditional(ctx.activeTab === "config" ? 64 : -1);
|
|
2014
2347
|
i0.ɵɵadvance();
|
|
2015
|
-
i0.ɵɵconditional(ctx.activeTab === "
|
|
2348
|
+
i0.ɵɵconditional(ctx.activeTab === "runs" ? 65 : -1);
|
|
2016
2349
|
i0.ɵɵadvance();
|
|
2017
|
-
i0.ɵɵconditional(ctx.activeTab === "
|
|
2350
|
+
i0.ɵɵconditional(ctx.activeTab === "suites" ? 66 : -1);
|
|
2351
|
+
i0.ɵɵadvance();
|
|
2352
|
+
i0.ɵɵconditional(ctx.activeTab === "analytics" ? 67 : -1);
|
|
2018
2353
|
i0.ɵɵadvance();
|
|
2019
2354
|
i0.ɵɵproperty("title", ctx.showShortcuts ? "Hide keyboard shortcuts" : "Show keyboard shortcuts");
|
|
2020
2355
|
i0.ɵɵadvance(2);
|
|
2021
|
-
i0.ɵɵconditional(ctx.showShortcuts ?
|
|
2356
|
+
i0.ɵɵconditional(ctx.showShortcuts ? 70 : -1);
|
|
2357
|
+
i0.ɵɵadvance();
|
|
2358
|
+
i0.ɵɵconditional(ctx.testingDialogService.IsPanelOpen ? 71 : -1);
|
|
2022
2359
|
i0.ɵɵadvance();
|
|
2023
|
-
i0.ɵɵ
|
|
2024
|
-
} }, dependencies: [i1.NgClass, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.NgModel, i3.MJButtonDirective, i4.CodeEditorComponent, i5.TestRunDialogComponent, i5.EvaluationModeToggleComponent, i6.LoadingComponent, i7.MjSlidePanelComponent, i8.EntityLinkPillComponent, i1.DatePipe], styles: ["\n\n\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\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\n.test-form[_ngcontent-%COMP%] {\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\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\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\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\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\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\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\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\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\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\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\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\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\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\n.runs-tab[_ngcontent-%COMP%], \n.suites-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\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\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\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\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\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\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\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\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.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--test-bg);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 36px;\n color: var(--test-text-muted);\n}\n\n.empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 20px 0;\n font-size: 14px;\n color: var(--test-text-secondary);\n max-width: 300px;\n}\n\n\n\n.no-data[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--test-text-muted);\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.no-data[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\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\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\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 .empty-state[_ngcontent-%COMP%] {\n padding: 40px 20px;\n }\n\n .empty-icon[_ngcontent-%COMP%] {\n width: 64px;\n height: 64px;\n }\n\n .empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\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\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\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\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\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\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\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\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\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\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\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 .empty-state[_ngcontent-%COMP%] {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}"], changeDetection: 0 }); }
|
|
2360
|
+
i0.ɵɵclassProp("save-bar--visible", ctx.isDirty);
|
|
2361
|
+
i0.ɵɵattribute("aria-hidden", !ctx.isDirty);
|
|
2362
|
+
i0.ɵɵadvance(8);
|
|
2363
|
+
i0.ɵɵconditional(ctx.dirtyFieldNames.length === 1 ? 80 : ctx.dirtyFieldNames.length > 1 ? 81 : -1);
|
|
2364
|
+
i0.ɵɵadvance(3);
|
|
2365
|
+
i0.ɵɵproperty("disabled", ctx.isSaving || !ctx.isDirty);
|
|
2366
|
+
i0.ɵɵattribute("tabindex", ctx.isDirty ? 0 : -1);
|
|
2367
|
+
i0.ɵɵadvance();
|
|
2368
|
+
i0.ɵɵconditional(ctx.isSaving ? 84 : 85);
|
|
2369
|
+
i0.ɵɵadvance(2);
|
|
2370
|
+
i0.ɵɵproperty("disabled", ctx.isSaving || !ctx.isDirty);
|
|
2371
|
+
i0.ɵɵattribute("tabindex", ctx.isDirty ? 0 : -1);
|
|
2372
|
+
} }, dependencies: [i1.NgClass, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.NumberValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.MinValidator, i2.NgModel, i3.MJButtonDirective, i4.CodeEditorComponent, i5.TestRunDialogComponent, i5.EvaluationModeToggleComponent, i6.LoadingComponent, i7.MjSlidePanelComponent, i8.EntityLinkPillComponent, i1.DatePipe], styles: ["\n\n\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\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\n.runs-tab[_ngcontent-%COMP%], \n.suites-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease-out;\n}\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\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\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\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\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\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\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\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.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--test-bg);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 36px;\n color: var(--test-text-muted);\n}\n\n.empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0 0 20px 0;\n font-size: 14px;\n color: var(--test-text-secondary);\n max-width: 300px;\n}\n\n\n\n.no-data[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--test-text-muted);\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.no-data[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\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\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\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 .empty-state[_ngcontent-%COMP%] {\n padding: 40px 20px;\n }\n\n .empty-icon[_ngcontent-%COMP%] {\n width: 64px;\n height: 64px;\n }\n\n .empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\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\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\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\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\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\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\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\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\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\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\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 .empty-state[_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\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\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\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\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\n.tab-content.has-savebar[_ngcontent-%COMP%] {\n padding-bottom: 84px;\n}\n\n\n\n\n\n\n.save-bar[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n right: 96px; \n\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(15, 23, 42, 0.18));\n backdrop-filter: blur(8px);\n \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\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 }); }
|
|
2025
2373
|
};
|
|
2026
2374
|
MJTestFormComponentExtended = __decorate([
|
|
2027
2375
|
RegisterClass(BaseFormComponent, 'MJ: Tests')
|
|
@@ -2029,10 +2377,13 @@ MJTestFormComponentExtended = __decorate([
|
|
|
2029
2377
|
export { MJTestFormComponentExtended };
|
|
2030
2378
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJTestFormComponentExtended, [{
|
|
2031
2379
|
type: Component,
|
|
2032
|
-
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>{{ record.Name }}</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 </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\">\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 <div class=\"config-section\">\n <h3><i class=\"fas fa-cogs\"></i> Execution Settings</h3>\n <div class=\"config-grid\">\n <div class=\"config-item\">\n <label>Priority</label>\n <input type=\"number\" [(ngModel)]=\"record.Priority\" class=\"config-input\" placeholder=\"Lower = Higher Priority\" />\n </div>\n <div class=\"config-item\">\n <label>Repeat Count</label>\n <input type=\"number\" [(ngModel)]=\"record.RepeatCount\" class=\"config-input\" min=\"1\" />\n </div>\n <div class=\"config-item\">\n <label>Estimated Duration (seconds)</label>\n <input type=\"number\" [(ngModel)]=\"record.EstimatedDurationSeconds\" class=\"config-input\" />\n </div>\n <div class=\"config-item\">\n <label>Estimated Cost (USD)</label>\n <input type=\"number\" step=\"0.000001\" [(ngModel)]=\"record.EstimatedCostUSD\" class=\"config-input\" />\n </div>\n <div class=\"config-item full-width\">\n <label>Max Execution Time (ms)</label>\n <input type=\"number\" [(ngModel)]=\"record.MaxExecutionTimeMS\" class=\"config-input\" placeholder=\"Default: 300000 (5 min)\" />\n <span class=\"config-hint\">Leave empty for default 5 minute timeout</span>\n </div>\n </div>\n </div>\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 <div class=\"config-section\">\n <h3><i class=\"fas fa-tags\"></i> Tags (JSON Array)</h3>\n <div class=\"config-editor-container small\">\n <mj-code-editor\n [value]=\"record.Tags || '[]'\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.Tags = $event\">\n </mj-code-editor>\n </div>\n </div>\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 <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-play-circle\"></i>\n </div>\n <h4>No Test Runs Yet</h4>\n <p>Run this test to see execution history and results here.</p>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test Now\n </button>\n </div>\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 <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-folder-open\"></i>\n </div>\n <h4>Not Part of Any Suite</h4>\n <p>This test is not included in any test suites. Add it to a suite to run it with other tests.</p>\n </div>\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 <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-chart-line\"></i>\n </div>\n <h4>No History Available</h4>\n <p>Run this test to start building history and analytics data.</p>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test Now\n </button>\n </div>\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>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</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 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 Empty States\n =========================== */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.empty-icon {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--test-bg);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon i {\n font-size: 36px;\n color: var(--test-text-muted);\n}\n\n.empty-state h4 {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.empty-state p {\n margin: 0 0 20px 0;\n font-size: 14px;\n color: var(--test-text-secondary);\n max-width: 300px;\n}\n\n/* Legacy no-data for backwards compatibility */\n.no-data {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--test-text-muted);\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.no-data i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data p {\n margin: 0;\n font-size: 14px;\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 .empty-state {\n padding: 40px 20px;\n }\n\n .empty-icon {\n width: 64px;\n height: 64px;\n }\n\n .empty-icon i {\n font-size: 28px;\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 .empty-state {\n break-inside: avoid;\n box-shadow: none;\n border: 1px solid var(--mj-border-default);\n }\n}\n"] }]
|
|
2380
|
+
args: [{ standalone: false, selector: 'mj-test-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-form\">\n <!-- Header Section -->\n <div class=\"test-header\">\n <!-- Breadcrumb Navigation -->\n <nav class=\"breadcrumb\" aria-label=\"Breadcrumb\">\n <ol>\n <li>\n <a href=\"javascript:void(0)\" (click)=\"navigateToTestingDashboard()\">\n <i class=\"fas fa-vial\"></i>\n <span class=\"breadcrumb-text\">Testing</span>\n </a>\n </li>\n <li class=\"current\">\n <i class=\"fas fa-chevron-right separator\"></i>\n <i class=\"fas fa-flask\"></i>\n <span>{{ record.Name }}</span>\n </li>\n </ol>\n </nav>\n\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"test-icon\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas fa-flask\"></i>\n </div>\n <div class=\"test-info\">\n <h1>\n {{ record.Name }}\n @if (isDirty) {\n <span class=\"dirty-indicator\" title=\"You have unsaved changes\" aria-label=\"Unsaved changes\">\u25CF</span>\n }\n </h1>\n <div class=\"test-meta\">\n <span class=\"status-badge\" [ngClass]=\"getStatusClass()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n @if (record.Type) {\n <span class=\"test-type\">\n <i class=\"fas fa-tag\"></i>\n {{ record.Type }}\n </span>\n }\n @if (isDirty) {\n <span class=\"unsaved-pill\" title=\"You have unsaved changes\">\n <i class=\"fas fa-circle\"></i> Unsaved\n </span>\n }\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <app-evaluation-mode-toggle></app-evaluation-mode-toggle>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test\n </button>\n <button mjButton (click)=\"refresh()\" [disabled]=\"isRefreshing\">\n <i class=\"fas\" [ngClass]=\"isRefreshing ? 'fa-sync fa-spin' : 'fa-sync'\"></i>\n {{ isRefreshing ? 'Refreshing...' : 'Refresh' }}\n </button>\n </div>\n </div>\n\n <!-- Test Description -->\n @if (record.Description) {\n <div class=\"test-description\">\n <p>{{ record.Description }}</p>\n </div>\n }\n\n <!-- Metrics Bar -->\n @if (testRunsLoaded && testRuns.length > 0) {\n <div class=\"metrics-bar\">\n <div class=\"metric-card\">\n <div class=\"metric-label\">Total Runs</div>\n <div class=\"metric-value\">{{ testRuns.length }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Pass Rate</div>\n <div class=\"metric-value\">{{ getPassRate().toFixed(1) }}%</div>\n <div class=\"metric-progress\">\n <div class=\"metric-progress-fill\" [style.width.%]=\"getPassRate()\"></div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Cost</div>\n <div class=\"metric-value\">{{ formatCost(getAverageCost()) }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Avg Duration</div>\n <div class=\"metric-value\">{{ formatDuration(getAverageDuration()) }}</div>\n </div>\n </div>\n }\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs-container\">\n <div class=\"tabs\" role=\"tablist\">\n <button class=\"tab\"\n [class.active]=\"activeTab === 'overview'\"\n (click)=\"changeTab('overview')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'overview'\">\n <i class=\"fas fa-th-large\"></i>\n <span>Overview</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'config'\"\n (click)=\"changeTab('config')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'config'\">\n <i class=\"fas fa-sliders-h\"></i>\n <span>Configuration</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'runs'\"\n (click)=\"changeTab('runs')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'runs'\">\n <i class=\"fas fa-history\"></i>\n <span>Runs</span>\n @if (testRunsLoaded) {\n <span class=\"tab-badge\">{{ testRuns.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'suites'\"\n (click)=\"changeTab('suites')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'suites'\">\n <i class=\"fas fa-layer-group\"></i>\n <span>Test Suites</span>\n @if (suiteTestsLoaded) {\n <span class=\"tab-badge\">{{ suiteTests.length }}</span>\n }\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'analytics'\"\n (click)=\"changeTab('analytics')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'analytics'\">\n <i class=\"fas fa-chart-line\"></i>\n <span>Analytics</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\" [class.has-savebar]=\"isDirty\">\n <!-- Overview Tab -->\n @if (activeTab === 'overview') {\n <div class=\"overview-tab\">\n <!-- Basic Information -->\n <div class=\"info-section\">\n <h3><i class=\"fas fa-info-circle\"></i> Test Information</h3>\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <div class=\"info-label\">Name</div>\n <div class=\"info-value\">{{ record.Name }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Type</div>\n <div class=\"info-value\">{{ record.Type || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Status</div>\n <div class=\"info-value\">\n <span class=\"status-badge-inline\" [ngClass]=\"getStatusClass()\">{{ record.Status }}</span>\n </div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Priority</div>\n <div class=\"info-value\">{{ record.Priority || 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Duration</div>\n <div class=\"info-value\">{{ record.EstimatedDurationSeconds ? formatDuration(record.EstimatedDurationSeconds) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Estimated Cost</div>\n <div class=\"info-value\">{{ record.EstimatedCostUSD ? formatCost(record.EstimatedCostUSD) : 'N/A' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Repeat Count</div>\n <div class=\"info-value\">{{ record.RepeatCount || 1 }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Max Execution Time</div>\n <div class=\"info-value\">{{ formatTimeout(record.MaxExecutionTimeMS) }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Created</div>\n <div class=\"info-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"info-item\">\n <div class=\"info-label\">Updated</div>\n <div class=\"info-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n </div>\n </div>\n <!-- JSON Data Views -->\n <div class=\"json-section\">\n <h3><i class=\"fas fa-code\"></i> Test Definition</h3>\n <div class=\"json-tabs\">\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'input'\"\n (click)=\"setJsonView('input')\">\n <i class=\"fas fa-sign-in-alt\"></i>\n Input Definition\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'expected'\"\n (click)=\"setJsonView('expected')\">\n <i class=\"fas fa-check-double\"></i>\n Expected Outcomes\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'config'\"\n (click)=\"setJsonView('config')\">\n <i class=\"fas fa-cog\"></i>\n Configuration\n </button>\n <button class=\"json-tab\"\n [class.active]=\"activeJsonView === 'tags'\"\n (click)=\"setJsonView('tags')\">\n <i class=\"fas fa-tags\"></i>\n Tags\n </button>\n </div>\n <div class=\"code-editor-container\">\n <mj-code-editor\n [value]=\"getJsonData()\"\n language=\"json\"\n [readonly]=\"true\"\n [toolbar]=\"jsonToolbar\"\n [lineWrapping]=\"true\">\n </mj-code-editor>\n </div>\n </div>\n </div>\n }\n\n <!-- Configuration Tab -->\n @if (activeTab === 'config') {\n <div class=\"config-tab\">\n <!-- Details -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-pen-to-square\"></i> Details</h3>\n <p class=\"edit-section-sub\">Edit any field \u2014 changes are saved with the bar at the bottom.</p>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-name\">Name <span class=\"required\">*</span></label>\n <input\n id=\"test-name\"\n type=\"text\"\n class=\"config-input\"\n placeholder=\"e.g., Agent Response Quality Test\"\n [(ngModel)]=\"record.Name\"\n />\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-description\">Description</label>\n <textarea\n id=\"test-description\"\n class=\"config-input config-textarea\"\n rows=\"3\"\n placeholder=\"What does this test evaluate?\"\n [ngModel]=\"record.Description\"\n (ngModelChange)=\"record.Description = $event || null\"\n ></textarea>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-status\">Status</label>\n <div class=\"select-wrapper\">\n <select\n id=\"test-status\"\n class=\"config-input\"\n [(ngModel)]=\"record.Status\"\n >\n @for (opt of statusOptions; track opt) {\n <option [ngValue]=\"opt\">{{ opt }}</option>\n }\n </select>\n </div>\n </div>\n\n <div class=\"edit-field\">\n <label for=\"test-type\">Test Type</label>\n <select\n id=\"test-type\"\n class=\"config-input\"\n [(ngModel)]=\"record.TypeID\"\n >\n @for (t of testTypeOptions; track t.ID) {\n <option [ngValue]=\"t.ID\">{{ t.Name }}</option>\n }\n </select>\n </div>\n\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-tags\">Tags</label>\n <div class=\"tag-editor\" (click)=\"tagInput.focus()\">\n @for (tag of tags; track tag) {\n <span class=\"tag-chip-editable\">\n {{ tag }}\n <button type=\"button\" class=\"tag-remove\" (click)=\"removeTag(tag); $event.stopPropagation()\" [attr.aria-label]=\"'Remove tag ' + tag\">\n <i class=\"fas fa-times\"></i>\n </button>\n </span>\n }\n <input\n #tagInput\n id=\"test-tags\"\n type=\"text\"\n class=\"tag-input-inline\"\n [placeholder]=\"tags.length === 0 ? 'Add tags, press Enter or comma...' : ''\"\n [(ngModel)]=\"tagDraft\"\n (keydown)=\"onTagInputKeydown($event)\"\n (blur)=\"addTagFromDraft()\"\n />\n </div>\n <span class=\"config-hint\">Press Enter or comma to add a tag. Backspace on empty input removes the last tag.</span>\n </div>\n </div>\n </section>\n\n <!-- Execution Settings -->\n <section class=\"edit-section\">\n <header class=\"edit-section-header\">\n <h3><i class=\"fas fa-cogs\"></i> Execution Settings</h3>\n </header>\n <div class=\"edit-grid\">\n <div class=\"edit-field\">\n <label for=\"test-priority\">Priority</label>\n <input\n id=\"test-priority\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0 (lower runs first)\"\n [ngModel]=\"record.Priority\"\n (ngModelChange)=\"record.Priority = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Lower numbers run first.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-repeat\">Repeat Count</label>\n <input\n id=\"test-repeat\"\n type=\"number\"\n class=\"config-input\"\n min=\"1\"\n placeholder=\"1\"\n [ngModel]=\"record.RepeatCount\"\n (ngModelChange)=\"record.RepeatCount = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Number of times to repeat for statistical analysis.</span>\n </div>\n <div class=\"edit-field\">\n <label for=\"test-duration\">Estimated Duration (seconds)</label>\n <input\n id=\"test-duration\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"0\"\n [ngModel]=\"record.EstimatedDurationSeconds\"\n (ngModelChange)=\"record.EstimatedDurationSeconds = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field\">\n <label for=\"test-cost\">Estimated Cost (USD)</label>\n <input\n id=\"test-cost\"\n type=\"number\"\n step=\"0.000001\"\n class=\"config-input\"\n placeholder=\"0.00\"\n [ngModel]=\"record.EstimatedCostUSD\"\n (ngModelChange)=\"record.EstimatedCostUSD = $event === '' || $event === null ? null : +$event\"\n />\n </div>\n <div class=\"edit-field edit-field--full\">\n <label for=\"test-timeout\">Max Execution Time (ms)</label>\n <input\n id=\"test-timeout\"\n type=\"number\"\n class=\"config-input\"\n placeholder=\"Default: 300000 (5 min)\"\n [ngModel]=\"record.MaxExecutionTimeMS\"\n (ngModelChange)=\"record.MaxExecutionTimeMS = $event === '' || $event === null ? null : +$event\"\n />\n <span class=\"config-hint\">Leave empty for the default 5 minute timeout. Currently: {{ formatTimeout(record.MaxExecutionTimeMS) }}</span>\n </div>\n </div>\n </section>\n\n <!-- JSON editors (preserved from original layout) -->\n <div class=\"config-section\">\n <h3><i class=\"fas fa-sign-in-alt\"></i> Input Definition (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.InputDefinition || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.InputDefinition = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-check-double\"></i> Expected Outcomes (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.ExpectedOutcomes || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.ExpectedOutcomes = $event\">\n </mj-code-editor>\n </div>\n </div>\n <div class=\"config-section\">\n <h3><i class=\"fas fa-cog\"></i> Configuration (JSON)</h3>\n <div class=\"config-editor-container\">\n <mj-code-editor\n [value]=\"record.Configuration || ''\"\n language=\"json\"\n [readonly]=\"false\"\n [lineWrapping]=\"true\"\n (change)=\"record.Configuration = $event\">\n </mj-code-editor>\n </div>\n </div>\n\n <!-- Metadata (read-only) -->\n <section class=\"meta-section\">\n <div class=\"meta-grid\">\n <div class=\"meta-item\">\n <div class=\"meta-label\">Created</div>\n <div class=\"meta-value\">{{ record.__mj_CreatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Last updated</div>\n <div class=\"meta-value\">{{ record.__mj_UpdatedAt | date:'medium' }}</div>\n </div>\n <div class=\"meta-item\">\n <div class=\"meta-label\">Test ID</div>\n <div class=\"meta-value meta-mono\">{{ record.ID }}</div>\n </div>\n </div>\n </section>\n </div>\n }\n\n <!-- Test Runs Tab -->\n @if (activeTab === 'runs') {\n <div class=\"runs-tab\">\n <!-- Loading State -->\n @if (loadingRuns) {\n <div class=\"loading-state\">\n <div class=\"skeleton-list\">\n @for (i of [1,2,3,4,5]; track i) {\n <div class=\"skeleton-card\">\n <div class=\"skeleton-icon\"></div>\n <div class=\"skeleton-content\">\n <div class=\"skeleton-line wide\"></div>\n <div class=\"skeleton-line narrow\"></div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n <!-- Runs List -->\n @if (!loadingRuns && testRuns.length > 0) {\n <div class=\"runs-list\">\n @for (run of testRuns; track run) {\n <div class=\"run-item\" (click)=\"openTestRun(run.ID)\">\n <div class=\"run-icon\" [style.background-color]=\"getRunStatusColor(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-stopwatch]=\"run.Status === 'Timeout'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n </div>\n <div class=\"run-content\">\n <div class=\"run-header\">\n <span class=\"run-id\">Run #{{ run.ID.substring(0, 8) }}</span>\n <span class=\"run-status\" [style.color]=\"getRunStatusColor(run.Status)\">{{ run.Status }}</span>\n </div>\n <div class=\"run-meta\">\n <span><i class=\"fas fa-calendar\"></i> {{ getRelativeTime(run.StartedAt) }}</span>\n @if (run.DurationSeconds) {\n <span><i class=\"fas fa-clock\"></i> {{ formatDuration(run.DurationSeconds) }}</span>\n }\n @if (run.CostUSD) {\n <span><i class=\"fas fa-dollar-sign\"></i> {{ formatCost(run.CostUSD) }}</span>\n }\n @if (run.TargetLogEntityID && run.TargetLogID) {\n <mj-entity-link-pill\n [entityName]=\"run.TargetLogEntity\"\n [recordId]=\"run.TargetLogID\">\n </mj-entity-link-pill>\n }\n </div>\n <!-- Evaluation indicators -->\n <div class=\"run-eval-stack\">\n <!-- Status indicator -->\n @if (evalPreferences.showExecution) {\n <span class=\"eval-pill status-pill\"\n [ngClass]=\"'status-' + run.Status.toLowerCase()\"\n [title]=\"getStatusTooltip(run.Status)\">\n <i class=\"fas\"\n [class.fa-check]=\"run.Status === 'Passed'\"\n [class.fa-times]=\"run.Status === 'Failed'\"\n [class.fa-exclamation]=\"run.Status === 'Error'\"\n [class.fa-hourglass-end]=\"run.Status === 'Timeout'\"\n [class.fa-forward]=\"run.Status === 'Skipped'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"></i>\n <span>{{ run.Status }}</span>\n </span>\n }\n <!-- Human feedback indicator -->\n @if (evalPreferences.showHuman) {\n @if (!getFeedbackForRun(run.ID)?.Rating) {\n <span class=\"eval-pill human-pill no-feedback\"\n title=\"Human Review: No rating submitted yet\">\n <i class=\"fas fa-user-slash\"></i>\n </span>\n }\n @if (getFeedbackForRun(run.ID)?.Rating; as rating) {\n <span class=\"eval-pill human-pill has-feedback\"\n [class.rating-low]=\"rating <= 4\"\n [class.rating-medium]=\"rating >= 5 && rating <= 6\"\n [class.rating-good]=\"rating >= 7 && rating <= 8\"\n [class.rating-excellent]=\"rating >= 9\"\n [title]=\"getHumanTooltip(rating, getFeedbackForRun(run.ID)?.CorrectionSummary || getFeedbackForRun(run.ID)?.Comments || null)\">\n <i class=\"fas fa-user\"></i>\n <span>{{ rating }}</span>\n </span>\n }\n }\n <!-- Auto score indicator -->\n @if (evalPreferences.showAuto) {\n @if (run.Score == null) {\n <span class=\"eval-pill auto-pill no-score\"\n title=\"Auto Score: No automated score available\">\n <i class=\"fas fa-robot\"></i>\n </span>\n }\n @if (run.Score != null) {\n <span class=\"eval-pill auto-pill has-score\"\n [class.score-low]=\"run.Score < 0.5\"\n [class.score-medium]=\"run.Score >= 0.5 && run.Score < 0.7\"\n [class.score-good]=\"run.Score >= 0.7 && run.Score < 0.85\"\n [class.score-excellent]=\"run.Score >= 0.85\"\n [title]=\"'Auto Score: ' + (run.Score * 100).toFixed(0) + '% automated evaluation'\">\n <i class=\"fas fa-robot\"></i>\n <span>{{ (run.Score * 100).toFixed(0) }}%</span>\n </span>\n }\n }\n </div>\n @if (getRunTags(run).length > 0) {\n <div class=\"run-tags\">\n @for (tag of getRunTags(run).slice(0, 3); track tag) {\n <span class=\"run-tag\">{{ tag }}</span>\n }\n @if (getRunTags(run).length > 3) {\n <span class=\"run-tag-more\">+{{ getRunTags(run).length - 3 }}</span>\n }\n </div>\n }\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n }\n </div>\n }\n <!-- Empty State -->\n @if (testRunsLoaded && !loadingRuns && testRuns.length === 0) {\n <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-play-circle\"></i>\n </div>\n <h4>No Test Runs Yet</h4>\n <p>Run this test to see execution history and results here.</p>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test Now\n </button>\n </div>\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 <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-folder-open\"></i>\n </div>\n <h4>Not Part of Any Suite</h4>\n <p>This test is not included in any test suites. Add it to a suite to run it with other tests.</p>\n </div>\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 <div class=\"empty-state\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-chart-line\"></i>\n </div>\n <h4>No History Available</h4>\n <p>Run this test to start building history and analytics data.</p>\n <button mjButton (click)=\"runTest()\" variant=\"primary\">\n <i class=\"fas fa-play\"></i> Run Test Now\n </button>\n </div>\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 Empty States\n =========================== */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 24px;\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.empty-icon {\n width: 80px;\n height: 80px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--test-bg);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon i {\n font-size: 36px;\n color: var(--test-text-muted);\n}\n\n.empty-state h4 {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--test-text);\n}\n\n.empty-state p {\n margin: 0 0 20px 0;\n font-size: 14px;\n color: var(--test-text-secondary);\n max-width: 300px;\n}\n\n/* Legacy no-data for backwards compatibility */\n.no-data {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--test-text-muted);\n text-align: center;\n background: var(--test-surface);\n border-radius: var(--test-radius-lg);\n}\n\n.no-data i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.3;\n}\n\n.no-data p {\n margin: 0;\n font-size: 14px;\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 .empty-state {\n padding: 40px 20px;\n }\n\n .empty-icon {\n width: 64px;\n height: 64px;\n }\n\n .empty-icon i {\n font-size: 28px;\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 .empty-state {\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(15, 23, 42, 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"] }]
|
|
2033
2381
|
}], null, { handleKeyboardShortcut: [{
|
|
2034
2382
|
type: HostListener,
|
|
2035
2383
|
args: ['document:keydown', ['$event']]
|
|
2384
|
+
}], handleBeforeUnload: [{
|
|
2385
|
+
type: HostListener,
|
|
2386
|
+
args: ['window:beforeunload', ['$event']]
|
|
2036
2387
|
}] }); })();
|
|
2037
2388
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJTestFormComponentExtended, { className: "MJTestFormComponentExtended", filePath: "src/lib/custom/Tests/test-form.component.ts", lineNumber: 62 }); })();
|
|
2038
2389
|
//# sourceMappingURL=test-form.component.js.map
|