@memberjunction/ng-core-entity-forms 2.129.0 → 2.130.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/entity-link-pill.component.d.ts +44 -0
- package/dist/lib/custom/Tests/entity-link-pill.component.d.ts.map +1 -0
- package/dist/lib/custom/Tests/entity-link-pill.component.js +124 -0
- package/dist/lib/custom/Tests/entity-link-pill.component.js.map +1 -0
- package/dist/lib/custom/Tests/test-form.component.d.ts +94 -8
- package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +1527 -276
- package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.d.ts +48 -8
- package/dist/lib/custom/Tests/test-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.js +1078 -426
- package/dist/lib/custom/Tests/test-run-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts +227 -5
- package/dist/lib/custom/Tests/test-suite-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-form.component.js +3307 -200
- package/dist/lib/custom/Tests/test-suite-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-suite-run-form.component.d.ts +86 -2
- package/dist/lib/custom/Tests/test-suite-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-suite-run-form.component.js +1975 -262
- package/dist/lib/custom/Tests/test-suite-run-form.component.js.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts +9 -2
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.d.ts.map +1 -1
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js +275 -244
- package/dist/lib/custom/ai-agent-run/ai-agent-run.component.js.map +1 -1
- package/dist/lib/custom/custom-forms.module.d.ts +27 -26
- package/dist/lib/custom/custom-forms.module.d.ts.map +1 -1
- package/dist/lib/custom/custom-forms.module.js +9 -3
- package/dist/lib/custom/custom-forms.module.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js +154 -122
- package/dist/lib/generated/Entities/AIAgent/aiagent.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.d.ts +11 -0
- package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.js +75 -0
- package/dist/lib/generated/Entities/AIAgentModality/aiagentmodality.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.d.ts +11 -0
- package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.js +121 -0
- package/dist/lib/generated/Entities/AIArchitecture/aiarchitecture.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js +77 -41
- package/dist/lib/generated/Entities/AIConfiguration/aiconfiguration.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIModality/aimodality.form.component.d.ts +11 -0
- package/dist/lib/generated/Entities/AIModality/aimodality.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/AIModality/aimodality.form.component.js +167 -0
- package/dist/lib/generated/Entities/AIModality/aimodality.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/AIModel/aimodel.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js +160 -102
- package/dist/lib/generated/Entities/AIModel/aimodel.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.d.ts +11 -0
- package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.js +73 -0
- package/dist/lib/generated/Entities/AIModelArchitecture/aimodelarchitecture.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.d.ts +11 -0
- package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.js +89 -0
- package/dist/lib/generated/Entities/AIModelModality/aimodelmodality.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.js +27 -13
- package/dist/lib/generated/Entities/AIModelType/aimodeltype.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js +39 -21
- package/dist/lib/generated/Entities/ConversationDetail/conversationdetail.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.d.ts +11 -0
- package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.d.ts.map +1 -0
- package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.js +95 -0
- package/dist/lib/generated/Entities/ConversationDetailAttachment/conversationdetailattachment.form.component.js.map +1 -0
- package/dist/lib/generated/Entities/Entity/entity.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/Entity/entity.form.component.js +61 -43
- package/dist/lib/generated/Entities/Entity/entity.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/File/file.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/File/file.form.component.js +22 -4
- package/dist/lib/generated/Entities/File/file.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.js +40 -4
- package/dist/lib/generated/Entities/FileStorageProvider/filestorageprovider.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/Test/test.form.component.js +17 -15
- package/dist/lib/generated/Entities/Test/test.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/TestRun/testrun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/TestRun/testrun.form.component.js +55 -43
- package/dist/lib/generated/Entities/TestRun/testrun.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/TestRunFeedback/testrunfeedback.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/TestRunFeedback/testrunfeedback.form.component.js +9 -15
- package/dist/lib/generated/Entities/TestRunFeedback/testrunfeedback.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/TestSuite/testsuite.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/TestSuite/testsuite.form.component.js +39 -19
- package/dist/lib/generated/Entities/TestSuite/testsuite.form.component.js.map +1 -1
- package/dist/lib/generated/Entities/TestSuiteRun/testsuiterun.form.component.d.ts.map +1 -1
- package/dist/lib/generated/Entities/TestSuiteRun/testsuiterun.form.component.js +40 -16
- package/dist/lib/generated/Entities/TestSuiteRun/testsuiterun.form.component.js.map +1 -1
- package/dist/lib/generated/generated-forms.module.d.ts +145 -134
- package/dist/lib/generated/generated-forms.module.d.ts.map +1 -1
- package/dist/lib/generated/generated-forms.module.js +168 -87
- package/dist/lib/generated/generated-forms.module.js.map +1 -1
- package/package.json +28 -27
|
@@ -4,27 +4,36 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
8
|
-
import { Subject } from 'rxjs';
|
|
7
|
+
import { Component, ChangeDetectionStrategy, HostListener } from '@angular/core';
|
|
8
|
+
import { Subject, interval } from 'rxjs';
|
|
9
|
+
import { takeUntil } from 'rxjs/operators';
|
|
9
10
|
import { CompositeKey, Metadata, RunView } from '@memberjunction/core';
|
|
11
|
+
import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
10
12
|
import { BaseFormComponent } from '@memberjunction/ng-base-forms';
|
|
11
13
|
import { RegisterClass } from '@memberjunction/global';
|
|
12
14
|
import { SharedService } from '@memberjunction/ng-shared';
|
|
13
15
|
import { TestSuiteRunFormComponent } from '../../generated/Entities/TestSuiteRun/testsuiterun.form.component';
|
|
16
|
+
import { TagsHelper, calculateEvaluationMetrics, normalizeExecutionStatus, getNeedsReviewItems } from '@memberjunction/ng-testing';
|
|
14
17
|
import * as i0 from "@angular/core";
|
|
15
18
|
import * as i1 from "@memberjunction/ng-shared";
|
|
16
19
|
import * as i2 from "@angular/router";
|
|
17
|
-
import * as i3 from "@
|
|
18
|
-
import * as i4 from "@
|
|
20
|
+
import * as i3 from "@memberjunction/ng-testing";
|
|
21
|
+
import * as i4 from "@angular/common";
|
|
22
|
+
import * as i5 from "@angular/forms";
|
|
23
|
+
import * as i6 from "@progress/kendo-angular-dialog";
|
|
24
|
+
import * as i7 from "@progress/kendo-angular-buttons";
|
|
25
|
+
import * as i8 from "./entity-link-pill.component";
|
|
26
|
+
const _c0 = () => [1, 2, 3, 4, 5];
|
|
27
|
+
const _c1 = () => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
19
28
|
function TestSuiteRunFormComponentExtended_div_2_Template(rf, ctx) { if (rf & 1) {
|
|
20
29
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
21
|
-
i0.ɵɵelementStart(0, "div",
|
|
30
|
+
i0.ɵɵelementStart(0, "div", 61)(1, "a", 62);
|
|
22
31
|
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_2_Template_a_click_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.openTestSuite()); });
|
|
23
|
-
i0.ɵɵelement(2, "i",
|
|
32
|
+
i0.ɵɵelement(2, "i", 63);
|
|
24
33
|
i0.ɵɵtext(3);
|
|
25
34
|
i0.ɵɵelementEnd();
|
|
26
|
-
i0.ɵɵelement(4, "i",
|
|
27
|
-
i0.ɵɵelementStart(5, "span");
|
|
35
|
+
i0.ɵɵelement(4, "i", 64);
|
|
36
|
+
i0.ɵɵelementStart(5, "span", 65);
|
|
28
37
|
i0.ɵɵtext(6);
|
|
29
38
|
i0.ɵɵelementEnd()();
|
|
30
39
|
} if (rf & 2) {
|
|
@@ -35,25 +44,140 @@ function TestSuiteRunFormComponentExtended_div_2_Template(rf, ctx) { if (rf & 1)
|
|
|
35
44
|
i0.ɵɵtextInterpolate1("Run #", ctx_r1.record.ID.substring(0, 8), "");
|
|
36
45
|
} }
|
|
37
46
|
function TestSuiteRunFormComponentExtended_span_14_Template(rf, ctx) { if (rf & 1) {
|
|
38
|
-
i0.ɵɵelementStart(0, "span",
|
|
47
|
+
i0.ɵɵelementStart(0, "span", 66);
|
|
48
|
+
i0.ɵɵelement(1, "i", 67);
|
|
49
|
+
i0.ɵɵtext(2);
|
|
50
|
+
i0.ɵɵelementEnd();
|
|
51
|
+
} if (rf & 2) {
|
|
52
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
53
|
+
i0.ɵɵadvance(2);
|
|
54
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.record.Environment, " ");
|
|
55
|
+
} }
|
|
56
|
+
function TestSuiteRunFormComponentExtended_span_15_Template(rf, ctx) { if (rf & 1) {
|
|
57
|
+
i0.ɵɵelementStart(0, "span", 68);
|
|
58
|
+
i0.ɵɵelement(1, "i", 69);
|
|
59
|
+
i0.ɵɵtext(2);
|
|
60
|
+
i0.ɵɵelementEnd();
|
|
61
|
+
} if (rf & 2) {
|
|
62
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
63
|
+
i0.ɵɵadvance(2);
|
|
64
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.record.TriggerType, " ");
|
|
65
|
+
} }
|
|
66
|
+
function TestSuiteRunFormComponentExtended_button_18_Template(rf, ctx) { if (rf & 1) {
|
|
67
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
68
|
+
i0.ɵɵelementStart(0, "button", 70);
|
|
69
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_button_18_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.reRunSuite()); });
|
|
70
|
+
i0.ɵɵelement(1, "i", 71);
|
|
71
|
+
i0.ɵɵtext(2, " Re-run Suite ");
|
|
72
|
+
i0.ɵɵelementEnd();
|
|
73
|
+
} }
|
|
74
|
+
function TestSuiteRunFormComponentExtended_div_96_div_4_span_1_Template(rf, ctx) { if (rf & 1) {
|
|
75
|
+
i0.ɵɵelementStart(0, "span", 82);
|
|
39
76
|
i0.ɵɵtext(1);
|
|
40
77
|
i0.ɵɵelementEnd();
|
|
78
|
+
} if (rf & 2) {
|
|
79
|
+
const tag_r5 = ctx.$implicit;
|
|
80
|
+
i0.ɵɵadvance();
|
|
81
|
+
i0.ɵɵtextInterpolate(tag_r5);
|
|
82
|
+
} }
|
|
83
|
+
function TestSuiteRunFormComponentExtended_div_96_div_4_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
+
i0.ɵɵelementStart(0, "div", 80);
|
|
85
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_96_div_4_span_1_Template, 2, 1, "span", 81);
|
|
86
|
+
i0.ɵɵelementEnd();
|
|
87
|
+
} if (rf & 2) {
|
|
88
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
89
|
+
i0.ɵɵadvance();
|
|
90
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.tags);
|
|
91
|
+
} }
|
|
92
|
+
function TestSuiteRunFormComponentExtended_div_96_span_5_Template(rf, ctx) { if (rf & 1) {
|
|
93
|
+
i0.ɵɵelementStart(0, "span", 83);
|
|
94
|
+
i0.ɵɵtext(1, "No tags");
|
|
95
|
+
i0.ɵɵelementEnd();
|
|
96
|
+
} }
|
|
97
|
+
function TestSuiteRunFormComponentExtended_div_96_Template(rf, ctx) { if (rf & 1) {
|
|
98
|
+
const _r4 = i0.ɵɵgetCurrentView();
|
|
99
|
+
i0.ɵɵelementStart(0, "div", 72)(1, "div", 73)(2, "span", 74);
|
|
100
|
+
i0.ɵɵelement(3, "i", 75);
|
|
101
|
+
i0.ɵɵelementEnd();
|
|
102
|
+
i0.ɵɵtemplate(4, TestSuiteRunFormComponentExtended_div_96_div_4_Template, 2, 1, "div", 76)(5, TestSuiteRunFormComponentExtended_div_96_span_5_Template, 2, 0, "span", 77);
|
|
103
|
+
i0.ɵɵelementStart(6, "button", 78);
|
|
104
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_96_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.startEditingTags()); });
|
|
105
|
+
i0.ɵɵelement(7, "i", 79);
|
|
106
|
+
i0.ɵɵtext(8, " Add ");
|
|
107
|
+
i0.ɵɵelementEnd()()();
|
|
41
108
|
} if (rf & 2) {
|
|
42
109
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
110
|
+
i0.ɵɵadvance(4);
|
|
111
|
+
i0.ɵɵproperty("ngIf", ctx_r1.tags.length > 0);
|
|
43
112
|
i0.ɵɵadvance();
|
|
44
|
-
i0.ɵɵ
|
|
113
|
+
i0.ɵɵproperty("ngIf", ctx_r1.tags.length === 0);
|
|
45
114
|
} }
|
|
46
|
-
function
|
|
47
|
-
i0.ɵɵ
|
|
115
|
+
function TestSuiteRunFormComponentExtended_div_97_span_7_Template(rf, ctx) { if (rf & 1) {
|
|
116
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
117
|
+
i0.ɵɵelementStart(0, "span", 98);
|
|
48
118
|
i0.ɵɵtext(1);
|
|
119
|
+
i0.ɵɵelementStart(2, "button", 99);
|
|
120
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_97_span_7_Template_button_click_2_listener() { const tag_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.removeTag(tag_r8)); });
|
|
121
|
+
i0.ɵɵelement(3, "i", 100);
|
|
122
|
+
i0.ɵɵelementEnd()();
|
|
123
|
+
} if (rf & 2) {
|
|
124
|
+
const tag_r8 = ctx.$implicit;
|
|
125
|
+
i0.ɵɵadvance();
|
|
126
|
+
i0.ɵɵtextInterpolate1(" ", tag_r8, " ");
|
|
127
|
+
} }
|
|
128
|
+
function TestSuiteRunFormComponentExtended_div_97_span_8_Template(rf, ctx) { if (rf & 1) {
|
|
129
|
+
i0.ɵɵelementStart(0, "span", 101);
|
|
130
|
+
i0.ɵɵtext(1, "No tags yet");
|
|
131
|
+
i0.ɵɵelementEnd();
|
|
132
|
+
} }
|
|
133
|
+
function TestSuiteRunFormComponentExtended_div_97_i_15_Template(rf, ctx) { if (rf & 1) {
|
|
134
|
+
i0.ɵɵelement(0, "i", 102);
|
|
135
|
+
} }
|
|
136
|
+
function TestSuiteRunFormComponentExtended_div_97_Template(rf, ctx) { if (rf & 1) {
|
|
137
|
+
const _r6 = i0.ɵɵgetCurrentView();
|
|
138
|
+
i0.ɵɵelementStart(0, "div", 84)(1, "div", 85)(2, "span", 86);
|
|
139
|
+
i0.ɵɵelement(3, "i", 75);
|
|
140
|
+
i0.ɵɵtext(4, " Edit Tags");
|
|
141
|
+
i0.ɵɵelementEnd()();
|
|
142
|
+
i0.ɵɵelementStart(5, "div", 87)(6, "div", 88);
|
|
143
|
+
i0.ɵɵtemplate(7, TestSuiteRunFormComponentExtended_div_97_span_7_Template, 4, 1, "span", 89)(8, TestSuiteRunFormComponentExtended_div_97_span_8_Template, 2, 0, "span", 90);
|
|
144
|
+
i0.ɵɵelementEnd();
|
|
145
|
+
i0.ɵɵelementStart(9, "div", 91)(10, "input", 92);
|
|
146
|
+
i0.ɵɵtwoWayListener("ngModelChange", function TestSuiteRunFormComponentExtended_div_97_Template_input_ngModelChange_10_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newTag, $event) || (ctx_r1.newTag = $event); return i0.ɵɵresetView($event); });
|
|
147
|
+
i0.ɵɵlistener("keyup.enter", function TestSuiteRunFormComponentExtended_div_97_Template_input_keyup_enter_10_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.addTag()); });
|
|
148
|
+
i0.ɵɵelementEnd();
|
|
149
|
+
i0.ɵɵelementStart(11, "button", 93);
|
|
150
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_97_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.addTag()); });
|
|
151
|
+
i0.ɵɵelement(12, "i", 79);
|
|
152
|
+
i0.ɵɵelementEnd()()();
|
|
153
|
+
i0.ɵɵelementStart(13, "div", 94)(14, "button", 95);
|
|
154
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_97_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.saveTags()); });
|
|
155
|
+
i0.ɵɵtemplate(15, TestSuiteRunFormComponentExtended_div_97_i_15_Template, 1, 0, "i", 96);
|
|
156
|
+
i0.ɵɵtext(16);
|
|
49
157
|
i0.ɵɵelementEnd();
|
|
158
|
+
i0.ɵɵelementStart(17, "button", 97);
|
|
159
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_97_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelEditingTags()); });
|
|
160
|
+
i0.ɵɵtext(18, "Cancel");
|
|
161
|
+
i0.ɵɵelementEnd()()();
|
|
50
162
|
} if (rf & 2) {
|
|
51
163
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
164
|
+
i0.ɵɵadvance(7);
|
|
165
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.tags);
|
|
52
166
|
i0.ɵɵadvance();
|
|
53
|
-
i0.ɵɵ
|
|
167
|
+
i0.ɵɵproperty("ngIf", ctx_r1.tags.length === 0);
|
|
168
|
+
i0.ɵɵadvance(2);
|
|
169
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newTag);
|
|
170
|
+
i0.ɵɵadvance();
|
|
171
|
+
i0.ɵɵproperty("disabled", !ctx_r1.newTag.trim());
|
|
172
|
+
i0.ɵɵadvance(3);
|
|
173
|
+
i0.ɵɵproperty("disabled", ctx_r1.savingTags);
|
|
174
|
+
i0.ɵɵadvance();
|
|
175
|
+
i0.ɵɵproperty("ngIf", ctx_r1.savingTags);
|
|
176
|
+
i0.ɵɵadvance();
|
|
177
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.savingTags ? "Saving..." : "Save", " ");
|
|
54
178
|
} }
|
|
55
|
-
function
|
|
56
|
-
i0.ɵɵelementStart(0, "span",
|
|
179
|
+
function TestSuiteRunFormComponentExtended_span_106_Template(rf, ctx) { if (rf & 1) {
|
|
180
|
+
i0.ɵɵelementStart(0, "span", 103);
|
|
57
181
|
i0.ɵɵtext(1);
|
|
58
182
|
i0.ɵɵelementEnd();
|
|
59
183
|
} if (rf & 2) {
|
|
@@ -61,222 +185,1309 @@ function TestSuiteRunFormComponentExtended_span_88_Template(rf, ctx) { if (rf &
|
|
|
61
185
|
i0.ɵɵadvance();
|
|
62
186
|
i0.ɵɵtextInterpolate(ctx_r1.testRuns.length);
|
|
63
187
|
} }
|
|
64
|
-
function
|
|
65
|
-
i0.ɵɵelementStart(0, "div",
|
|
66
|
-
i0.ɵɵ
|
|
188
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_11_Template(rf, ctx) { if (rf & 1) {
|
|
189
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "span", 124);
|
|
190
|
+
i0.ɵɵtext(2, "Avg Rating");
|
|
191
|
+
i0.ɵɵelementEnd();
|
|
192
|
+
i0.ɵɵelementStart(3, "span", 125);
|
|
193
|
+
i0.ɵɵtext(4);
|
|
194
|
+
i0.ɵɵelementEnd()();
|
|
195
|
+
} if (rf & 2) {
|
|
196
|
+
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
197
|
+
i0.ɵɵadvance(4);
|
|
198
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.evaluationMetrics.humanAvgRating.toFixed(1), "/10");
|
|
199
|
+
} }
|
|
200
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_12_span_5_Template(rf, ctx) { if (rf & 1) {
|
|
201
|
+
i0.ɵɵelementStart(0, "span", 130);
|
|
202
|
+
i0.ɵɵtext(1);
|
|
203
|
+
i0.ɵɵelementEnd();
|
|
204
|
+
} if (rf & 2) {
|
|
205
|
+
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
206
|
+
i0.ɵɵadvance();
|
|
207
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.evaluationMetrics.humanIncorrectCount, " incorrect");
|
|
208
|
+
} }
|
|
209
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_12_Template(rf, ctx) { if (rf & 1) {
|
|
210
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "span", 124);
|
|
211
|
+
i0.ɵɵtext(2, "Correct");
|
|
212
|
+
i0.ɵɵelementEnd();
|
|
213
|
+
i0.ɵɵelementStart(3, "span", 128);
|
|
214
|
+
i0.ɵɵtext(4);
|
|
215
|
+
i0.ɵɵelementEnd();
|
|
216
|
+
i0.ɵɵtemplate(5, TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_12_span_5_Template, 2, 1, "span", 129);
|
|
217
|
+
i0.ɵɵelementEnd();
|
|
218
|
+
} if (rf & 2) {
|
|
219
|
+
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
220
|
+
i0.ɵɵadvance(4);
|
|
221
|
+
i0.ɵɵtextInterpolate(ctx_r1.evaluationMetrics.humanCorrectCount);
|
|
222
|
+
i0.ɵɵadvance();
|
|
223
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.humanIncorrectCount > 0);
|
|
224
|
+
} }
|
|
225
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_13_Template(rf, ctx) { if (rf & 1) {
|
|
226
|
+
i0.ɵɵelementStart(0, "div", 131)(1, "span", 132);
|
|
227
|
+
i0.ɵɵelement(2, "i", 133);
|
|
228
|
+
i0.ɵɵtext(3);
|
|
229
|
+
i0.ɵɵelementEnd()();
|
|
230
|
+
} if (rf & 2) {
|
|
231
|
+
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
232
|
+
i0.ɵɵadvance(3);
|
|
233
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.evaluationMetrics.humanPendingCount, " need review ");
|
|
234
|
+
} }
|
|
235
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_2_Template(rf, ctx) { if (rf & 1) {
|
|
236
|
+
i0.ɵɵelementStart(0, "div", 119)(1, "div", 120);
|
|
237
|
+
i0.ɵɵelement(2, "i", 121);
|
|
238
|
+
i0.ɵɵelementStart(3, "span");
|
|
239
|
+
i0.ɵɵtext(4, "Human Feedback");
|
|
240
|
+
i0.ɵɵelementEnd()();
|
|
241
|
+
i0.ɵɵelementStart(5, "div", 122)(6, "div", 123)(7, "span", 124);
|
|
242
|
+
i0.ɵɵtext(8, "Reviewed");
|
|
243
|
+
i0.ɵɵelementEnd();
|
|
244
|
+
i0.ɵɵelementStart(9, "span", 125);
|
|
245
|
+
i0.ɵɵtext(10);
|
|
246
|
+
i0.ɵɵelementEnd()();
|
|
247
|
+
i0.ɵɵtemplate(11, TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_11_Template, 5, 1, "div", 126)(12, TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_12_Template, 6, 2, "div", 126);
|
|
248
|
+
i0.ɵɵelementEnd();
|
|
249
|
+
i0.ɵɵtemplate(13, TestSuiteRunFormComponentExtended_div_118_div_19_div_2_div_13_Template, 4, 1, "div", 127);
|
|
250
|
+
i0.ɵɵelementEnd();
|
|
251
|
+
} if (rf & 2) {
|
|
252
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
253
|
+
i0.ɵɵadvance(10);
|
|
254
|
+
i0.ɵɵtextInterpolate2("", ctx_r1.evaluationMetrics.humanReviewedCount, " / ", ctx_r1.evaluationMetrics.totalRuns, "");
|
|
255
|
+
i0.ɵɵadvance();
|
|
256
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.humanReviewedCount > 0);
|
|
257
|
+
i0.ɵɵadvance();
|
|
258
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.humanReviewedCount > 0);
|
|
259
|
+
i0.ɵɵadvance();
|
|
260
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.humanPendingCount > 0);
|
|
261
|
+
} }
|
|
262
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_3_div_11_Template(rf, ctx) { if (rf & 1) {
|
|
263
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "span", 124);
|
|
264
|
+
i0.ɵɵtext(2, "Avg Score");
|
|
265
|
+
i0.ɵɵelementEnd();
|
|
266
|
+
i0.ɵɵelementStart(3, "span", 125);
|
|
267
|
+
i0.ɵɵtext(4);
|
|
268
|
+
i0.ɵɵelementEnd()();
|
|
269
|
+
} if (rf & 2) {
|
|
270
|
+
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
271
|
+
i0.ɵɵadvance(4);
|
|
272
|
+
i0.ɵɵtextInterpolate1("", (ctx_r1.evaluationMetrics.autoAvgScore * 100).toFixed(0), "%");
|
|
273
|
+
} }
|
|
274
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_3_div_12_Template(rf, ctx) { if (rf & 1) {
|
|
275
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "span", 124);
|
|
276
|
+
i0.ɵɵtext(2, "Pass Rate");
|
|
67
277
|
i0.ɵɵelementEnd();
|
|
68
|
-
i0.ɵɵelementStart(
|
|
278
|
+
i0.ɵɵelementStart(3, "span", 125);
|
|
279
|
+
i0.ɵɵtext(4);
|
|
280
|
+
i0.ɵɵelementEnd()();
|
|
281
|
+
} if (rf & 2) {
|
|
282
|
+
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
283
|
+
i0.ɵɵadvance(4);
|
|
284
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.evaluationMetrics.autoPassRate.toFixed(0), "%");
|
|
285
|
+
} }
|
|
286
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_3_Template(rf, ctx) { if (rf & 1) {
|
|
287
|
+
i0.ɵɵelementStart(0, "div", 119)(1, "div", 120);
|
|
288
|
+
i0.ɵɵelement(2, "i", 134);
|
|
289
|
+
i0.ɵɵelementStart(3, "span");
|
|
290
|
+
i0.ɵɵtext(4, "Auto Evaluation");
|
|
291
|
+
i0.ɵɵelementEnd()();
|
|
292
|
+
i0.ɵɵelementStart(5, "div", 122)(6, "div", 123)(7, "span", 124);
|
|
293
|
+
i0.ɵɵtext(8, "Evaluated");
|
|
294
|
+
i0.ɵɵelementEnd();
|
|
295
|
+
i0.ɵɵelementStart(9, "span", 125);
|
|
296
|
+
i0.ɵɵtext(10);
|
|
297
|
+
i0.ɵɵelementEnd()();
|
|
298
|
+
i0.ɵɵtemplate(11, TestSuiteRunFormComponentExtended_div_118_div_19_div_3_div_11_Template, 5, 1, "div", 126)(12, TestSuiteRunFormComponentExtended_div_118_div_19_div_3_div_12_Template, 5, 1, "div", 126);
|
|
299
|
+
i0.ɵɵelementEnd()();
|
|
300
|
+
} if (rf & 2) {
|
|
301
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
302
|
+
i0.ɵɵadvance(10);
|
|
303
|
+
i0.ɵɵtextInterpolate2("", ctx_r1.evaluationMetrics.autoEvaluatedCount, " / ", ctx_r1.evaluationMetrics.totalRuns, "");
|
|
304
|
+
i0.ɵɵadvance();
|
|
305
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.autoEvaluatedCount > 0);
|
|
306
|
+
i0.ɵɵadvance();
|
|
307
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.autoEvaluatedCount > 0);
|
|
308
|
+
} }
|
|
309
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_4_div_16_span_3_Template(rf, ctx) { if (rf & 1) {
|
|
310
|
+
i0.ɵɵelementStart(0, "span", 138);
|
|
311
|
+
i0.ɵɵtext(1);
|
|
312
|
+
i0.ɵɵelementEnd();
|
|
313
|
+
} if (rf & 2) {
|
|
314
|
+
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
315
|
+
i0.ɵɵadvance();
|
|
316
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.evaluationMetrics.execErrorCount, " errors");
|
|
317
|
+
} }
|
|
318
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_4_div_16_span_4_Template(rf, ctx) { if (rf & 1) {
|
|
319
|
+
i0.ɵɵelementStart(0, "span", 139);
|
|
320
|
+
i0.ɵɵtext(1);
|
|
321
|
+
i0.ɵɵelementEnd();
|
|
322
|
+
} if (rf & 2) {
|
|
323
|
+
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
324
|
+
i0.ɵɵadvance();
|
|
325
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.evaluationMetrics.execTimeoutCount, " timeouts");
|
|
326
|
+
} }
|
|
327
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_4_div_16_Template(rf, ctx) { if (rf & 1) {
|
|
328
|
+
i0.ɵɵelementStart(0, "div", 123)(1, "span", 124);
|
|
329
|
+
i0.ɵɵtext(2, "Issues");
|
|
330
|
+
i0.ɵɵelementEnd();
|
|
331
|
+
i0.ɵɵtemplate(3, TestSuiteRunFormComponentExtended_div_118_div_19_div_4_div_16_span_3_Template, 2, 1, "span", 136)(4, TestSuiteRunFormComponentExtended_div_118_div_19_div_4_div_16_span_4_Template, 2, 1, "span", 137);
|
|
332
|
+
i0.ɵɵelementEnd();
|
|
333
|
+
} if (rf & 2) {
|
|
334
|
+
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
335
|
+
i0.ɵɵadvance(3);
|
|
336
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.execErrorCount > 0);
|
|
337
|
+
i0.ɵɵadvance();
|
|
338
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.execTimeoutCount > 0);
|
|
339
|
+
} }
|
|
340
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_div_4_Template(rf, ctx) { if (rf & 1) {
|
|
341
|
+
i0.ɵɵelementStart(0, "div", 119)(1, "div", 120);
|
|
342
|
+
i0.ɵɵelement(2, "i", 135);
|
|
343
|
+
i0.ɵɵelementStart(3, "span");
|
|
344
|
+
i0.ɵɵtext(4, "Execution");
|
|
345
|
+
i0.ɵɵelementEnd()();
|
|
346
|
+
i0.ɵɵelementStart(5, "div", 122)(6, "div", 123)(7, "span", 124);
|
|
347
|
+
i0.ɵɵtext(8, "Completed");
|
|
348
|
+
i0.ɵɵelementEnd();
|
|
349
|
+
i0.ɵɵelementStart(9, "span", 125);
|
|
350
|
+
i0.ɵɵtext(10);
|
|
351
|
+
i0.ɵɵelementEnd()();
|
|
352
|
+
i0.ɵɵelementStart(11, "div", 123)(12, "span", 124);
|
|
353
|
+
i0.ɵɵtext(13, "Success Rate");
|
|
354
|
+
i0.ɵɵelementEnd();
|
|
355
|
+
i0.ɵɵelementStart(14, "span", 125);
|
|
356
|
+
i0.ɵɵtext(15);
|
|
357
|
+
i0.ɵɵelementEnd()();
|
|
358
|
+
i0.ɵɵtemplate(16, TestSuiteRunFormComponentExtended_div_118_div_19_div_4_div_16_Template, 5, 2, "div", 126);
|
|
359
|
+
i0.ɵɵelementEnd()();
|
|
360
|
+
} if (rf & 2) {
|
|
361
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
362
|
+
i0.ɵɵadvance(10);
|
|
363
|
+
i0.ɵɵtextInterpolate2("", ctx_r1.evaluationMetrics.execCompletedCount, " / ", ctx_r1.evaluationMetrics.totalRuns, "");
|
|
364
|
+
i0.ɵɵadvance(5);
|
|
365
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.evaluationMetrics.execSuccessRate.toFixed(0), "%");
|
|
366
|
+
i0.ɵɵadvance();
|
|
367
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics.execErrorCount > 0 || ctx_r1.evaluationMetrics.execTimeoutCount > 0);
|
|
368
|
+
} }
|
|
369
|
+
function TestSuiteRunFormComponentExtended_div_118_div_19_Template(rf, ctx) { if (rf & 1) {
|
|
370
|
+
i0.ɵɵelementStart(0, "div", 116)(1, "div", 117);
|
|
371
|
+
i0.ɵɵtemplate(2, TestSuiteRunFormComponentExtended_div_118_div_19_div_2_Template, 14, 5, "div", 118)(3, TestSuiteRunFormComponentExtended_div_118_div_19_div_3_Template, 13, 4, "div", 118)(4, TestSuiteRunFormComponentExtended_div_118_div_19_div_4_Template, 17, 4, "div", 118);
|
|
372
|
+
i0.ɵɵelementEnd()();
|
|
373
|
+
} if (rf & 2) {
|
|
374
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
375
|
+
i0.ɵɵadvance(2);
|
|
376
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showHuman);
|
|
377
|
+
i0.ɵɵadvance();
|
|
378
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showAuto);
|
|
379
|
+
i0.ɵɵadvance();
|
|
380
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showExecution);
|
|
381
|
+
} }
|
|
382
|
+
function TestSuiteRunFormComponentExtended_div_118_div_20_div_8_i_2_Template(rf, ctx) { if (rf & 1) {
|
|
383
|
+
i0.ɵɵelement(0, "i", 157);
|
|
384
|
+
} }
|
|
385
|
+
function TestSuiteRunFormComponentExtended_div_118_div_20_div_8_i_3_Template(rf, ctx) { if (rf & 1) {
|
|
386
|
+
i0.ɵɵelement(0, "i", 158);
|
|
387
|
+
} }
|
|
388
|
+
function TestSuiteRunFormComponentExtended_div_118_div_20_div_8_i_4_Template(rf, ctx) { if (rf & 1) {
|
|
389
|
+
i0.ɵɵelement(0, "i", 133);
|
|
390
|
+
} }
|
|
391
|
+
function TestSuiteRunFormComponentExtended_div_118_div_20_div_8_Template(rf, ctx) { if (rf & 1) {
|
|
392
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
393
|
+
i0.ɵɵelementStart(0, "div", 147);
|
|
394
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_118_div_20_div_8_Template_div_click_0_listener() { const item_r10 = i0.ɵɵrestoreView(_r9).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleRunExpanded(item_r10.run.id)); });
|
|
395
|
+
i0.ɵɵelementStart(1, "div", 148);
|
|
396
|
+
i0.ɵɵtemplate(2, TestSuiteRunFormComponentExtended_div_118_div_20_div_8_i_2_Template, 1, 0, "i", 149)(3, TestSuiteRunFormComponentExtended_div_118_div_20_div_8_i_3_Template, 1, 0, "i", 150)(4, TestSuiteRunFormComponentExtended_div_118_div_20_div_8_i_4_Template, 1, 0, "i", 151);
|
|
397
|
+
i0.ɵɵelementEnd();
|
|
398
|
+
i0.ɵɵelementStart(5, "div", 152)(6, "span", 153);
|
|
399
|
+
i0.ɵɵtext(7);
|
|
400
|
+
i0.ɵɵelementEnd();
|
|
401
|
+
i0.ɵɵelementStart(8, "span", 154);
|
|
402
|
+
i0.ɵɵtext(9);
|
|
403
|
+
i0.ɵɵelementEnd()();
|
|
404
|
+
i0.ɵɵelementStart(10, "div", 155);
|
|
405
|
+
i0.ɵɵelement(11, "i", 156);
|
|
406
|
+
i0.ɵɵelementEnd()();
|
|
407
|
+
} if (rf & 2) {
|
|
408
|
+
const item_r10 = ctx.$implicit;
|
|
409
|
+
i0.ɵɵclassProp("high-priority", item_r10.priority === "high")("medium-priority", item_r10.priority === "medium");
|
|
410
|
+
i0.ɵɵadvance(2);
|
|
411
|
+
i0.ɵɵproperty("ngIf", item_r10.priority === "high");
|
|
412
|
+
i0.ɵɵadvance();
|
|
413
|
+
i0.ɵɵproperty("ngIf", item_r10.priority === "medium");
|
|
414
|
+
i0.ɵɵadvance();
|
|
415
|
+
i0.ɵɵproperty("ngIf", item_r10.priority === "low");
|
|
416
|
+
i0.ɵɵadvance(3);
|
|
417
|
+
i0.ɵɵtextInterpolate(item_r10.run.testName);
|
|
418
|
+
i0.ɵɵadvance(2);
|
|
419
|
+
i0.ɵɵtextInterpolate(item_r10.reason);
|
|
420
|
+
} }
|
|
421
|
+
function TestSuiteRunFormComponentExtended_div_118_div_20_div_9_Template(rf, ctx) { if (rf & 1) {
|
|
422
|
+
const _r11 = i0.ɵɵgetCurrentView();
|
|
423
|
+
i0.ɵɵelementStart(0, "div", 159)(1, "button", 97);
|
|
424
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_118_div_20_div_9_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.changeTab("runs")); });
|
|
425
|
+
i0.ɵɵtext(2);
|
|
426
|
+
i0.ɵɵelementEnd()();
|
|
427
|
+
} if (rf & 2) {
|
|
428
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
429
|
+
i0.ɵɵadvance(2);
|
|
430
|
+
i0.ɵɵtextInterpolate1(" View all ", ctx_r1.needsReviewItems.length, " items ");
|
|
431
|
+
} }
|
|
432
|
+
function TestSuiteRunFormComponentExtended_div_118_div_20_Template(rf, ctx) { if (rf & 1) {
|
|
433
|
+
i0.ɵɵelementStart(0, "div", 140)(1, "div", 141)(2, "h3");
|
|
434
|
+
i0.ɵɵelement(3, "i", 142);
|
|
435
|
+
i0.ɵɵtext(4, " Needs Review");
|
|
436
|
+
i0.ɵɵelementEnd();
|
|
437
|
+
i0.ɵɵelementStart(5, "span", 143);
|
|
69
438
|
i0.ɵɵtext(6);
|
|
439
|
+
i0.ɵɵelementEnd()();
|
|
440
|
+
i0.ɵɵelementStart(7, "div", 144);
|
|
441
|
+
i0.ɵɵtemplate(8, TestSuiteRunFormComponentExtended_div_118_div_20_div_8_Template, 12, 9, "div", 145)(9, TestSuiteRunFormComponentExtended_div_118_div_20_div_9_Template, 3, 1, "div", 146);
|
|
442
|
+
i0.ɵɵelementEnd()();
|
|
443
|
+
} if (rf & 2) {
|
|
444
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
445
|
+
i0.ɵɵadvance(6);
|
|
446
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.needsReviewItems.length, " items");
|
|
447
|
+
i0.ɵɵadvance(2);
|
|
448
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.needsReviewItems.slice(0, 5));
|
|
449
|
+
i0.ɵɵadvance();
|
|
450
|
+
i0.ɵɵproperty("ngIf", ctx_r1.needsReviewItems.length > 5);
|
|
451
|
+
} }
|
|
452
|
+
function TestSuiteRunFormComponentExtended_div_118_div_21_Template(rf, ctx) { if (rf & 1) {
|
|
453
|
+
i0.ɵɵelementStart(0, "div", 160)(1, "div", 161);
|
|
454
|
+
i0.ɵɵelement(2, "i", 162);
|
|
455
|
+
i0.ɵɵelementStart(3, "span");
|
|
456
|
+
i0.ɵɵtext(4, "Suite execution in progress...");
|
|
457
|
+
i0.ɵɵelementEnd()();
|
|
458
|
+
i0.ɵɵelementStart(5, "div", 163);
|
|
459
|
+
i0.ɵɵelement(6, "i", 164);
|
|
460
|
+
i0.ɵɵtext(7, " Auto-refreshing every 5 seconds ");
|
|
461
|
+
i0.ɵɵelementEnd()();
|
|
462
|
+
} }
|
|
463
|
+
function TestSuiteRunFormComponentExtended_div_118_Template(rf, ctx) { if (rf & 1) {
|
|
464
|
+
i0.ɵɵelementStart(0, "div", 104)(1, "div", 105)(2, "div", 106);
|
|
465
|
+
i0.ɵɵelement(3, "i", 6);
|
|
70
466
|
i0.ɵɵelementEnd();
|
|
71
|
-
i0.ɵɵelementStart(
|
|
72
|
-
i0.ɵɵtext(
|
|
467
|
+
i0.ɵɵelementStart(4, "div", 107)(5, "h2");
|
|
468
|
+
i0.ɵɵtext(6);
|
|
73
469
|
i0.ɵɵelementEnd();
|
|
74
|
-
i0.ɵɵelementStart(
|
|
470
|
+
i0.ɵɵelementStart(7, "div", 108)(8, "div", 109)(9, "span", 110);
|
|
75
471
|
i0.ɵɵtext(10);
|
|
76
|
-
i0.ɵɵelementEnd()
|
|
472
|
+
i0.ɵɵelementEnd();
|
|
473
|
+
i0.ɵɵelementStart(11, "span", 111);
|
|
474
|
+
i0.ɵɵtext(12, "Pass Rate");
|
|
475
|
+
i0.ɵɵelementEnd()();
|
|
476
|
+
i0.ɵɵelement(13, "div", 112);
|
|
477
|
+
i0.ɵɵelementStart(14, "div", 109)(15, "span", 110);
|
|
478
|
+
i0.ɵɵtext(16);
|
|
479
|
+
i0.ɵɵelementEnd();
|
|
480
|
+
i0.ɵɵelementStart(17, "span", 111);
|
|
481
|
+
i0.ɵɵtext(18, "Tests Passed");
|
|
482
|
+
i0.ɵɵelementEnd()()()()();
|
|
483
|
+
i0.ɵɵtemplate(19, TestSuiteRunFormComponentExtended_div_118_div_19_Template, 5, 3, "div", 113)(20, TestSuiteRunFormComponentExtended_div_118_div_20_Template, 10, 3, "div", 114)(21, TestSuiteRunFormComponentExtended_div_118_div_21_Template, 8, 0, "div", 115);
|
|
484
|
+
i0.ɵɵelementEnd();
|
|
77
485
|
} if (rf & 2) {
|
|
78
486
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
79
487
|
i0.ɵɵadvance();
|
|
80
|
-
i0.ɵɵclassProp("passed", ctx_r1.record.Status === "Completed" && ctx_r1.getPassRate() >= 90)("failed", ctx_r1.record.Status === "Failed");
|
|
488
|
+
i0.ɵɵclassProp("passed", ctx_r1.record.Status === "Completed" && ctx_r1.getPassRate() >= 90)("failed", ctx_r1.record.Status === "Failed" || ctx_r1.getPassRate() < 50)("running", ctx_r1.record.Status === "Running")("pending", ctx_r1.record.Status === "Pending");
|
|
81
489
|
i0.ɵɵadvance(2);
|
|
82
490
|
i0.ɵɵproperty("ngClass", ctx_r1.getStatusIcon());
|
|
83
491
|
i0.ɵɵadvance(3);
|
|
84
|
-
i0.ɵɵtextInterpolate1("SUITE ", ctx_r1.record.Status.toUpperCase(), "");
|
|
492
|
+
i0.ɵɵtextInterpolate1("SUITE ", ctx_r1.record.Status.toUpperCase() || "UNKNOWN", "");
|
|
493
|
+
i0.ɵɵadvance(4);
|
|
494
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.getPassRate().toFixed(1), "%");
|
|
495
|
+
i0.ɵɵadvance(6);
|
|
496
|
+
i0.ɵɵtextInterpolate2("", ctx_r1.record.PassedTests || 0, " / ", ctx_r1.record.TotalTests || 0, "");
|
|
497
|
+
i0.ɵɵadvance(3);
|
|
498
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evaluationMetrics && ctx_r1.feedbacksLoaded);
|
|
499
|
+
i0.ɵɵadvance();
|
|
500
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showHuman && ctx_r1.needsReviewItems.length > 0 && ctx_r1.feedbacksLoaded);
|
|
501
|
+
i0.ɵɵadvance();
|
|
502
|
+
i0.ɵɵproperty("ngIf", ctx_r1.record.Status === "Running" || ctx_r1.record.Status === "Pending");
|
|
503
|
+
} }
|
|
504
|
+
function TestSuiteRunFormComponentExtended_div_119_div_1_button_4_Template(rf, ctx) { if (rf & 1) {
|
|
505
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
506
|
+
i0.ɵɵelementStart(0, "button", 179);
|
|
507
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_1_button_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.setRunStatusFilter("Passed")); });
|
|
508
|
+
i0.ɵɵelement(1, "i", 180);
|
|
509
|
+
i0.ɵɵtext(2);
|
|
510
|
+
i0.ɵɵelementEnd();
|
|
511
|
+
} if (rf & 2) {
|
|
512
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
513
|
+
i0.ɵɵclassProp("active", ctx_r1.runStatusFilter === "Passed");
|
|
514
|
+
i0.ɵɵadvance(2);
|
|
515
|
+
i0.ɵɵtextInterpolate1(" Passed (", ctx_r1.getRunCountByStatus("Passed"), ") ");
|
|
516
|
+
} }
|
|
517
|
+
function TestSuiteRunFormComponentExtended_div_119_div_1_button_5_Template(rf, ctx) { if (rf & 1) {
|
|
518
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
519
|
+
i0.ɵɵelementStart(0, "button", 181);
|
|
520
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_1_button_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.setRunStatusFilter("Failed")); });
|
|
521
|
+
i0.ɵɵelement(1, "i", 100);
|
|
522
|
+
i0.ɵɵtext(2);
|
|
523
|
+
i0.ɵɵelementEnd();
|
|
524
|
+
} if (rf & 2) {
|
|
525
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
526
|
+
i0.ɵɵclassProp("active", ctx_r1.runStatusFilter === "Failed");
|
|
527
|
+
i0.ɵɵadvance(2);
|
|
528
|
+
i0.ɵɵtextInterpolate1(" Failed (", ctx_r1.getRunCountByStatus("Failed"), ") ");
|
|
529
|
+
} }
|
|
530
|
+
function TestSuiteRunFormComponentExtended_div_119_div_1_button_6_Template(rf, ctx) { if (rf & 1) {
|
|
531
|
+
const _r15 = i0.ɵɵgetCurrentView();
|
|
532
|
+
i0.ɵɵelementStart(0, "button", 182);
|
|
533
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_1_button_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r15); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.setRunStatusFilter("Error")); });
|
|
534
|
+
i0.ɵɵelement(1, "i", 183);
|
|
535
|
+
i0.ɵɵtext(2);
|
|
536
|
+
i0.ɵɵelementEnd();
|
|
537
|
+
} if (rf & 2) {
|
|
538
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
539
|
+
i0.ɵɵclassProp("active", ctx_r1.runStatusFilter === "Error");
|
|
540
|
+
i0.ɵɵadvance(2);
|
|
541
|
+
i0.ɵɵtextInterpolate1(" Error (", ctx_r1.getRunCountByStatus("Error"), ") ");
|
|
542
|
+
} }
|
|
543
|
+
function TestSuiteRunFormComponentExtended_div_119_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
544
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
545
|
+
i0.ɵɵelementStart(0, "div", 170)(1, "div", 171)(2, "button", 172);
|
|
546
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_1_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setRunStatusFilter(null)); });
|
|
547
|
+
i0.ɵɵtext(3);
|
|
548
|
+
i0.ɵɵelementEnd();
|
|
549
|
+
i0.ɵɵtemplate(4, TestSuiteRunFormComponentExtended_div_119_div_1_button_4_Template, 3, 3, "button", 173)(5, TestSuiteRunFormComponentExtended_div_119_div_1_button_5_Template, 3, 3, "button", 174)(6, TestSuiteRunFormComponentExtended_div_119_div_1_button_6_Template, 3, 3, "button", 175);
|
|
550
|
+
i0.ɵɵelementEnd();
|
|
551
|
+
i0.ɵɵelementStart(7, "div", 176)(8, "button", 177);
|
|
552
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_1_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.exportToCSV()); });
|
|
553
|
+
i0.ɵɵelement(9, "i", 178);
|
|
554
|
+
i0.ɵɵtext(10, " Export CSV ");
|
|
555
|
+
i0.ɵɵelementEnd()()();
|
|
556
|
+
} if (rf & 2) {
|
|
557
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
558
|
+
i0.ɵɵadvance(2);
|
|
559
|
+
i0.ɵɵclassProp("active", ctx_r1.runStatusFilter === null);
|
|
560
|
+
i0.ɵɵadvance();
|
|
561
|
+
i0.ɵɵtextInterpolate1(" All (", ctx_r1.testRuns.length, ") ");
|
|
562
|
+
i0.ɵɵadvance();
|
|
563
|
+
i0.ɵɵproperty("ngIf", ctx_r1.getRunCountByStatus("Passed") > 0);
|
|
564
|
+
i0.ɵɵadvance();
|
|
565
|
+
i0.ɵɵproperty("ngIf", ctx_r1.getRunCountByStatus("Failed") > 0);
|
|
566
|
+
i0.ɵɵadvance();
|
|
567
|
+
i0.ɵɵproperty("ngIf", ctx_r1.getRunCountByStatus("Error") > 0);
|
|
568
|
+
} }
|
|
569
|
+
function TestSuiteRunFormComponentExtended_div_119_div_2_div_2_Template(rf, ctx) { if (rf & 1) {
|
|
570
|
+
i0.ɵɵelementStart(0, "div", 187);
|
|
571
|
+
i0.ɵɵelement(1, "div", 188)(2, "div", 189);
|
|
572
|
+
i0.ɵɵelementStart(3, "div", 190);
|
|
573
|
+
i0.ɵɵelement(4, "div", 191)(5, "div", 192);
|
|
574
|
+
i0.ɵɵelementEnd()();
|
|
575
|
+
} }
|
|
576
|
+
function TestSuiteRunFormComponentExtended_div_119_div_2_Template(rf, ctx) { if (rf & 1) {
|
|
577
|
+
i0.ɵɵelementStart(0, "div", 184)(1, "div", 185);
|
|
578
|
+
i0.ɵɵtemplate(2, TestSuiteRunFormComponentExtended_div_119_div_2_div_2_Template, 6, 0, "div", 186);
|
|
579
|
+
i0.ɵɵelementEnd()();
|
|
580
|
+
} if (rf & 2) {
|
|
581
|
+
i0.ɵɵadvance(2);
|
|
582
|
+
i0.ɵɵproperty("ngForOf", i0.ɵɵpureFunction0(1, _c0));
|
|
583
|
+
} }
|
|
584
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_span_12_Template(rf, ctx) { if (rf & 1) {
|
|
585
|
+
i0.ɵɵelementStart(0, "span", 211);
|
|
586
|
+
i0.ɵɵelement(1, "i", 18);
|
|
587
|
+
i0.ɵɵtext(2);
|
|
588
|
+
i0.ɵɵelementEnd();
|
|
589
|
+
} if (rf & 2) {
|
|
590
|
+
const run_r17 = i0.ɵɵnextContext().$implicit;
|
|
591
|
+
i0.ɵɵadvance(2);
|
|
592
|
+
i0.ɵɵtextInterpolate1(" ", run_r17.DurationSeconds.toFixed(1), "s ");
|
|
593
|
+
} }
|
|
594
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_span_13_Template(rf, ctx) { if (rf & 1) {
|
|
595
|
+
i0.ɵɵelementStart(0, "span", 212);
|
|
596
|
+
i0.ɵɵelement(1, "i", 23);
|
|
597
|
+
i0.ɵɵtext(2);
|
|
598
|
+
i0.ɵɵelementEnd();
|
|
599
|
+
} if (rf & 2) {
|
|
600
|
+
const run_r17 = i0.ɵɵnextContext().$implicit;
|
|
601
|
+
i0.ɵɵadvance(2);
|
|
602
|
+
i0.ɵɵtextInterpolate1(" ", run_r17.CostUSD.toFixed(6), " ");
|
|
603
|
+
} }
|
|
604
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_mj_entity_link_pill_14_Template(rf, ctx) { if (rf & 1) {
|
|
605
|
+
i0.ɵɵelement(0, "mj-entity-link-pill", 213);
|
|
606
|
+
} if (rf & 2) {
|
|
607
|
+
const run_r17 = i0.ɵɵnextContext().$implicit;
|
|
608
|
+
i0.ɵɵproperty("entityName", run_r17.TargetLogEntity)("recordId", run_r17.TargetLogID);
|
|
609
|
+
} }
|
|
610
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_15_span_1_Template(rf, ctx) { if (rf & 1) {
|
|
611
|
+
i0.ɵɵelementStart(0, "span", 216);
|
|
612
|
+
i0.ɵɵtext(1);
|
|
613
|
+
i0.ɵɵelementEnd();
|
|
614
|
+
} if (rf & 2) {
|
|
615
|
+
const tag_r18 = ctx.$implicit;
|
|
616
|
+
i0.ɵɵadvance();
|
|
617
|
+
i0.ɵɵtextInterpolate(tag_r18);
|
|
618
|
+
} }
|
|
619
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_15_Template(rf, ctx) { if (rf & 1) {
|
|
620
|
+
i0.ɵɵelementStart(0, "div", 214);
|
|
621
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_15_span_1_Template, 2, 1, "span", 215);
|
|
622
|
+
i0.ɵɵelementEnd();
|
|
623
|
+
} if (rf & 2) {
|
|
624
|
+
const run_r17 = i0.ɵɵnextContext().$implicit;
|
|
625
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
626
|
+
i0.ɵɵadvance();
|
|
627
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.getRunTags(run_r17));
|
|
628
|
+
} }
|
|
629
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_button_7_Template(rf, ctx) { if (rf & 1) {
|
|
630
|
+
const _r20 = i0.ɵɵgetCurrentView();
|
|
631
|
+
i0.ɵɵelementStart(0, "button", 234);
|
|
632
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_button_7_Template_button_click_0_listener($event) { const num_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); ctx_r1.setInlineRating(num_r21); return i0.ɵɵresetView($event.stopPropagation()); })("mouseenter", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_button_7_Template_button_mouseenter_0_listener() { const num_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.inlineHoverRating = num_r21); })("mouseleave", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_button_7_Template_button_mouseleave_0_listener() { i0.ɵɵrestoreView(_r20); const ctx_r1 = i0.ɵɵnextContext(5); return i0.ɵɵresetView(ctx_r1.inlineHoverRating = 0); });
|
|
633
|
+
i0.ɵɵtext(1);
|
|
634
|
+
i0.ɵɵelementEnd();
|
|
635
|
+
} if (rf & 2) {
|
|
636
|
+
const num_r21 = ctx.$implicit;
|
|
637
|
+
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
638
|
+
i0.ɵɵclassProp("selected", num_r21 === ctx_r1.inlineRating)("hover", num_r21 === ctx_r1.inlineHoverRating)("low", num_r21 <= 3)("mid", num_r21 >= 4 && num_r21 <= 6)("high", num_r21 >= 7);
|
|
639
|
+
i0.ɵɵadvance();
|
|
640
|
+
i0.ɵɵtextInterpolate1(" ", num_r21, " ");
|
|
641
|
+
} }
|
|
642
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_div_8_Template(rf, ctx) { if (rf & 1) {
|
|
643
|
+
i0.ɵɵelementStart(0, "div", 235)(1, "span", 236);
|
|
644
|
+
i0.ɵɵtext(2);
|
|
645
|
+
i0.ɵɵelementEnd();
|
|
646
|
+
i0.ɵɵelementStart(3, "span", 237);
|
|
647
|
+
i0.ɵɵtext(4);
|
|
648
|
+
i0.ɵɵelementEnd()();
|
|
649
|
+
} if (rf & 2) {
|
|
650
|
+
const ctx_r1 = i0.ɵɵnextContext(5);
|
|
651
|
+
i0.ɵɵadvance(2);
|
|
652
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.inlineRating, "/10");
|
|
653
|
+
i0.ɵɵadvance(2);
|
|
654
|
+
i0.ɵɵtextInterpolate(ctx_r1.getInlineRatingLabel());
|
|
655
|
+
} }
|
|
656
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template(rf, ctx) { if (rf & 1) {
|
|
657
|
+
const _r19 = i0.ɵɵgetCurrentView();
|
|
658
|
+
i0.ɵɵelementStart(0, "div", 217);
|
|
659
|
+
i0.ɵɵelement(1, "div", 218);
|
|
660
|
+
i0.ɵɵelementStart(2, "div", 219)(3, "div", 220);
|
|
661
|
+
i0.ɵɵtext(4, "Quick Feedback");
|
|
662
|
+
i0.ɵɵelementEnd();
|
|
663
|
+
i0.ɵɵelementStart(5, "div", 221)(6, "div", 222);
|
|
664
|
+
i0.ɵɵtemplate(7, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_button_7_Template, 2, 11, "button", 223);
|
|
665
|
+
i0.ɵɵelementEnd();
|
|
666
|
+
i0.ɵɵtemplate(8, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_div_8_Template, 5, 2, "div", 224);
|
|
667
|
+
i0.ɵɵelementEnd();
|
|
668
|
+
i0.ɵɵelementStart(9, "div", 225)(10, "span", 226);
|
|
669
|
+
i0.ɵɵtext(11, "Was it correct?");
|
|
670
|
+
i0.ɵɵelementEnd();
|
|
671
|
+
i0.ɵɵelementStart(12, "div", 227)(13, "label", 228);
|
|
672
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_label_click_13_listener($event) { i0.ɵɵrestoreView(_r19); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
673
|
+
i0.ɵɵelementStart(14, "input", 229);
|
|
674
|
+
i0.ɵɵtwoWayListener("ngModelChange", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_input_ngModelChange_14_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.inlineIsCorrect, $event) || (ctx_r1.inlineIsCorrect = $event); return i0.ɵɵresetView($event); });
|
|
675
|
+
i0.ɵɵelementEnd();
|
|
676
|
+
i0.ɵɵelementStart(15, "span");
|
|
677
|
+
i0.ɵɵtext(16, "Yes");
|
|
678
|
+
i0.ɵɵelementEnd()();
|
|
679
|
+
i0.ɵɵelementStart(17, "label", 228);
|
|
680
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_label_click_17_listener($event) { i0.ɵɵrestoreView(_r19); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
681
|
+
i0.ɵɵelementStart(18, "input", 229);
|
|
682
|
+
i0.ɵɵtwoWayListener("ngModelChange", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_input_ngModelChange_18_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.inlineIsCorrect, $event) || (ctx_r1.inlineIsCorrect = $event); return i0.ɵɵresetView($event); });
|
|
683
|
+
i0.ɵɵelementEnd();
|
|
684
|
+
i0.ɵɵelementStart(19, "span");
|
|
685
|
+
i0.ɵɵtext(20, "No");
|
|
686
|
+
i0.ɵɵelementEnd()();
|
|
687
|
+
i0.ɵɵelementStart(21, "label", 228);
|
|
688
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_label_click_21_listener($event) { i0.ɵɵrestoreView(_r19); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
689
|
+
i0.ɵɵelementStart(22, "input", 229);
|
|
690
|
+
i0.ɵɵtwoWayListener("ngModelChange", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_input_ngModelChange_22_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.inlineIsCorrect, $event) || (ctx_r1.inlineIsCorrect = $event); return i0.ɵɵresetView($event); });
|
|
691
|
+
i0.ɵɵelementEnd();
|
|
692
|
+
i0.ɵɵelementStart(23, "span");
|
|
693
|
+
i0.ɵɵtext(24, "Not Sure");
|
|
694
|
+
i0.ɵɵelementEnd()()()();
|
|
695
|
+
i0.ɵɵelementStart(25, "div", 230);
|
|
696
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_div_click_25_listener($event) { i0.ɵɵrestoreView(_r19); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
697
|
+
i0.ɵɵelementStart(26, "textarea", 231);
|
|
698
|
+
i0.ɵɵtwoWayListener("ngModelChange", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_textarea_ngModelChange_26_listener($event) { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(4); i0.ɵɵtwoWayBindingSet(ctx_r1.inlineComments, $event) || (ctx_r1.inlineComments = $event); return i0.ɵɵresetView($event); });
|
|
699
|
+
i0.ɵɵelementEnd()();
|
|
700
|
+
i0.ɵɵelementStart(27, "div", 232);
|
|
701
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_div_click_27_listener($event) { i0.ɵɵrestoreView(_r19); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
702
|
+
i0.ɵɵelementStart(28, "button", 177);
|
|
703
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_button_click_28_listener() { i0.ɵɵrestoreView(_r19); const run_r17 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openTestRun(run_r17.ID)); });
|
|
704
|
+
i0.ɵɵelement(29, "i", 233);
|
|
705
|
+
i0.ɵɵtext(30, " View Full Details ");
|
|
706
|
+
i0.ɵɵelementEnd();
|
|
707
|
+
i0.ɵɵelementStart(31, "button", 95);
|
|
708
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template_button_click_31_listener() { i0.ɵɵrestoreView(_r19); const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.saveInlineFeedback()); });
|
|
709
|
+
i0.ɵɵelement(32, "i", 6);
|
|
710
|
+
i0.ɵɵtext(33);
|
|
711
|
+
i0.ɵɵelementEnd()()()();
|
|
712
|
+
} if (rf & 2) {
|
|
713
|
+
const run_r17 = i0.ɵɵnextContext().$implicit;
|
|
714
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
715
|
+
i0.ɵɵadvance(7);
|
|
716
|
+
i0.ɵɵproperty("ngForOf", i0.ɵɵpureFunction0(18, _c1));
|
|
717
|
+
i0.ɵɵadvance();
|
|
718
|
+
i0.ɵɵproperty("ngIf", ctx_r1.inlineRating > 0);
|
|
719
|
+
i0.ɵɵadvance(6);
|
|
720
|
+
i0.ɵɵpropertyInterpolate1("name", "correct-", run_r17.ID, "");
|
|
721
|
+
i0.ɵɵproperty("value", true);
|
|
722
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.inlineIsCorrect);
|
|
723
|
+
i0.ɵɵadvance(4);
|
|
724
|
+
i0.ɵɵpropertyInterpolate1("name", "correct-", run_r17.ID, "");
|
|
725
|
+
i0.ɵɵproperty("value", false);
|
|
726
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.inlineIsCorrect);
|
|
727
|
+
i0.ɵɵadvance(4);
|
|
728
|
+
i0.ɵɵpropertyInterpolate1("name", "correct-", run_r17.ID, "");
|
|
729
|
+
i0.ɵɵproperty("value", null);
|
|
730
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.inlineIsCorrect);
|
|
731
|
+
i0.ɵɵadvance(4);
|
|
732
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.inlineComments);
|
|
733
|
+
i0.ɵɵadvance(5);
|
|
734
|
+
i0.ɵɵproperty("disabled", !ctx_r1.canSubmitInlineFeedback() || ctx_r1.savingInlineFeedback);
|
|
735
|
+
i0.ɵɵadvance();
|
|
736
|
+
i0.ɵɵproperty("ngClass", ctx_r1.savingInlineFeedback ? "fa-spinner fa-spin" : "fa-save");
|
|
737
|
+
i0.ɵɵadvance();
|
|
738
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.savingInlineFeedback ? "Saving..." : ctx_r1.hasFeedback(run_r17.ID) ? "Update" : "Save", " ");
|
|
739
|
+
} }
|
|
740
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
741
|
+
const _r16 = i0.ɵɵgetCurrentView();
|
|
742
|
+
i0.ɵɵelementStart(0, "div", 195)(1, "div", 196);
|
|
743
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_3_div_1_Template_div_click_1_listener() { const run_r17 = i0.ɵɵrestoreView(_r16).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleRunExpanded(run_r17.ID)); });
|
|
744
|
+
i0.ɵɵelementStart(2, "div", 197);
|
|
745
|
+
i0.ɵɵtext(3);
|
|
746
|
+
i0.ɵɵelementEnd();
|
|
747
|
+
i0.ɵɵelementStart(4, "div", 198);
|
|
748
|
+
i0.ɵɵelement(5, "i", 6);
|
|
749
|
+
i0.ɵɵelementEnd();
|
|
750
|
+
i0.ɵɵelementStart(6, "div", 199)(7, "div", 200)(8, "div", 201);
|
|
751
|
+
i0.ɵɵtext(9);
|
|
752
|
+
i0.ɵɵelementEnd();
|
|
753
|
+
i0.ɵɵelement(10, "app-evaluation-badge", 202);
|
|
754
|
+
i0.ɵɵelementEnd();
|
|
755
|
+
i0.ɵɵelementStart(11, "div", 203);
|
|
756
|
+
i0.ɵɵtemplate(12, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_span_12_Template, 3, 1, "span", 204)(13, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_span_13_Template, 3, 1, "span", 205)(14, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_mj_entity_link_pill_14_Template, 1, 2, "mj-entity-link-pill", 206);
|
|
757
|
+
i0.ɵɵelementEnd();
|
|
758
|
+
i0.ɵɵtemplate(15, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_15_Template, 2, 1, "div", 207);
|
|
759
|
+
i0.ɵɵelementEnd();
|
|
760
|
+
i0.ɵɵelementStart(16, "div", 208);
|
|
761
|
+
i0.ɵɵelement(17, "i", 209);
|
|
762
|
+
i0.ɵɵelementEnd()();
|
|
763
|
+
i0.ɵɵtemplate(18, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_div_18_Template, 34, 19, "div", 210);
|
|
764
|
+
i0.ɵɵelementEnd();
|
|
765
|
+
} if (rf & 2) {
|
|
766
|
+
const run_r17 = ctx.$implicit;
|
|
767
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
768
|
+
i0.ɵɵadvance(3);
|
|
769
|
+
i0.ɵɵtextInterpolate(run_r17.Sequence || "-");
|
|
770
|
+
i0.ɵɵadvance();
|
|
771
|
+
i0.ɵɵstyleProp("background-color", ctx_r1.getRunStatusColor(run_r17.Status));
|
|
772
|
+
i0.ɵɵadvance();
|
|
773
|
+
i0.ɵɵproperty("ngClass", ctx_r1.getRunStatusIcon(run_r17.Status));
|
|
774
|
+
i0.ɵɵadvance(4);
|
|
775
|
+
i0.ɵɵtextInterpolate(run_r17.Test);
|
|
776
|
+
i0.ɵɵadvance();
|
|
777
|
+
i0.ɵɵproperty("executionStatus", run_r17.Status)("originalStatus", run_r17.Status)("autoScore", run_r17.Score)("humanRating", ctx_r1.getFeedbackRating(run_r17.ID) || null)("humanIsCorrect", ctx_r1.getHumanIsCorrect(run_r17.ID))("hasHumanFeedback", ctx_r1.hasFeedback(run_r17.ID))("preferences", ctx_r1.evalPreferences)("mode", "compact");
|
|
85
778
|
i0.ɵɵadvance(2);
|
|
86
|
-
i0.ɵɵ
|
|
779
|
+
i0.ɵɵproperty("ngIf", run_r17.DurationSeconds);
|
|
780
|
+
i0.ɵɵadvance();
|
|
781
|
+
i0.ɵɵproperty("ngIf", run_r17.CostUSD);
|
|
782
|
+
i0.ɵɵadvance();
|
|
783
|
+
i0.ɵɵproperty("ngIf", run_r17.TargetLogEntityID && run_r17.TargetLogID);
|
|
784
|
+
i0.ɵɵadvance();
|
|
785
|
+
i0.ɵɵproperty("ngIf", ctx_r1.getRunTags(run_r17).length > 0);
|
|
87
786
|
i0.ɵɵadvance(2);
|
|
88
|
-
i0.ɵɵ
|
|
787
|
+
i0.ɵɵclassProp("fa-chevron-down", ctx_r1.expandedRunId !== run_r17.ID)("fa-chevron-up", ctx_r1.expandedRunId === run_r17.ID);
|
|
788
|
+
i0.ɵɵadvance();
|
|
789
|
+
i0.ɵɵproperty("ngIf", ctx_r1.expandedRunId === run_r17.ID);
|
|
790
|
+
} }
|
|
791
|
+
function TestSuiteRunFormComponentExtended_div_119_div_3_Template(rf, ctx) { if (rf & 1) {
|
|
792
|
+
i0.ɵɵelementStart(0, "div", 193);
|
|
793
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_119_div_3_div_1_Template, 19, 22, "div", 194);
|
|
794
|
+
i0.ɵɵelementEnd();
|
|
795
|
+
} if (rf & 2) {
|
|
796
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
797
|
+
i0.ɵɵadvance();
|
|
798
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.getFilteredTestRuns());
|
|
799
|
+
} }
|
|
800
|
+
function TestSuiteRunFormComponentExtended_div_119_div_4_Template(rf, ctx) { if (rf & 1) {
|
|
801
|
+
i0.ɵɵelementStart(0, "div", 238)(1, "div", 239);
|
|
802
|
+
i0.ɵɵelement(2, "i", 240);
|
|
803
|
+
i0.ɵɵelementEnd();
|
|
804
|
+
i0.ɵɵelementStart(3, "h4");
|
|
805
|
+
i0.ɵɵtext(4, "No Test Runs Found");
|
|
806
|
+
i0.ɵɵelementEnd();
|
|
807
|
+
i0.ɵɵelementStart(5, "p");
|
|
808
|
+
i0.ɵɵtext(6, "No test runs have been recorded for this suite execution.");
|
|
809
|
+
i0.ɵɵelementEnd()();
|
|
810
|
+
} }
|
|
811
|
+
function TestSuiteRunFormComponentExtended_div_119_div_5_Template(rf, ctx) { if (rf & 1) {
|
|
812
|
+
const _r22 = i0.ɵɵgetCurrentView();
|
|
813
|
+
i0.ɵɵelementStart(0, "div", 238)(1, "div", 239);
|
|
814
|
+
i0.ɵɵelement(2, "i", 241);
|
|
815
|
+
i0.ɵɵelementEnd();
|
|
816
|
+
i0.ɵɵelementStart(3, "h4");
|
|
817
|
+
i0.ɵɵtext(4, "No Matching Runs");
|
|
818
|
+
i0.ɵɵelementEnd();
|
|
819
|
+
i0.ɵɵelementStart(5, "p");
|
|
820
|
+
i0.ɵɵtext(6, "No test runs match the current filter.");
|
|
821
|
+
i0.ɵɵelementEnd();
|
|
822
|
+
i0.ɵɵelementStart(7, "button", 177);
|
|
823
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_119_div_5_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r22); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setRunStatusFilter(null)); });
|
|
824
|
+
i0.ɵɵtext(8, "Clear Filter");
|
|
825
|
+
i0.ɵɵelementEnd()();
|
|
826
|
+
} }
|
|
827
|
+
function TestSuiteRunFormComponentExtended_div_119_Template(rf, ctx) { if (rf & 1) {
|
|
828
|
+
i0.ɵɵelementStart(0, "div", 165);
|
|
829
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_119_div_1_Template, 11, 6, "div", 166)(2, TestSuiteRunFormComponentExtended_div_119_div_2_Template, 3, 2, "div", 167)(3, TestSuiteRunFormComponentExtended_div_119_div_3_Template, 2, 1, "div", 168)(4, TestSuiteRunFormComponentExtended_div_119_div_4_Template, 7, 0, "div", 169)(5, TestSuiteRunFormComponentExtended_div_119_div_5_Template, 9, 0, "div", 169);
|
|
830
|
+
i0.ɵɵelementEnd();
|
|
831
|
+
} if (rf & 2) {
|
|
832
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
833
|
+
i0.ɵɵadvance();
|
|
834
|
+
i0.ɵɵproperty("ngIf", ctx_r1.testRunsLoaded && ctx_r1.testRuns.length > 0);
|
|
835
|
+
i0.ɵɵadvance();
|
|
836
|
+
i0.ɵɵproperty("ngIf", ctx_r1.loadingTestRuns);
|
|
837
|
+
i0.ɵɵadvance();
|
|
838
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.loadingTestRuns && ctx_r1.testRuns.length > 0);
|
|
839
|
+
i0.ɵɵadvance();
|
|
840
|
+
i0.ɵɵproperty("ngIf", ctx_r1.testRunsLoaded && !ctx_r1.loadingTestRuns && ctx_r1.testRuns.length === 0);
|
|
841
|
+
i0.ɵɵadvance();
|
|
842
|
+
i0.ɵɵproperty("ngIf", ctx_r1.testRunsLoaded && !ctx_r1.loadingTestRuns && ctx_r1.testRuns.length > 0 && ctx_r1.getFilteredTestRuns().length === 0);
|
|
843
|
+
} }
|
|
844
|
+
function TestSuiteRunFormComponentExtended_div_120_a_15_Template(rf, ctx) { if (rf & 1) {
|
|
845
|
+
const _r23 = i0.ɵɵgetCurrentView();
|
|
846
|
+
i0.ɵɵelementStart(0, "a", 62);
|
|
847
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_120_a_15_Template_a_click_0_listener() { i0.ɵɵrestoreView(_r23); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.openTestSuite()); });
|
|
848
|
+
i0.ɵɵtext(1);
|
|
849
|
+
i0.ɵɵelementEnd();
|
|
850
|
+
} if (rf & 2) {
|
|
851
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
852
|
+
i0.ɵɵadvance();
|
|
853
|
+
i0.ɵɵtextInterpolate(ctx_r1.testSuite.Name);
|
|
854
|
+
} }
|
|
855
|
+
function TestSuiteRunFormComponentExtended_div_120_span_16_Template(rf, ctx) { if (rf & 1) {
|
|
856
|
+
i0.ɵɵelementStart(0, "span");
|
|
857
|
+
i0.ɵɵtext(1, "Loading...");
|
|
858
|
+
i0.ɵɵelementEnd();
|
|
859
|
+
} }
|
|
860
|
+
function TestSuiteRunFormComponentExtended_div_120_Template(rf, ctx) { if (rf & 1) {
|
|
861
|
+
i0.ɵɵelementStart(0, "div", 242)(1, "div", 243)(2, "h3");
|
|
862
|
+
i0.ɵɵelement(3, "i", 47);
|
|
863
|
+
i0.ɵɵtext(4, " Run Information");
|
|
864
|
+
i0.ɵɵelementEnd();
|
|
865
|
+
i0.ɵɵelementStart(5, "div", 244)(6, "div", 245)(7, "div", 246);
|
|
866
|
+
i0.ɵɵtext(8, "Run ID");
|
|
867
|
+
i0.ɵɵelementEnd();
|
|
868
|
+
i0.ɵɵelementStart(9, "div", 247);
|
|
869
|
+
i0.ɵɵtext(10);
|
|
870
|
+
i0.ɵɵelementEnd()();
|
|
871
|
+
i0.ɵɵelementStart(11, "div", 245)(12, "div", 246);
|
|
872
|
+
i0.ɵɵtext(13, "Test Suite");
|
|
873
|
+
i0.ɵɵelementEnd();
|
|
874
|
+
i0.ɵɵelementStart(14, "div", 248);
|
|
875
|
+
i0.ɵɵtemplate(15, TestSuiteRunFormComponentExtended_div_120_a_15_Template, 2, 1, "a", 249)(16, TestSuiteRunFormComponentExtended_div_120_span_16_Template, 2, 0, "span", 250);
|
|
876
|
+
i0.ɵɵelementEnd()();
|
|
877
|
+
i0.ɵɵelementStart(17, "div", 245)(18, "div", 246);
|
|
878
|
+
i0.ɵɵtext(19, "Status");
|
|
879
|
+
i0.ɵɵelementEnd();
|
|
880
|
+
i0.ɵɵelementStart(20, "div", 248)(21, "span", 251);
|
|
881
|
+
i0.ɵɵtext(22);
|
|
882
|
+
i0.ɵɵelementEnd()()();
|
|
883
|
+
i0.ɵɵelementStart(23, "div", 245)(24, "div", 246);
|
|
884
|
+
i0.ɵɵtext(25, "Run By");
|
|
885
|
+
i0.ɵɵelementEnd();
|
|
886
|
+
i0.ɵɵelementStart(26, "div", 248);
|
|
887
|
+
i0.ɵɵtext(27);
|
|
888
|
+
i0.ɵɵelementEnd()();
|
|
889
|
+
i0.ɵɵelementStart(28, "div", 245)(29, "div", 246);
|
|
890
|
+
i0.ɵɵtext(30, "Started At");
|
|
891
|
+
i0.ɵɵelementEnd();
|
|
892
|
+
i0.ɵɵelementStart(31, "div", 248);
|
|
893
|
+
i0.ɵɵtext(32);
|
|
894
|
+
i0.ɵɵpipe(33, "date");
|
|
895
|
+
i0.ɵɵelementEnd()();
|
|
896
|
+
i0.ɵɵelementStart(34, "div", 245)(35, "div", 246);
|
|
897
|
+
i0.ɵɵtext(36, "Completed At");
|
|
898
|
+
i0.ɵɵelementEnd();
|
|
899
|
+
i0.ɵɵelementStart(37, "div", 248);
|
|
900
|
+
i0.ɵɵtext(38);
|
|
901
|
+
i0.ɵɵpipe(39, "date");
|
|
902
|
+
i0.ɵɵelementEnd()();
|
|
903
|
+
i0.ɵɵelementStart(40, "div", 245)(41, "div", 246);
|
|
904
|
+
i0.ɵɵtext(42, "Environment");
|
|
905
|
+
i0.ɵɵelementEnd();
|
|
906
|
+
i0.ɵɵelementStart(43, "div", 248);
|
|
907
|
+
i0.ɵɵtext(44);
|
|
908
|
+
i0.ɵɵelementEnd()();
|
|
909
|
+
i0.ɵɵelementStart(45, "div", 245)(46, "div", 246);
|
|
910
|
+
i0.ɵɵtext(47, "Trigger Type");
|
|
911
|
+
i0.ɵɵelementEnd();
|
|
912
|
+
i0.ɵɵelementStart(48, "div", 248);
|
|
913
|
+
i0.ɵɵtext(49);
|
|
914
|
+
i0.ɵɵelementEnd()();
|
|
915
|
+
i0.ɵɵelementStart(50, "div", 245)(51, "div", 246);
|
|
916
|
+
i0.ɵɵtext(52, "Git Commit");
|
|
917
|
+
i0.ɵɵelementEnd();
|
|
918
|
+
i0.ɵɵelementStart(53, "div", 247);
|
|
919
|
+
i0.ɵɵtext(54);
|
|
920
|
+
i0.ɵɵelementEnd()();
|
|
921
|
+
i0.ɵɵelementStart(55, "div", 245)(56, "div", 246);
|
|
922
|
+
i0.ɵɵtext(57, "Agent Version");
|
|
923
|
+
i0.ɵɵelementEnd();
|
|
924
|
+
i0.ɵɵelementStart(58, "div", 248);
|
|
925
|
+
i0.ɵɵtext(59);
|
|
926
|
+
i0.ɵɵelementEnd()()()()();
|
|
927
|
+
} if (rf & 2) {
|
|
928
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
929
|
+
i0.ɵɵadvance(10);
|
|
930
|
+
i0.ɵɵtextInterpolate(ctx_r1.record.ID);
|
|
931
|
+
i0.ɵɵadvance(5);
|
|
932
|
+
i0.ɵɵproperty("ngIf", ctx_r1.testSuite);
|
|
933
|
+
i0.ɵɵadvance();
|
|
934
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.testSuite);
|
|
935
|
+
i0.ɵɵadvance(5);
|
|
936
|
+
i0.ɵɵproperty("ngClass", ctx_r1.getStatusClass());
|
|
937
|
+
i0.ɵɵadvance();
|
|
938
|
+
i0.ɵɵtextInterpolate(ctx_r1.record.Status);
|
|
939
|
+
i0.ɵɵadvance(5);
|
|
940
|
+
i0.ɵɵtextInterpolate(ctx_r1.record.RunByUser || "N/A");
|
|
941
|
+
i0.ɵɵadvance(5);
|
|
942
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(33, 12, ctx_r1.record.StartedAt, "medium"));
|
|
943
|
+
i0.ɵɵadvance(6);
|
|
944
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(39, 15, ctx_r1.record.CompletedAt, "medium"));
|
|
945
|
+
i0.ɵɵadvance(6);
|
|
946
|
+
i0.ɵɵtextInterpolate(ctx_r1.record.Environment || "N/A");
|
|
947
|
+
i0.ɵɵadvance(5);
|
|
948
|
+
i0.ɵɵtextInterpolate(ctx_r1.record.TriggerType || "N/A");
|
|
949
|
+
i0.ɵɵadvance(5);
|
|
950
|
+
i0.ɵɵtextInterpolate(ctx_r1.record.GitCommit || "N/A");
|
|
951
|
+
i0.ɵɵadvance(5);
|
|
952
|
+
i0.ɵɵtextInterpolate(ctx_r1.record.AgentVersion || "N/A");
|
|
953
|
+
} }
|
|
954
|
+
function TestSuiteRunFormComponentExtended_div_121_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
955
|
+
i0.ɵɵelementStart(0, "div", 255);
|
|
956
|
+
i0.ɵɵelement(1, "i", 102);
|
|
957
|
+
i0.ɵɵelementStart(2, "span");
|
|
958
|
+
i0.ɵɵtext(3, "Loading test results...");
|
|
959
|
+
i0.ɵɵelementEnd()();
|
|
960
|
+
} }
|
|
961
|
+
function TestSuiteRunFormComponentExtended_div_121_div_2_Template(rf, ctx) { if (rf & 1) {
|
|
962
|
+
i0.ɵɵelementStart(0, "div", 256)(1, "h3");
|
|
963
|
+
i0.ɵɵelement(2, "i", 257);
|
|
964
|
+
i0.ɵɵtext(3, " Summary Statistics");
|
|
965
|
+
i0.ɵɵelementEnd();
|
|
966
|
+
i0.ɵɵelementStart(4, "div", 258)(5, "div", 259)(6, "div", 260);
|
|
967
|
+
i0.ɵɵelement(7, "i", 28);
|
|
968
|
+
i0.ɵɵelementEnd();
|
|
969
|
+
i0.ɵɵelementStart(8, "div", 261)(9, "div", 110);
|
|
970
|
+
i0.ɵɵtext(10);
|
|
971
|
+
i0.ɵɵelementEnd();
|
|
972
|
+
i0.ɵɵelementStart(11, "div", 111);
|
|
973
|
+
i0.ɵɵtext(12, "Passed");
|
|
974
|
+
i0.ɵɵelementEnd();
|
|
975
|
+
i0.ɵɵelementStart(13, "div", 262);
|
|
976
|
+
i0.ɵɵtext(14);
|
|
977
|
+
i0.ɵɵelementEnd()()();
|
|
978
|
+
i0.ɵɵelementStart(15, "div", 259)(16, "div", 263);
|
|
979
|
+
i0.ɵɵelement(17, "i", 33);
|
|
980
|
+
i0.ɵɵelementEnd();
|
|
981
|
+
i0.ɵɵelementStart(18, "div", 261)(19, "div", 110);
|
|
982
|
+
i0.ɵɵtext(20);
|
|
983
|
+
i0.ɵɵelementEnd();
|
|
984
|
+
i0.ɵɵelementStart(21, "div", 111);
|
|
985
|
+
i0.ɵɵtext(22, "Failed");
|
|
986
|
+
i0.ɵɵelementEnd();
|
|
987
|
+
i0.ɵɵelementStart(23, "div", 262);
|
|
988
|
+
i0.ɵɵtext(24);
|
|
989
|
+
i0.ɵɵelementEnd()()();
|
|
990
|
+
i0.ɵɵelementStart(25, "div", 259)(26, "div", 264);
|
|
991
|
+
i0.ɵɵelement(27, "i", 265);
|
|
992
|
+
i0.ɵɵelementEnd();
|
|
993
|
+
i0.ɵɵelementStart(28, "div", 261)(29, "div", 110);
|
|
994
|
+
i0.ɵɵtext(30);
|
|
995
|
+
i0.ɵɵelementEnd();
|
|
996
|
+
i0.ɵɵelementStart(31, "div", 111);
|
|
997
|
+
i0.ɵɵtext(32, "Avg Score");
|
|
998
|
+
i0.ɵɵelementEnd()()();
|
|
999
|
+
i0.ɵɵelementStart(33, "div", 259)(34, "div", 266);
|
|
1000
|
+
i0.ɵɵelement(35, "i", 18);
|
|
1001
|
+
i0.ɵɵelementEnd();
|
|
1002
|
+
i0.ɵɵelementStart(36, "div", 261)(37, "div", 110);
|
|
1003
|
+
i0.ɵɵtext(38);
|
|
1004
|
+
i0.ɵɵelementEnd();
|
|
1005
|
+
i0.ɵɵelementStart(39, "div", 111);
|
|
1006
|
+
i0.ɵɵtext(40, "Avg Duration");
|
|
1007
|
+
i0.ɵɵelementEnd()()();
|
|
1008
|
+
i0.ɵɵelementStart(41, "div", 259)(42, "div", 267);
|
|
1009
|
+
i0.ɵɵelement(43, "i", 23);
|
|
1010
|
+
i0.ɵɵelementEnd();
|
|
1011
|
+
i0.ɵɵelementStart(44, "div", 261)(45, "div", 110);
|
|
1012
|
+
i0.ɵɵtext(46);
|
|
1013
|
+
i0.ɵɵelementEnd();
|
|
1014
|
+
i0.ɵɵelementStart(47, "div", 111);
|
|
1015
|
+
i0.ɵɵtext(48, "Total Cost");
|
|
1016
|
+
i0.ɵɵelementEnd()()()()();
|
|
1017
|
+
} if (rf & 2) {
|
|
1018
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
1019
|
+
i0.ɵɵadvance(10);
|
|
1020
|
+
i0.ɵɵtextInterpolate(ctx_r1.getPassedCount());
|
|
1021
|
+
i0.ɵɵadvance(4);
|
|
1022
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.getPassedPercent().toFixed(1), "%");
|
|
1023
|
+
i0.ɵɵadvance(6);
|
|
1024
|
+
i0.ɵɵtextInterpolate(ctx_r1.getFailedCount());
|
|
1025
|
+
i0.ɵɵadvance(4);
|
|
1026
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.getFailedPercent().toFixed(1), "%");
|
|
1027
|
+
i0.ɵɵadvance(6);
|
|
1028
|
+
i0.ɵɵtextInterpolate1("", (ctx_r1.getAverageScore() * 100).toFixed(1), "%");
|
|
1029
|
+
i0.ɵɵadvance(8);
|
|
1030
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.getAverageDuration().toFixed(1), "s");
|
|
1031
|
+
i0.ɵɵadvance(8);
|
|
1032
|
+
i0.ɵɵtextInterpolate1("$", ctx_r1.getTotalCost().toFixed(4), "");
|
|
1033
|
+
} }
|
|
1034
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_th_26_Template(rf, ctx) { if (rf & 1) {
|
|
1035
|
+
i0.ɵɵelementStart(0, "th", 285);
|
|
1036
|
+
i0.ɵɵtext(1, "Status");
|
|
1037
|
+
i0.ɵɵelementEnd();
|
|
1038
|
+
} }
|
|
1039
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_th_27_Template(rf, ctx) { if (rf & 1) {
|
|
1040
|
+
i0.ɵɵelementStart(0, "th", 286);
|
|
1041
|
+
i0.ɵɵtext(1, "Auto Score");
|
|
1042
|
+
i0.ɵɵelementEnd();
|
|
1043
|
+
} }
|
|
1044
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_th_28_Template(rf, ctx) { if (rf & 1) {
|
|
1045
|
+
i0.ɵɵelementStart(0, "th", 287);
|
|
1046
|
+
i0.ɵɵtext(1, "Human Score");
|
|
1047
|
+
i0.ɵɵelementEnd();
|
|
1048
|
+
} }
|
|
1049
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_div_7_span_1_Template(rf, ctx) { if (rf & 1) {
|
|
1050
|
+
i0.ɵɵelementStart(0, "span", 295);
|
|
1051
|
+
i0.ɵɵtext(1);
|
|
1052
|
+
i0.ɵɵelementEnd();
|
|
1053
|
+
} if (rf & 2) {
|
|
1054
|
+
const tag_r26 = ctx.$implicit;
|
|
1055
|
+
i0.ɵɵadvance();
|
|
1056
|
+
i0.ɵɵtextInterpolate(tag_r26);
|
|
1057
|
+
} }
|
|
1058
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_div_7_Template(rf, ctx) { if (rf & 1) {
|
|
1059
|
+
i0.ɵɵelementStart(0, "div", 293);
|
|
1060
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_div_7_span_1_Template, 2, 1, "span", 294);
|
|
1061
|
+
i0.ɵɵelementEnd();
|
|
1062
|
+
} if (rf & 2) {
|
|
1063
|
+
const run_r25 = i0.ɵɵnextContext().$implicit;
|
|
1064
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
1065
|
+
i0.ɵɵadvance();
|
|
1066
|
+
i0.ɵɵproperty("ngForOf", ctx_r1.getRunTags(run_r25).slice(0, 2));
|
|
1067
|
+
} }
|
|
1068
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_8_Template(rf, ctx) { if (rf & 1) {
|
|
1069
|
+
i0.ɵɵelementStart(0, "td", 285)(1, "span", 9);
|
|
1070
|
+
i0.ɵɵelement(2, "i", 209);
|
|
1071
|
+
i0.ɵɵtext(3);
|
|
1072
|
+
i0.ɵɵelementEnd()();
|
|
1073
|
+
} if (rf & 2) {
|
|
1074
|
+
const run_r25 = i0.ɵɵnextContext().$implicit;
|
|
1075
|
+
i0.ɵɵadvance();
|
|
1076
|
+
i0.ɵɵproperty("ngClass", "status-" + run_r25.Status.toLowerCase());
|
|
1077
|
+
i0.ɵɵadvance();
|
|
1078
|
+
i0.ɵɵclassProp("fa-check-circle", run_r25.Status === "Passed")("fa-times-circle", run_r25.Status === "Failed")("fa-exclamation-circle", run_r25.Status === "Error")("fa-forward", run_r25.Status === "Skipped")("fa-clock", run_r25.Status === "Pending")("fa-spinner", run_r25.Status === "Running")("fa-spin", run_r25.Status === "Running");
|
|
1079
|
+
i0.ɵɵadvance();
|
|
1080
|
+
i0.ɵɵtextInterpolate1(" ", run_r25.Status, " ");
|
|
1081
|
+
} }
|
|
1082
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_9_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
1083
|
+
i0.ɵɵelementStart(0, "div", 297)(1, "div", 298);
|
|
1084
|
+
i0.ɵɵelement(2, "div", 299);
|
|
1085
|
+
i0.ɵɵelementEnd();
|
|
1086
|
+
i0.ɵɵelementStart(3, "span", 300);
|
|
1087
|
+
i0.ɵɵtext(4);
|
|
1088
|
+
i0.ɵɵelementEnd()();
|
|
1089
|
+
} if (rf & 2) {
|
|
1090
|
+
const run_r25 = i0.ɵɵnextContext(2).$implicit;
|
|
1091
|
+
i0.ɵɵadvance(2);
|
|
1092
|
+
i0.ɵɵstyleProp("width", run_r25.Score * 100, "%");
|
|
1093
|
+
i0.ɵɵclassProp("high", run_r25.Score >= 0.8)("medium", run_r25.Score >= 0.5 && run_r25.Score < 0.8)("low", run_r25.Score < 0.5);
|
|
1094
|
+
i0.ɵɵadvance(2);
|
|
1095
|
+
i0.ɵɵtextInterpolate1("", (run_r25.Score * 100).toFixed(0), "%");
|
|
1096
|
+
} }
|
|
1097
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_9_span_2_Template(rf, ctx) { if (rf & 1) {
|
|
1098
|
+
i0.ɵɵelementStart(0, "span", 301);
|
|
1099
|
+
i0.ɵɵtext(1, "\u2014");
|
|
1100
|
+
i0.ɵɵelementEnd();
|
|
1101
|
+
} }
|
|
1102
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_9_Template(rf, ctx) { if (rf & 1) {
|
|
1103
|
+
i0.ɵɵelementStart(0, "td", 286);
|
|
1104
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_9_div_1_Template, 5, 9, "div", 296)(2, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_9_span_2_Template, 2, 0, "span", 292);
|
|
1105
|
+
i0.ɵɵelementEnd();
|
|
1106
|
+
} if (rf & 2) {
|
|
1107
|
+
const run_r25 = i0.ɵɵnextContext().$implicit;
|
|
1108
|
+
i0.ɵɵadvance();
|
|
1109
|
+
i0.ɵɵproperty("ngIf", run_r25.Score != null);
|
|
1110
|
+
i0.ɵɵadvance();
|
|
1111
|
+
i0.ɵɵproperty("ngIf", run_r25.Score == null);
|
|
1112
|
+
} }
|
|
1113
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_div_1_span_3_Template(rf, ctx) { if (rf & 1) {
|
|
1114
|
+
i0.ɵɵelementStart(0, "span", 307);
|
|
1115
|
+
i0.ɵɵelement(1, "i", 209);
|
|
1116
|
+
i0.ɵɵelementEnd();
|
|
1117
|
+
} if (rf & 2) {
|
|
1118
|
+
const run_r25 = i0.ɵɵnextContext(3).$implicit;
|
|
1119
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
1120
|
+
i0.ɵɵadvance();
|
|
1121
|
+
i0.ɵɵclassProp("fa-check", ctx_r1.getHumanIsCorrect(run_r25.ID) === true)("fa-times", ctx_r1.getHumanIsCorrect(run_r25.ID) === false)("correct", ctx_r1.getHumanIsCorrect(run_r25.ID) === true)("incorrect", ctx_r1.getHumanIsCorrect(run_r25.ID) === false);
|
|
1122
|
+
} }
|
|
1123
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_div_1_Template(rf, ctx) { if (rf & 1) {
|
|
1124
|
+
i0.ɵɵelementStart(0, "div", 304)(1, "span", 305);
|
|
1125
|
+
i0.ɵɵtext(2);
|
|
1126
|
+
i0.ɵɵelementEnd();
|
|
1127
|
+
i0.ɵɵtemplate(3, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_div_1_span_3_Template, 2, 8, "span", 306);
|
|
1128
|
+
i0.ɵɵelementEnd();
|
|
1129
|
+
} if (rf & 2) {
|
|
1130
|
+
const run_r25 = i0.ɵɵnextContext(2).$implicit;
|
|
1131
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
1132
|
+
i0.ɵɵadvance();
|
|
1133
|
+
i0.ɵɵclassProp("low", ctx_r1.getFeedbackRating(run_r25.ID) <= 3)("mid", ctx_r1.getFeedbackRating(run_r25.ID) >= 4 && ctx_r1.getFeedbackRating(run_r25.ID) <= 6)("high", ctx_r1.getFeedbackRating(run_r25.ID) >= 7);
|
|
1134
|
+
i0.ɵɵadvance();
|
|
1135
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.getFeedbackRating(run_r25.ID), "/10 ");
|
|
1136
|
+
i0.ɵɵadvance();
|
|
1137
|
+
i0.ɵɵproperty("ngIf", ctx_r1.getHumanIsCorrect(run_r25.ID) !== null);
|
|
1138
|
+
} }
|
|
1139
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_span_2_Template(rf, ctx) { if (rf & 1) {
|
|
1140
|
+
i0.ɵɵelementStart(0, "span", 308);
|
|
1141
|
+
i0.ɵɵelement(1, "i", 309);
|
|
1142
|
+
i0.ɵɵelementEnd();
|
|
1143
|
+
} }
|
|
1144
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_Template(rf, ctx) { if (rf & 1) {
|
|
1145
|
+
i0.ɵɵelementStart(0, "td", 287);
|
|
1146
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_div_1_Template, 4, 8, "div", 302)(2, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_span_2_Template, 2, 0, "span", 303);
|
|
1147
|
+
i0.ɵɵelementEnd();
|
|
1148
|
+
} if (rf & 2) {
|
|
1149
|
+
const run_r25 = i0.ɵɵnextContext().$implicit;
|
|
1150
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
1151
|
+
i0.ɵɵadvance();
|
|
1152
|
+
i0.ɵɵproperty("ngIf", ctx_r1.hasFeedback(run_r25.ID));
|
|
1153
|
+
i0.ɵɵadvance();
|
|
1154
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.hasFeedback(run_r25.ID));
|
|
89
1155
|
} }
|
|
90
|
-
function
|
|
1156
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_12_Template(rf, ctx) { if (rf & 1) {
|
|
91
1157
|
i0.ɵɵelementStart(0, "span");
|
|
92
1158
|
i0.ɵɵtext(1);
|
|
93
1159
|
i0.ɵɵelementEnd();
|
|
94
1160
|
} if (rf & 2) {
|
|
95
|
-
const
|
|
1161
|
+
const run_r25 = i0.ɵɵnextContext().$implicit;
|
|
96
1162
|
i0.ɵɵadvance();
|
|
97
|
-
i0.ɵɵtextInterpolate1("
|
|
1163
|
+
i0.ɵɵtextInterpolate1("", run_r25.DurationSeconds.toFixed(1), "s");
|
|
98
1164
|
} }
|
|
99
|
-
function
|
|
1165
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_13_Template(rf, ctx) { if (rf & 1) {
|
|
1166
|
+
i0.ɵɵelementStart(0, "span", 301);
|
|
1167
|
+
i0.ɵɵtext(1, "\u2014");
|
|
1168
|
+
i0.ɵɵelementEnd();
|
|
1169
|
+
} }
|
|
1170
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_15_Template(rf, ctx) { if (rf & 1) {
|
|
100
1171
|
i0.ɵɵelementStart(0, "span");
|
|
101
1172
|
i0.ɵɵtext(1);
|
|
102
1173
|
i0.ɵɵelementEnd();
|
|
103
1174
|
} if (rf & 2) {
|
|
104
|
-
const
|
|
1175
|
+
const run_r25 = i0.ɵɵnextContext().$implicit;
|
|
105
1176
|
i0.ɵɵadvance();
|
|
106
|
-
i0.ɵɵtextInterpolate1("",
|
|
1177
|
+
i0.ɵɵtextInterpolate1("$", run_r25.CostUSD.toFixed(4), "");
|
|
107
1178
|
} }
|
|
108
|
-
function
|
|
109
|
-
|
|
110
|
-
i0.ɵɵ
|
|
111
|
-
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_95_div_1_div_1_Template_div_click_0_listener() { const run_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openTestRun(run_r4.ID)); });
|
|
112
|
-
i0.ɵɵelementStart(1, "div", 61);
|
|
113
|
-
i0.ɵɵtext(2);
|
|
1179
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_16_Template(rf, ctx) { if (rf & 1) {
|
|
1180
|
+
i0.ɵɵelementStart(0, "span", 301);
|
|
1181
|
+
i0.ɵɵtext(1, "\u2014");
|
|
114
1182
|
i0.ɵɵelementEnd();
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
i0.ɵɵ
|
|
118
|
-
i0.ɵɵelementStart(
|
|
119
|
-
i0.ɵɵ
|
|
1183
|
+
} }
|
|
1184
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_Template(rf, ctx) { if (rf & 1) {
|
|
1185
|
+
const _r24 = i0.ɵɵgetCurrentView();
|
|
1186
|
+
i0.ɵɵelementStart(0, "tr", 288);
|
|
1187
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_Template_tr_click_0_listener() { const run_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openTestRun(run_r25.ID)); });
|
|
1188
|
+
i0.ɵɵelementStart(1, "td", 277);
|
|
1189
|
+
i0.ɵɵtext(2);
|
|
120
1190
|
i0.ɵɵelementEnd();
|
|
121
|
-
i0.ɵɵelementStart(
|
|
122
|
-
i0.ɵɵtext(
|
|
1191
|
+
i0.ɵɵelementStart(3, "td", 278)(4, "div", 289)(5, "span", 290);
|
|
1192
|
+
i0.ɵɵtext(6);
|
|
123
1193
|
i0.ɵɵelementEnd();
|
|
124
|
-
i0.ɵɵtemplate(
|
|
1194
|
+
i0.ɵɵtemplate(7, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_div_7_Template, 2, 1, "div", 291);
|
|
125
1195
|
i0.ɵɵelementEnd()();
|
|
126
|
-
i0.ɵɵ
|
|
1196
|
+
i0.ɵɵtemplate(8, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_8_Template, 4, 16, "td", 279)(9, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_9_Template, 3, 2, "td", 280)(10, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_td_10_Template, 3, 2, "td", 281);
|
|
1197
|
+
i0.ɵɵelementStart(11, "td", 282);
|
|
1198
|
+
i0.ɵɵtemplate(12, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_12_Template, 2, 1, "span", 250)(13, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_13_Template, 2, 0, "span", 292);
|
|
127
1199
|
i0.ɵɵelementEnd();
|
|
1200
|
+
i0.ɵɵelementStart(14, "td", 283);
|
|
1201
|
+
i0.ɵɵtemplate(15, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_15_Template, 2, 1, "span", 250)(16, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_span_16_Template, 2, 0, "span", 292);
|
|
1202
|
+
i0.ɵɵelementEnd()();
|
|
128
1203
|
} if (rf & 2) {
|
|
129
|
-
const
|
|
1204
|
+
const run_r25 = ctx.$implicit;
|
|
1205
|
+
const i_r27 = ctx.index;
|
|
1206
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
1207
|
+
i0.ɵɵclassProp("row-passed", run_r25.Status === "Passed")("row-failed", run_r25.Status === "Failed")("row-error", run_r25.Status === "Error")("row-skipped", run_r25.Status === "Skipped");
|
|
130
1208
|
i0.ɵɵadvance(2);
|
|
131
|
-
i0.ɵɵtextInterpolate(
|
|
1209
|
+
i0.ɵɵtextInterpolate(i_r27 + 1);
|
|
1210
|
+
i0.ɵɵadvance(4);
|
|
1211
|
+
i0.ɵɵtextInterpolate(run_r25.Test || "Unknown Test");
|
|
132
1212
|
i0.ɵɵadvance();
|
|
133
|
-
i0.ɵɵ
|
|
1213
|
+
i0.ɵɵproperty("ngIf", ctx_r1.getRunTags(run_r25).length > 0);
|
|
134
1214
|
i0.ɵɵadvance();
|
|
135
|
-
i0.ɵɵ
|
|
136
|
-
i0.ɵɵadvance(
|
|
137
|
-
i0.ɵɵ
|
|
138
|
-
i0.ɵɵadvance(2);
|
|
139
|
-
i0.ɵɵstyleProp("color", run_r4.Status === "Passed" ? "#4caf50" : run_r4.Status === "Failed" ? "#f44336" : "#ff9800");
|
|
1215
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showExecution);
|
|
1216
|
+
i0.ɵɵadvance();
|
|
1217
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showAuto);
|
|
140
1218
|
i0.ɵɵadvance();
|
|
141
|
-
i0.ɵɵ
|
|
1219
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showHuman);
|
|
1220
|
+
i0.ɵɵadvance(2);
|
|
1221
|
+
i0.ɵɵproperty("ngIf", run_r25.DurationSeconds);
|
|
142
1222
|
i0.ɵɵadvance();
|
|
143
|
-
i0.ɵɵproperty("ngIf",
|
|
1223
|
+
i0.ɵɵproperty("ngIf", !run_r25.DurationSeconds);
|
|
1224
|
+
i0.ɵɵadvance(2);
|
|
1225
|
+
i0.ɵɵproperty("ngIf", run_r25.CostUSD);
|
|
144
1226
|
i0.ɵɵadvance();
|
|
145
|
-
i0.ɵɵproperty("ngIf",
|
|
1227
|
+
i0.ɵɵproperty("ngIf", !run_r25.CostUSD);
|
|
146
1228
|
} }
|
|
147
|
-
function
|
|
148
|
-
i0.ɵɵelementStart(0, "div",
|
|
149
|
-
i0.ɵɵ
|
|
1229
|
+
function TestSuiteRunFormComponentExtended_div_121_div_3_Template(rf, ctx) { if (rf & 1) {
|
|
1230
|
+
i0.ɵɵelementStart(0, "div", 256)(1, "div", 268)(2, "h3");
|
|
1231
|
+
i0.ɵɵelement(3, "i", 269);
|
|
1232
|
+
i0.ɵɵtext(4, " Test Results");
|
|
150
1233
|
i0.ɵɵelementEnd();
|
|
1234
|
+
i0.ɵɵelementStart(5, "div", 270)(6, "span", 271);
|
|
1235
|
+
i0.ɵɵelement(7, "i", 28);
|
|
1236
|
+
i0.ɵɵtext(8, " Passed");
|
|
1237
|
+
i0.ɵɵelementEnd();
|
|
1238
|
+
i0.ɵɵelementStart(9, "span", 272);
|
|
1239
|
+
i0.ɵɵelement(10, "i", 33);
|
|
1240
|
+
i0.ɵɵtext(11, " Failed");
|
|
1241
|
+
i0.ɵɵelementEnd();
|
|
1242
|
+
i0.ɵɵelementStart(12, "span", 273);
|
|
1243
|
+
i0.ɵɵelement(13, "i", 35);
|
|
1244
|
+
i0.ɵɵtext(14, " Error");
|
|
1245
|
+
i0.ɵɵelementEnd();
|
|
1246
|
+
i0.ɵɵelementStart(15, "span", 274);
|
|
1247
|
+
i0.ɵɵelement(16, "i", 37);
|
|
1248
|
+
i0.ɵɵtext(17, " Skipped");
|
|
1249
|
+
i0.ɵɵelementEnd()()();
|
|
1250
|
+
i0.ɵɵelementStart(18, "div", 275)(19, "table", 276)(20, "thead")(21, "tr")(22, "th", 277);
|
|
1251
|
+
i0.ɵɵtext(23, "#");
|
|
1252
|
+
i0.ɵɵelementEnd();
|
|
1253
|
+
i0.ɵɵelementStart(24, "th", 278);
|
|
1254
|
+
i0.ɵɵtext(25, "Test Name");
|
|
1255
|
+
i0.ɵɵelementEnd();
|
|
1256
|
+
i0.ɵɵtemplate(26, TestSuiteRunFormComponentExtended_div_121_div_3_th_26_Template, 2, 0, "th", 279)(27, TestSuiteRunFormComponentExtended_div_121_div_3_th_27_Template, 2, 0, "th", 280)(28, TestSuiteRunFormComponentExtended_div_121_div_3_th_28_Template, 2, 0, "th", 281);
|
|
1257
|
+
i0.ɵɵelementStart(29, "th", 282);
|
|
1258
|
+
i0.ɵɵtext(30, "Duration");
|
|
1259
|
+
i0.ɵɵelementEnd();
|
|
1260
|
+
i0.ɵɵelementStart(31, "th", 283);
|
|
1261
|
+
i0.ɵɵtext(32, "Cost");
|
|
1262
|
+
i0.ɵɵelementEnd()()();
|
|
1263
|
+
i0.ɵɵelementStart(33, "tbody");
|
|
1264
|
+
i0.ɵɵtemplate(34, TestSuiteRunFormComponentExtended_div_121_div_3_tr_34_Template, 17, 18, "tr", 284);
|
|
1265
|
+
i0.ɵɵelementEnd()()()();
|
|
151
1266
|
} if (rf & 2) {
|
|
152
1267
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
1268
|
+
i0.ɵɵadvance(26);
|
|
1269
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showExecution);
|
|
1270
|
+
i0.ɵɵadvance();
|
|
1271
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showAuto);
|
|
153
1272
|
i0.ɵɵadvance();
|
|
1273
|
+
i0.ɵɵproperty("ngIf", ctx_r1.evalPreferences.showHuman);
|
|
1274
|
+
i0.ɵɵadvance(6);
|
|
154
1275
|
i0.ɵɵproperty("ngForOf", ctx_r1.testRuns);
|
|
155
1276
|
} }
|
|
156
|
-
function
|
|
157
|
-
i0.ɵɵelementStart(0, "div",
|
|
158
|
-
i0.ɵɵelement(
|
|
159
|
-
i0.ɵɵ
|
|
160
|
-
i0.ɵɵ
|
|
1277
|
+
function TestSuiteRunFormComponentExtended_div_121_div_4_Template(rf, ctx) { if (rf & 1) {
|
|
1278
|
+
i0.ɵɵelementStart(0, "div", 238)(1, "div", 239);
|
|
1279
|
+
i0.ɵɵelement(2, "i", 49);
|
|
1280
|
+
i0.ɵɵelementEnd();
|
|
1281
|
+
i0.ɵɵelementStart(3, "h4");
|
|
1282
|
+
i0.ɵɵtext(4, "No Test Results Yet");
|
|
1283
|
+
i0.ɵɵelementEnd();
|
|
1284
|
+
i0.ɵɵelementStart(5, "p");
|
|
1285
|
+
i0.ɵɵtext(6, "Test runs will appear here once the suite execution completes.");
|
|
161
1286
|
i0.ɵɵelementEnd()();
|
|
162
1287
|
} }
|
|
163
|
-
function
|
|
164
|
-
i0.ɵɵelementStart(0, "div",
|
|
165
|
-
i0.ɵɵtemplate(1,
|
|
1288
|
+
function TestSuiteRunFormComponentExtended_div_121_Template(rf, ctx) { if (rf & 1) {
|
|
1289
|
+
i0.ɵɵelementStart(0, "div", 252);
|
|
1290
|
+
i0.ɵɵtemplate(1, TestSuiteRunFormComponentExtended_div_121_div_1_Template, 4, 0, "div", 253)(2, TestSuiteRunFormComponentExtended_div_121_div_2_Template, 49, 7, "div", 254)(3, TestSuiteRunFormComponentExtended_div_121_div_3_Template, 35, 4, "div", 254)(4, TestSuiteRunFormComponentExtended_div_121_div_4_Template, 7, 0, "div", 169);
|
|
166
1291
|
i0.ɵɵelementEnd();
|
|
167
1292
|
} if (rf & 2) {
|
|
168
1293
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
169
1294
|
i0.ɵɵadvance();
|
|
170
|
-
i0.ɵɵproperty("ngIf", ctx_r1.
|
|
1295
|
+
i0.ɵɵproperty("ngIf", ctx_r1.loadingTestRuns);
|
|
1296
|
+
i0.ɵɵadvance();
|
|
1297
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.loadingTestRuns && ctx_r1.testRuns.length > 0);
|
|
171
1298
|
i0.ɵɵadvance();
|
|
172
|
-
i0.ɵɵproperty("ngIf", ctx_r1.
|
|
1299
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.loadingTestRuns && ctx_r1.testRuns.length > 0);
|
|
1300
|
+
i0.ɵɵadvance();
|
|
1301
|
+
i0.ɵɵproperty("ngIf", !ctx_r1.loadingTestRuns && ctx_r1.testRunsLoaded && ctx_r1.testRuns.length === 0);
|
|
173
1302
|
} }
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
i0.ɵɵ
|
|
177
|
-
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_96_a_11_Template_a_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.openTestSuite()); });
|
|
178
|
-
i0.ɵɵtext(1);
|
|
1303
|
+
function TestSuiteRunFormComponentExtended_div_122_Template(rf, ctx) { if (rf & 1) {
|
|
1304
|
+
i0.ɵɵelementStart(0, "div", 310);
|
|
1305
|
+
i0.ɵɵelement(1, "mj-execution-context", 311);
|
|
179
1306
|
i0.ɵɵelementEnd();
|
|
180
1307
|
} if (rf & 2) {
|
|
181
|
-
const ctx_r1 = i0.ɵɵnextContext(
|
|
1308
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
182
1309
|
i0.ɵɵadvance();
|
|
183
|
-
i0.ɵɵ
|
|
1310
|
+
i0.ɵɵproperty("machineName", ctx_r1.record.MachineName)("machineId", ctx_r1.record.MachineID)("runByUserName", ctx_r1.record.RunByUserName)("runByUserEmail", ctx_r1.record.RunByUserEmail)("runContextDetailsJson", ctx_r1.record.RunContextDetails);
|
|
184
1311
|
} }
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
i0.ɵɵ
|
|
188
|
-
i0.ɵɵ
|
|
189
|
-
i0.ɵɵ
|
|
190
|
-
i0.ɵɵ
|
|
1312
|
+
function TestSuiteRunFormComponentExtended_div_125_Template(rf, ctx) { if (rf & 1) {
|
|
1313
|
+
const _r28 = i0.ɵɵgetCurrentView();
|
|
1314
|
+
i0.ɵɵelementStart(0, "div", 312)(1, "div", 313);
|
|
1315
|
+
i0.ɵɵelement(2, "i", 59);
|
|
1316
|
+
i0.ɵɵtext(3, " Shortcuts ");
|
|
1317
|
+
i0.ɵɵelementStart(4, "button", 314);
|
|
1318
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_div_125_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r28); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleShortcuts()); });
|
|
1319
|
+
i0.ɵɵelement(5, "i", 100);
|
|
191
1320
|
i0.ɵɵelementEnd()();
|
|
192
|
-
i0.ɵɵelementStart(
|
|
193
|
-
i0.ɵɵtext(9, "
|
|
1321
|
+
i0.ɵɵelementStart(6, "div", 315)(7, "div", 316)(8, "span");
|
|
1322
|
+
i0.ɵɵtext(9, "Refresh");
|
|
194
1323
|
i0.ɵɵelementEnd();
|
|
195
|
-
i0.ɵɵelementStart(10, "
|
|
196
|
-
i0.ɵɵ
|
|
197
|
-
i0.ɵɵelementEnd()();
|
|
198
|
-
i0.ɵɵelementStart(12, "div", 73)(13, "div", 74);
|
|
199
|
-
i0.ɵɵtext(14, "Status");
|
|
1324
|
+
i0.ɵɵelementStart(10, "span", 317)(11, "kbd");
|
|
1325
|
+
i0.ɵɵtext(12, "Cmd");
|
|
200
1326
|
i0.ɵɵelementEnd();
|
|
201
|
-
i0.ɵɵelementStart(
|
|
202
|
-
i0.ɵɵtext(
|
|
203
|
-
i0.ɵɵelementEnd()();
|
|
204
|
-
i0.ɵɵelementStart(
|
|
205
|
-
i0.ɵɵtext(
|
|
1327
|
+
i0.ɵɵelementStart(13, "kbd");
|
|
1328
|
+
i0.ɵɵtext(14, "R");
|
|
1329
|
+
i0.ɵɵelementEnd()()();
|
|
1330
|
+
i0.ɵɵelementStart(15, "div", 316)(16, "span");
|
|
1331
|
+
i0.ɵɵtext(17, "Re-run Suite");
|
|
206
1332
|
i0.ɵɵelementEnd();
|
|
207
|
-
i0.ɵɵelementStart(
|
|
208
|
-
i0.ɵɵtext(
|
|
209
|
-
i0.ɵɵelementEnd()();
|
|
210
|
-
i0.ɵɵelementStart(22, "div", 73)(23, "div", 74);
|
|
211
|
-
i0.ɵɵtext(24, "Environment");
|
|
1333
|
+
i0.ɵɵelementStart(18, "span", 317)(19, "kbd");
|
|
1334
|
+
i0.ɵɵtext(20, "Cmd");
|
|
212
1335
|
i0.ɵɵelementEnd();
|
|
213
|
-
i0.ɵɵelementStart(
|
|
214
|
-
i0.ɵɵtext(
|
|
215
|
-
i0.ɵɵelementEnd()();
|
|
216
|
-
i0.ɵɵelementStart(27, "div", 73)(28, "div", 74);
|
|
217
|
-
i0.ɵɵtext(29, "Trigger Type");
|
|
1336
|
+
i0.ɵɵelementStart(21, "kbd");
|
|
1337
|
+
i0.ɵɵtext(22, "Shift");
|
|
218
1338
|
i0.ɵɵelementEnd();
|
|
219
|
-
i0.ɵɵelementStart(
|
|
220
|
-
i0.ɵɵtext(
|
|
221
|
-
i0.ɵɵelementEnd()();
|
|
222
|
-
i0.ɵɵelementStart(
|
|
223
|
-
i0.ɵɵtext(
|
|
1339
|
+
i0.ɵɵelementStart(23, "kbd");
|
|
1340
|
+
i0.ɵɵtext(24, "R");
|
|
1341
|
+
i0.ɵɵelementEnd()()();
|
|
1342
|
+
i0.ɵɵelementStart(25, "div", 316)(26, "span");
|
|
1343
|
+
i0.ɵɵtext(27, "Switch Tabs");
|
|
224
1344
|
i0.ɵɵelementEnd();
|
|
225
|
-
i0.ɵɵelementStart(
|
|
226
|
-
i0.ɵɵtext(
|
|
227
|
-
i0.ɵɵelementEnd()();
|
|
228
|
-
i0.ɵɵelementStart(37, "div", 73)(38, "div", 74);
|
|
229
|
-
i0.ɵɵtext(39, "Agent Version");
|
|
1345
|
+
i0.ɵɵelementStart(28, "span", 317)(29, "kbd");
|
|
1346
|
+
i0.ɵɵtext(30, "1");
|
|
230
1347
|
i0.ɵɵelementEnd();
|
|
231
|
-
i0.ɵɵ
|
|
232
|
-
i0.ɵɵ
|
|
233
|
-
i0.ɵɵ
|
|
234
|
-
|
|
235
|
-
const ctx_r1 = i0.ɵɵnextContext();
|
|
236
|
-
i0.ɵɵadvance(6);
|
|
237
|
-
i0.ɵɵtextInterpolate(ctx_r1.record.ID);
|
|
238
|
-
i0.ɵɵadvance(5);
|
|
239
|
-
i0.ɵɵproperty("ngIf", ctx_r1.testSuite);
|
|
240
|
-
i0.ɵɵadvance(5);
|
|
241
|
-
i0.ɵɵtextInterpolate(ctx_r1.record.Status);
|
|
242
|
-
i0.ɵɵadvance(5);
|
|
243
|
-
i0.ɵɵtextInterpolate(ctx_r1.record.RunByUser);
|
|
244
|
-
i0.ɵɵadvance(5);
|
|
245
|
-
i0.ɵɵtextInterpolate(ctx_r1.record.Environment || "N/A");
|
|
246
|
-
i0.ɵɵadvance(5);
|
|
247
|
-
i0.ɵɵtextInterpolate(ctx_r1.record.TriggerType || "N/A");
|
|
248
|
-
i0.ɵɵadvance(5);
|
|
249
|
-
i0.ɵɵtextInterpolate(ctx_r1.record.GitCommit || "N/A");
|
|
250
|
-
i0.ɵɵadvance(5);
|
|
251
|
-
i0.ɵɵtextInterpolate(ctx_r1.record.AgentVersion || "N/A");
|
|
1348
|
+
i0.ɵɵtext(31, "-");
|
|
1349
|
+
i0.ɵɵelementStart(32, "kbd");
|
|
1350
|
+
i0.ɵɵtext(33, "5");
|
|
1351
|
+
i0.ɵɵelementEnd()()()()();
|
|
252
1352
|
} }
|
|
1353
|
+
/** Settings key for keyboard shortcuts visibility */
|
|
1354
|
+
const SHORTCUTS_SETTINGS_KEY = '__mj.Testing.ShowKeyboardShortcuts';
|
|
253
1355
|
let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended extends TestSuiteRunFormComponent {
|
|
254
|
-
constructor(elementRef, sharedService, router, route, cdr) {
|
|
1356
|
+
constructor(elementRef, sharedService, router, route, cdr, testingDialogService, evalPrefsService) {
|
|
255
1357
|
super(elementRef, sharedService, router, route, cdr);
|
|
256
1358
|
this.router = router;
|
|
257
1359
|
this.cdr = cdr;
|
|
1360
|
+
this.testingDialogService = testingDialogService;
|
|
1361
|
+
this.evalPrefsService = evalPrefsService;
|
|
258
1362
|
this.destroy$ = new Subject();
|
|
259
1363
|
// UI state
|
|
260
1364
|
this.activeTab = 'overview';
|
|
261
1365
|
this.loading = false;
|
|
1366
|
+
this.loadingTestRuns = false;
|
|
1367
|
+
this.loadingFeedbacks = false;
|
|
262
1368
|
this.error = null;
|
|
263
1369
|
this.testRunsLoaded = false;
|
|
1370
|
+
this.feedbacksLoaded = false;
|
|
1371
|
+
this.isRefreshing = false;
|
|
1372
|
+
this.autoRefreshEnabled = false;
|
|
264
1373
|
// Related entities
|
|
265
1374
|
this.testSuite = null;
|
|
266
1375
|
this.testRuns = [];
|
|
1376
|
+
this.feedbacks = new Map();
|
|
1377
|
+
// Tags
|
|
1378
|
+
this.tags = [];
|
|
1379
|
+
this.newTag = '';
|
|
1380
|
+
this.editingTags = false;
|
|
1381
|
+
this.savingTags = false;
|
|
1382
|
+
// Inline feedback
|
|
1383
|
+
this.expandedRunId = null;
|
|
1384
|
+
this.inlineRating = 0;
|
|
1385
|
+
this.inlineHoverRating = 0;
|
|
1386
|
+
this.inlineIsCorrect = null;
|
|
1387
|
+
this.inlineComments = '';
|
|
1388
|
+
this.savingInlineFeedback = false;
|
|
1389
|
+
// Filter for test runs
|
|
1390
|
+
this.runStatusFilter = null;
|
|
1391
|
+
// Keyboard shortcuts
|
|
1392
|
+
this.keyboardShortcutsEnabled = true;
|
|
1393
|
+
this.showShortcuts = false; // Hidden by default
|
|
1394
|
+
this.shortcutsSettingEntity = null;
|
|
1395
|
+
this.metadata = new Metadata();
|
|
1396
|
+
// Evaluation system
|
|
1397
|
+
this.evalPreferences = {
|
|
1398
|
+
showExecution: true,
|
|
1399
|
+
showHuman: true,
|
|
1400
|
+
showAuto: false
|
|
1401
|
+
};
|
|
1402
|
+
this.testRunsWithFeedback = [];
|
|
1403
|
+
this.evaluationMetrics = null;
|
|
1404
|
+
this.needsReviewItems = [];
|
|
267
1405
|
}
|
|
268
1406
|
async ngOnInit() {
|
|
269
1407
|
await super.ngOnInit();
|
|
1408
|
+
this.loadShortcutsSetting();
|
|
1409
|
+
// Subscribe to evaluation preferences
|
|
1410
|
+
this.evalPrefsService.preferences$
|
|
1411
|
+
.pipe(takeUntil(this.destroy$))
|
|
1412
|
+
.subscribe(prefs => {
|
|
1413
|
+
this.evalPreferences = prefs;
|
|
1414
|
+
this.cdr.markForCheck();
|
|
1415
|
+
});
|
|
270
1416
|
if (this.record && this.record.ID) {
|
|
271
1417
|
await this.loadRelatedData();
|
|
1418
|
+
this.parseTags();
|
|
1419
|
+
// Auto-refresh for running suite executions
|
|
1420
|
+
if (this.record.Status === 'Running' || this.record.Status === 'Pending') {
|
|
1421
|
+
this.startAutoRefresh();
|
|
1422
|
+
}
|
|
272
1423
|
}
|
|
273
1424
|
}
|
|
1425
|
+
parseTags() {
|
|
1426
|
+
this.tags = TagsHelper.parseTags(this.record.Tags);
|
|
1427
|
+
}
|
|
274
1428
|
ngOnDestroy() {
|
|
275
1429
|
this.destroy$.next();
|
|
276
1430
|
this.destroy$.complete();
|
|
277
1431
|
}
|
|
1432
|
+
// Keyboard shortcuts
|
|
1433
|
+
handleKeyboardShortcut(event) {
|
|
1434
|
+
if (!this.keyboardShortcutsEnabled)
|
|
1435
|
+
return;
|
|
1436
|
+
// Cmd/Ctrl + R: Refresh
|
|
1437
|
+
if ((event.metaKey || event.ctrlKey) && event.key === 'r' && !event.shiftKey) {
|
|
1438
|
+
event.preventDefault();
|
|
1439
|
+
this.refresh();
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
// Cmd/Ctrl + Shift + R: Re-run suite
|
|
1443
|
+
if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'r') {
|
|
1444
|
+
event.preventDefault();
|
|
1445
|
+
this.reRunSuite();
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
// Number keys for tabs (1-4)
|
|
1449
|
+
if (!event.metaKey && !event.ctrlKey && !event.altKey) {
|
|
1450
|
+
switch (event.key) {
|
|
1451
|
+
case '1':
|
|
1452
|
+
this.changeTab('overview');
|
|
1453
|
+
break;
|
|
1454
|
+
case '2':
|
|
1455
|
+
this.changeTab('runs');
|
|
1456
|
+
break;
|
|
1457
|
+
case '3':
|
|
1458
|
+
this.changeTab('details');
|
|
1459
|
+
break;
|
|
1460
|
+
case '4':
|
|
1461
|
+
this.changeTab('analytics');
|
|
1462
|
+
break;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
startAutoRefresh() {
|
|
1467
|
+
this.autoRefreshEnabled = true;
|
|
1468
|
+
interval(5000)
|
|
1469
|
+
.pipe(takeUntil(this.destroy$))
|
|
1470
|
+
.subscribe(() => {
|
|
1471
|
+
if (this.autoRefreshEnabled && (this.record.Status === 'Running' || this.record.Status === 'Pending')) {
|
|
1472
|
+
this.silentRefresh();
|
|
1473
|
+
}
|
|
1474
|
+
else {
|
|
1475
|
+
this.autoRefreshEnabled = false;
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
async silentRefresh() {
|
|
1480
|
+
try {
|
|
1481
|
+
await this.record.Load(this.record.ID);
|
|
1482
|
+
this.cdr.markForCheck();
|
|
1483
|
+
}
|
|
1484
|
+
catch {
|
|
1485
|
+
// Silently fail on auto-refresh
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
278
1488
|
async loadRelatedData() {
|
|
279
1489
|
this.loading = true;
|
|
1490
|
+
this.error = null;
|
|
280
1491
|
try {
|
|
281
1492
|
// Load test suite
|
|
282
1493
|
if (this.record.SuiteID) {
|
|
@@ -290,16 +1501,22 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
290
1501
|
}
|
|
291
1502
|
catch (error) {
|
|
292
1503
|
console.error('Error loading related data:', error);
|
|
293
|
-
this.error = 'Failed to load related data';
|
|
1504
|
+
this.error = 'Failed to load related data. Click to retry.';
|
|
294
1505
|
}
|
|
295
1506
|
finally {
|
|
296
1507
|
this.loading = false;
|
|
297
1508
|
this.cdr.markForCheck();
|
|
298
1509
|
}
|
|
299
1510
|
}
|
|
1511
|
+
async retryLoad() {
|
|
1512
|
+
this.error = null;
|
|
1513
|
+
await this.loadRelatedData();
|
|
1514
|
+
}
|
|
300
1515
|
async loadTestRuns() {
|
|
301
1516
|
if (this.testRunsLoaded)
|
|
302
1517
|
return;
|
|
1518
|
+
this.loadingTestRuns = true;
|
|
1519
|
+
this.cdr.markForCheck();
|
|
303
1520
|
try {
|
|
304
1521
|
const rv = new RunView();
|
|
305
1522
|
const result = await rv.RunView({
|
|
@@ -312,40 +1529,51 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
312
1529
|
this.testRuns = result.Results || [];
|
|
313
1530
|
}
|
|
314
1531
|
this.testRunsLoaded = true;
|
|
315
|
-
|
|
1532
|
+
// Also load feedbacks for these runs
|
|
1533
|
+
if (this.testRuns.length > 0) {
|
|
1534
|
+
await this.loadFeedbacks();
|
|
1535
|
+
}
|
|
316
1536
|
}
|
|
317
1537
|
catch (error) {
|
|
318
1538
|
console.error('Error loading test runs:', error);
|
|
1539
|
+
SharedService.Instance.CreateSimpleNotification('Failed to load test runs', 'error', 3000);
|
|
1540
|
+
}
|
|
1541
|
+
finally {
|
|
1542
|
+
this.loadingTestRuns = false;
|
|
1543
|
+
this.cdr.markForCheck();
|
|
319
1544
|
}
|
|
320
1545
|
}
|
|
321
1546
|
changeTab(tab) {
|
|
322
1547
|
this.activeTab = tab;
|
|
323
1548
|
// Lazy load tabs
|
|
324
|
-
if (tab === 'runs' && !this.testRunsLoaded) {
|
|
1549
|
+
if ((tab === 'runs' || tab === 'analytics') && !this.testRunsLoaded) {
|
|
325
1550
|
this.loadTestRuns();
|
|
326
1551
|
}
|
|
327
1552
|
this.cdr.markForCheck();
|
|
328
1553
|
}
|
|
329
1554
|
getStatusColor() {
|
|
330
1555
|
switch (this.record.Status) {
|
|
331
|
-
case 'Completed': return '#
|
|
332
|
-
case 'Failed': return '#
|
|
333
|
-
case 'Running': return '#
|
|
334
|
-
case 'Pending': return '#
|
|
335
|
-
case 'Cancelled': return '#
|
|
336
|
-
default: return '#
|
|
1556
|
+
case 'Completed': return '#10b981';
|
|
1557
|
+
case 'Failed': return '#ef4444';
|
|
1558
|
+
case 'Running': return '#3b82f6';
|
|
1559
|
+
case 'Pending': return '#8b5cf6';
|
|
1560
|
+
case 'Cancelled': return '#6b7280';
|
|
1561
|
+
default: return '#9ca3af';
|
|
337
1562
|
}
|
|
338
1563
|
}
|
|
339
1564
|
getStatusIcon() {
|
|
340
1565
|
switch (this.record.Status) {
|
|
341
1566
|
case 'Completed': return 'fa-check-circle';
|
|
342
1567
|
case 'Failed': return 'fa-times-circle';
|
|
343
|
-
case 'Running': return 'fa-
|
|
344
|
-
case 'Pending': return 'fa-
|
|
1568
|
+
case 'Running': return 'fa-circle-notch fa-spin';
|
|
1569
|
+
case 'Pending': return 'fa-hourglass-half';
|
|
345
1570
|
case 'Cancelled': return 'fa-ban';
|
|
346
1571
|
default: return 'fa-question-circle';
|
|
347
1572
|
}
|
|
348
1573
|
}
|
|
1574
|
+
getStatusClass() {
|
|
1575
|
+
return `status-${this.record.Status?.toLowerCase() || 'unknown'}`;
|
|
1576
|
+
}
|
|
349
1577
|
calculateDuration() {
|
|
350
1578
|
if (!this.record.TotalDurationSeconds)
|
|
351
1579
|
return 'N/A';
|
|
@@ -373,6 +1601,25 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
373
1601
|
return 0;
|
|
374
1602
|
return (passed / total) * 100;
|
|
375
1603
|
}
|
|
1604
|
+
getRelativeTime(date) {
|
|
1605
|
+
if (!date)
|
|
1606
|
+
return 'N/A';
|
|
1607
|
+
const d = new Date(date);
|
|
1608
|
+
const now = new Date();
|
|
1609
|
+
const diffMs = now.getTime() - d.getTime();
|
|
1610
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
1611
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
1612
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
1613
|
+
if (diffMins < 1)
|
|
1614
|
+
return 'Just now';
|
|
1615
|
+
if (diffMins < 60)
|
|
1616
|
+
return `${diffMins}m ago`;
|
|
1617
|
+
if (diffHours < 24)
|
|
1618
|
+
return `${diffHours}h ago`;
|
|
1619
|
+
if (diffDays < 7)
|
|
1620
|
+
return `${diffDays}d ago`;
|
|
1621
|
+
return d.toLocaleDateString();
|
|
1622
|
+
}
|
|
376
1623
|
openTestSuite() {
|
|
377
1624
|
if (this.testSuite) {
|
|
378
1625
|
SharedService.Instance.OpenEntityRecord('MJ: Test Suites', CompositeKey.FromID(this.testSuite.ID));
|
|
@@ -381,136 +1628,572 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
381
1628
|
openTestRun(runId) {
|
|
382
1629
|
SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(runId));
|
|
383
1630
|
}
|
|
1631
|
+
async reRunSuite() {
|
|
1632
|
+
if (!this.record.SuiteID) {
|
|
1633
|
+
SharedService.Instance.CreateSimpleNotification('Cannot re-run: Suite ID not available', 'error', 3000);
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
this.testingDialogService.OpenSuiteDialog(this.record.SuiteID);
|
|
1637
|
+
}
|
|
384
1638
|
async refresh() {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
await this.
|
|
1639
|
+
this.isRefreshing = true;
|
|
1640
|
+
this.cdr.markForCheck();
|
|
1641
|
+
try {
|
|
1642
|
+
await this.record.Load(this.record.ID);
|
|
1643
|
+
await this.loadRelatedData();
|
|
1644
|
+
// Reset lazy-loaded data
|
|
1645
|
+
if (this.testRunsLoaded) {
|
|
1646
|
+
this.testRunsLoaded = false;
|
|
1647
|
+
this.testRuns = [];
|
|
1648
|
+
await this.loadTestRuns();
|
|
1649
|
+
}
|
|
1650
|
+
SharedService.Instance.CreateSimpleNotification('Refreshed successfully', 'success', 2000);
|
|
1651
|
+
}
|
|
1652
|
+
catch {
|
|
1653
|
+
SharedService.Instance.CreateSimpleNotification('Failed to refresh', 'error', 3000);
|
|
1654
|
+
}
|
|
1655
|
+
finally {
|
|
1656
|
+
this.isRefreshing = false;
|
|
1657
|
+
this.cdr.markForCheck();
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
getRunStatusColor(status) {
|
|
1661
|
+
switch (status) {
|
|
1662
|
+
case 'Passed': return '#10b981';
|
|
1663
|
+
case 'Failed': return '#ef4444';
|
|
1664
|
+
case 'Error': return '#f59e0b';
|
|
1665
|
+
case 'Timeout': return '#f97316';
|
|
1666
|
+
case 'Running': return '#3b82f6';
|
|
1667
|
+
case 'Pending': return '#8b5cf6';
|
|
1668
|
+
case 'Skipped': return '#6b7280';
|
|
1669
|
+
default: return '#9ca3af';
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
getRunStatusIcon(status) {
|
|
1673
|
+
switch (status) {
|
|
1674
|
+
case 'Passed': return 'fa-check';
|
|
1675
|
+
case 'Failed': return 'fa-times';
|
|
1676
|
+
case 'Error': return 'fa-exclamation';
|
|
1677
|
+
case 'Timeout': return 'fa-clock';
|
|
1678
|
+
case 'Running': return 'fa-circle-notch fa-spin';
|
|
1679
|
+
case 'Pending': return 'fa-hourglass-half';
|
|
1680
|
+
case 'Skipped': return 'fa-forward';
|
|
1681
|
+
default: return 'fa-question';
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
// ===========================
|
|
1685
|
+
// Tag Management
|
|
1686
|
+
// ===========================
|
|
1687
|
+
startEditingTags() {
|
|
1688
|
+
this.editingTags = true;
|
|
1689
|
+
this.cdr.markForCheck();
|
|
1690
|
+
}
|
|
1691
|
+
cancelEditingTags() {
|
|
1692
|
+
this.editingTags = false;
|
|
1693
|
+
this.newTag = '';
|
|
1694
|
+
this.parseTags(); // Reset to original
|
|
1695
|
+
this.cdr.markForCheck();
|
|
1696
|
+
}
|
|
1697
|
+
addTag() {
|
|
1698
|
+
const tag = this.newTag.trim();
|
|
1699
|
+
if (tag && !this.tags.includes(tag)) {
|
|
1700
|
+
this.tags = [...this.tags, tag];
|
|
1701
|
+
this.newTag = '';
|
|
1702
|
+
this.cdr.markForCheck();
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
removeTag(tag) {
|
|
1706
|
+
this.tags = this.tags.filter(t => t !== tag);
|
|
1707
|
+
this.cdr.markForCheck();
|
|
1708
|
+
}
|
|
1709
|
+
async saveTags() {
|
|
1710
|
+
// Auto-add any pending tag in the input before saving
|
|
1711
|
+
const pendingTag = this.newTag.trim();
|
|
1712
|
+
if (pendingTag && !this.tags.includes(pendingTag)) {
|
|
1713
|
+
this.tags = [...this.tags, pendingTag];
|
|
1714
|
+
this.newTag = '';
|
|
1715
|
+
}
|
|
1716
|
+
this.savingTags = true;
|
|
1717
|
+
this.cdr.markForCheck();
|
|
1718
|
+
try {
|
|
1719
|
+
this.record.Tags = TagsHelper.toJson(this.tags);
|
|
1720
|
+
const result = await this.record.Save();
|
|
1721
|
+
if (result) {
|
|
1722
|
+
this.editingTags = false;
|
|
1723
|
+
SharedService.Instance.CreateSimpleNotification('Tags saved successfully', 'success', 2000);
|
|
1724
|
+
}
|
|
1725
|
+
else {
|
|
1726
|
+
SharedService.Instance.CreateSimpleNotification(this.record.LatestResult?.Message || 'Failed to save tags', 'error', 3000);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
catch (error) {
|
|
1730
|
+
SharedService.Instance.CreateSimpleNotification('Failed to save tags', 'error', 3000);
|
|
1731
|
+
}
|
|
1732
|
+
finally {
|
|
1733
|
+
this.savingTags = false;
|
|
1734
|
+
this.cdr.markForCheck();
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
// ===========================
|
|
1738
|
+
// Test Run Filtering
|
|
1739
|
+
// ===========================
|
|
1740
|
+
setRunStatusFilter(status) {
|
|
1741
|
+
this.runStatusFilter = status;
|
|
1742
|
+
this.cdr.markForCheck();
|
|
1743
|
+
}
|
|
1744
|
+
getFilteredTestRuns() {
|
|
1745
|
+
if (!this.runStatusFilter)
|
|
1746
|
+
return this.testRuns;
|
|
1747
|
+
return this.testRuns.filter(run => run.Status === this.runStatusFilter);
|
|
1748
|
+
}
|
|
1749
|
+
getRunCountByStatus(status) {
|
|
1750
|
+
return this.testRuns.filter(run => run.Status === status).length;
|
|
1751
|
+
}
|
|
1752
|
+
// ===========================
|
|
1753
|
+
// Inline Feedback
|
|
1754
|
+
// ===========================
|
|
1755
|
+
async loadFeedbacks() {
|
|
1756
|
+
if (this.feedbacksLoaded)
|
|
1757
|
+
return;
|
|
1758
|
+
this.loadingFeedbacks = true;
|
|
1759
|
+
this.cdr.markForCheck();
|
|
1760
|
+
try {
|
|
1761
|
+
const testRunIds = this.testRuns.map(r => `'${r.ID}'`).join(',');
|
|
1762
|
+
if (!testRunIds)
|
|
1763
|
+
return;
|
|
1764
|
+
const rv = new RunView();
|
|
1765
|
+
const result = await rv.RunView({
|
|
1766
|
+
EntityName: 'MJ: Test Run Feedbacks',
|
|
1767
|
+
ExtraFilter: `TestRunID IN (${testRunIds})`,
|
|
1768
|
+
ResultType: 'entity_object'
|
|
1769
|
+
});
|
|
1770
|
+
if (result.Success && result.Results) {
|
|
1771
|
+
this.feedbacks.clear();
|
|
1772
|
+
for (const feedback of result.Results) {
|
|
1773
|
+
this.feedbacks.set(feedback.TestRunID, feedback);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
// Build TestRunWithFeedback array and calculate metrics
|
|
1777
|
+
this.buildTestRunsWithFeedback();
|
|
1778
|
+
this.feedbacksLoaded = true;
|
|
1779
|
+
}
|
|
1780
|
+
catch (error) {
|
|
1781
|
+
console.error('Error loading feedbacks:', error);
|
|
1782
|
+
}
|
|
1783
|
+
finally {
|
|
1784
|
+
this.loadingFeedbacks = false;
|
|
1785
|
+
this.cdr.markForCheck();
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
/**
|
|
1789
|
+
* Build TestRunWithFeedback array from testRuns and feedbacks
|
|
1790
|
+
*/
|
|
1791
|
+
buildTestRunsWithFeedback() {
|
|
1792
|
+
this.testRunsWithFeedback = this.testRuns.map(run => {
|
|
1793
|
+
const feedback = this.feedbacks.get(run.ID);
|
|
1794
|
+
return {
|
|
1795
|
+
id: run.ID,
|
|
1796
|
+
testId: run.TestID,
|
|
1797
|
+
testName: run.Test || 'Unknown Test',
|
|
1798
|
+
executionStatus: normalizeExecutionStatus(run.Status || 'Completed'),
|
|
1799
|
+
originalStatus: run.Status || 'Completed',
|
|
1800
|
+
duration: (run.DurationSeconds || 0) * 1000, // Convert to ms
|
|
1801
|
+
cost: run.CostUSD || 0,
|
|
1802
|
+
runDateTime: run.StartedAt ? new Date(run.StartedAt) : new Date(),
|
|
1803
|
+
autoScore: run.Score,
|
|
1804
|
+
passedChecks: null,
|
|
1805
|
+
failedChecks: null,
|
|
1806
|
+
totalChecks: null,
|
|
1807
|
+
humanRating: feedback?.Rating || null,
|
|
1808
|
+
humanIsCorrect: feedback?.IsCorrect ?? null,
|
|
1809
|
+
humanComments: feedback?.CorrectionSummary || null,
|
|
1810
|
+
hasHumanFeedback: !!feedback,
|
|
1811
|
+
feedbackId: feedback?.ID || null,
|
|
1812
|
+
tags: TagsHelper.parseTags(run.Tags),
|
|
1813
|
+
targetType: null,
|
|
1814
|
+
targetLogID: null
|
|
1815
|
+
};
|
|
1816
|
+
});
|
|
1817
|
+
// Calculate metrics
|
|
1818
|
+
this.evaluationMetrics = calculateEvaluationMetrics(this.testRunsWithFeedback);
|
|
1819
|
+
// Get items needing review
|
|
1820
|
+
this.needsReviewItems = getNeedsReviewItems(this.testRunsWithFeedback);
|
|
1821
|
+
}
|
|
1822
|
+
toggleRunExpanded(runId) {
|
|
1823
|
+
if (this.expandedRunId === runId) {
|
|
1824
|
+
this.expandedRunId = null;
|
|
1825
|
+
}
|
|
1826
|
+
else {
|
|
1827
|
+
this.expandedRunId = runId;
|
|
1828
|
+
this.initializeInlineFeedback(runId);
|
|
1829
|
+
}
|
|
1830
|
+
this.cdr.markForCheck();
|
|
1831
|
+
}
|
|
1832
|
+
initializeInlineFeedback(runId) {
|
|
1833
|
+
const existingFeedback = this.feedbacks.get(runId);
|
|
1834
|
+
if (existingFeedback) {
|
|
1835
|
+
this.inlineRating = existingFeedback.Rating || 0;
|
|
1836
|
+
this.inlineIsCorrect = existingFeedback.IsCorrect;
|
|
1837
|
+
this.inlineComments = existingFeedback.CorrectionSummary || '';
|
|
1838
|
+
}
|
|
1839
|
+
else {
|
|
1840
|
+
this.inlineRating = 0;
|
|
1841
|
+
this.inlineIsCorrect = null;
|
|
1842
|
+
this.inlineComments = '';
|
|
1843
|
+
}
|
|
1844
|
+
this.inlineHoverRating = 0;
|
|
1845
|
+
}
|
|
1846
|
+
setInlineRating(value) {
|
|
1847
|
+
this.inlineRating = value;
|
|
1848
|
+
this.cdr.markForCheck();
|
|
1849
|
+
}
|
|
1850
|
+
getInlineRatingLabel() {
|
|
1851
|
+
if (this.inlineRating <= 3)
|
|
1852
|
+
return 'Poor';
|
|
1853
|
+
if (this.inlineRating <= 5)
|
|
1854
|
+
return 'Below Average';
|
|
1855
|
+
if (this.inlineRating <= 6)
|
|
1856
|
+
return 'Average';
|
|
1857
|
+
if (this.inlineRating <= 7)
|
|
1858
|
+
return 'Good';
|
|
1859
|
+
if (this.inlineRating <= 8)
|
|
1860
|
+
return 'Very Good';
|
|
1861
|
+
if (this.inlineRating <= 9)
|
|
1862
|
+
return 'Excellent';
|
|
1863
|
+
return 'Outstanding';
|
|
1864
|
+
}
|
|
1865
|
+
canSubmitInlineFeedback() {
|
|
1866
|
+
return this.inlineRating > 0 && this.inlineComments.trim().length > 0;
|
|
1867
|
+
}
|
|
1868
|
+
async saveInlineFeedback() {
|
|
1869
|
+
if (!this.expandedRunId || !this.canSubmitInlineFeedback())
|
|
1870
|
+
return;
|
|
1871
|
+
this.savingInlineFeedback = true;
|
|
1872
|
+
this.cdr.markForCheck();
|
|
1873
|
+
try {
|
|
1874
|
+
const md = new Metadata();
|
|
1875
|
+
const currentUser = md.CurrentUser;
|
|
1876
|
+
let feedback = this.feedbacks.get(this.expandedRunId);
|
|
1877
|
+
if (!feedback) {
|
|
1878
|
+
feedback = await md.GetEntityObject('MJ: Test Run Feedbacks', currentUser);
|
|
1879
|
+
feedback.TestRunID = this.expandedRunId;
|
|
1880
|
+
feedback.ReviewerUserID = currentUser.ID;
|
|
1881
|
+
}
|
|
1882
|
+
feedback.Rating = this.inlineRating;
|
|
1883
|
+
feedback.IsCorrect = this.inlineIsCorrect;
|
|
1884
|
+
feedback.CorrectionSummary = this.inlineComments.trim() || null;
|
|
1885
|
+
const result = await feedback.Save();
|
|
1886
|
+
if (result) {
|
|
1887
|
+
this.feedbacks.set(this.expandedRunId, feedback);
|
|
1888
|
+
// Rebuild the metrics after feedback update
|
|
1889
|
+
this.buildTestRunsWithFeedback();
|
|
1890
|
+
SharedService.Instance.CreateSimpleNotification('Feedback saved', 'success', 2000);
|
|
1891
|
+
this.expandedRunId = null;
|
|
1892
|
+
}
|
|
1893
|
+
else {
|
|
1894
|
+
SharedService.Instance.CreateSimpleNotification(feedback.LatestResult?.Message || 'Failed to save feedback', 'error', 3000);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
catch (error) {
|
|
1898
|
+
SharedService.Instance.CreateSimpleNotification('Failed to save feedback', 'error', 3000);
|
|
1899
|
+
}
|
|
1900
|
+
finally {
|
|
1901
|
+
this.savingInlineFeedback = false;
|
|
1902
|
+
this.cdr.markForCheck();
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
hasFeedback(runId) {
|
|
1906
|
+
return this.feedbacks.has(runId);
|
|
1907
|
+
}
|
|
1908
|
+
getFeedbackRating(runId) {
|
|
1909
|
+
return this.feedbacks.get(runId)?.Rating || 0;
|
|
1910
|
+
}
|
|
1911
|
+
/**
|
|
1912
|
+
* Get TestRunWithFeedback by run ID for template binding
|
|
1913
|
+
*/
|
|
1914
|
+
getRunWithFeedback(runId) {
|
|
1915
|
+
return this.testRunsWithFeedback.find(r => r.id === runId);
|
|
1916
|
+
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Get the human correctness status for a run
|
|
1919
|
+
*/
|
|
1920
|
+
getHumanIsCorrect(runId) {
|
|
1921
|
+
return this.feedbacks.get(runId)?.IsCorrect ?? null;
|
|
1922
|
+
}
|
|
1923
|
+
// ===========================
|
|
1924
|
+
// Run Tags
|
|
1925
|
+
// ===========================
|
|
1926
|
+
getRunTags(run) {
|
|
1927
|
+
return TagsHelper.parseTags(run.Tags);
|
|
1928
|
+
}
|
|
1929
|
+
// ===========================
|
|
1930
|
+
// Keyboard Shortcuts Settings
|
|
1931
|
+
// ===========================
|
|
1932
|
+
/**
|
|
1933
|
+
* Load keyboard shortcuts visibility setting from user settings
|
|
1934
|
+
*/
|
|
1935
|
+
loadShortcutsSetting() {
|
|
1936
|
+
try {
|
|
1937
|
+
const engine = UserInfoEngine.Instance;
|
|
1938
|
+
const setting = engine.UserSettings.find(s => s.Setting === SHORTCUTS_SETTINGS_KEY);
|
|
1939
|
+
if (setting) {
|
|
1940
|
+
this.shortcutsSettingEntity = setting;
|
|
1941
|
+
this.showShortcuts = setting.Value === 'true';
|
|
1942
|
+
}
|
|
1943
|
+
else {
|
|
1944
|
+
// Default to hidden
|
|
1945
|
+
this.showShortcuts = false;
|
|
1946
|
+
}
|
|
1947
|
+
this.cdr.markForCheck();
|
|
1948
|
+
}
|
|
1949
|
+
catch (error) {
|
|
1950
|
+
console.warn('Failed to load shortcuts setting:', error);
|
|
389
1951
|
}
|
|
1952
|
+
}
|
|
1953
|
+
/**
|
|
1954
|
+
* Toggle keyboard shortcuts visibility and save preference
|
|
1955
|
+
*/
|
|
1956
|
+
async toggleShortcuts() {
|
|
1957
|
+
this.showShortcuts = !this.showShortcuts;
|
|
390
1958
|
this.cdr.markForCheck();
|
|
1959
|
+
try {
|
|
1960
|
+
const userId = this.metadata.CurrentUser?.ID;
|
|
1961
|
+
if (!userId)
|
|
1962
|
+
return;
|
|
1963
|
+
if (!this.shortcutsSettingEntity) {
|
|
1964
|
+
const engine = UserInfoEngine.Instance;
|
|
1965
|
+
const setting = engine.UserSettings.find(s => s.Setting === SHORTCUTS_SETTINGS_KEY);
|
|
1966
|
+
if (setting) {
|
|
1967
|
+
this.shortcutsSettingEntity = setting;
|
|
1968
|
+
}
|
|
1969
|
+
else {
|
|
1970
|
+
this.shortcutsSettingEntity = await this.metadata.GetEntityObject('MJ: User Settings');
|
|
1971
|
+
this.shortcutsSettingEntity.UserID = userId;
|
|
1972
|
+
this.shortcutsSettingEntity.Setting = SHORTCUTS_SETTINGS_KEY;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
this.shortcutsSettingEntity.Value = this.showShortcuts ? 'true' : 'false';
|
|
1976
|
+
await this.shortcutsSettingEntity.Save();
|
|
1977
|
+
}
|
|
1978
|
+
catch (error) {
|
|
1979
|
+
console.warn('Failed to save shortcuts setting:', error);
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
// ===========================
|
|
1983
|
+
// Analytics Calculations
|
|
1984
|
+
// ===========================
|
|
1985
|
+
getPassedCount() {
|
|
1986
|
+
return this.testRuns.filter(r => r.Status === 'Passed').length;
|
|
1987
|
+
}
|
|
1988
|
+
getFailedCount() {
|
|
1989
|
+
return this.testRuns.filter(r => r.Status === 'Failed' || r.Status === 'Error').length;
|
|
1990
|
+
}
|
|
1991
|
+
getPassedPercent() {
|
|
1992
|
+
if (this.testRuns.length === 0)
|
|
1993
|
+
return 0;
|
|
1994
|
+
return (this.getPassedCount() / this.testRuns.length) * 100;
|
|
1995
|
+
}
|
|
1996
|
+
getFailedPercent() {
|
|
1997
|
+
if (this.testRuns.length === 0)
|
|
1998
|
+
return 0;
|
|
1999
|
+
return (this.getFailedCount() / this.testRuns.length) * 100;
|
|
2000
|
+
}
|
|
2001
|
+
getAverageScore() {
|
|
2002
|
+
const runsWithScore = this.testRuns.filter(r => r.Score != null);
|
|
2003
|
+
if (runsWithScore.length === 0)
|
|
2004
|
+
return 0;
|
|
2005
|
+
const sum = runsWithScore.reduce((acc, r) => acc + (r.Score || 0), 0);
|
|
2006
|
+
return sum / runsWithScore.length;
|
|
2007
|
+
}
|
|
2008
|
+
getAverageDuration() {
|
|
2009
|
+
const runsWithDuration = this.testRuns.filter(r => r.DurationSeconds != null);
|
|
2010
|
+
if (runsWithDuration.length === 0)
|
|
2011
|
+
return 0;
|
|
2012
|
+
const sum = runsWithDuration.reduce((acc, r) => acc + (r.DurationSeconds || 0), 0);
|
|
2013
|
+
return sum / runsWithDuration.length;
|
|
2014
|
+
}
|
|
2015
|
+
getTotalCost() {
|
|
2016
|
+
return this.testRuns.reduce((acc, r) => acc + (r.CostUSD || 0), 0);
|
|
2017
|
+
}
|
|
2018
|
+
// ===========================
|
|
2019
|
+
// Export
|
|
2020
|
+
// ===========================
|
|
2021
|
+
exportToCSV() {
|
|
2022
|
+
const headers = ['Test Name', 'Status', 'Score', 'Duration (s)', 'Cost (USD)', 'Started At', 'Tags'];
|
|
2023
|
+
const rows = this.testRuns.map(run => [
|
|
2024
|
+
run.Test || '',
|
|
2025
|
+
run.Status || '',
|
|
2026
|
+
run.Score?.toFixed(4) || '',
|
|
2027
|
+
run.DurationSeconds?.toFixed(2) || '',
|
|
2028
|
+
run.CostUSD?.toFixed(6) || '',
|
|
2029
|
+
run.StartedAt ? new Date(run.StartedAt).toISOString() : '',
|
|
2030
|
+
this.getRunTags(run).join('; ')
|
|
2031
|
+
]);
|
|
2032
|
+
const csvContent = [headers, ...rows]
|
|
2033
|
+
.map(row => row.map(cell => `"${cell}"`).join(','))
|
|
2034
|
+
.join('\n');
|
|
2035
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
2036
|
+
const link = document.createElement('a');
|
|
2037
|
+
link.href = URL.createObjectURL(blob);
|
|
2038
|
+
link.download = `test-suite-run-${this.record.ID.substring(0, 8)}-results.csv`;
|
|
2039
|
+
link.click();
|
|
2040
|
+
URL.revokeObjectURL(link.href);
|
|
2041
|
+
SharedService.Instance.CreateSimpleNotification('Export complete', 'success', 2000);
|
|
391
2042
|
}
|
|
392
|
-
static { this.ɵfac = function TestSuiteRunFormComponentExtended_Factory(t) { return new (t || TestSuiteRunFormComponentExtended)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.SharedService), i0.ɵɵdirectiveInject(i2.Router), i0.ɵɵdirectiveInject(i2.ActivatedRoute), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); }; }
|
|
393
|
-
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestSuiteRunFormComponentExtended, selectors: [["mj-test-suite-run-form"]],
|
|
2043
|
+
static { this.ɵfac = function TestSuiteRunFormComponentExtended_Factory(t) { return new (t || TestSuiteRunFormComponentExtended)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.SharedService), i0.ɵɵdirectiveInject(i2.Router), i0.ɵɵdirectiveInject(i2.ActivatedRoute), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i3.TestingDialogService), i0.ɵɵdirectiveInject(i3.EvaluationPreferencesService)); }; }
|
|
2044
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestSuiteRunFormComponentExtended, selectors: [["mj-test-suite-run-form"]], hostBindings: function TestSuiteRunFormComponentExtended_HostBindings(rf, ctx) { if (rf & 1) {
|
|
2045
|
+
i0.ɵɵlistener("keydown", function TestSuiteRunFormComponentExtended_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, false, i0.ɵɵresolveDocument);
|
|
2046
|
+
} }, features: [i0.ɵɵInheritDefinitionFeature], decls: 126, vars: 47, consts: [["kendoDialogContainer", "", 1, "test-suite-run-form"], [1, "suite-run-header"], ["class", "breadcrumb", 4, "ngIf"], [1, "header-content"], [1, "header-left"], [1, "suite-run-icon"], [1, "fas", 3, "ngClass"], [1, "suite-run-info"], [1, "suite-run-meta"], [1, "status-badge", 3, "ngClass"], ["class", "meta-tag environment", 4, "ngIf"], ["class", "meta-tag trigger", 4, "ngIf"], [1, "header-actions"], ["kendoButton", "", "themeColor", "primary", 3, "click", 4, "ngIf"], ["kendoButton", "", 3, "click", "disabled"], [1, "metrics-bar"], [1, "metric-card"], [1, "metric-icon"], [1, "fas", "fa-clock"], [1, "metric-content"], [1, "metric-value"], [1, "metric-label"], [1, "fas", "fa-percentage"], [1, "fas", "fa-dollar-sign"], [1, "fas", "fa-calendar"], [1, "results-summary"], [1, "result-item", "passed"], [1, "result-icon"], [1, "fas", "fa-check-circle"], [1, "result-content"], [1, "result-count"], [1, "result-label"], [1, "result-item", "failed"], [1, "fas", "fa-times-circle"], [1, "result-item", "error"], [1, "fas", "fa-exclamation-circle"], [1, "result-item", "skipped"], [1, "fas", "fa-forward"], [1, "result-item", "total"], [1, "fas", "fa-list"], ["class", "tags-bar", 4, "ngIf"], ["class", "tags-editor-panel", 4, "ngIf"], [1, "tabs-container"], ["role", "tablist", 1, "tabs"], ["role", "tab", 1, "tab", 3, "click"], [1, "fas", "fa-th-large"], ["class", "tab-badge", 4, "ngIf"], [1, "fas", "fa-info-circle"], ["role", "tab", "title", "Press 4", 1, "tab", 3, "click"], [1, "fas", "fa-chart-bar"], ["role", "tab", "title", "Press 5", 1, "tab", 3, "click"], [1, "fas", "fa-microchip"], [1, "tab-content"], ["class", "overview-tab", 4, "ngIf"], ["class", "runs-tab", 4, "ngIf"], ["class", "details-tab", 4, "ngIf"], ["class", "analytics-tab", 4, "ngIf"], ["class", "execution-tab", 4, "ngIf"], [1, "shortcuts-toggle", 3, "click", "title"], [1, "fas", "fa-keyboard"], ["class", "keyboard-shortcuts", 4, "ngIf"], [1, "breadcrumb"], ["href", "javascript:void(0)", 3, "click"], [1, "fas", "fa-layer-group"], [1, "fas", "fa-chevron-right", "separator"], [1, "current"], [1, "meta-tag", "environment"], [1, "fas", "fa-server"], [1, "meta-tag", "trigger"], [1, "fas", "fa-bolt"], ["kendoButton", "", "themeColor", "primary", 3, "click"], [1, "fas", "fa-play"], [1, "tags-bar"], [1, "tags-bar-content"], [1, "tags-bar-label"], [1, "fas", "fa-tags"], ["class", "tags-bar-chips", 4, "ngIf"], ["class", "tags-bar-empty", 4, "ngIf"], ["title", "Edit tags", 1, "tags-bar-edit", 3, "click"], [1, "fas", "fa-plus"], [1, "tags-bar-chips"], ["class", "tag-inline", 4, "ngFor", "ngForOf"], [1, "tag-inline"], [1, "tags-bar-empty"], [1, "tags-editor-panel"], [1, "tags-editor-header"], [1, "tags-editor-title"], [1, "tags-editor-body"], [1, "tags-editor-chips"], ["class", "tag-editable", 4, "ngFor", "ngForOf"], ["class", "tags-empty-hint", 4, "ngIf"], [1, "tags-editor-input"], ["type", "text", "placeholder", "Type a tag and press Enter...", 1, "tag-text-input", 3, "ngModelChange", "keyup.enter", "ngModel"], ["kendoButton", "", "fillMode", "flat", 3, "click", "disabled"], [1, "tags-editor-footer"], ["kendoButton", "", "themeColor", "primary", 3, "click", "disabled"], ["class", "fas fa-spinner fa-spin", 4, "ngIf"], ["kendoButton", "", "fillMode", "flat", 3, "click"], [1, "tag-editable"], ["title", "Remove tag", 1, "tag-remove-btn", 3, "click"], [1, "fas", "fa-times"], [1, "tags-empty-hint"], [1, "fas", "fa-spinner", "fa-spin"], [1, "tab-badge"], [1, "overview-tab"], [1, "result-hero"], [1, "result-hero-icon"], [1, "result-hero-text"], [1, "result-hero-stats"], [1, "stat-item"], [1, "stat-value"], [1, "stat-label"], [1, "stat-divider"], ["class", "evaluation-summary", 4, "ngIf"], ["class", "needs-review-section", 4, "ngIf"], ["class", "progress-section", 4, "ngIf"], [1, "evaluation-summary"], [1, "eval-summary-grid"], ["class", "eval-summary-card", 4, "ngIf"], [1, "eval-summary-card"], [1, "eval-card-header"], [1, "fa-solid", "fa-user"], [1, "eval-card-body"], [1, "eval-stat-row"], [1, "eval-stat-label"], [1, "eval-stat-value"], ["class", "eval-stat-row", 4, "ngIf"], ["class", "eval-card-footer", 4, "ngIf"], [1, "eval-stat-value", "correct"], ["class", "eval-stat-value incorrect", 4, "ngIf"], [1, "eval-stat-value", "incorrect"], [1, "eval-card-footer"], [1, "pending-badge"], [1, "fa-solid", "fa-clock"], [1, "fa-solid", "fa-robot"], [1, "fa-solid", "fa-circle-check"], ["class", "eval-stat-value error", 4, "ngIf"], ["class", "eval-stat-value timeout", 4, "ngIf"], [1, "eval-stat-value", "error"], [1, "eval-stat-value", "timeout"], [1, "needs-review-section"], [1, "needs-review-header"], [1, "fa-solid", "fa-user-clock"], [1, "review-count"], [1, "needs-review-list"], ["class", "review-item", 3, "high-priority", "medium-priority", "click", 4, "ngFor", "ngForOf"], ["class", "review-more", 4, "ngIf"], [1, "review-item", 3, "click"], [1, "review-item-icon"], ["class", "fa-solid fa-exclamation-triangle", 4, "ngIf"], ["class", "fa-solid fa-circle-dot", 4, "ngIf"], ["class", "fa-solid fa-clock", 4, "ngIf"], [1, "review-item-content"], [1, "review-item-name"], [1, "review-item-reason"], [1, "review-item-action"], [1, "fa-solid", "fa-chevron-right"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "fa-solid", "fa-circle-dot"], [1, "review-more"], [1, "progress-section"], [1, "progress-info"], [1, "fas", "fa-circle-notch", "fa-spin"], [1, "auto-refresh-notice"], [1, "fas", "fa-sync"], [1, "runs-tab"], ["class", "runs-toolbar", 4, "ngIf"], ["class", "loading-state", 4, "ngIf"], ["class", "test-runs-list", 4, "ngIf"], ["class", "empty-state", 4, "ngIf"], [1, "runs-toolbar"], [1, "run-filters"], [1, "filter-btn", 3, "click"], ["class", "filter-btn passed", 3, "active", "click", 4, "ngIf"], ["class", "filter-btn failed", 3, "active", "click", 4, "ngIf"], ["class", "filter-btn error", 3, "active", "click", 4, "ngIf"], [1, "runs-actions"], ["kendoButton", "", 3, "click"], [1, "fas", "fa-download"], [1, "filter-btn", "passed", 3, "click"], [1, "fas", "fa-check"], [1, "filter-btn", "failed", 3, "click"], [1, "filter-btn", "error", 3, "click"], [1, "fas", "fa-exclamation"], [1, "loading-state"], [1, "skeleton-list"], ["class", "skeleton-card", 4, "ngFor", "ngForOf"], [1, "skeleton-card"], [1, "skeleton-sequence"], [1, "skeleton-icon"], [1, "skeleton-content"], [1, "skeleton-line", "wide"], [1, "skeleton-line", "narrow"], [1, "test-runs-list"], ["class", "test-run-card", 4, "ngFor", "ngForOf"], [1, "test-run-card"], [1, "test-run-item", 3, "click"], [1, "run-sequence"], [1, "run-icon"], [1, "run-content"], [1, "run-header-row"], [1, "run-name"], [3, "executionStatus", "originalStatus", "autoScore", "humanRating", "humanIsCorrect", "hasHumanFeedback", "preferences", "mode"], [1, "run-meta"], ["class", "run-duration", 4, "ngIf"], ["class", "run-cost", 4, "ngIf"], [3, "entityName", "recordId", 4, "ngIf"], ["class", "run-tags", 4, "ngIf"], [1, "run-expand"], [1, "fas"], ["class", "inline-feedback", 4, "ngIf"], [1, "run-duration"], [1, "run-cost"], [3, "entityName", "recordId"], [1, "run-tags"], ["class", "tag-chip", 4, "ngFor", "ngForOf"], [1, "tag-chip"], [1, "inline-feedback"], [1, "feedback-divider"], [1, "feedback-section"], [1, "feedback-label"], [1, "inline-rating"], [1, "rating-numbers"], ["type", "button", "class", "rating-btn", 3, "selected", "hover", "low", "mid", "high", "click", "mouseenter", "mouseleave", 4, "ngFor", "ngForOf"], ["class", "rating-info", 4, "ngIf"], [1, "correctness-row"], [1, "correctness-label"], [1, "correctness-options"], [1, "radio-opt", 3, "click"], ["type", "radio", 3, "ngModelChange", "name", "value", "ngModel"], [1, "comments-row", 3, "click"], ["placeholder", "Add comments or corrections...", "rows", "3", 1, "feedback-textarea", 3, "ngModelChange", "ngModel"], [1, "feedback-actions", 3, "click"], [1, "fas", "fa-external-link-alt"], ["type", "button", 1, "rating-btn", 3, "click", "mouseenter", "mouseleave"], [1, "rating-info"], [1, "rating-value"], [1, "rating-label-text"], [1, "empty-state"], [1, "empty-icon"], [1, "fas", "fa-inbox"], [1, "fas", "fa-filter"], [1, "details-tab"], [1, "details-card"], [1, "details-grid"], [1, "detail-item"], [1, "detail-label"], [1, "detail-value", "monospace"], [1, "detail-value"], ["href", "javascript:void(0)", 3, "click", 4, "ngIf"], [4, "ngIf"], [1, "status-inline", 3, "ngClass"], [1, "analytics-tab"], ["class", "analytics-loading", 4, "ngIf"], ["class", "analytics-section", 4, "ngIf"], [1, "analytics-loading"], [1, "analytics-section"], [1, "fas", "fa-chart-pie"], [1, "stats-grid"], [1, "stat-card"], [1, "stat-icon", "passed"], [1, "stat-content"], [1, "stat-percent"], [1, "stat-icon", "failed"], [1, "stat-icon", "score"], [1, "fas", "fa-star"], [1, "stat-icon", "duration"], [1, "stat-icon", "cost"], [1, "analytics-header"], [1, "fas", "fa-table"], [1, "analytics-legend"], [1, "legend-item", "passed"], [1, "legend-item", "failed"], [1, "legend-item", "error"], [1, "legend-item", "skipped"], [1, "results-table-wrapper"], [1, "results-table"], [1, "seq-col"], [1, "name-col"], ["class", "status-col", 4, "ngIf"], ["class", "score-col", 4, "ngIf"], ["class", "feedback-col", 4, "ngIf"], [1, "duration-col"], [1, "cost-col"], ["class", "result-row", 3, "row-passed", "row-failed", "row-error", "row-skipped", "click", 4, "ngFor", "ngForOf"], [1, "status-col"], [1, "score-col"], [1, "feedback-col"], [1, "result-row", 3, "click"], [1, "test-name-wrapper"], [1, "test-name"], ["class", "test-tags", 4, "ngIf"], ["class", "na-value", 4, "ngIf"], [1, "test-tags"], ["class", "tag-mini", 4, "ngFor", "ngForOf"], [1, "tag-mini"], ["class", "score-display", 4, "ngIf"], [1, "score-display"], [1, "score-bar-mini"], [1, "score-fill"], [1, "score-text"], [1, "na-value"], ["class", "feedback-display", 4, "ngIf"], ["class", "na-value needs-review", 4, "ngIf"], [1, "feedback-display"], [1, "feedback-rating"], ["class", "feedback-correctness", 4, "ngIf"], [1, "feedback-correctness"], [1, "na-value", "needs-review"], [1, "fas", "fa-user-clock"], [1, "execution-tab"], [3, "machineName", "machineId", "runByUserName", "runByUserEmail", "runContextDetailsJson"], [1, "keyboard-shortcuts"], [1, "shortcuts-header"], ["title", "Hide shortcuts", 1, "shortcuts-close", 3, "click"], [1, "shortcut-list"], [1, "shortcut-item"], [1, "shortcut-keys"]], template: function TestSuiteRunFormComponentExtended_Template(rf, ctx) { if (rf & 1) {
|
|
394
2047
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
|
|
395
2048
|
i0.ɵɵtemplate(2, TestSuiteRunFormComponentExtended_div_2_Template, 7, 2, "div", 2);
|
|
396
2049
|
i0.ɵɵelementStart(3, "div", 3)(4, "div", 4)(5, "div", 5);
|
|
397
2050
|
i0.ɵɵelement(6, "i", 6);
|
|
398
2051
|
i0.ɵɵelementEnd();
|
|
399
2052
|
i0.ɵɵelementStart(7, "div", 7)(8, "h1");
|
|
400
|
-
i0.ɵɵtext(9, "
|
|
2053
|
+
i0.ɵɵtext(9, "Suite Run");
|
|
401
2054
|
i0.ɵɵelementEnd();
|
|
402
2055
|
i0.ɵɵelementStart(10, "div", 8)(11, "span", 9);
|
|
403
|
-
i0.ɵɵelement(12, "i",
|
|
2056
|
+
i0.ɵɵelement(12, "i", 6);
|
|
404
2057
|
i0.ɵɵtext(13);
|
|
405
2058
|
i0.ɵɵelementEnd();
|
|
406
|
-
i0.ɵɵtemplate(14, TestSuiteRunFormComponentExtended_span_14_Template,
|
|
2059
|
+
i0.ɵɵtemplate(14, TestSuiteRunFormComponentExtended_span_14_Template, 3, 1, "span", 10)(15, TestSuiteRunFormComponentExtended_span_15_Template, 3, 1, "span", 11);
|
|
407
2060
|
i0.ɵɵelementEnd()()();
|
|
408
|
-
i0.ɵɵelementStart(16, "div",
|
|
409
|
-
i0.ɵɵ
|
|
410
|
-
i0.ɵɵ
|
|
2061
|
+
i0.ɵɵelementStart(16, "div", 12);
|
|
2062
|
+
i0.ɵɵelement(17, "app-evaluation-mode-toggle");
|
|
2063
|
+
i0.ɵɵtemplate(18, TestSuiteRunFormComponentExtended_button_18_Template, 3, 0, "button", 13);
|
|
2064
|
+
i0.ɵɵelementStart(19, "button", 14);
|
|
2065
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_19_listener() { return ctx.refresh(); });
|
|
2066
|
+
i0.ɵɵelement(20, "i", 6);
|
|
2067
|
+
i0.ɵɵtext(21);
|
|
411
2068
|
i0.ɵɵelementEnd()()();
|
|
412
|
-
i0.ɵɵelementStart(
|
|
413
|
-
i0.ɵɵ
|
|
2069
|
+
i0.ɵɵelementStart(22, "div", 15)(23, "div", 16)(24, "div", 17);
|
|
2070
|
+
i0.ɵɵelement(25, "i", 18);
|
|
414
2071
|
i0.ɵɵelementEnd();
|
|
415
|
-
i0.ɵɵelementStart(
|
|
416
|
-
i0.ɵɵtext(
|
|
417
|
-
i0.ɵɵpipe(25, "date");
|
|
418
|
-
i0.ɵɵelementEnd()();
|
|
419
|
-
i0.ɵɵelementStart(26, "div", 16)(27, "div", 17);
|
|
420
|
-
i0.ɵɵtext(28, "Completed");
|
|
2072
|
+
i0.ɵɵelementStart(26, "div", 19)(27, "div", 20);
|
|
2073
|
+
i0.ɵɵtext(28);
|
|
421
2074
|
i0.ɵɵelementEnd();
|
|
422
|
-
i0.ɵɵelementStart(29, "div",
|
|
423
|
-
i0.ɵɵtext(30);
|
|
424
|
-
i0.ɵɵ
|
|
425
|
-
i0.ɵɵ
|
|
426
|
-
i0.ɵɵ
|
|
427
|
-
i0.ɵɵtext(34, "Duration");
|
|
2075
|
+
i0.ɵɵelementStart(29, "div", 21);
|
|
2076
|
+
i0.ɵɵtext(30, "Duration");
|
|
2077
|
+
i0.ɵɵelementEnd()()();
|
|
2078
|
+
i0.ɵɵelementStart(31, "div", 16)(32, "div", 17);
|
|
2079
|
+
i0.ɵɵelement(33, "i", 22);
|
|
428
2080
|
i0.ɵɵelementEnd();
|
|
429
|
-
i0.ɵɵelementStart(35, "div",
|
|
2081
|
+
i0.ɵɵelementStart(34, "div", 19)(35, "div", 20);
|
|
430
2082
|
i0.ɵɵtext(36);
|
|
431
|
-
i0.ɵɵelementEnd()();
|
|
432
|
-
i0.ɵɵelementStart(37, "div", 16)(38, "div", 17);
|
|
433
|
-
i0.ɵɵtext(39, "Pass Rate");
|
|
434
2083
|
i0.ɵɵelementEnd();
|
|
435
|
-
i0.ɵɵelementStart(
|
|
436
|
-
i0.ɵɵtext(
|
|
437
|
-
i0.ɵɵelementEnd()();
|
|
438
|
-
i0.ɵɵelementStart(
|
|
439
|
-
i0.ɵɵ
|
|
2084
|
+
i0.ɵɵelementStart(37, "div", 21);
|
|
2085
|
+
i0.ɵɵtext(38, "Pass Rate");
|
|
2086
|
+
i0.ɵɵelementEnd()()();
|
|
2087
|
+
i0.ɵɵelementStart(39, "div", 16)(40, "div", 17);
|
|
2088
|
+
i0.ɵɵelement(41, "i", 23);
|
|
2089
|
+
i0.ɵɵelementEnd();
|
|
2090
|
+
i0.ɵɵelementStart(42, "div", 19)(43, "div", 20);
|
|
2091
|
+
i0.ɵɵtext(44);
|
|
440
2092
|
i0.ɵɵelementEnd();
|
|
441
|
-
i0.ɵɵelementStart(45, "div",
|
|
442
|
-
i0.ɵɵtext(46);
|
|
2093
|
+
i0.ɵɵelementStart(45, "div", 21);
|
|
2094
|
+
i0.ɵɵtext(46, "Total Cost");
|
|
443
2095
|
i0.ɵɵelementEnd()()();
|
|
444
|
-
i0.ɵɵelementStart(47, "div",
|
|
445
|
-
i0.ɵɵelement(49, "i",
|
|
446
|
-
i0.ɵɵ
|
|
447
|
-
i0.ɵɵ
|
|
2096
|
+
i0.ɵɵelementStart(47, "div", 16)(48, "div", 17);
|
|
2097
|
+
i0.ɵɵelement(49, "i", 24);
|
|
2098
|
+
i0.ɵɵelementEnd();
|
|
2099
|
+
i0.ɵɵelementStart(50, "div", 19)(51, "div", 20);
|
|
2100
|
+
i0.ɵɵtext(52);
|
|
448
2101
|
i0.ɵɵelementEnd();
|
|
449
|
-
i0.ɵɵelementStart(
|
|
450
|
-
i0.ɵɵtext(
|
|
451
|
-
i0.ɵɵelementEnd()();
|
|
452
|
-
i0.ɵɵelementStart(
|
|
453
|
-
i0.ɵɵelement(
|
|
454
|
-
i0.ɵɵ
|
|
455
|
-
i0.ɵɵ
|
|
2102
|
+
i0.ɵɵelementStart(53, "div", 21);
|
|
2103
|
+
i0.ɵɵtext(54, "Started");
|
|
2104
|
+
i0.ɵɵelementEnd()()()();
|
|
2105
|
+
i0.ɵɵelementStart(55, "div", 25)(56, "div", 26)(57, "div", 27);
|
|
2106
|
+
i0.ɵɵelement(58, "i", 28);
|
|
2107
|
+
i0.ɵɵelementEnd();
|
|
2108
|
+
i0.ɵɵelementStart(59, "div", 29)(60, "span", 30);
|
|
2109
|
+
i0.ɵɵtext(61);
|
|
456
2110
|
i0.ɵɵelementEnd();
|
|
457
|
-
i0.ɵɵelementStart(
|
|
458
|
-
i0.ɵɵtext(
|
|
459
|
-
i0.ɵɵelementEnd()();
|
|
460
|
-
i0.ɵɵelementStart(
|
|
461
|
-
i0.ɵɵelement(
|
|
462
|
-
i0.ɵɵelementStart(62, "span", 22);
|
|
463
|
-
i0.ɵɵtext(63);
|
|
2111
|
+
i0.ɵɵelementStart(62, "span", 31);
|
|
2112
|
+
i0.ɵɵtext(63, "Passed");
|
|
2113
|
+
i0.ɵɵelementEnd()()();
|
|
2114
|
+
i0.ɵɵelementStart(64, "div", 32)(65, "div", 27);
|
|
2115
|
+
i0.ɵɵelement(66, "i", 33);
|
|
464
2116
|
i0.ɵɵelementEnd();
|
|
465
|
-
i0.ɵɵelementStart(
|
|
466
|
-
i0.ɵɵtext(65, "Skipped");
|
|
467
|
-
i0.ɵɵelementEnd()();
|
|
468
|
-
i0.ɵɵelementStart(66, "div", 28);
|
|
469
|
-
i0.ɵɵelement(67, "i", 29);
|
|
470
|
-
i0.ɵɵelementStart(68, "span", 22);
|
|
2117
|
+
i0.ɵɵelementStart(67, "div", 29)(68, "span", 30);
|
|
471
2118
|
i0.ɵɵtext(69);
|
|
472
2119
|
i0.ɵɵelementEnd();
|
|
473
|
-
i0.ɵɵelementStart(70, "span",
|
|
474
|
-
i0.ɵɵtext(71, "
|
|
475
|
-
i0.ɵɵelementEnd()();
|
|
476
|
-
i0.ɵɵelementStart(72, "div",
|
|
477
|
-
i0.ɵɵelement(
|
|
478
|
-
i0.ɵɵ
|
|
479
|
-
i0.ɵɵ
|
|
2120
|
+
i0.ɵɵelementStart(70, "span", 31);
|
|
2121
|
+
i0.ɵɵtext(71, "Failed");
|
|
2122
|
+
i0.ɵɵelementEnd()()();
|
|
2123
|
+
i0.ɵɵelementStart(72, "div", 34)(73, "div", 27);
|
|
2124
|
+
i0.ɵɵelement(74, "i", 35);
|
|
2125
|
+
i0.ɵɵelementEnd();
|
|
2126
|
+
i0.ɵɵelementStart(75, "div", 29)(76, "span", 30);
|
|
2127
|
+
i0.ɵɵtext(77);
|
|
2128
|
+
i0.ɵɵelementEnd();
|
|
2129
|
+
i0.ɵɵelementStart(78, "span", 31);
|
|
2130
|
+
i0.ɵɵtext(79, "Errors");
|
|
2131
|
+
i0.ɵɵelementEnd()()();
|
|
2132
|
+
i0.ɵɵelementStart(80, "div", 36)(81, "div", 27);
|
|
2133
|
+
i0.ɵɵelement(82, "i", 37);
|
|
2134
|
+
i0.ɵɵelementEnd();
|
|
2135
|
+
i0.ɵɵelementStart(83, "div", 29)(84, "span", 30);
|
|
2136
|
+
i0.ɵɵtext(85);
|
|
480
2137
|
i0.ɵɵelementEnd();
|
|
481
|
-
i0.ɵɵelementStart(
|
|
482
|
-
i0.ɵɵtext(
|
|
2138
|
+
i0.ɵɵelementStart(86, "span", 31);
|
|
2139
|
+
i0.ɵɵtext(87, "Skipped");
|
|
2140
|
+
i0.ɵɵelementEnd()()();
|
|
2141
|
+
i0.ɵɵelementStart(88, "div", 38)(89, "div", 27);
|
|
2142
|
+
i0.ɵɵelement(90, "i", 39);
|
|
2143
|
+
i0.ɵɵelementEnd();
|
|
2144
|
+
i0.ɵɵelementStart(91, "div", 29)(92, "span", 30);
|
|
2145
|
+
i0.ɵɵtext(93);
|
|
2146
|
+
i0.ɵɵelementEnd();
|
|
2147
|
+
i0.ɵɵelementStart(94, "span", 31);
|
|
2148
|
+
i0.ɵɵtext(95, "Total");
|
|
483
2149
|
i0.ɵɵelementEnd()()()();
|
|
484
|
-
i0.ɵɵ
|
|
485
|
-
i0.ɵɵ
|
|
486
|
-
i0.ɵɵ
|
|
487
|
-
i0.ɵɵ
|
|
488
|
-
i0.ɵɵ
|
|
489
|
-
i0.ɵɵ
|
|
490
|
-
i0.ɵɵelementStart(84, "button", 34);
|
|
491
|
-
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_84_listener() { return ctx.changeTab("runs"); });
|
|
492
|
-
i0.ɵɵelement(85, "i", 31);
|
|
493
|
-
i0.ɵɵelementStart(86, "span");
|
|
494
|
-
i0.ɵɵtext(87, "Test Runs");
|
|
2150
|
+
i0.ɵɵtemplate(96, TestSuiteRunFormComponentExtended_div_96_Template, 9, 2, "div", 40)(97, TestSuiteRunFormComponentExtended_div_97_Template, 19, 7, "div", 41);
|
|
2151
|
+
i0.ɵɵelementEnd();
|
|
2152
|
+
i0.ɵɵelementStart(98, "div", 42)(99, "div", 43)(100, "button", 44);
|
|
2153
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_100_listener() { return ctx.changeTab("overview"); });
|
|
2154
|
+
i0.ɵɵelement(101, "i", 45);
|
|
2155
|
+
i0.ɵɵtext(102, " Overview ");
|
|
495
2156
|
i0.ɵɵelementEnd();
|
|
496
|
-
i0.ɵɵ
|
|
2157
|
+
i0.ɵɵelementStart(103, "button", 44);
|
|
2158
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_103_listener() { return ctx.changeTab("runs"); });
|
|
2159
|
+
i0.ɵɵelement(104, "i", 39);
|
|
2160
|
+
i0.ɵɵtext(105, " Test Runs ");
|
|
2161
|
+
i0.ɵɵtemplate(106, TestSuiteRunFormComponentExtended_span_106_Template, 2, 1, "span", 46);
|
|
497
2162
|
i0.ɵɵelementEnd();
|
|
498
|
-
i0.ɵɵelementStart(
|
|
499
|
-
i0.ɵɵlistener("click", function
|
|
500
|
-
i0.ɵɵelement(
|
|
501
|
-
i0.ɵɵ
|
|
502
|
-
i0.ɵɵ
|
|
2163
|
+
i0.ɵɵelementStart(107, "button", 44);
|
|
2164
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_107_listener() { return ctx.changeTab("details"); });
|
|
2165
|
+
i0.ɵɵelement(108, "i", 47);
|
|
2166
|
+
i0.ɵɵtext(109, " Details ");
|
|
2167
|
+
i0.ɵɵelementEnd();
|
|
2168
|
+
i0.ɵɵelementStart(110, "button", 48);
|
|
2169
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_110_listener() { return ctx.changeTab("analytics"); });
|
|
2170
|
+
i0.ɵɵelement(111, "i", 49);
|
|
2171
|
+
i0.ɵɵtext(112, " Analytics ");
|
|
2172
|
+
i0.ɵɵelementEnd();
|
|
2173
|
+
i0.ɵɵelementStart(113, "button", 50);
|
|
2174
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_113_listener() { return ctx.changeTab("execution"); });
|
|
2175
|
+
i0.ɵɵelement(114, "i", 51);
|
|
2176
|
+
i0.ɵɵelementStart(115, "span");
|
|
2177
|
+
i0.ɵɵtext(116, "Execution");
|
|
503
2178
|
i0.ɵɵelementEnd()()()();
|
|
504
|
-
i0.ɵɵelementStart(
|
|
505
|
-
i0.ɵɵtemplate(
|
|
506
|
-
i0.ɵɵelementEnd()
|
|
2179
|
+
i0.ɵɵelementStart(117, "div", 52);
|
|
2180
|
+
i0.ɵɵtemplate(118, TestSuiteRunFormComponentExtended_div_118_Template, 22, 16, "div", 53)(119, TestSuiteRunFormComponentExtended_div_119_Template, 6, 5, "div", 54)(120, TestSuiteRunFormComponentExtended_div_120_Template, 60, 18, "div", 55)(121, TestSuiteRunFormComponentExtended_div_121_Template, 5, 4, "div", 56)(122, TestSuiteRunFormComponentExtended_div_122_Template, 2, 5, "div", 57);
|
|
2181
|
+
i0.ɵɵelementEnd();
|
|
2182
|
+
i0.ɵɵelementStart(123, "button", 58);
|
|
2183
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_123_listener() { return ctx.toggleShortcuts(); });
|
|
2184
|
+
i0.ɵɵelement(124, "i", 59);
|
|
2185
|
+
i0.ɵɵelementEnd();
|
|
2186
|
+
i0.ɵɵtemplate(125, TestSuiteRunFormComponentExtended_div_125_Template, 34, 0, "div", 60);
|
|
2187
|
+
i0.ɵɵelementEnd();
|
|
507
2188
|
} if (rf & 2) {
|
|
508
2189
|
i0.ɵɵadvance(2);
|
|
509
2190
|
i0.ɵɵproperty("ngIf", ctx.testSuite);
|
|
510
2191
|
i0.ɵɵadvance(3);
|
|
511
2192
|
i0.ɵɵstyleProp("background-color", ctx.getStatusColor());
|
|
512
|
-
i0.ɵɵadvance(
|
|
513
|
-
i0.ɵɵ
|
|
2193
|
+
i0.ɵɵadvance();
|
|
2194
|
+
i0.ɵɵproperty("ngClass", ctx.getStatusIcon());
|
|
2195
|
+
i0.ɵɵadvance(5);
|
|
2196
|
+
i0.ɵɵproperty("ngClass", ctx.getStatusClass());
|
|
514
2197
|
i0.ɵɵadvance();
|
|
515
2198
|
i0.ɵɵproperty("ngClass", ctx.getStatusIcon());
|
|
516
2199
|
i0.ɵɵadvance();
|
|
@@ -519,41 +2202,68 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
519
2202
|
i0.ɵɵproperty("ngIf", ctx.record.Environment);
|
|
520
2203
|
i0.ɵɵadvance();
|
|
521
2204
|
i0.ɵɵproperty("ngIf", ctx.record.TriggerType);
|
|
522
|
-
i0.ɵɵadvance(
|
|
523
|
-
i0.ɵɵ
|
|
524
|
-
i0.ɵɵadvance(
|
|
525
|
-
i0.ɵɵ
|
|
526
|
-
i0.ɵɵadvance(
|
|
2205
|
+
i0.ɵɵadvance(3);
|
|
2206
|
+
i0.ɵɵproperty("ngIf", ctx.record.SuiteID);
|
|
2207
|
+
i0.ɵɵadvance();
|
|
2208
|
+
i0.ɵɵproperty("disabled", ctx.isRefreshing);
|
|
2209
|
+
i0.ɵɵadvance();
|
|
2210
|
+
i0.ɵɵproperty("ngClass", ctx.isRefreshing ? "fa-sync fa-spin" : "fa-sync");
|
|
2211
|
+
i0.ɵɵadvance();
|
|
2212
|
+
i0.ɵɵtextInterpolate1(" ", ctx.isRefreshing ? "Refreshing..." : "Refresh", " ");
|
|
2213
|
+
i0.ɵɵadvance(7);
|
|
527
2214
|
i0.ɵɵtextInterpolate(ctx.calculateDuration());
|
|
528
|
-
i0.ɵɵadvance(
|
|
2215
|
+
i0.ɵɵadvance(8);
|
|
529
2216
|
i0.ɵɵtextInterpolate1("", ctx.getPassRate().toFixed(1), "%");
|
|
530
|
-
i0.ɵɵadvance(
|
|
2217
|
+
i0.ɵɵadvance(8);
|
|
531
2218
|
i0.ɵɵtextInterpolate(ctx.formatCost(ctx.record.TotalCostUSD));
|
|
532
|
-
i0.ɵɵadvance(
|
|
2219
|
+
i0.ɵɵadvance(8);
|
|
2220
|
+
i0.ɵɵtextInterpolate(ctx.getRelativeTime(ctx.record.StartedAt));
|
|
2221
|
+
i0.ɵɵadvance(9);
|
|
533
2222
|
i0.ɵɵtextInterpolate(ctx.record.PassedTests || 0);
|
|
534
|
-
i0.ɵɵadvance(
|
|
2223
|
+
i0.ɵɵadvance(8);
|
|
535
2224
|
i0.ɵɵtextInterpolate(ctx.record.FailedTests || 0);
|
|
536
|
-
i0.ɵɵadvance(
|
|
537
|
-
i0.ɵɵtextInterpolate(ctx.record.SkippedTests || 0);
|
|
538
|
-
i0.ɵɵadvance(6);
|
|
2225
|
+
i0.ɵɵadvance(8);
|
|
539
2226
|
i0.ɵɵtextInterpolate(ctx.record.ErrorTests || 0);
|
|
540
|
-
i0.ɵɵadvance(
|
|
2227
|
+
i0.ɵɵadvance(8);
|
|
2228
|
+
i0.ɵɵtextInterpolate(ctx.record.SkippedTests || 0);
|
|
2229
|
+
i0.ɵɵadvance(8);
|
|
541
2230
|
i0.ɵɵtextInterpolate(ctx.record.TotalTests || 0);
|
|
542
|
-
i0.ɵɵadvance(
|
|
2231
|
+
i0.ɵɵadvance(3);
|
|
2232
|
+
i0.ɵɵproperty("ngIf", !ctx.editingTags);
|
|
2233
|
+
i0.ɵɵadvance();
|
|
2234
|
+
i0.ɵɵproperty("ngIf", ctx.editingTags);
|
|
2235
|
+
i0.ɵɵadvance(3);
|
|
543
2236
|
i0.ɵɵclassProp("active", ctx.activeTab === "overview");
|
|
544
|
-
i0.ɵɵ
|
|
2237
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "overview");
|
|
2238
|
+
i0.ɵɵadvance(3);
|
|
545
2239
|
i0.ɵɵclassProp("active", ctx.activeTab === "runs");
|
|
546
|
-
i0.ɵɵ
|
|
2240
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "runs");
|
|
2241
|
+
i0.ɵɵadvance(3);
|
|
547
2242
|
i0.ɵɵproperty("ngIf", ctx.testRunsLoaded);
|
|
548
2243
|
i0.ɵɵadvance();
|
|
549
2244
|
i0.ɵɵclassProp("active", ctx.activeTab === "details");
|
|
2245
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "details");
|
|
2246
|
+
i0.ɵɵadvance(3);
|
|
2247
|
+
i0.ɵɵclassProp("active", ctx.activeTab === "analytics");
|
|
2248
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "analytics");
|
|
2249
|
+
i0.ɵɵadvance(3);
|
|
2250
|
+
i0.ɵɵclassProp("active", ctx.activeTab === "execution");
|
|
2251
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "execution");
|
|
550
2252
|
i0.ɵɵadvance(5);
|
|
551
2253
|
i0.ɵɵproperty("ngIf", ctx.activeTab === "overview");
|
|
552
2254
|
i0.ɵɵadvance();
|
|
553
2255
|
i0.ɵɵproperty("ngIf", ctx.activeTab === "runs");
|
|
554
2256
|
i0.ɵɵadvance();
|
|
555
2257
|
i0.ɵɵproperty("ngIf", ctx.activeTab === "details");
|
|
556
|
-
|
|
2258
|
+
i0.ɵɵadvance();
|
|
2259
|
+
i0.ɵɵproperty("ngIf", ctx.activeTab === "analytics");
|
|
2260
|
+
i0.ɵɵadvance();
|
|
2261
|
+
i0.ɵɵproperty("ngIf", ctx.activeTab === "execution");
|
|
2262
|
+
i0.ɵɵadvance();
|
|
2263
|
+
i0.ɵɵproperty("title", ctx.showShortcuts ? "Hide keyboard shortcuts" : "Show keyboard shortcuts");
|
|
2264
|
+
i0.ɵɵadvance(2);
|
|
2265
|
+
i0.ɵɵproperty("ngIf", ctx.showShortcuts);
|
|
2266
|
+
} }, dependencies: [i4.NgClass, i4.NgForOf, i4.NgIf, i5.DefaultValueAccessor, i5.RadioControlValueAccessor, i5.NgControlStatus, i5.NgModel, i6.DialogContainerDirective, i7.ButtonComponent, i3.EvaluationBadgeComponent, i3.EvaluationModeToggleComponent, i3.ExecutionContextComponent, i8.EntityLinkPillComponent, i4.DatePipe], styles: ["\n\n\n\n\n\n\n\n[_nghost-%COMP%] {\n --suite-run-primary: #3b82f6;\n --suite-run-primary-light: #eff6ff;\n --suite-run-success: #10b981;\n --suite-run-success-light: #ecfdf5;\n --suite-run-danger: #ef4444;\n --suite-run-danger-light: #fef2f2;\n --suite-run-warning: #f59e0b;\n --suite-run-warning-light: #fffbeb;\n --suite-run-info: #8b5cf6;\n --suite-run-info-light: #f5f3ff;\n --suite-run-neutral: #6b7280;\n --suite-run-neutral-light: #f9fafb;\n --suite-run-bg: #f8fafc;\n --suite-run-card: #ffffff;\n --suite-run-border: #e2e8f0;\n --suite-run-text: #1e293b;\n --suite-run-text-secondary: #64748b;\n --suite-run-radius: 12px;\n --suite-run-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);\n --suite-run-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n --suite-run-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n\n\n.test-suite-run-form[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--suite-run-bg);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n}\n\n\n\n\n\n.suite-run-header[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border-bottom: 1px solid var(--suite-run-border);\n padding: 20px 24px;\n}\n\n\n\n.breadcrumb[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--suite-run-text-secondary);\n margin-bottom: 16px;\n}\n\n.breadcrumb[_ngcontent-%COMP%] a[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n text-decoration: none;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: var(--suite-run-transition);\n}\n\n.breadcrumb[_ngcontent-%COMP%] a[_ngcontent-%COMP%]:hover {\n color: #2563eb;\n}\n\n.breadcrumb[_ngcontent-%COMP%] .separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: #cbd5e1;\n}\n\n.breadcrumb[_ngcontent-%COMP%] .current[_ngcontent-%COMP%] {\n color: var(--suite-run-text);\n font-weight: 500;\n}\n\n\n\n.header-content[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 16px;\n margin-bottom: 24px;\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n align-items: flex-start;\n}\n\n.suite-run-icon[_ngcontent-%COMP%] {\n width: 56px;\n height: 56px;\n border-radius: var(--suite-run-radius);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 24px;\n flex-shrink: 0;\n box-shadow: var(--suite-run-shadow);\n}\n\n.suite-run-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 24px;\n font-weight: 700;\n color: var(--suite-run-text);\n letter-spacing: -0.025em;\n}\n\n.suite-run-meta[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n.status-badge.status-completed[_ngcontent-%COMP%] {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.status-badge.status-failed[_ngcontent-%COMP%] {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.status-badge.status-running[_ngcontent-%COMP%] {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.status-badge.status-pending[_ngcontent-%COMP%] {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.status-badge.status-cancelled[_ngcontent-%COMP%] {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\n}\n\n.meta-tag[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: var(--suite-run-neutral-light);\n border-radius: 6px;\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n.meta-tag[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n\n\n\n\n.metrics-bar[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n}\n\n.metric-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border: 1px solid var(--suite-run-border);\n border-radius: 10px;\n padding: 14px;\n transition: var(--suite-run-transition);\n}\n\n.metric-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--suite-run-shadow);\n}\n\n.metric-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--suite-run-card);\n border-radius: 10px;\n color: var(--suite-run-primary);\n font-size: 16px;\n box-shadow: var(--suite-run-shadow);\n}\n\n.metric-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.metric-value[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--suite-run-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.metric-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n margin-top: 2px;\n}\n\n\n\n\n\n.results-summary[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n padding-top: 20px;\n border-top: 1px solid var(--suite-run-border);\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.result-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: 10px;\n flex-shrink: 0;\n transition: var(--suite-run-transition);\n}\n\n.result-item[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--suite-run-shadow);\n}\n\n.result-icon[_ngcontent-%COMP%] {\n font-size: 24px;\n}\n\n.result-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n.result-count[_ngcontent-%COMP%] {\n font-size: 20px;\n font-weight: 700;\n line-height: 1.2;\n}\n\n.result-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.result-item.passed[_ngcontent-%COMP%] .result-icon[_ngcontent-%COMP%], \n.result-item.passed[_ngcontent-%COMP%] .result-count[_ngcontent-%COMP%] {\n color: var(--suite-run-success);\n}\n\n.result-item.failed[_ngcontent-%COMP%] .result-icon[_ngcontent-%COMP%], \n.result-item.failed[_ngcontent-%COMP%] .result-count[_ngcontent-%COMP%] {\n color: var(--suite-run-danger);\n}\n\n.result-item.error[_ngcontent-%COMP%] .result-icon[_ngcontent-%COMP%], \n.result-item.error[_ngcontent-%COMP%] .result-count[_ngcontent-%COMP%] {\n color: var(--suite-run-warning);\n}\n\n.result-item.skipped[_ngcontent-%COMP%] .result-icon[_ngcontent-%COMP%], \n.result-item.skipped[_ngcontent-%COMP%] .result-count[_ngcontent-%COMP%] {\n color: var(--suite-run-neutral);\n}\n\n.result-item.total[_ngcontent-%COMP%] .result-icon[_ngcontent-%COMP%], \n.result-item.total[_ngcontent-%COMP%] .result-count[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n\n\n\n\n.tabs-container[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border-bottom: 1px solid var(--suite-run-border);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.tabs[_ngcontent-%COMP%] {\n display: flex;\n padding: 0 24px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: 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: 16px 20px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: var(--suite-run-text-secondary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--suite-run-transition);\n white-space: nowrap;\n position: relative;\n}\n\n.tab[_ngcontent-%COMP%]:hover {\n color: var(--suite-run-primary);\n background: var(--suite-run-primary-light);\n}\n\n.tab.active[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n border-bottom-color: var(--suite-run-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(--suite-run-border);\n color: var(--suite-run-text-secondary);\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.tab.active[_ngcontent-%COMP%] .tab-badge[_ngcontent-%COMP%] {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.tab-shortcut[_ngcontent-%COMP%] {\n display: none;\n width: 18px;\n height: 18px;\n background: var(--suite-run-neutral-light);\n border-radius: 4px;\n font-size: 10px;\n font-weight: 600;\n color: var(--suite-run-text-secondary);\n align-items: center;\n justify-content: center;\n margin-left: 4px;\n}\n\n\n\n\n\n.tab-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n}\n\n\n\n\n\n.overview-tab[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 20px;\n max-width: 800px;\n margin: 0 auto;\n width: 100%;\n}\n\n.result-hero[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n padding: 48px 32px;\n text-align: center;\n border: 2px solid var(--suite-run-border);\n transition: var(--suite-run-transition);\n}\n\n.result-hero.passed[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);\n border-color: var(--suite-run-success);\n}\n\n.result-hero.failed[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #fef2f2 0%, #fecaca 100%);\n border-color: var(--suite-run-danger);\n}\n\n.result-hero.running[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n border-color: var(--suite-run-primary);\n}\n\n.result-hero.pending[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f5f3ff 0%, #ede9fe 100%);\n border-color: var(--suite-run-info);\n}\n\n.result-hero-icon[_ngcontent-%COMP%] {\n font-size: 72px;\n margin-bottom: 20px;\n}\n\n.result-hero.passed[_ngcontent-%COMP%] .result-hero-icon[_ngcontent-%COMP%] {\n color: var(--suite-run-success);\n}\n\n.result-hero.failed[_ngcontent-%COMP%] .result-hero-icon[_ngcontent-%COMP%] {\n color: var(--suite-run-danger);\n}\n\n.result-hero.running[_ngcontent-%COMP%] .result-hero-icon[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.result-hero.pending[_ngcontent-%COMP%] .result-hero-icon[_ngcontent-%COMP%] {\n color: var(--suite-run-info);\n}\n\n.result-hero-text[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 32px;\n font-weight: 800;\n color: var(--suite-run-text);\n letter-spacing: -0.025em;\n}\n\n.result-hero-stats[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 32px;\n}\n\n.stat-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.stat-value[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: var(--suite-run-text);\n}\n\n.stat-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.stat-divider[_ngcontent-%COMP%] {\n width: 1px;\n height: 40px;\n background: var(--suite-run-border);\n}\n\n\n\n.progress-section[_ngcontent-%COMP%] {\n background: var(--suite-run-primary-light);\n border: 1px solid rgba(59, 130, 246, 0.2);\n border-radius: var(--suite-run-radius);\n padding: 20px;\n text-align: center;\n}\n\n.progress-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n font-size: 16px;\n font-weight: 500;\n color: var(--suite-run-primary);\n margin-bottom: 8px;\n}\n\n.progress-info[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 20px;\n}\n\n.auto-refresh-notice[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n\n\n\n\n.runs-tab[_ngcontent-%COMP%] {\n max-width: 900px;\n margin: 0 auto;\n width: 100%;\n}\n\n\n\n.loading-state[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\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: 12px;\n padding: 16px;\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n border: 1px solid var(--suite-run-border);\n}\n\n.skeleton-sequence[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);\n background-size: 200% 100%;\n animation: _ngcontent-%COMP%_shimmer 1.5s infinite;\n border-radius: 50%;\n}\n\n.skeleton-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);\n background-size: 200% 100%;\n animation: _ngcontent-%COMP%_shimmer 1.5s infinite;\n border-radius: 8px;\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 background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);\n background-size: 200% 100%;\n animation: _ngcontent-%COMP%_shimmer 1.5s infinite;\n border-radius: 4px;\n}\n\n.skeleton-line.wide[_ngcontent-%COMP%] {\n width: 70%;\n}\n\n.skeleton-line.narrow[_ngcontent-%COMP%] {\n width: 40%;\n}\n\n@keyframes _ngcontent-%COMP%_shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n\n\n.test-runs-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.test-run-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.test-run-item[_ngcontent-%COMP%]:hover {\n background: var(--suite-run-primary-light);\n border-color: #93c5fd;\n transform: translateX(4px);\n}\n\n.test-run-item[_ngcontent-%COMP%]:active {\n transform: translateX(2px);\n}\n\n.run-sequence[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--suite-run-neutral-light);\n border-radius: 50%;\n font-size: 13px;\n font-weight: 700;\n color: var(--suite-run-text-secondary);\n flex-shrink: 0;\n}\n\n.run-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n color: white;\n font-size: 16px;\n flex-shrink: 0;\n box-shadow: var(--suite-run-shadow);\n}\n\n.run-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.run-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--suite-run-text);\n margin-bottom: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.run-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n flex-wrap: wrap;\n}\n\n.run-status[_ngcontent-%COMP%] {\n font-weight: 700;\n}\n\n.run-score[_ngcontent-%COMP%], \n.run-duration[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-score[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.run-duration[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.test-run-item[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n color: #cbd5e1;\n font-size: 14px;\n transition: var(--suite-run-transition);\n}\n\n.test-run-item[_ngcontent-%COMP%]:hover > i[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n transform: translateX(4px);\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 20px;\n text-align: center;\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n border: 2px dashed var(--suite-run-border);\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(--suite-run-neutral-light);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: #cbd5e1;\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(--suite-run-text);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--suite-run-text-secondary);\n max-width: 300px;\n}\n\n\n\n\n\n.details-tab[_ngcontent-%COMP%] {\n max-width: 900px;\n margin: 0 auto;\n width: 100%;\n}\n\n.details-card[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n padding: 24px;\n box-shadow: var(--suite-run-shadow);\n}\n\n.details-card[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--suite-run-text);\n padding-bottom: 12px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.details-card[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.details-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 20px;\n}\n\n.detail-item[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.detail-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n}\n\n.detail-value[_ngcontent-%COMP%] {\n font-size: 14px;\n color: var(--suite-run-text);\n word-wrap: break-word;\n}\n\n.detail-value.monospace[_ngcontent-%COMP%] {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n font-size: 12px;\n background: var(--suite-run-neutral-light);\n padding: 6px 10px;\n border-radius: 6px;\n}\n\n.detail-value[_ngcontent-%COMP%] a[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n text-decoration: none;\n font-weight: 500;\n transition: var(--suite-run-transition);\n}\n\n.detail-value[_ngcontent-%COMP%] a[_ngcontent-%COMP%]:hover {\n color: #2563eb;\n text-decoration: underline;\n}\n\n.status-inline[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.status-inline.status-completed[_ngcontent-%COMP%] {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.status-inline.status-failed[_ngcontent-%COMP%] {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.status-inline.status-running[_ngcontent-%COMP%] {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.status-inline.status-pending[_ngcontent-%COMP%] {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.status-inline.status-cancelled[_ngcontent-%COMP%] {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\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(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n box-shadow: var(--suite-run-shadow);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--suite-run-text-secondary);\n font-size: 14px;\n z-index: 99;\n transition: var(--suite-run-transition);\n opacity: 0.7;\n}\n\n.shortcuts-toggle[_ngcontent-%COMP%]:hover {\n opacity: 1;\n transform: scale(1.1);\n color: var(--suite-run-primary);\n border-color: var(--suite-run-primary);\n}\n\n.keyboard-shortcuts[_ngcontent-%COMP%] {\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n padding: 12px 16px;\n box-shadow: var(--suite-run-shadow-lg);\n font-size: 12px;\n z-index: 100;\n opacity: 0.9;\n transition: var(--suite-run-transition);\n}\n\n.keyboard-shortcuts[_ngcontent-%COMP%]:hover {\n opacity: 1;\n}\n\n.shortcuts-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n color: var(--suite-run-text);\n margin-bottom: 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.shortcuts-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.shortcuts-close[_ngcontent-%COMP%] {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--suite-run-text-muted);\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 4px;\n transition: var(--suite-run-transition);\n}\n\n.shortcuts-close[_ngcontent-%COMP%]:hover {\n color: var(--suite-run-text);\n background: var(--suite-run-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 gap: 16px;\n}\n\n.shortcut-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%]:first-child {\n color: var(--suite-run-text-secondary);\n}\n\n.shortcut-keys[_ngcontent-%COMP%] {\n display: flex;\n gap: 4px;\n}\n\nkbd[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 6px;\n background: linear-gradient(180deg, #f8fafc 0%, #e2e8f0 100%);\n border: 1px solid #cbd5e1;\n border-radius: 4px;\n font-family: inherit;\n font-size: 10px;\n font-weight: 600;\n color: var(--suite-run-text);\n box-shadow: 0 1px 0 #94a3b8;\n}\n\n\n\n\n\n@media (max-width: 1024px) {\n .suite-run-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .result-hero-stats[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n }\n\n .stat-divider[_ngcontent-%COMP%] {\n display: none;\n }\n\n .details-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .tab-shortcut[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n@media (max-width: 768px) {\n .suite-run-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 .suite-run-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .suite-run-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 20px;\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: 8px;\n }\n\n .metric-card[_ngcontent-%COMP%] {\n padding: 12px;\n flex-direction: column;\n text-align: center;\n gap: 8px;\n }\n\n .metric-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n }\n\n .metric-value[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .results-summary[_ngcontent-%COMP%] {\n gap: 8px;\n padding-top: 16px;\n flex-wrap: nowrap;\n overflow-x: auto;\n padding-bottom: 8px;\n margin-bottom: -8px;\n }\n\n .result-item[_ngcontent-%COMP%] {\n padding: 10px 12px;\n min-width: 90px;\n }\n\n .result-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n\n .result-count[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 16px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 14px 16px;\n font-size: 13px;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .result-hero[_ngcontent-%COMP%] {\n padding: 32px 20px;\n }\n\n .result-hero-icon[_ngcontent-%COMP%] {\n font-size: 56px;\n }\n\n .result-hero-text[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n font-size: 24px;\n }\n\n .stat-value[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n\n .test-run-item[_ngcontent-%COMP%] {\n padding: 14px;\n }\n\n .run-sequence[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n font-size: 12px;\n }\n\n .run-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n font-size: 14px;\n }\n\n .run-name[_ngcontent-%COMP%] {\n font-size: 13px;\n }\n\n .run-meta[_ngcontent-%COMP%] {\n gap: 10px;\n font-size: 11px;\n }\n\n .empty-state[_ngcontent-%COMP%] {\n padding: 40px 16px;\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 .details-card[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .details-grid[_ngcontent-%COMP%] {\n gap: 16px;\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: 480px) {\n .suite-run-header[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .breadcrumb[_ngcontent-%COMP%] {\n font-size: 12px;\n margin-bottom: 12px;\n }\n\n .suite-run-icon[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n font-size: 18px;\n }\n\n .suite-run-info[_ngcontent-%COMP%] h1[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .suite-run-meta[_ngcontent-%COMP%] {\n gap: 8px;\n }\n\n .status-badge[_ngcontent-%COMP%] {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .meta-tag[_ngcontent-%COMP%] {\n font-size: 11px;\n padding: 3px 8px;\n }\n\n .metrics-bar[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n\n .metric-card[_ngcontent-%COMP%] {\n padding: 10px;\n gap: 6px;\n }\n\n .metric-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n font-size: 14px;\n }\n\n .metric-value[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n\n .metric-label[_ngcontent-%COMP%] {\n font-size: 9px;\n }\n\n .result-item[_ngcontent-%COMP%] {\n padding: 8px 10px;\n min-width: 80px;\n gap: 8px;\n }\n\n .result-icon[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .result-count[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .result-label[_ngcontent-%COMP%] {\n font-size: 9px;\n }\n\n .tabs[_ngcontent-%COMP%] {\n padding: 0 12px;\n }\n\n .tab[_ngcontent-%COMP%] {\n padding: 12px 14px;\n gap: 6px;\n }\n\n .tab[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .result-hero[_ngcontent-%COMP%] {\n padding: 24px 16px;\n }\n\n .result-hero-icon[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n }\n\n .result-hero-text[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n font-size: 20px;\n margin-bottom: 12px;\n }\n\n .stat-value[_ngcontent-%COMP%] {\n font-size: 18px;\n }\n\n .stat-label[_ngcontent-%COMP%] {\n font-size: 10px;\n }\n\n .progress-section[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .progress-info[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n\n .test-run-item[_ngcontent-%COMP%] {\n padding: 12px;\n gap: 10px;\n }\n\n .run-sequence[_ngcontent-%COMP%] {\n width: 24px;\n height: 24px;\n font-size: 11px;\n }\n\n .run-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n font-size: 12px;\n border-radius: 8px;\n }\n\n .run-name[_ngcontent-%COMP%] {\n font-size: 12px;\n margin-bottom: 3px;\n }\n\n .run-meta[_ngcontent-%COMP%] {\n gap: 8px;\n font-size: 10px;\n }\n\n .empty-state[_ngcontent-%COMP%] {\n padding: 32px 12px;\n }\n\n .empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n font-size: 16px;\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 13px;\n }\n\n .details-card[_ngcontent-%COMP%] {\n padding: 14px;\n }\n\n .details-card[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n margin-bottom: 16px;\n }\n\n .detail-label[_ngcontent-%COMP%] {\n font-size: 10px;\n }\n\n .detail-value[_ngcontent-%COMP%] {\n font-size: 13px;\n }\n}\n\n\n\n\n\n@media (hover: none) and (pointer: coarse) {\n .test-run-item[_ngcontent-%COMP%] {\n min-height: 64px;\n }\n\n .test-run-item[_ngcontent-%COMP%]:hover {\n transform: none;\n background: var(--suite-run-card);\n border-color: var(--suite-run-border);\n }\n\n .test-run-item[_ngcontent-%COMP%]:active {\n background: var(--suite-run-primary-light);\n border-color: #93c5fd;\n }\n\n .tab[_ngcontent-%COMP%]:hover {\n background: transparent;\n color: var(--suite-run-text-secondary);\n }\n\n .tab[_ngcontent-%COMP%]:active {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n }\n\n .metric-card[_ngcontent-%COMP%]:hover {\n transform: none;\n box-shadow: none;\n }\n\n .result-item[_ngcontent-%COMP%]:hover {\n transform: none;\n box-shadow: none;\n }\n\n .keyboard-shortcuts[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n@media print {\n .suite-run-header[_ngcontent-%COMP%] {\n background: white;\n box-shadow: none;\n border-bottom: 2px solid #000;\n }\n\n .tabs-container[_ngcontent-%COMP%], \n .header-actions[_ngcontent-%COMP%], \n .keyboard-shortcuts[_ngcontent-%COMP%] {\n display: none;\n }\n\n .tab-content[_ngcontent-%COMP%] {\n padding: 20px 0;\n }\n\n .result-hero[_ngcontent-%COMP%], \n .test-run-item[_ngcontent-%COMP%], \n .details-card[_ngcontent-%COMP%] {\n box-shadow: none;\n border: 1px solid #ccc;\n }\n}\n\n\n\n\n\n@media (prefers-color-scheme: dark) {\n \n\n}\n\n\n\n\n\n.tags-bar[_ngcontent-%COMP%] {\n margin-top: 16px;\n padding: 8px 14px;\n background: linear-gradient(135deg, rgba(59, 130, 246, 0.04) 0%, rgba(59, 130, 246, 0.08) 100%);\n border: 1px solid rgba(59, 130, 246, 0.15);\n border-radius: 8px;\n max-width: 600px;\n}\n\n.tags-bar-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.tags-bar-label[_ngcontent-%COMP%] {\n color: var(--suite-run-text-secondary);\n font-size: 14px;\n}\n\n.tags-bar-label[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n opacity: 0.6;\n}\n\n.tags-bar-chips[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n flex: 1;\n}\n\n.tag-inline[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.01em;\n}\n\n.tags-bar-empty[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n opacity: 0.7;\n flex: 1;\n}\n\n.tags-bar-edit[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: transparent;\n border: 1px dashed var(--suite-run-border);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.tags-bar-edit[_ngcontent-%COMP%]:hover {\n border-color: var(--suite-run-primary);\n color: var(--suite-run-primary);\n background: var(--suite-run-primary-light);\n}\n\n.tags-bar-edit[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n\n\n\n\n.tags-editor-panel[_ngcontent-%COMP%] {\n margin-top: 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-primary);\n border-radius: 10px;\n overflow: hidden;\n box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1);\n max-width: 600px;\n}\n\n.tags-editor-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n background: var(--suite-run-primary-light);\n border-bottom: 1px solid rgba(59, 130, 246, 0.2);\n}\n\n.tags-editor-title[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--suite-run-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.tags-editor-body[_ngcontent-%COMP%] {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.tags-editor-chips[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n min-height: 32px;\n}\n\n.tag-editable[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 8px 5px 12px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-primary);\n color: var(--suite-run-primary);\n border-radius: 14px;\n font-size: 12px;\n font-weight: 500;\n}\n\n.tag-remove-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n background: transparent;\n border: none;\n color: var(--suite-run-primary);\n cursor: pointer;\n border-radius: 50%;\n font-size: 9px;\n opacity: 0.6;\n transition: var(--suite-run-transition);\n}\n\n.tag-remove-btn[_ngcontent-%COMP%]:hover {\n opacity: 1;\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.tags-empty-hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n font-style: italic;\n padding: 4px 0;\n}\n\n.tags-editor-input[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.tag-text-input[_ngcontent-%COMP%] {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n font-size: 13px;\n background: var(--suite-run-neutral-light);\n}\n\n.tag-text-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--suite-run-primary);\n background: var(--suite-run-card);\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.tag-text-input[_ngcontent-%COMP%]::placeholder {\n color: var(--suite-run-text-secondary);\n opacity: 0.6;\n}\n\n.tags-editor-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-start;\n gap: 8px;\n padding: 12px 16px;\n background: var(--suite-run-neutral-light);\n border-top: 1px solid var(--suite-run-border);\n}\n\n\n\n\n\n.runs-toolbar[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n padding: 12px 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n flex-wrap: wrap;\n gap: 12px;\n}\n\n.run-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\n padding: 6px 14px;\n border: 1px solid var(--suite-run-border);\n background: var(--suite-run-card);\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n cursor: pointer;\n transition: var(--suite-run-transition);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--suite-run-primary);\n color: var(--suite-run-primary);\n}\n\n.filter-btn.active[_ngcontent-%COMP%] {\n background: var(--suite-run-primary);\n border-color: var(--suite-run-primary);\n color: white;\n}\n\n.filter-btn.passed[_ngcontent-%COMP%]:hover, \n.filter-btn.passed.active[_ngcontent-%COMP%] {\n background: var(--suite-run-success);\n border-color: var(--suite-run-success);\n color: white;\n}\n\n.filter-btn.failed[_ngcontent-%COMP%]:hover, \n.filter-btn.failed.active[_ngcontent-%COMP%] {\n background: var(--suite-run-danger);\n border-color: var(--suite-run-danger);\n color: white;\n}\n\n.filter-btn.error[_ngcontent-%COMP%]:hover, \n.filter-btn.error.active[_ngcontent-%COMP%] {\n background: var(--suite-run-warning);\n border-color: var(--suite-run-warning);\n color: white;\n}\n\n.runs-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n\n\n\n\n.test-run-card[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n overflow: hidden;\n transition: var(--suite-run-transition);\n margin-bottom: 10px;\n}\n\n.test-run-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--suite-run-shadow);\n}\n\n.test-run-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.test-run-item[_ngcontent-%COMP%]:hover {\n background: var(--suite-run-primary-light);\n}\n\n.run-header-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-feedback-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.run-feedback-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n}\n\n.run-tags[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-top: 6px;\n}\n\n.tag-mini[_ngcontent-%COMP%] {\n display: inline-flex;\n padding: 2px 8px;\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-text-secondary);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 500;\n}\n\n.tag-chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 3px 10px;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n border: 1px solid #bfdbfe;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: #1d4ed8;\n}\n\n.run-expand[_ngcontent-%COMP%] {\n color: var(--suite-run-text-secondary);\n transition: var(--suite-run-transition);\n}\n\n.test-run-item[_ngcontent-%COMP%]:hover .run-expand[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.run-cost[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-cost[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 10px;\n opacity: 0.7;\n}\n\n\n\n\n\n.inline-feedback[_ngcontent-%COMP%] {\n padding: 0 16px 16px;\n animation: _ngcontent-%COMP%_slideDown 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.feedback-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--suite-run-border);\n margin-bottom: 16px;\n}\n\n.feedback-section[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.feedback-label[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.inline-rating[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.rating-numbers[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.rating-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border: 2px solid var(--suite-run-border);\n border-radius: 8px;\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-text-secondary);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.rating-btn[_ngcontent-%COMP%]:hover, \n.rating-btn.hover[_ngcontent-%COMP%] {\n transform: scale(1.1);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n}\n\n.rating-btn.low[_ngcontent-%COMP%]:hover, \n.rating-btn.low.hover[_ngcontent-%COMP%] {\n border-color: var(--suite-run-danger);\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.rating-btn.mid[_ngcontent-%COMP%]:hover, \n.rating-btn.mid.hover[_ngcontent-%COMP%] {\n border-color: var(--suite-run-warning);\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.rating-btn.high[_ngcontent-%COMP%]:hover, \n.rating-btn.high.hover[_ngcontent-%COMP%] {\n border-color: var(--suite-run-success);\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.rating-btn.selected[_ngcontent-%COMP%] {\n transform: scale(1.1);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n}\n\n.rating-btn.selected.low[_ngcontent-%COMP%] {\n border-color: var(--suite-run-danger);\n background: var(--suite-run-danger);\n color: white;\n}\n\n.rating-btn.selected.mid[_ngcontent-%COMP%] {\n border-color: var(--suite-run-warning);\n background: var(--suite-run-warning);\n color: white;\n}\n\n.rating-btn.selected.high[_ngcontent-%COMP%] {\n border-color: var(--suite-run-success);\n background: var(--suite-run-success);\n color: white;\n}\n\n.rating-info[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 14px;\n background: var(--suite-run-neutral-light);\n border-radius: 8px;\n}\n\n.rating-value[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: var(--suite-run-text);\n}\n\n.rating-label-text[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--suite-run-text-secondary);\n}\n\n.correctness-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.correctness-label[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--suite-run-text);\n}\n\n.correctness-options[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n}\n\n.radio-opt[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--suite-run-text-secondary);\n}\n\n.radio-opt[_ngcontent-%COMP%] input[type=\"radio\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n\n.comments-row[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n.feedback-textarea[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n}\n\n.feedback-textarea[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--suite-run-primary);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n\n.feedback-actions[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n padding-top: 8px;\n}\n\n\n\n\n\n@media (max-width: 768px) {\n .tags-bar[_ngcontent-%COMP%] {\n padding: 8px 12px;\n }\n\n .tags-bar-content[_ngcontent-%COMP%] {\n gap: 8px;\n }\n\n .tag-inline[_ngcontent-%COMP%] {\n padding: 3px 8px;\n font-size: 10px;\n }\n\n .tags-editor-panel[_ngcontent-%COMP%] {\n margin-top: 12px;\n }\n\n .tags-editor-body[_ngcontent-%COMP%] {\n padding: 12px;\n }\n\n .tags-editor-footer[_ngcontent-%COMP%] {\n padding: 10px 12px;\n }\n\n .runs-toolbar[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n }\n\n .run-filters[_ngcontent-%COMP%] {\n justify-content: center;\n }\n\n .runs-actions[_ngcontent-%COMP%] {\n justify-content: center;\n }\n\n .rating-numbers[_ngcontent-%COMP%] {\n justify-content: center;\n }\n\n .rating-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n font-size: 12px;\n }\n\n .correctness-row[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n }\n\n .feedback-actions[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .feedback-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] {\n width: 100%;\n }\n}\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n\n.result-hero.running[_ngcontent-%COMP%] .result-hero-icon[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_pulse 2s ease-in-out infinite;\n}\n\n\n\n.overview-tab[_ngcontent-%COMP%], \n.runs-tab[_ngcontent-%COMP%], \n.details-tab[_ngcontent-%COMP%], \n.analytics-tab[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_fadeIn 0.3s ease;\n}\n\n\n\n\n\n.analytics-tab[_ngcontent-%COMP%] {\n max-width: 1200px;\n margin: 0 auto;\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n.analytics-section[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n padding: 24px;\n box-shadow: var(--suite-run-shadow);\n}\n\n.analytics-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--suite-run-text);\n padding-bottom: 12px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.analytics-section[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.analytics-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n margin-bottom: 20px;\n padding-bottom: 12px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.analytics-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n padding: 0;\n border: none;\n}\n\n.analytics-legend[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.legend-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 500;\n}\n\n.legend-item.passed[_ngcontent-%COMP%] {\n color: var(--suite-run-success);\n}\n\n.legend-item.failed[_ngcontent-%COMP%] {\n color: var(--suite-run-danger);\n}\n\n.legend-item.error[_ngcontent-%COMP%] {\n color: var(--suite-run-warning);\n}\n\n.legend-item.skipped[_ngcontent-%COMP%] {\n color: var(--suite-run-neutral);\n}\n\n\n\n.performance-matrix[_ngcontent-%COMP%] {\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.matrix-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 120px 150px 100px 100px;\n border-bottom: 1px solid var(--suite-run-border);\n transition: var(--suite-run-transition);\n cursor: pointer;\n}\n\n.matrix-row[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.matrix-row[_ngcontent-%COMP%]:hover:not(.matrix-header-row) {\n background: var(--suite-run-primary-light);\n}\n\n.matrix-row.passed[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-success);\n}\n\n.matrix-row.failed[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-danger);\n}\n\n.matrix-row.error[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-warning);\n}\n\n.matrix-row.skipped[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-neutral);\n}\n\n.matrix-header-row[_ngcontent-%COMP%] {\n background: var(--suite-run-neutral-light);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n cursor: default;\n}\n\n.matrix-cell[_ngcontent-%COMP%] {\n padding: 12px 16px;\n display: flex;\n align-items: center;\n}\n\n.test-name-cell[_ngcontent-%COMP%] {\n gap: 12px;\n}\n\n.test-sequence[_ngcontent-%COMP%] {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--suite-run-neutral-light);\n border-radius: 50%;\n font-size: 11px;\n font-weight: 600;\n color: var(--suite-run-text-secondary);\n flex-shrink: 0;\n}\n\n.test-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--suite-run-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.status-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.status-indicator.status-passed[_ngcontent-%COMP%] {\n color: var(--suite-run-success);\n}\n\n.status-indicator.status-failed[_ngcontent-%COMP%] {\n color: var(--suite-run-danger);\n}\n\n.status-indicator.status-error[_ngcontent-%COMP%] {\n color: var(--suite-run-warning);\n}\n\n.status-indicator.status-skipped[_ngcontent-%COMP%] {\n color: var(--suite-run-neutral);\n}\n\n.status-indicator.status-pending[_ngcontent-%COMP%] {\n color: var(--suite-run-info);\n}\n\n.status-indicator.status-running[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.score-bar[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n height: 20px;\n background: var(--suite-run-neutral-light);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.score-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 10px;\n transition: width 0.3s ease;\n}\n\n.score-fill.high[_ngcontent-%COMP%] {\n background: linear-gradient(90deg, var(--suite-run-success) 0%, #34d399 100%);\n}\n\n.score-fill.medium[_ngcontent-%COMP%] {\n background: linear-gradient(90deg, var(--suite-run-warning) 0%, #fbbf24 100%);\n}\n\n.score-fill.low[_ngcontent-%COMP%] {\n background: linear-gradient(90deg, var(--suite-run-danger) 0%, #f87171 100%);\n}\n\n.score-text[_ngcontent-%COMP%] {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n font-size: 11px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.na-value[_ngcontent-%COMP%] {\n color: var(--suite-run-text-secondary);\n opacity: 0.6;\n}\n\n\n\n.stats-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 16px;\n}\n\n.stat-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 20px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border: 1px solid var(--suite-run-border);\n border-radius: 12px;\n transition: var(--suite-run-transition);\n}\n\n.stat-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: var(--suite-run-shadow);\n}\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 12px;\n font-size: 20px;\n}\n\n.stat-icon.passed[_ngcontent-%COMP%] {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.stat-icon.failed[_ngcontent-%COMP%] {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.stat-icon.score[_ngcontent-%COMP%] {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.stat-icon.duration[_ngcontent-%COMP%] {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.stat-icon.cost[_ngcontent-%COMP%] {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.stat-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.stat-card[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: var(--suite-run-text);\n}\n\n.stat-card[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.stat-percent[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n\n\n@media (max-width: 768px) {\n .analytics-header[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .matrix-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n gap: 8px;\n padding: 12px;\n }\n\n .matrix-header-row[_ngcontent-%COMP%] {\n display: none;\n }\n\n .matrix-cell[_ngcontent-%COMP%] {\n padding: 4px 0;\n }\n\n .test-name-cell[_ngcontent-%COMP%]::before, \n .status-cell[_ngcontent-%COMP%]::before, \n .score-cell[_ngcontent-%COMP%]::before, \n .duration-cell[_ngcontent-%COMP%]::before, \n .cost-cell[_ngcontent-%COMP%]::before {\n font-size: 10px;\n font-weight: 600;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n margin-right: 8px;\n min-width: 80px;\n }\n\n .status-cell[_ngcontent-%COMP%]::before { content: 'Status:'; }\n .score-cell[_ngcontent-%COMP%]::before { content: 'Score:'; }\n .duration-cell[_ngcontent-%COMP%]::before { content: 'Duration:'; }\n .cost-cell[_ngcontent-%COMP%]::before { content: 'Cost:'; }\n\n .stats-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n\n .stat-card[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .stat-icon[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .stat-card[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 20px;\n }\n}\n\n\n\n.tab[_ngcontent-%COMP%]:focus-visible, \n.test-run-item[_ngcontent-%COMP%]:focus-visible, \nbutton[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--suite-run-primary);\n outline-offset: 2px;\n}\n\n\n\n\n\n.analytics-loading[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 60px 20px;\n color: var(--suite-run-text-secondary);\n}\n\n.analytics-loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--suite-run-primary);\n}\n\n\n\n\n\n.results-table-wrapper[_ngcontent-%COMP%] {\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.results-table[_ngcontent-%COMP%] {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n}\n\n.results-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] {\n background: var(--suite-run-neutral-light);\n}\n\n.results-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n padding: 12px 16px;\n text-align: left;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.results-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 12px 16px;\n border-bottom: 1px solid #f1f5f9;\n vertical-align: middle;\n}\n\n.results-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:last-child td[_ngcontent-%COMP%] {\n border-bottom: none;\n}\n\n\n\n.seq-col[_ngcontent-%COMP%] {\n width: 40px;\n min-width: 40px;\n text-align: center;\n white-space: nowrap;\n}\n\n.name-col[_ngcontent-%COMP%] {\n \n\n width: auto;\n max-width: 50%;\n}\n\n.status-col[_ngcontent-%COMP%] {\n width: 1%; \n\n white-space: nowrap;\n}\n\n.score-col[_ngcontent-%COMP%] {\n width: 1%; \n\n min-width: 120px; \n\n white-space: nowrap;\n}\n\n.duration-col[_ngcontent-%COMP%] {\n width: 1%; \n\n white-space: nowrap;\n text-align: right;\n}\n\n.cost-col[_ngcontent-%COMP%] {\n width: 1%; \n\n white-space: nowrap;\n text-align: right;\n}\n\n\n\n.result-row[_ngcontent-%COMP%] {\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.result-row[_ngcontent-%COMP%]:hover {\n background: var(--suite-run-primary-light);\n}\n\n.result-row.row-passed[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-success);\n}\n\n.result-row.row-failed[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-danger);\n}\n\n.result-row.row-error[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-warning);\n}\n\n.result-row.row-skipped[_ngcontent-%COMP%] {\n border-left: 4px solid var(--suite-run-neutral);\n}\n\n\n\n.test-name-wrapper[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.test-name-wrapper[_ngcontent-%COMP%] .test-name[_ngcontent-%COMP%] {\n font-weight: 500;\n color: var(--suite-run-text);\n}\n\n.test-tags[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n\n\n.score-display[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.score-bar-mini[_ngcontent-%COMP%] {\n flex: 1;\n height: 6px;\n background: var(--suite-run-neutral-light);\n border-radius: 3px;\n overflow: hidden;\n min-width: 60px;\n}\n\n.score-bar-mini[_ngcontent-%COMP%] .score-fill[_ngcontent-%COMP%] {\n height: 100%;\n border-radius: 3px;\n transition: width 0.3s ease;\n}\n\n.score-bar-mini[_ngcontent-%COMP%] .score-fill.high[_ngcontent-%COMP%] {\n background: var(--suite-run-success);\n}\n\n.score-bar-mini[_ngcontent-%COMP%] .score-fill.medium[_ngcontent-%COMP%] {\n background: var(--suite-run-warning);\n}\n\n.score-bar-mini[_ngcontent-%COMP%] .score-fill.low[_ngcontent-%COMP%] {\n background: var(--suite-run-danger);\n}\n\n.score-display[_ngcontent-%COMP%] .score-text[_ngcontent-%COMP%] {\n position: static;\n transform: none;\n font-size: 12px;\n font-weight: 600;\n color: var(--suite-run-text);\n min-width: 35px;\n text-align: right;\n}\n\n\n\n.results-table[_ngcontent-%COMP%] .status-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.results-table[_ngcontent-%COMP%] .status-badge.status-passed[_ngcontent-%COMP%] {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.results-table[_ngcontent-%COMP%] .status-badge.status-failed[_ngcontent-%COMP%] {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.results-table[_ngcontent-%COMP%] .status-badge.status-error[_ngcontent-%COMP%] {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.results-table[_ngcontent-%COMP%] .status-badge.status-skipped[_ngcontent-%COMP%] {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\n}\n\n.results-table[_ngcontent-%COMP%] .status-badge.status-pending[_ngcontent-%COMP%] {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.results-table[_ngcontent-%COMP%] .status-badge.status-running[_ngcontent-%COMP%] {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n\n\n@media (max-width: 768px) {\n .results-table-wrapper[_ngcontent-%COMP%] {\n overflow-x: auto;\n }\n\n .results-table[_ngcontent-%COMP%] {\n min-width: 600px;\n }\n\n .results-table[_ngcontent-%COMP%] th[_ngcontent-%COMP%], \n .results-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n padding: 10px 12px;\n }\n\n .name-col[_ngcontent-%COMP%] {\n min-width: 150px;\n }\n}\n\n\n\n\n\n@media (prefers-contrast: high) {\n .status-badge[_ngcontent-%COMP%], \n .status-inline[_ngcontent-%COMP%] {\n border: 2px solid currentColor;\n }\n\n .test-run-item[_ngcontent-%COMP%] {\n border-width: 2px;\n }\n\n .tab.active[_ngcontent-%COMP%] {\n border-bottom-width: 4px;\n }\n}\n\n\n\n\n\n.evaluation-summary[_ngcontent-%COMP%] {\n margin-top: 20px;\n}\n\n.eval-summary-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 16px;\n}\n\n.eval-summary-card[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n overflow: hidden;\n transition: var(--suite-run-transition);\n}\n\n.eval-summary-card[_ngcontent-%COMP%]:hover {\n box-shadow: var(--suite-run-shadow);\n}\n\n.eval-card-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: var(--suite-run-neutral-light);\n border-bottom: 1px solid var(--suite-run-border);\n font-size: 13px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.eval-card-header[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.eval-card-body[_ngcontent-%COMP%] {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.eval-stat-row[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n}\n\n.eval-stat-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n.eval-stat-value[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.eval-stat-value.correct[_ngcontent-%COMP%] {\n color: var(--suite-run-success);\n}\n\n.eval-stat-value.incorrect[_ngcontent-%COMP%] {\n color: var(--suite-run-danger);\n font-weight: 500;\n font-size: 12px;\n}\n\n.eval-stat-value.error[_ngcontent-%COMP%] {\n color: var(--suite-run-danger);\n}\n\n.eval-stat-value.timeout[_ngcontent-%COMP%] {\n color: var(--suite-run-warning);\n}\n\n.eval-card-footer[_ngcontent-%COMP%] {\n padding: 10px 16px;\n background: var(--suite-run-warning-light);\n border-top: 1px solid rgba(245, 158, 11, 0.2);\n}\n\n.pending-badge[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-warning);\n}\n\n.pending-badge[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n\n\n\n.needs-review-section[_ngcontent-%COMP%] {\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n overflow: hidden;\n}\n\n.needs-review-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 14px 20px;\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n border-bottom: 1px solid rgba(245, 158, 11, 0.3);\n}\n\n.needs-review-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: #92400e;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.needs-review-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.review-count[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #92400e;\n background: rgba(255, 255, 255, 0.6);\n padding: 2px 10px;\n border-radius: 12px;\n}\n\n.needs-review-list[_ngcontent-%COMP%] {\n padding: 8px;\n}\n\n.review-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border-radius: 8px;\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.review-item[_ngcontent-%COMP%]:hover {\n background: var(--suite-run-primary-light);\n}\n\n.review-item-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.review-item.high-priority[_ngcontent-%COMP%] .review-item-icon[_ngcontent-%COMP%] {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.review-item.medium-priority[_ngcontent-%COMP%] .review-item-icon[_ngcontent-%COMP%] {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.review-item[_ngcontent-%COMP%]:not(.high-priority):not(.medium-priority) .review-item-icon[_ngcontent-%COMP%] {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\n}\n\n.review-item-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.review-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: var(--suite-run-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.review-item-reason[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--suite-run-text-secondary);\n}\n\n.review-item-action[_ngcontent-%COMP%] {\n color: var(--suite-run-text-secondary);\n font-size: 12px;\n}\n\n.review-item[_ngcontent-%COMP%]:hover .review-item-action[_ngcontent-%COMP%] {\n color: var(--suite-run-primary);\n}\n\n.review-more[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: 8px;\n border-top: 1px solid var(--suite-run-border);\n}\n\n\n\n@media (max-width: 768px) {\n .eval-summary-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .eval-card-header[_ngcontent-%COMP%] {\n padding: 10px 14px;\n font-size: 12px;\n }\n\n .eval-card-body[_ngcontent-%COMP%] {\n padding: 12px 14px;\n }\n\n .needs-review-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .needs-review-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 13px;\n }\n\n .review-item[_ngcontent-%COMP%] {\n padding: 10px 12px;\n }\n\n .review-item-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n font-size: 12px;\n }\n}\n\n\n\n\n\n.feedback-col[_ngcontent-%COMP%] {\n width: 1%; \n\n white-space: nowrap;\n text-align: center;\n}\n\n.feedback-display[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n}\n\n.feedback-rating[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--suite-run-neutral-light);\n}\n\n.feedback-rating.low[_ngcontent-%COMP%] {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.feedback-rating.mid[_ngcontent-%COMP%] {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.feedback-rating.high[_ngcontent-%COMP%] {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.feedback-correctness[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.feedback-correctness[_ngcontent-%COMP%] i.correct[_ngcontent-%COMP%] {\n color: var(--suite-run-success);\n}\n\n.feedback-correctness[_ngcontent-%COMP%] i.incorrect[_ngcontent-%COMP%] {\n color: var(--suite-run-danger);\n}\n\n.na-value.needs-review[_ngcontent-%COMP%] {\n color: var(--suite-run-warning);\n opacity: 0.7;\n}\n\n.na-value.needs-review[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}"], changeDetection: 0 }); }
|
|
557
2267
|
};
|
|
558
2268
|
TestSuiteRunFormComponentExtended = __decorate([
|
|
559
2269
|
RegisterClass(BaseFormComponent, 'MJ: Test Suite Runs')
|
|
@@ -561,9 +2271,12 @@ TestSuiteRunFormComponentExtended = __decorate([
|
|
|
561
2271
|
export { TestSuiteRunFormComponentExtended };
|
|
562
2272
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TestSuiteRunFormComponentExtended, [{
|
|
563
2273
|
type: Component,
|
|
564
|
-
args: [{ selector: 'mj-test-suite-run-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-suite-run-form\">\n <!-- Header Section -->\n <div class=\"suite-run-header\">\n <div class=\"breadcrumb\" *ngIf=\"testSuite\">\n <a href=\"javascript:void(0)\" (click)=\"openTestSuite()\">\n <i class=\"fas fa-folder\"></i> {{ testSuite.Name }}\n </a>\n <i class=\"fas fa-chevron-right\"></i>\n <span>Run #{{ record.ID.substring(0, 8) }}</span>\n </div>\n\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"suite-run-icon\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas fa-layer-group\"></i>\n </div>\n <div class=\"suite-run-info\">\n <h1>Test Suite Run</h1>\n <div class=\"suite-run-meta\">\n <span class=\"status-badge\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n <span class=\"environment\" *ngIf=\"record.Environment\">{{ record.Environment }}</span>\n <span class=\"trigger\" *ngIf=\"record.TriggerType\">{{ record.TriggerType }}</span>\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <button kendoButton (click)=\"refresh()\" icon=\"sync\">\n Refresh\n </button>\n </div>\n </div>\n\n <!-- Metrics Bar -->\n <div class=\"metrics-bar\">\n <div class=\"metric-card\">\n <div class=\"metric-label\">Started</div>\n <div class=\"metric-value\">{{ record.StartedAt | date:'short' }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Completed</div>\n <div class=\"metric-value\">{{ record.CompletedAt | date:'short' }}</div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Duration</div>\n <div class=\"metric-value\">{{ calculateDuration() }}</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>\n <div class=\"metric-card\">\n <div class=\"metric-label\">Cost</div>\n <div class=\"metric-value\">{{ formatCost(record.TotalCostUSD) }}</div>\n </div>\n </div>\n\n <!-- Test Results Summary -->\n <div class=\"results-summary\">\n <div class=\"result-item passed\">\n <i class=\"fas fa-check-circle\"></i>\n <span class=\"count\">{{ record.PassedTests || 0 }}</span>\n <span class=\"label\">Passed</span>\n </div>\n <div class=\"result-item failed\">\n <i class=\"fas fa-times-circle\"></i>\n <span class=\"count\">{{ record.FailedTests || 0 }}</span>\n <span class=\"label\">Failed</span>\n </div>\n <div class=\"result-item skipped\">\n <i class=\"fas fa-forward\"></i>\n <span class=\"count\">{{ record.SkippedTests || 0 }}</span>\n <span class=\"label\">Skipped</span>\n </div>\n <div class=\"result-item error\">\n <i class=\"fas fa-exclamation-circle\"></i>\n <span class=\"count\">{{ record.ErrorTests || 0 }}</span>\n <span class=\"label\">Errors</span>\n </div>\n <div class=\"result-item total\">\n <i class=\"fas fa-list\"></i>\n <span class=\"count\">{{ record.TotalTests || 0 }}</span>\n <span class=\"label\">Total</span>\n </div>\n </div>\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs-container\">\n <div class=\"tabs\">\n <button class=\"tab\" [class.active]=\"activeTab === 'overview'\" (click)=\"changeTab('overview')\">\n <i class=\"fas fa-th-large\"></i>\n <span>Overview</span>\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'runs'\" (click)=\"changeTab('runs')\">\n <i class=\"fas fa-list\"></i>\n <span>Test Runs</span>\n <span class=\"tab-badge\" *ngIf=\"testRunsLoaded\">{{ testRuns.length }}</span>\n </button>\n <button class=\"tab\" [class.active]=\"activeTab === 'details'\" (click)=\"changeTab('details')\">\n <i class=\"fas fa-info-circle\"></i>\n <span>Details</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\">\n <!-- Overview Tab -->\n <div class=\"overview-tab\" *ngIf=\"activeTab === 'overview'\">\n <!-- Result Hero -->\n <div class=\"result-hero\" [class.passed]=\"record.Status === 'Completed' && getPassRate() >= 90\" [class.failed]=\"record.Status === 'Failed'\">\n <div class=\"result-icon\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n </div>\n <div class=\"result-text\">\n <h2>SUITE {{ record.Status.toUpperCase() }}</h2>\n <div class=\"result-stats\">Pass Rate: {{ getPassRate().toFixed(1) }}%</div>\n <div class=\"result-counts\">{{ record.PassedTests }} of {{ record.TotalTests }} tests passed</div>\n </div>\n </div>\n </div>\n\n <!-- Test Runs Tab -->\n <div class=\"runs-tab\" *ngIf=\"activeTab === 'runs'\">\n <div class=\"test-runs-list\" *ngIf=\"testRuns.length > 0\">\n <div class=\"test-run-item\" *ngFor=\"let run of testRuns\" (click)=\"openTestRun(run.ID)\">\n <div class=\"run-sequence\">{{ run.Sequence }}</div>\n <div class=\"run-icon\" [style.background-color]=\"run.Status === 'Passed' ? '#4caf50' : run.Status === 'Failed' ? '#f44336' : '#ff9800'\">\n <i class=\"fas\" [class.fa-check]=\"run.Status === 'Passed'\" [class.fa-times]=\"run.Status === 'Failed'\" [class.fa-exclamation]=\"run.Status === 'Error'\"></i>\n </div>\n <div class=\"run-content\">\n <div class=\"run-name\">{{ run.Test }}</div>\n <div class=\"run-meta\">\n <span class=\"status\" [style.color]=\"run.Status === 'Passed' ? '#4caf50' : run.Status === 'Failed' ? '#f44336' : '#ff9800'\">{{ run.Status }}</span>\n <span *ngIf=\"run.Score != null\">Score: {{ run.Score.toFixed(4) }}</span>\n <span *ngIf=\"run.DurationSeconds\">{{ run.DurationSeconds.toFixed(1) }}s</span>\n </div>\n </div>\n <i class=\"fas fa-chevron-right\"></i>\n </div>\n </div>\n\n <div class=\"no-data\" *ngIf=\"testRunsLoaded && testRuns.length === 0\">\n <i class=\"fas fa-inbox\"></i>\n <p>No test runs found for this suite execution</p>\n </div>\n </div>\n\n <!-- Details Tab -->\n <div class=\"details-tab\" *ngIf=\"activeTab === 'details'\">\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <div class=\"detail-label\">Run ID</div>\n <div class=\"detail-value\">{{ record.ID }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Test Suite</div>\n <div class=\"detail-value\">\n <a href=\"javascript:void(0)\" (click)=\"openTestSuite()\" *ngIf=\"testSuite\">{{ testSuite.Name }}</a>\n </div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Status</div>\n <div class=\"detail-value\">{{ record.Status }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Run By</div>\n <div class=\"detail-value\">{{ record.RunByUser }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Environment</div>\n <div class=\"detail-value\">{{ record.Environment || 'N/A' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Trigger Type</div>\n <div class=\"detail-value\">{{ record.TriggerType || 'N/A' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Git Commit</div>\n <div class=\"detail-value\">{{ record.GitCommit || 'N/A' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Agent Version</div>\n <div class=\"detail-value\">{{ record.AgentVersion || 'N/A' }}</div>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".test-suite-run-form {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8f9fa;\n}\n\n/* Header */\n.suite-run-header {\n background: white;\n border-bottom: 1px solid #e0e0e0;\n padding: 20px;\n}\n\n.breadcrumb {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #666;\n margin-bottom: 16px;\n}\n\n.breadcrumb a {\n color: #2196f3;\n text-decoration: none;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.breadcrumb a:hover {\n text-decoration: underline;\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 20px;\n}\n\n.header-left {\n display: flex;\n gap: 16px;\n}\n\n.suite-run-icon {\n width: 56px;\n height: 56px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 24px;\n}\n\n.suite-run-info h1 {\n margin: 0 0 8px 0;\n font-size: 24px;\n font-weight: 600;\n color: #333;\n}\n\n.suite-run-meta {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 12px;\n color: white;\n font-size: 12px;\n font-weight: 600;\n}\n\n.environment,\n.trigger {\n font-size: 13px;\n color: #666;\n padding: 4px 8px;\n background: #f0f0f0;\n border-radius: 6px;\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n.metrics-bar {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n gap: 16px;\n margin-bottom: 16px;\n}\n\n.metric-card {\n background: #f5f7fa;\n border-radius: 8px;\n padding: 12px;\n text-align: center;\n}\n\n.metric-label {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #999;\n margin-bottom: 4px;\n}\n\n.metric-value {\n font-size: 16px;\n font-weight: 600;\n color: #333;\n}\n\n.results-summary {\n display: flex;\n gap: 16px;\n padding-top: 16px;\n border-top: 1px solid #e0e0e0;\n}\n\n.result-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: 8px;\n background: #f8f9fa;\n}\n\n.result-item i {\n font-size: 20px;\n}\n\n.result-item .count {\n font-size: 20px;\n font-weight: 700;\n}\n\n.result-item .label {\n font-size: 12px;\n font-weight: 500;\n color: #666;\n}\n\n.result-item.passed i,\n.result-item.passed .count {\n color: #4caf50;\n}\n\n.result-item.failed i,\n.result-item.failed .count {\n color: #f44336;\n}\n\n.result-item.skipped i,\n.result-item.skipped .count {\n color: #9e9e9e;\n}\n\n.result-item.error i,\n.result-item.error .count {\n color: #ff9800;\n}\n\n.result-item.total i,\n.result-item.total .count {\n color: #2196f3;\n}\n\n/* Tabs */\n.tabs-container {\n background: white;\n border-bottom: 1px solid #e0e0e0;\n}\n\n.tabs {\n display: flex;\n padding: 0 20px;\n overflow-x: auto;\n}\n\n.tab {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 20px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: #666;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.tab:hover {\n color: #2196f3;\n background: rgba(33, 150, 243, 0.05);\n}\n\n.tab.active {\n color: #2196f3;\n border-bottom-color: #2196f3;\n}\n\n.tab i {\n font-size: 16px;\n}\n\n.tab-badge {\n background: #e0e0e0;\n color: #666;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.tab.active .tab-badge {\n background: #e3f2fd;\n color: #2196f3;\n}\n\n/* Tab Content */\n.tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 20px;\n}\n\n/* Overview Tab */\n.overview-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n}\n\n.result-hero {\n background: white;\n border-radius: 12px;\n padding: 32px;\n text-align: center;\n border: 3px solid #e0e0e0;\n}\n\n.result-hero.passed {\n background: #e8f5e9;\n border-color: #4caf50;\n}\n\n.result-hero.failed {\n background: #ffebee;\n border-color: #f44336;\n}\n\n.result-icon {\n font-size: 64px;\n margin-bottom: 16px;\n}\n\n.result-hero.passed .result-icon {\n color: #4caf50;\n}\n\n.result-hero.failed .result-icon {\n color: #f44336;\n}\n\n.result-text h2 {\n margin: 0 0 12px 0;\n font-size: 32px;\n font-weight: 700;\n color: #333;\n}\n\n.result-stats {\n font-size: 20px;\n font-weight: 600;\n color: #666;\n margin-bottom: 8px;\n}\n\n.result-counts {\n font-size: 16px;\n color: #999;\n}\n\n/* Test Runs Tab */\n.test-runs-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.test-run-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n background: white;\n border: 2px solid transparent;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.test-run-item:hover {\n background: #e3f2fd;\n border-color: #90caf9;\n}\n\n.run-sequence {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #f0f0f0;\n border-radius: 50%;\n font-size: 14px;\n font-weight: 700;\n color: #666;\n flex-shrink: 0;\n}\n\n.run-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n color: white;\n font-size: 18px;\n flex-shrink: 0;\n}\n\n.run-content {\n flex: 1;\n}\n\n.run-name {\n font-size: 14px;\n font-weight: 600;\n color: #333;\n margin-bottom: 4px;\n}\n\n.run-meta {\n display: flex;\n gap: 12px;\n font-size: 12px;\n color: #666;\n}\n\n.run-meta .status {\n font-weight: 700;\n}\n\n.test-run-item > i {\n color: #999;\n font-size: 14px;\n}\n\n/* Details Tab */\n.details-tab {\n background: white;\n border-radius: 12px;\n padding: 20px;\n}\n\n.details-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 16px;\n}\n\n.detail-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.detail-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: #999;\n}\n\n.detail-value {\n font-size: 14px;\n color: #333;\n word-wrap: break-word;\n}\n\n.detail-value a {\n color: #2196f3;\n text-decoration: none;\n}\n\n.detail-value a:hover {\n text-decoration: underline;\n}\n\n/* No Data State */\n.no-data {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: #999;\n text-align: center;\n background: white;\n border-radius: 12px;\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/* Responsive */\n@media (max-width: 1200px) {\n .metrics-bar {\n grid-template-columns: repeat(3, 1fr);\n }\n\n .results-summary {\n flex-wrap: wrap;\n }\n}\n\n@media (max-width: 768px) {\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .details-grid {\n grid-template-columns: 1fr;\n }\n\n .header-content {\n flex-direction: column;\n gap: 16px;\n }\n\n .tabs {\n overflow-x: auto;\n }\n}\n"] }]
|
|
565
|
-
}], () => [{ type: i0.ElementRef }, { type: i1.SharedService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i0.ChangeDetectorRef }],
|
|
566
|
-
|
|
2274
|
+
args: [{ selector: 'mj-test-suite-run-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"test-suite-run-form\" kendoDialogContainer>\n <!-- Header Section -->\n <div class=\"suite-run-header\">\n <!-- Breadcrumb -->\n <div class=\"breadcrumb\" *ngIf=\"testSuite\">\n <a href=\"javascript:void(0)\" (click)=\"openTestSuite()\">\n <i class=\"fas fa-layer-group\"></i>\n {{ testSuite.Name }}\n </a>\n <i class=\"fas fa-chevron-right separator\"></i>\n <span class=\"current\">Run #{{ record.ID.substring(0, 8) }}</span>\n </div>\n\n <!-- Header Content -->\n <div class=\"header-content\">\n <div class=\"header-left\">\n <div class=\"suite-run-icon\" [style.background-color]=\"getStatusColor()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n </div>\n <div class=\"suite-run-info\">\n <h1>Suite Run</h1>\n <div class=\"suite-run-meta\">\n <span class=\"status-badge\" [ngClass]=\"getStatusClass()\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n {{ record.Status }}\n </span>\n <span class=\"meta-tag environment\" *ngIf=\"record.Environment\">\n <i class=\"fas fa-server\"></i>\n {{ record.Environment }}\n </span>\n <span class=\"meta-tag trigger\" *ngIf=\"record.TriggerType\">\n <i class=\"fas fa-bolt\"></i>\n {{ record.TriggerType }}\n </span>\n </div>\n </div>\n </div>\n <div class=\"header-actions\">\n <!-- Evaluation Mode Toggle -->\n <app-evaluation-mode-toggle></app-evaluation-mode-toggle>\n <button kendoButton (click)=\"reRunSuite()\" themeColor=\"primary\" *ngIf=\"record.SuiteID\">\n <i class=\"fas fa-play\"></i> Re-run Suite\n </button>\n <button kendoButton (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 <!-- Metrics Bar -->\n <div class=\"metrics-bar\">\n <div class=\"metric-card\">\n <div class=\"metric-icon\">\n <i class=\"fas fa-clock\"></i>\n </div>\n <div class=\"metric-content\">\n <div class=\"metric-value\">{{ calculateDuration() }}</div>\n <div class=\"metric-label\">Duration</div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">\n <i class=\"fas fa-percentage\"></i>\n </div>\n <div class=\"metric-content\">\n <div class=\"metric-value\">{{ getPassRate().toFixed(1) }}%</div>\n <div class=\"metric-label\">Pass Rate</div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">\n <i class=\"fas fa-dollar-sign\"></i>\n </div>\n <div class=\"metric-content\">\n <div class=\"metric-value\">{{ formatCost(record.TotalCostUSD) }}</div>\n <div class=\"metric-label\">Total Cost</div>\n </div>\n </div>\n <div class=\"metric-card\">\n <div class=\"metric-icon\">\n <i class=\"fas fa-calendar\"></i>\n </div>\n <div class=\"metric-content\">\n <div class=\"metric-value\">{{ getRelativeTime(record.StartedAt) }}</div>\n <div class=\"metric-label\">Started</div>\n </div>\n </div>\n </div>\n\n <!-- Results Summary -->\n <div class=\"results-summary\">\n <div class=\"result-item passed\">\n <div class=\"result-icon\">\n <i class=\"fas fa-check-circle\"></i>\n </div>\n <div class=\"result-content\">\n <span class=\"result-count\">{{ record.PassedTests || 0 }}</span>\n <span class=\"result-label\">Passed</span>\n </div>\n </div>\n <div class=\"result-item failed\">\n <div class=\"result-icon\">\n <i class=\"fas fa-times-circle\"></i>\n </div>\n <div class=\"result-content\">\n <span class=\"result-count\">{{ record.FailedTests || 0 }}</span>\n <span class=\"result-label\">Failed</span>\n </div>\n </div>\n <div class=\"result-item error\">\n <div class=\"result-icon\">\n <i class=\"fas fa-exclamation-circle\"></i>\n </div>\n <div class=\"result-content\">\n <span class=\"result-count\">{{ record.ErrorTests || 0 }}</span>\n <span class=\"result-label\">Errors</span>\n </div>\n </div>\n <div class=\"result-item skipped\">\n <div class=\"result-icon\">\n <i class=\"fas fa-forward\"></i>\n </div>\n <div class=\"result-content\">\n <span class=\"result-count\">{{ record.SkippedTests || 0 }}</span>\n <span class=\"result-label\">Skipped</span>\n </div>\n </div>\n <div class=\"result-item total\">\n <div class=\"result-icon\">\n <i class=\"fas fa-list\"></i>\n </div>\n <div class=\"result-content\">\n <span class=\"result-count\">{{ record.TotalTests || 0 }}</span>\n <span class=\"result-label\">Total</span>\n </div>\n </div>\n </div>\n\n <!-- Tags Section - Sleek inline design -->\n <div class=\"tags-bar\" *ngIf=\"!editingTags\">\n <div class=\"tags-bar-content\">\n <span class=\"tags-bar-label\"><i class=\"fas fa-tags\"></i></span>\n <div class=\"tags-bar-chips\" *ngIf=\"tags.length > 0\">\n <span class=\"tag-inline\" *ngFor=\"let tag of tags\">{{ tag }}</span>\n </div>\n <span class=\"tags-bar-empty\" *ngIf=\"tags.length === 0\">No tags</span>\n <button class=\"tags-bar-edit\" (click)=\"startEditingTags()\" title=\"Edit tags\">\n <i class=\"fas fa-plus\"></i> Add\n </button>\n </div>\n </div>\n\n <!-- Tags Editor - Expanded when editing -->\n <div class=\"tags-editor-panel\" *ngIf=\"editingTags\">\n <div class=\"tags-editor-header\">\n <span class=\"tags-editor-title\"><i class=\"fas fa-tags\"></i> Edit Tags</span>\n </div>\n <div class=\"tags-editor-body\">\n <div class=\"tags-editor-chips\">\n <span class=\"tag-editable\" *ngFor=\"let tag of tags\">\n {{ tag }}\n <button class=\"tag-remove-btn\" (click)=\"removeTag(tag)\" title=\"Remove tag\">\n <i class=\"fas fa-times\"></i>\n </button>\n </span>\n <span class=\"tags-empty-hint\" *ngIf=\"tags.length === 0\">No tags yet</span>\n </div>\n <div class=\"tags-editor-input\">\n <input type=\"text\"\n [(ngModel)]=\"newTag\"\n placeholder=\"Type a tag and press Enter...\"\n (keyup.enter)=\"addTag()\"\n class=\"tag-text-input\" />\n <button kendoButton (click)=\"addTag()\" [disabled]=\"!newTag.trim()\" fillMode=\"flat\">\n <i class=\"fas fa-plus\"></i>\n </button>\n </div>\n </div>\n <div class=\"tags-editor-footer\">\n <button kendoButton (click)=\"saveTags()\" themeColor=\"primary\" [disabled]=\"savingTags\">\n <i class=\"fas fa-spinner fa-spin\" *ngIf=\"savingTags\"></i>\n {{ savingTags ? 'Saving...' : 'Save' }}\n </button>\n <button kendoButton (click)=\"cancelEditingTags()\" fillMode=\"flat\">Cancel</button>\n </div>\n </div>\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> Overview\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-list\"></i> Test Runs\n <span class=\"tab-badge\" *ngIf=\"testRunsLoaded\">{{ testRuns.length }}</span>\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'details'\"\n (click)=\"changeTab('details')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'details'\">\n <i class=\"fas fa-info-circle\"></i> Details\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 title=\"Press 4\">\n <i class=\"fas fa-chart-bar\"></i> Analytics\n </button>\n <button class=\"tab\"\n [class.active]=\"activeTab === 'execution'\"\n (click)=\"changeTab('execution')\"\n role=\"tab\"\n [attr.aria-selected]=\"activeTab === 'execution'\"\n title=\"Press 5\">\n <i class=\"fas fa-microchip\"></i>\n <span>Execution</span>\n </button>\n </div>\n </div>\n\n <!-- Tab Content -->\n <div class=\"tab-content\">\n <!-- Overview Tab -->\n <div class=\"overview-tab\" *ngIf=\"activeTab === 'overview'\">\n <!-- Result Hero -->\n <div class=\"result-hero\"\n [class.passed]=\"record.Status === 'Completed' && getPassRate() >= 90\"\n [class.failed]=\"record.Status === 'Failed' || getPassRate() < 50\"\n [class.running]=\"record.Status === 'Running'\"\n [class.pending]=\"record.Status === 'Pending'\">\n <div class=\"result-hero-icon\">\n <i class=\"fas\" [ngClass]=\"getStatusIcon()\"></i>\n </div>\n <div class=\"result-hero-text\">\n <h2>SUITE {{ record.Status.toUpperCase() || 'UNKNOWN' }}</h2>\n <div class=\"result-hero-stats\">\n <div class=\"stat-item\">\n <span class=\"stat-value\">{{ getPassRate().toFixed(1) }}%</span>\n <span class=\"stat-label\">Pass Rate</span>\n </div>\n <div class=\"stat-divider\"></div>\n <div class=\"stat-item\">\n <span class=\"stat-value\">{{ record.PassedTests || 0 }} / {{ record.TotalTests || 0 }}</span>\n <span class=\"stat-label\">Tests Passed</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Evaluation Metrics Summary -->\n <div class=\"evaluation-summary\" *ngIf=\"evaluationMetrics && feedbacksLoaded\">\n <div class=\"eval-summary-grid\">\n <!-- Human Feedback Card -->\n <div class=\"eval-summary-card\" *ngIf=\"evalPreferences.showHuman\">\n <div class=\"eval-card-header\">\n <i class=\"fa-solid fa-user\"></i>\n <span>Human Feedback</span>\n </div>\n <div class=\"eval-card-body\">\n <div class=\"eval-stat-row\">\n <span class=\"eval-stat-label\">Reviewed</span>\n <span class=\"eval-stat-value\">{{ evaluationMetrics.humanReviewedCount }} / {{ evaluationMetrics.totalRuns }}</span>\n </div>\n <div class=\"eval-stat-row\" *ngIf=\"evaluationMetrics.humanReviewedCount > 0\">\n <span class=\"eval-stat-label\">Avg Rating</span>\n <span class=\"eval-stat-value\">{{ evaluationMetrics.humanAvgRating.toFixed(1) }}/10</span>\n </div>\n <div class=\"eval-stat-row\" *ngIf=\"evaluationMetrics.humanReviewedCount > 0\">\n <span class=\"eval-stat-label\">Correct</span>\n <span class=\"eval-stat-value correct\">{{ evaluationMetrics.humanCorrectCount }}</span>\n <span class=\"eval-stat-value incorrect\" *ngIf=\"evaluationMetrics.humanIncorrectCount > 0\">{{ evaluationMetrics.humanIncorrectCount }} incorrect</span>\n </div>\n </div>\n <div class=\"eval-card-footer\" *ngIf=\"evaluationMetrics.humanPendingCount > 0\">\n <span class=\"pending-badge\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ evaluationMetrics.humanPendingCount }} need review\n </span>\n </div>\n </div>\n\n <!-- Auto Score Card -->\n <div class=\"eval-summary-card\" *ngIf=\"evalPreferences.showAuto\">\n <div class=\"eval-card-header\">\n <i class=\"fa-solid fa-robot\"></i>\n <span>Auto Evaluation</span>\n </div>\n <div class=\"eval-card-body\">\n <div class=\"eval-stat-row\">\n <span class=\"eval-stat-label\">Evaluated</span>\n <span class=\"eval-stat-value\">{{ evaluationMetrics.autoEvaluatedCount }} / {{ evaluationMetrics.totalRuns }}</span>\n </div>\n <div class=\"eval-stat-row\" *ngIf=\"evaluationMetrics.autoEvaluatedCount > 0\">\n <span class=\"eval-stat-label\">Avg Score</span>\n <span class=\"eval-stat-value\">{{ (evaluationMetrics.autoAvgScore * 100).toFixed(0) }}%</span>\n </div>\n <div class=\"eval-stat-row\" *ngIf=\"evaluationMetrics.autoEvaluatedCount > 0\">\n <span class=\"eval-stat-label\">Pass Rate</span>\n <span class=\"eval-stat-value\">{{ evaluationMetrics.autoPassRate.toFixed(0) }}%</span>\n </div>\n </div>\n </div>\n\n <!-- Execution Card -->\n <div class=\"eval-summary-card\" *ngIf=\"evalPreferences.showExecution\">\n <div class=\"eval-card-header\">\n <i class=\"fa-solid fa-circle-check\"></i>\n <span>Execution</span>\n </div>\n <div class=\"eval-card-body\">\n <div class=\"eval-stat-row\">\n <span class=\"eval-stat-label\">Completed</span>\n <span class=\"eval-stat-value\">{{ evaluationMetrics.execCompletedCount }} / {{ evaluationMetrics.totalRuns }}</span>\n </div>\n <div class=\"eval-stat-row\">\n <span class=\"eval-stat-label\">Success Rate</span>\n <span class=\"eval-stat-value\">{{ evaluationMetrics.execSuccessRate.toFixed(0) }}%</span>\n </div>\n <div class=\"eval-stat-row\" *ngIf=\"evaluationMetrics.execErrorCount > 0 || evaluationMetrics.execTimeoutCount > 0\">\n <span class=\"eval-stat-label\">Issues</span>\n <span class=\"eval-stat-value error\" *ngIf=\"evaluationMetrics.execErrorCount > 0\">{{ evaluationMetrics.execErrorCount }} errors</span>\n <span class=\"eval-stat-value timeout\" *ngIf=\"evaluationMetrics.execTimeoutCount > 0\">{{ evaluationMetrics.execTimeoutCount }} timeouts</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Needs Review Section -->\n <div class=\"needs-review-section\" *ngIf=\"evalPreferences.showHuman && needsReviewItems.length > 0 && feedbacksLoaded\">\n <div class=\"needs-review-header\">\n <h3><i class=\"fa-solid fa-user-clock\"></i> Needs Review</h3>\n <span class=\"review-count\">{{ needsReviewItems.length }} items</span>\n </div>\n <div class=\"needs-review-list\">\n <div class=\"review-item\" *ngFor=\"let item of needsReviewItems.slice(0, 5)\"\n [class.high-priority]=\"item.priority === 'high'\"\n [class.medium-priority]=\"item.priority === 'medium'\"\n (click)=\"toggleRunExpanded(item.run.id)\">\n <div class=\"review-item-icon\">\n <i class=\"fa-solid fa-exclamation-triangle\" *ngIf=\"item.priority === 'high'\"></i>\n <i class=\"fa-solid fa-circle-dot\" *ngIf=\"item.priority === 'medium'\"></i>\n <i class=\"fa-solid fa-clock\" *ngIf=\"item.priority === 'low'\"></i>\n </div>\n <div class=\"review-item-content\">\n <span class=\"review-item-name\">{{ item.run.testName }}</span>\n <span class=\"review-item-reason\">{{ item.reason }}</span>\n </div>\n <div class=\"review-item-action\">\n <i class=\"fa-solid fa-chevron-right\"></i>\n </div>\n </div>\n <div class=\"review-more\" *ngIf=\"needsReviewItems.length > 5\">\n <button kendoButton fillMode=\"flat\" (click)=\"changeTab('runs')\">\n View all {{ needsReviewItems.length }} items\n </button>\n </div>\n </div>\n </div>\n\n <!-- Progress Ring (when running) -->\n <div class=\"progress-section\" *ngIf=\"record.Status === 'Running' || record.Status === 'Pending'\">\n <div class=\"progress-info\">\n <i class=\"fas fa-circle-notch fa-spin\"></i>\n <span>Suite execution in progress...</span>\n </div>\n <div class=\"auto-refresh-notice\">\n <i class=\"fas fa-sync\"></i>\n Auto-refreshing every 5 seconds\n </div>\n </div>\n </div>\n\n <!-- Test Runs Tab -->\n <div class=\"runs-tab\" *ngIf=\"activeTab === 'runs'\">\n <!-- Toolbar -->\n <div class=\"runs-toolbar\" *ngIf=\"testRunsLoaded && testRuns.length > 0\">\n <div class=\"run-filters\">\n <button class=\"filter-btn\"\n [class.active]=\"runStatusFilter === null\"\n (click)=\"setRunStatusFilter(null)\">\n All ({{ testRuns.length }})\n </button>\n <button class=\"filter-btn passed\"\n [class.active]=\"runStatusFilter === 'Passed'\"\n (click)=\"setRunStatusFilter('Passed')\"\n *ngIf=\"getRunCountByStatus('Passed') > 0\">\n <i class=\"fas fa-check\"></i> Passed ({{ getRunCountByStatus('Passed') }})\n </button>\n <button class=\"filter-btn failed\"\n [class.active]=\"runStatusFilter === 'Failed'\"\n (click)=\"setRunStatusFilter('Failed')\"\n *ngIf=\"getRunCountByStatus('Failed') > 0\">\n <i class=\"fas fa-times\"></i> Failed ({{ getRunCountByStatus('Failed') }})\n </button>\n <button class=\"filter-btn error\"\n [class.active]=\"runStatusFilter === 'Error'\"\n (click)=\"setRunStatusFilter('Error')\"\n *ngIf=\"getRunCountByStatus('Error') > 0\">\n <i class=\"fas fa-exclamation\"></i> Error ({{ getRunCountByStatus('Error') }})\n </button>\n </div>\n <div class=\"runs-actions\">\n <button kendoButton (click)=\"exportToCSV()\">\n <i class=\"fas fa-download\"></i> Export CSV\n </button>\n </div>\n </div>\n\n <!-- Loading State -->\n <div class=\"loading-state\" *ngIf=\"loadingTestRuns\">\n <div class=\"skeleton-list\">\n <div class=\"skeleton-card\" *ngFor=\"let i of [1,2,3,4,5]\">\n <div class=\"skeleton-sequence\"></div>\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 </div>\n </div>\n\n <!-- Test Runs List -->\n <div class=\"test-runs-list\" *ngIf=\"!loadingTestRuns && testRuns.length > 0\">\n <div class=\"test-run-card\" *ngFor=\"let run of getFilteredTestRuns()\">\n <div class=\"test-run-item\" (click)=\"toggleRunExpanded(run.ID)\">\n <div class=\"run-sequence\">{{ run.Sequence || '-' }}</div>\n <div class=\"run-icon\" [style.background-color]=\"getRunStatusColor(run.Status)\">\n <i class=\"fas\" [ngClass]=\"getRunStatusIcon(run.Status)\"></i>\n </div>\n <div class=\"run-content\">\n <div class=\"run-header-row\">\n <div class=\"run-name\">{{ run.Test }}</div>\n <!-- Evaluation Badge -->\n <app-evaluation-badge\n [executionStatus]=\"run.Status\"\n [originalStatus]=\"run.Status\"\n [autoScore]=\"run.Score\"\n [humanRating]=\"getFeedbackRating(run.ID) || null\"\n [humanIsCorrect]=\"getHumanIsCorrect(run.ID)\"\n [hasHumanFeedback]=\"hasFeedback(run.ID)\"\n [preferences]=\"evalPreferences\"\n [mode]=\"'compact'\">\n </app-evaluation-badge>\n </div>\n <div class=\"run-meta\">\n <span class=\"run-duration\" *ngIf=\"run.DurationSeconds\">\n <i class=\"fas fa-clock\"></i> {{ run.DurationSeconds.toFixed(1) }}s\n </span>\n <span class=\"run-cost\" *ngIf=\"run.CostUSD\">\n <i class=\"fas fa-dollar-sign\"></i> {{ run.CostUSD.toFixed(6) }}\n </span>\n <mj-entity-link-pill\n *ngIf=\"run.TargetLogEntityID && run.TargetLogID\"\n [entityName]=\"run.TargetLogEntity\"\n [recordId]=\"run.TargetLogID\">\n </mj-entity-link-pill>\n </div>\n <div class=\"run-tags\" *ngIf=\"getRunTags(run).length > 0\">\n <span class=\"tag-chip\" *ngFor=\"let tag of getRunTags(run)\">{{ tag }}</span>\n </div>\n </div>\n <div class=\"run-expand\">\n <i class=\"fas\" [class.fa-chevron-down]=\"expandedRunId !== run.ID\" [class.fa-chevron-up]=\"expandedRunId === run.ID\"></i>\n </div>\n </div>\n\n <!-- Expanded Inline Feedback -->\n <div class=\"inline-feedback\" *ngIf=\"expandedRunId === run.ID\">\n <div class=\"feedback-divider\"></div>\n\n <div class=\"feedback-section\">\n <div class=\"feedback-label\">Quick Feedback</div>\n\n <div class=\"inline-rating\">\n <div class=\"rating-numbers\">\n <button *ngFor=\"let num of [1,2,3,4,5,6,7,8,9,10]\"\n type=\"button\"\n class=\"rating-btn\"\n [class.selected]=\"num === inlineRating\"\n [class.hover]=\"num === inlineHoverRating\"\n [class.low]=\"num <= 3\"\n [class.mid]=\"num >= 4 && num <= 6\"\n [class.high]=\"num >= 7\"\n (click)=\"setInlineRating(num); $event.stopPropagation()\"\n (mouseenter)=\"inlineHoverRating = num\"\n (mouseleave)=\"inlineHoverRating = 0\">\n {{ num }}\n </button>\n </div>\n <div class=\"rating-info\" *ngIf=\"inlineRating > 0\">\n <span class=\"rating-value\">{{ inlineRating }}/10</span>\n <span class=\"rating-label-text\">{{ getInlineRatingLabel() }}</span>\n </div>\n </div>\n\n <div class=\"correctness-row\">\n <span class=\"correctness-label\">Was it correct?</span>\n <div class=\"correctness-options\">\n <label class=\"radio-opt\" (click)=\"$event.stopPropagation()\">\n <input type=\"radio\" name=\"correct-{{run.ID}}\" [value]=\"true\" [(ngModel)]=\"inlineIsCorrect\">\n <span>Yes</span>\n </label>\n <label class=\"radio-opt\" (click)=\"$event.stopPropagation()\">\n <input type=\"radio\" name=\"correct-{{run.ID}}\" [value]=\"false\" [(ngModel)]=\"inlineIsCorrect\">\n <span>No</span>\n </label>\n <label class=\"radio-opt\" (click)=\"$event.stopPropagation()\">\n <input type=\"radio\" name=\"correct-{{run.ID}}\" [value]=\"null\" [(ngModel)]=\"inlineIsCorrect\">\n <span>Not Sure</span>\n </label>\n </div>\n </div>\n\n <div class=\"comments-row\" (click)=\"$event.stopPropagation()\">\n <textarea\n class=\"feedback-textarea\"\n [(ngModel)]=\"inlineComments\"\n placeholder=\"Add comments or corrections...\"\n rows=\"3\"></textarea>\n </div>\n\n <div class=\"feedback-actions\" (click)=\"$event.stopPropagation()\">\n <button kendoButton (click)=\"openTestRun(run.ID)\">\n <i class=\"fas fa-external-link-alt\"></i> View Full Details\n </button>\n <button kendoButton\n themeColor=\"primary\"\n (click)=\"saveInlineFeedback()\"\n [disabled]=\"!canSubmitInlineFeedback() || savingInlineFeedback\">\n <i class=\"fas\" [ngClass]=\"savingInlineFeedback ? 'fa-spinner fa-spin' : 'fa-save'\"></i>\n {{ savingInlineFeedback ? 'Saving...' : (hasFeedback(run.ID) ? 'Update' : 'Save') }}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"empty-state\" *ngIf=\"testRunsLoaded && !loadingTestRuns && testRuns.length === 0\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-inbox\"></i>\n </div>\n <h4>No Test Runs Found</h4>\n <p>No test runs have been recorded for this suite execution.</p>\n </div>\n\n <!-- Filtered Empty -->\n <div class=\"empty-state\" *ngIf=\"testRunsLoaded && !loadingTestRuns && testRuns.length > 0 && getFilteredTestRuns().length === 0\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-filter\"></i>\n </div>\n <h4>No Matching Runs</h4>\n <p>No test runs match the current filter.</p>\n <button kendoButton (click)=\"setRunStatusFilter(null)\">Clear Filter</button>\n </div>\n </div>\n\n <!-- Details Tab -->\n <div class=\"details-tab\" *ngIf=\"activeTab === 'details'\">\n <div class=\"details-card\">\n <h3><i class=\"fas fa-info-circle\"></i> Run Information</h3>\n <div class=\"details-grid\">\n <div class=\"detail-item\">\n <div class=\"detail-label\">Run ID</div>\n <div class=\"detail-value monospace\">{{ record.ID }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Test Suite</div>\n <div class=\"detail-value\">\n <a href=\"javascript:void(0)\" (click)=\"openTestSuite()\" *ngIf=\"testSuite\">{{ testSuite.Name }}</a>\n <span *ngIf=\"!testSuite\">Loading...</span>\n </div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Status</div>\n <div class=\"detail-value\">\n <span class=\"status-inline\" [ngClass]=\"getStatusClass()\">{{ record.Status }}</span>\n </div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Run By</div>\n <div class=\"detail-value\">{{ record.RunByUser || 'N/A' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Started At</div>\n <div class=\"detail-value\">{{ record.StartedAt | date:'medium' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Completed At</div>\n <div class=\"detail-value\">{{ record.CompletedAt | date:'medium' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Environment</div>\n <div class=\"detail-value\">{{ record.Environment || 'N/A' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Trigger Type</div>\n <div class=\"detail-value\">{{ record.TriggerType || 'N/A' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Git Commit</div>\n <div class=\"detail-value monospace\">{{ record.GitCommit || 'N/A' }}</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-label\">Agent Version</div>\n <div class=\"detail-value\">{{ record.AgentVersion || 'N/A' }}</div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Analytics Tab -->\n <div class=\"analytics-tab\" *ngIf=\"activeTab === 'analytics'\">\n <!-- Loading State -->\n <div class=\"analytics-loading\" *ngIf=\"loadingTestRuns\">\n <i class=\"fas fa-spinner fa-spin\"></i>\n <span>Loading test results...</span>\n </div>\n\n <!-- Summary Statistics - Moved to top for better overview -->\n <div class=\"analytics-section\" *ngIf=\"!loadingTestRuns && testRuns.length > 0\">\n <h3><i class=\"fas fa-chart-pie\"></i> Summary Statistics</h3>\n <div class=\"stats-grid\">\n <div class=\"stat-card\">\n <div class=\"stat-icon passed\"><i class=\"fas fa-check-circle\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ getPassedCount() }}</div>\n <div class=\"stat-label\">Passed</div>\n <div class=\"stat-percent\">{{ getPassedPercent().toFixed(1) }}%</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon failed\"><i class=\"fas fa-times-circle\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ getFailedCount() }}</div>\n <div class=\"stat-label\">Failed</div>\n <div class=\"stat-percent\">{{ getFailedPercent().toFixed(1) }}%</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon score\"><i class=\"fas fa-star\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ (getAverageScore() * 100).toFixed(1) }}%</div>\n <div class=\"stat-label\">Avg Score</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon duration\"><i class=\"fas fa-clock\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ getAverageDuration().toFixed(1) }}s</div>\n <div class=\"stat-label\">Avg Duration</div>\n </div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-icon cost\"><i class=\"fas fa-dollar-sign\"></i></div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">${{ getTotalCost().toFixed(4) }}</div>\n <div class=\"stat-label\">Total Cost</div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Test Results Table -->\n <div class=\"analytics-section\" *ngIf=\"!loadingTestRuns && testRuns.length > 0\">\n <div class=\"analytics-header\">\n <h3><i class=\"fas fa-table\"></i> Test Results</h3>\n <div class=\"analytics-legend\">\n <span class=\"legend-item passed\"><i class=\"fas fa-check-circle\"></i> Passed</span>\n <span class=\"legend-item failed\"><i class=\"fas fa-times-circle\"></i> Failed</span>\n <span class=\"legend-item error\"><i class=\"fas fa-exclamation-circle\"></i> Error</span>\n <span class=\"legend-item skipped\"><i class=\"fas fa-forward\"></i> Skipped</span>\n </div>\n </div>\n\n <!-- Results Table -->\n <div class=\"results-table-wrapper\">\n <table class=\"results-table\">\n <thead>\n <tr>\n <th class=\"seq-col\">#</th>\n <th class=\"name-col\">Test Name</th>\n <th class=\"status-col\" *ngIf=\"evalPreferences.showExecution\">Status</th>\n <th class=\"score-col\" *ngIf=\"evalPreferences.showAuto\">Auto Score</th>\n <th class=\"feedback-col\" *ngIf=\"evalPreferences.showHuman\">Human Score</th>\n <th class=\"duration-col\">Duration</th>\n <th class=\"cost-col\">Cost</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let run of testRuns; let i = index\"\n class=\"result-row\"\n [class.row-passed]=\"run.Status === 'Passed'\"\n [class.row-failed]=\"run.Status === 'Failed'\"\n [class.row-error]=\"run.Status === 'Error'\"\n [class.row-skipped]=\"run.Status === 'Skipped'\"\n (click)=\"openTestRun(run.ID)\">\n <td class=\"seq-col\">{{ i + 1 }}</td>\n <td class=\"name-col\">\n <div class=\"test-name-wrapper\">\n <span class=\"test-name\">{{ run.Test || 'Unknown Test' }}</span>\n <div class=\"test-tags\" *ngIf=\"getRunTags(run).length > 0\">\n <span class=\"tag-mini\" *ngFor=\"let tag of getRunTags(run).slice(0, 2)\">{{ tag }}</span>\n </div>\n </div>\n </td>\n <td class=\"status-col\" *ngIf=\"evalPreferences.showExecution\">\n <span class=\"status-badge\" [ngClass]=\"'status-' + run.Status.toLowerCase()\">\n <i class=\"fas\"\n [class.fa-check-circle]=\"run.Status === 'Passed'\"\n [class.fa-times-circle]=\"run.Status === 'Failed'\"\n [class.fa-exclamation-circle]=\"run.Status === 'Error'\"\n [class.fa-forward]=\"run.Status === 'Skipped'\"\n [class.fa-clock]=\"run.Status === 'Pending'\"\n [class.fa-spinner]=\"run.Status === 'Running'\"\n [class.fa-spin]=\"run.Status === 'Running'\"></i>\n {{ run.Status }}\n </span>\n </td>\n <td class=\"score-col\" *ngIf=\"evalPreferences.showAuto\">\n <div class=\"score-display\" *ngIf=\"run.Score != null\">\n <div class=\"score-bar-mini\">\n <div class=\"score-fill\"\n [style.width.%]=\"run.Score * 100\"\n [class.high]=\"run.Score >= 0.8\"\n [class.medium]=\"run.Score >= 0.5 && run.Score < 0.8\"\n [class.low]=\"run.Score < 0.5\"></div>\n </div>\n <span class=\"score-text\">{{ (run.Score * 100).toFixed(0) }}%</span>\n </div>\n <span class=\"na-value\" *ngIf=\"run.Score == null\">\u2014</span>\n </td>\n <td class=\"feedback-col\" *ngIf=\"evalPreferences.showHuman\">\n <div class=\"feedback-display\" *ngIf=\"hasFeedback(run.ID)\">\n <span class=\"feedback-rating\" [class.low]=\"getFeedbackRating(run.ID) <= 3\" [class.mid]=\"getFeedbackRating(run.ID) >= 4 && getFeedbackRating(run.ID) <= 6\" [class.high]=\"getFeedbackRating(run.ID) >= 7\">\n {{ getFeedbackRating(run.ID) }}/10\n </span>\n <span class=\"feedback-correctness\" *ngIf=\"getHumanIsCorrect(run.ID) !== null\">\n <i class=\"fas\" [class.fa-check]=\"getHumanIsCorrect(run.ID) === true\" [class.fa-times]=\"getHumanIsCorrect(run.ID) === false\" [class.correct]=\"getHumanIsCorrect(run.ID) === true\" [class.incorrect]=\"getHumanIsCorrect(run.ID) === false\"></i>\n </span>\n </div>\n <span class=\"na-value needs-review\" *ngIf=\"!hasFeedback(run.ID)\">\n <i class=\"fas fa-user-clock\"></i>\n </span>\n </td>\n <td class=\"duration-col\">\n <span *ngIf=\"run.DurationSeconds\">{{ run.DurationSeconds.toFixed(1) }}s</span>\n <span class=\"na-value\" *ngIf=\"!run.DurationSeconds\">\u2014</span>\n </td>\n <td class=\"cost-col\">\n <span *ngIf=\"run.CostUSD\">${{ run.CostUSD.toFixed(4) }}</span>\n <span class=\"na-value\" *ngIf=\"!run.CostUSD\">\u2014</span>\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"empty-state\" *ngIf=\"!loadingTestRuns && testRunsLoaded && testRuns.length === 0\">\n <div class=\"empty-icon\">\n <i class=\"fas fa-chart-bar\"></i>\n </div>\n <h4>No Test Results Yet</h4>\n <p>Test runs will appear here once the suite execution completes.</p>\n </div>\n </div>\n\n <!-- Execution Tab -->\n <div class=\"execution-tab\" *ngIf=\"activeTab === 'execution'\">\n <mj-execution-context\n [machineName]=\"record.MachineName\"\n [machineId]=\"record.MachineID\"\n [runByUserName]=\"record.RunByUserName\"\n [runByUserEmail]=\"record.RunByUserEmail\"\n [runContextDetailsJson]=\"record.RunContextDetails\">\n </mj-execution-context>\n </div>\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 <div class=\"keyboard-shortcuts\" *ngIf=\"showShortcuts\">\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>Re-run Suite</span>\n <span class=\"shortcut-keys\"><kbd>Cmd</kbd><kbd>Shift</kbd><kbd>R</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</div>\n", styles: ["/* ===================================\n Test Suite Run Form - Premium UX\n World-class responsive design\n =================================== */\n\n/* CSS Custom Properties */\n:host {\n --suite-run-primary: #3b82f6;\n --suite-run-primary-light: #eff6ff;\n --suite-run-success: #10b981;\n --suite-run-success-light: #ecfdf5;\n --suite-run-danger: #ef4444;\n --suite-run-danger-light: #fef2f2;\n --suite-run-warning: #f59e0b;\n --suite-run-warning-light: #fffbeb;\n --suite-run-info: #8b5cf6;\n --suite-run-info-light: #f5f3ff;\n --suite-run-neutral: #6b7280;\n --suite-run-neutral-light: #f9fafb;\n --suite-run-bg: #f8fafc;\n --suite-run-card: #ffffff;\n --suite-run-border: #e2e8f0;\n --suite-run-text: #1e293b;\n --suite-run-text-secondary: #64748b;\n --suite-run-radius: 12px;\n --suite-run-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);\n --suite-run-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n --suite-run-transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/* Base Container */\n.test-suite-run-form {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--suite-run-bg);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n}\n\n/* ===================================\n Header Section\n =================================== */\n.suite-run-header {\n background: var(--suite-run-card);\n border-bottom: 1px solid var(--suite-run-border);\n padding: 20px 24px;\n}\n\n/* Breadcrumb */\n.breadcrumb {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: var(--suite-run-text-secondary);\n margin-bottom: 16px;\n}\n\n.breadcrumb a {\n color: var(--suite-run-primary);\n text-decoration: none;\n display: flex;\n align-items: center;\n gap: 6px;\n transition: var(--suite-run-transition);\n}\n\n.breadcrumb a:hover {\n color: #2563eb;\n}\n\n.breadcrumb .separator {\n font-size: 10px;\n color: #cbd5e1;\n}\n\n.breadcrumb .current {\n color: var(--suite-run-text);\n font-weight: 500;\n}\n\n/* Header Content */\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 16px;\n margin-bottom: 24px;\n}\n\n.header-left {\n display: flex;\n gap: 16px;\n align-items: flex-start;\n}\n\n.suite-run-icon {\n width: 56px;\n height: 56px;\n border-radius: var(--suite-run-radius);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 24px;\n flex-shrink: 0;\n box-shadow: var(--suite-run-shadow);\n}\n\n.suite-run-info h1 {\n margin: 0 0 8px 0;\n font-size: 24px;\n font-weight: 700;\n color: var(--suite-run-text);\n letter-spacing: -0.025em;\n}\n\n.suite-run-meta {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n.status-badge.status-completed {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.status-badge.status-failed {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.status-badge.status-running {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.status-badge.status-pending {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.status-badge.status-cancelled {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\n}\n\n.meta-tag {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background: var(--suite-run-neutral-light);\n border-radius: 6px;\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n.meta-tag i {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n}\n\n/* ===================================\n Metrics Bar\n =================================== */\n.metrics-bar {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 12px;\n margin-bottom: 20px;\n}\n\n.metric-card {\n display: flex;\n align-items: center;\n gap: 12px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border: 1px solid var(--suite-run-border);\n border-radius: 10px;\n padding: 14px;\n transition: var(--suite-run-transition);\n}\n\n.metric-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--suite-run-shadow);\n}\n\n.metric-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--suite-run-card);\n border-radius: 10px;\n color: var(--suite-run-primary);\n font-size: 16px;\n box-shadow: var(--suite-run-shadow);\n}\n\n.metric-content {\n flex: 1;\n min-width: 0;\n}\n\n.metric-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--suite-run-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.metric-label {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n margin-top: 2px;\n}\n\n/* ===================================\n Results Summary\n =================================== */\n.results-summary {\n display: flex;\n gap: 12px;\n padding-top: 20px;\n border-top: 1px solid var(--suite-run-border);\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n}\n\n.result-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: 10px;\n flex-shrink: 0;\n transition: var(--suite-run-transition);\n}\n\n.result-item:hover {\n transform: translateY(-2px);\n box-shadow: var(--suite-run-shadow);\n}\n\n.result-icon {\n font-size: 24px;\n}\n\n.result-content {\n display: flex;\n flex-direction: column;\n}\n\n.result-count {\n font-size: 20px;\n font-weight: 700;\n line-height: 1.2;\n}\n\n.result-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.result-item.passed .result-icon,\n.result-item.passed .result-count {\n color: var(--suite-run-success);\n}\n\n.result-item.failed .result-icon,\n.result-item.failed .result-count {\n color: var(--suite-run-danger);\n}\n\n.result-item.error .result-icon,\n.result-item.error .result-count {\n color: var(--suite-run-warning);\n}\n\n.result-item.skipped .result-icon,\n.result-item.skipped .result-count {\n color: var(--suite-run-neutral);\n}\n\n.result-item.total .result-icon,\n.result-item.total .result-count {\n color: var(--suite-run-primary);\n}\n\n/* ===================================\n Tabs\n =================================== */\n.tabs-container {\n background: var(--suite-run-card);\n border-bottom: 1px solid var(--suite-run-border);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.tabs {\n display: flex;\n padding: 0 24px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: 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: 16px 20px;\n border: none;\n background: transparent;\n border-bottom: 3px solid transparent;\n color: var(--suite-run-text-secondary);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: var(--suite-run-transition);\n white-space: nowrap;\n position: relative;\n}\n\n.tab:hover {\n color: var(--suite-run-primary);\n background: var(--suite-run-primary-light);\n}\n\n.tab.active {\n color: var(--suite-run-primary);\n border-bottom-color: var(--suite-run-primary);\n font-weight: 600;\n}\n\n.tab i {\n font-size: 15px;\n}\n\n.tab-badge {\n background: var(--suite-run-border);\n color: var(--suite-run-text-secondary);\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.tab.active .tab-badge {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.tab-shortcut {\n display: none;\n width: 18px;\n height: 18px;\n background: var(--suite-run-neutral-light);\n border-radius: 4px;\n font-size: 10px;\n font-weight: 600;\n color: var(--suite-run-text-secondary);\n align-items: center;\n justify-content: center;\n margin-left: 4px;\n}\n\n/* ===================================\n Tab Content\n =================================== */\n.tab-content {\n flex: 1;\n overflow-y: auto;\n padding: 24px;\n}\n\n/* ===================================\n Overview Tab\n =================================== */\n.overview-tab {\n display: flex;\n flex-direction: column;\n gap: 20px;\n max-width: 800px;\n margin: 0 auto;\n width: 100%;\n}\n\n.result-hero {\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n padding: 48px 32px;\n text-align: center;\n border: 2px solid var(--suite-run-border);\n transition: var(--suite-run-transition);\n}\n\n.result-hero.passed {\n background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);\n border-color: var(--suite-run-success);\n}\n\n.result-hero.failed {\n background: linear-gradient(135deg, #fef2f2 0%, #fecaca 100%);\n border-color: var(--suite-run-danger);\n}\n\n.result-hero.running {\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n border-color: var(--suite-run-primary);\n}\n\n.result-hero.pending {\n background: linear-gradient(135deg, #f5f3ff 0%, #ede9fe 100%);\n border-color: var(--suite-run-info);\n}\n\n.result-hero-icon {\n font-size: 72px;\n margin-bottom: 20px;\n}\n\n.result-hero.passed .result-hero-icon {\n color: var(--suite-run-success);\n}\n\n.result-hero.failed .result-hero-icon {\n color: var(--suite-run-danger);\n}\n\n.result-hero.running .result-hero-icon {\n color: var(--suite-run-primary);\n}\n\n.result-hero.pending .result-hero-icon {\n color: var(--suite-run-info);\n}\n\n.result-hero-text h2 {\n margin: 0 0 16px 0;\n font-size: 32px;\n font-weight: 800;\n color: var(--suite-run-text);\n letter-spacing: -0.025em;\n}\n\n.result-hero-stats {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 32px;\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.stat-value {\n font-size: 24px;\n font-weight: 700;\n color: var(--suite-run-text);\n}\n\n.stat-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.stat-divider {\n width: 1px;\n height: 40px;\n background: var(--suite-run-border);\n}\n\n/* Progress Section */\n.progress-section {\n background: var(--suite-run-primary-light);\n border: 1px solid rgba(59, 130, 246, 0.2);\n border-radius: var(--suite-run-radius);\n padding: 20px;\n text-align: center;\n}\n\n.progress-info {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 10px;\n font-size: 16px;\n font-weight: 500;\n color: var(--suite-run-primary);\n margin-bottom: 8px;\n}\n\n.progress-info i {\n font-size: 20px;\n}\n\n.auto-refresh-notice {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n/* ===================================\n Test Runs Tab\n =================================== */\n.runs-tab {\n max-width: 900px;\n margin: 0 auto;\n width: 100%;\n}\n\n/* Loading Skeleton */\n.loading-state {\n animation: fadeIn 0.3s ease;\n}\n\n@keyframes fadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\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: 12px;\n padding: 16px;\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n border: 1px solid var(--suite-run-border);\n}\n\n.skeleton-sequence {\n width: 32px;\n height: 32px;\n background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n border-radius: 50%;\n}\n\n.skeleton-icon {\n width: 40px;\n height: 40px;\n background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n border-radius: 8px;\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 background: linear-gradient(90deg, #f1f5f9 25%, #e2e8f0 50%, #f1f5f9 75%);\n background-size: 200% 100%;\n animation: shimmer 1.5s infinite;\n border-radius: 4px;\n}\n\n.skeleton-line.wide {\n width: 70%;\n}\n\n.skeleton-line.narrow {\n width: 40%;\n}\n\n@keyframes shimmer {\n 0% { background-position: 200% 0; }\n 100% { background-position: -200% 0; }\n}\n\n/* Test Runs List */\n.test-runs-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.test-run-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.test-run-item:hover {\n background: var(--suite-run-primary-light);\n border-color: #93c5fd;\n transform: translateX(4px);\n}\n\n.test-run-item:active {\n transform: translateX(2px);\n}\n\n.run-sequence {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--suite-run-neutral-light);\n border-radius: 50%;\n font-size: 13px;\n font-weight: 700;\n color: var(--suite-run-text-secondary);\n flex-shrink: 0;\n}\n\n.run-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n color: white;\n font-size: 16px;\n flex-shrink: 0;\n box-shadow: var(--suite-run-shadow);\n}\n\n.run-content {\n flex: 1;\n min-width: 0;\n}\n\n.run-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--suite-run-text);\n margin-bottom: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.run-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n flex-wrap: wrap;\n}\n\n.run-status {\n font-weight: 700;\n}\n\n.run-score,\n.run-duration {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-score i,\n.run-duration i {\n font-size: 10px;\n opacity: 0.7;\n}\n\n.test-run-item > i {\n color: #cbd5e1;\n font-size: 14px;\n transition: var(--suite-run-transition);\n}\n\n.test-run-item:hover > i {\n color: var(--suite-run-primary);\n transform: translateX(4px);\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n text-align: center;\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n border: 2px dashed var(--suite-run-border);\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(--suite-run-neutral-light);\n border-radius: 50%;\n margin-bottom: 20px;\n}\n\n.empty-icon i {\n font-size: 32px;\n color: #cbd5e1;\n}\n\n.empty-state h4 {\n margin: 0 0 8px 0;\n font-size: 18px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n color: var(--suite-run-text-secondary);\n max-width: 300px;\n}\n\n/* ===================================\n Details Tab\n =================================== */\n.details-tab {\n max-width: 900px;\n margin: 0 auto;\n width: 100%;\n}\n\n.details-card {\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n padding: 24px;\n box-shadow: var(--suite-run-shadow);\n}\n\n.details-card h3 {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--suite-run-text);\n padding-bottom: 12px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.details-card h3 i {\n color: var(--suite-run-primary);\n}\n\n.details-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 20px;\n}\n\n.detail-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.detail-label {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n}\n\n.detail-value {\n font-size: 14px;\n color: var(--suite-run-text);\n word-wrap: break-word;\n}\n\n.detail-value.monospace {\n font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;\n font-size: 12px;\n background: var(--suite-run-neutral-light);\n padding: 6px 10px;\n border-radius: 6px;\n}\n\n.detail-value a {\n color: var(--suite-run-primary);\n text-decoration: none;\n font-weight: 500;\n transition: var(--suite-run-transition);\n}\n\n.detail-value a:hover {\n color: #2563eb;\n text-decoration: underline;\n}\n\n.status-inline {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.status-inline.status-completed {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.status-inline.status-failed {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.status-inline.status-running {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.status-inline.status-pending {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.status-inline.status-cancelled {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\n}\n\n/* ===================================\n Keyboard Shortcuts\n =================================== */\n/* Toggle button - visible when shortcuts are hidden */\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(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n box-shadow: var(--suite-run-shadow);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--suite-run-text-secondary);\n font-size: 14px;\n z-index: 99;\n transition: var(--suite-run-transition);\n opacity: 0.7;\n}\n\n.shortcuts-toggle:hover {\n opacity: 1;\n transform: scale(1.1);\n color: var(--suite-run-primary);\n border-color: var(--suite-run-primary);\n}\n\n.keyboard-shortcuts {\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n padding: 12px 16px;\n box-shadow: var(--suite-run-shadow-lg);\n font-size: 12px;\n z-index: 100;\n opacity: 0.9;\n transition: var(--suite-run-transition);\n}\n\n.keyboard-shortcuts:hover {\n opacity: 1;\n}\n\n.shortcuts-header {\n display: flex;\n align-items: center;\n gap: 6px;\n font-weight: 600;\n color: var(--suite-run-text);\n margin-bottom: 10px;\n padding-bottom: 8px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.shortcuts-header i {\n color: var(--suite-run-primary);\n}\n\n.shortcuts-close {\n margin-left: auto;\n background: none;\n border: none;\n cursor: pointer;\n color: var(--suite-run-text-muted);\n font-size: 12px;\n padding: 2px 4px;\n border-radius: 4px;\n transition: var(--suite-run-transition);\n}\n\n.shortcuts-close:hover {\n color: var(--suite-run-text);\n background: var(--suite-run-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 gap: 16px;\n}\n\n.shortcut-item span:first-child {\n color: var(--suite-run-text-secondary);\n}\n\n.shortcut-keys {\n display: flex;\n gap: 4px;\n}\n\nkbd {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 20px;\n padding: 0 6px;\n background: linear-gradient(180deg, #f8fafc 0%, #e2e8f0 100%);\n border: 1px solid #cbd5e1;\n border-radius: 4px;\n font-family: inherit;\n font-size: 10px;\n font-weight: 600;\n color: var(--suite-run-text);\n box-shadow: 0 1px 0 #94a3b8;\n}\n\n/* ===================================\n Responsive Design - Tablet\n =================================== */\n@media (max-width: 1024px) {\n .suite-run-header {\n padding: 16px 20px;\n }\n\n .metrics-bar {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .result-hero-stats {\n flex-direction: column;\n gap: 16px;\n }\n\n .stat-divider {\n display: none;\n }\n\n .details-grid {\n grid-template-columns: 1fr;\n }\n\n .tab-shortcut {\n display: none;\n }\n}\n\n/* ===================================\n Responsive Design - Mobile\n =================================== */\n@media (max-width: 768px) {\n .suite-run-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 .suite-run-icon {\n width: 48px;\n height: 48px;\n font-size: 20px;\n }\n\n .suite-run-info h1 {\n font-size: 20px;\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: 8px;\n }\n\n .metric-card {\n padding: 12px;\n flex-direction: column;\n text-align: center;\n gap: 8px;\n }\n\n .metric-icon {\n width: 36px;\n height: 36px;\n }\n\n .metric-value {\n font-size: 16px;\n }\n\n .results-summary {\n gap: 8px;\n padding-top: 16px;\n flex-wrap: nowrap;\n overflow-x: auto;\n padding-bottom: 8px;\n margin-bottom: -8px;\n }\n\n .result-item {\n padding: 10px 12px;\n min-width: 90px;\n }\n\n .result-icon {\n font-size: 20px;\n }\n\n .result-count {\n font-size: 18px;\n }\n\n .tabs {\n padding: 0 16px;\n }\n\n .tab {\n padding: 14px 16px;\n font-size: 13px;\n }\n\n .tab-content {\n padding: 16px;\n }\n\n .result-hero {\n padding: 32px 20px;\n }\n\n .result-hero-icon {\n font-size: 56px;\n }\n\n .result-hero-text h2 {\n font-size: 24px;\n }\n\n .stat-value {\n font-size: 20px;\n }\n\n .test-run-item {\n padding: 14px;\n }\n\n .run-sequence {\n width: 28px;\n height: 28px;\n font-size: 12px;\n }\n\n .run-icon {\n width: 36px;\n height: 36px;\n font-size: 14px;\n }\n\n .run-name {\n font-size: 13px;\n }\n\n .run-meta {\n gap: 10px;\n font-size: 11px;\n }\n\n .empty-state {\n padding: 40px 16px;\n }\n\n .empty-icon {\n width: 64px;\n height: 64px;\n }\n\n .empty-icon i {\n font-size: 28px;\n }\n\n .details-card {\n padding: 16px;\n }\n\n .details-grid {\n gap: 16px;\n }\n\n .keyboard-shortcuts, .shortcuts-toggle {\n display: none;\n }\n}\n\n/* ===================================\n Responsive Design - Small Mobile\n =================================== */\n@media (max-width: 480px) {\n .suite-run-header {\n padding: 12px;\n }\n\n .breadcrumb {\n font-size: 12px;\n margin-bottom: 12px;\n }\n\n .suite-run-icon {\n width: 44px;\n height: 44px;\n font-size: 18px;\n }\n\n .suite-run-info h1 {\n font-size: 18px;\n }\n\n .suite-run-meta {\n gap: 8px;\n }\n\n .status-badge {\n padding: 4px 10px;\n font-size: 11px;\n }\n\n .meta-tag {\n font-size: 11px;\n padding: 3px 8px;\n }\n\n .metrics-bar {\n grid-template-columns: 1fr 1fr;\n }\n\n .metric-card {\n padding: 10px;\n gap: 6px;\n }\n\n .metric-icon {\n width: 32px;\n height: 32px;\n font-size: 14px;\n }\n\n .metric-value {\n font-size: 14px;\n }\n\n .metric-label {\n font-size: 9px;\n }\n\n .result-item {\n padding: 8px 10px;\n min-width: 80px;\n gap: 8px;\n }\n\n .result-icon {\n font-size: 18px;\n }\n\n .result-count {\n font-size: 16px;\n }\n\n .result-label {\n font-size: 9px;\n }\n\n .tabs {\n padding: 0 12px;\n }\n\n .tab {\n padding: 12px 14px;\n gap: 6px;\n }\n\n .tab i {\n font-size: 14px;\n }\n\n .tab-content {\n padding: 12px;\n }\n\n .result-hero {\n padding: 24px 16px;\n }\n\n .result-hero-icon {\n font-size: 48px;\n margin-bottom: 16px;\n }\n\n .result-hero-text h2 {\n font-size: 20px;\n margin-bottom: 12px;\n }\n\n .stat-value {\n font-size: 18px;\n }\n\n .stat-label {\n font-size: 10px;\n }\n\n .progress-section {\n padding: 16px;\n }\n\n .progress-info {\n font-size: 14px;\n }\n\n .test-run-item {\n padding: 12px;\n gap: 10px;\n }\n\n .run-sequence {\n width: 24px;\n height: 24px;\n font-size: 11px;\n }\n\n .run-icon {\n width: 32px;\n height: 32px;\n font-size: 12px;\n border-radius: 8px;\n }\n\n .run-name {\n font-size: 12px;\n margin-bottom: 3px;\n }\n\n .run-meta {\n gap: 8px;\n font-size: 10px;\n }\n\n .empty-state {\n padding: 32px 12px;\n }\n\n .empty-state h4 {\n font-size: 16px;\n }\n\n .empty-state p {\n font-size: 13px;\n }\n\n .details-card {\n padding: 14px;\n }\n\n .details-card h3 {\n font-size: 14px;\n margin-bottom: 16px;\n }\n\n .detail-label {\n font-size: 10px;\n }\n\n .detail-value {\n font-size: 13px;\n }\n}\n\n/* ===================================\n Touch Device Optimizations\n =================================== */\n@media (hover: none) and (pointer: coarse) {\n .test-run-item {\n min-height: 64px;\n }\n\n .test-run-item:hover {\n transform: none;\n background: var(--suite-run-card);\n border-color: var(--suite-run-border);\n }\n\n .test-run-item:active {\n background: var(--suite-run-primary-light);\n border-color: #93c5fd;\n }\n\n .tab:hover {\n background: transparent;\n color: var(--suite-run-text-secondary);\n }\n\n .tab:active {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n }\n\n .metric-card:hover {\n transform: none;\n box-shadow: none;\n }\n\n .result-item:hover {\n transform: none;\n box-shadow: none;\n }\n\n .keyboard-shortcuts {\n display: none;\n }\n}\n\n/* ===================================\n Print Styles\n =================================== */\n@media print {\n .suite-run-header {\n background: white;\n box-shadow: none;\n border-bottom: 2px solid #000;\n }\n\n .tabs-container,\n .header-actions,\n .keyboard-shortcuts {\n display: none;\n }\n\n .tab-content {\n padding: 20px 0;\n }\n\n .result-hero,\n .test-run-item,\n .details-card {\n box-shadow: none;\n border: 1px solid #ccc;\n }\n}\n\n/* ===================================\n Dark Mode Support (Future)\n =================================== */\n@media (prefers-color-scheme: dark) {\n /* Ready for dark mode implementation */\n}\n\n/* ===================================\n Tags Bar - Sleek Inline Display\n =================================== */\n.tags-bar {\n margin-top: 16px;\n padding: 8px 14px;\n background: linear-gradient(135deg, rgba(59, 130, 246, 0.04) 0%, rgba(59, 130, 246, 0.08) 100%);\n border: 1px solid rgba(59, 130, 246, 0.15);\n border-radius: 8px;\n max-width: 600px;\n}\n\n.tags-bar-content {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.tags-bar-label {\n color: var(--suite-run-text-secondary);\n font-size: 14px;\n}\n\n.tags-bar-label i {\n opacity: 0.6;\n}\n\n.tags-bar-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n flex: 1;\n}\n\n.tag-inline {\n display: inline-flex;\n align-items: center;\n padding: 4px 10px;\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n letter-spacing: 0.01em;\n}\n\n.tags-bar-empty {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n opacity: 0.7;\n flex: 1;\n}\n\n.tags-bar-edit {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n background: transparent;\n border: 1px dashed var(--suite-run-border);\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.tags-bar-edit:hover {\n border-color: var(--suite-run-primary);\n color: var(--suite-run-primary);\n background: var(--suite-run-primary-light);\n}\n\n.tags-bar-edit i {\n font-size: 10px;\n}\n\n/* ===================================\n Tags Editor Panel - Expanded Edit Mode\n =================================== */\n.tags-editor-panel {\n margin-top: 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-primary);\n border-radius: 10px;\n overflow: hidden;\n box-shadow: 0 4px 12px rgba(59, 130, 246, 0.1);\n max-width: 600px;\n}\n\n.tags-editor-header {\n display: flex;\n align-items: center;\n padding: 12px 16px;\n background: var(--suite-run-primary-light);\n border-bottom: 1px solid rgba(59, 130, 246, 0.2);\n}\n\n.tags-editor-title {\n font-size: 13px;\n font-weight: 600;\n color: var(--suite-run-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.tags-editor-body {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.tags-editor-chips {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n min-height: 32px;\n}\n\n.tag-editable {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 8px 5px 12px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-primary);\n color: var(--suite-run-primary);\n border-radius: 14px;\n font-size: 12px;\n font-weight: 500;\n}\n\n.tag-remove-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n background: transparent;\n border: none;\n color: var(--suite-run-primary);\n cursor: pointer;\n border-radius: 50%;\n font-size: 9px;\n opacity: 0.6;\n transition: var(--suite-run-transition);\n}\n\n.tag-remove-btn:hover {\n opacity: 1;\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.tags-empty-hint {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n font-style: italic;\n padding: 4px 0;\n}\n\n.tags-editor-input {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.tag-text-input {\n flex: 1;\n padding: 10px 14px;\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n font-size: 13px;\n background: var(--suite-run-neutral-light);\n}\n\n.tag-text-input:focus {\n outline: none;\n border-color: var(--suite-run-primary);\n background: var(--suite-run-card);\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.tag-text-input::placeholder {\n color: var(--suite-run-text-secondary);\n opacity: 0.6;\n}\n\n.tags-editor-footer {\n display: flex;\n justify-content: flex-start;\n gap: 8px;\n padding: 12px 16px;\n background: var(--suite-run-neutral-light);\n border-top: 1px solid var(--suite-run-border);\n}\n\n/* ===================================\n Runs Toolbar\n =================================== */\n.runs-toolbar {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n padding: 12px 16px;\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n flex-wrap: wrap;\n gap: 12px;\n}\n\n.run-filters {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.filter-btn {\n padding: 6px 14px;\n border: 1px solid var(--suite-run-border);\n background: var(--suite-run-card);\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n cursor: pointer;\n transition: var(--suite-run-transition);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-btn:hover {\n border-color: var(--suite-run-primary);\n color: var(--suite-run-primary);\n}\n\n.filter-btn.active {\n background: var(--suite-run-primary);\n border-color: var(--suite-run-primary);\n color: white;\n}\n\n.filter-btn.passed:hover,\n.filter-btn.passed.active {\n background: var(--suite-run-success);\n border-color: var(--suite-run-success);\n color: white;\n}\n\n.filter-btn.failed:hover,\n.filter-btn.failed.active {\n background: var(--suite-run-danger);\n border-color: var(--suite-run-danger);\n color: white;\n}\n\n.filter-btn.error:hover,\n.filter-btn.error.active {\n background: var(--suite-run-warning);\n border-color: var(--suite-run-warning);\n color: white;\n}\n\n.runs-actions {\n display: flex;\n gap: 8px;\n}\n\n/* ===================================\n Test Run Card (Expandable)\n =================================== */\n.test-run-card {\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n overflow: hidden;\n transition: var(--suite-run-transition);\n margin-bottom: 10px;\n}\n\n.test-run-card:hover {\n box-shadow: var(--suite-run-shadow);\n}\n\n.test-run-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 16px;\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.test-run-item:hover {\n background: var(--suite-run-primary-light);\n}\n\n.run-header-row {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 4px;\n}\n\n.run-feedback-indicator {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 2px 8px;\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.run-feedback-indicator i {\n font-size: 10px;\n}\n\n.run-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-top: 6px;\n}\n\n.tag-mini {\n display: inline-flex;\n padding: 2px 8px;\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-text-secondary);\n border-radius: 10px;\n font-size: 10px;\n font-weight: 500;\n}\n\n.tag-chip {\n display: inline-flex;\n align-items: center;\n padding: 3px 10px;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n border: 1px solid #bfdbfe;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 500;\n color: #1d4ed8;\n}\n\n.run-expand {\n color: var(--suite-run-text-secondary);\n transition: var(--suite-run-transition);\n}\n\n.test-run-item:hover .run-expand {\n color: var(--suite-run-primary);\n}\n\n.run-cost {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.run-cost i {\n font-size: 10px;\n opacity: 0.7;\n}\n\n/* ===================================\n Inline Feedback\n =================================== */\n.inline-feedback {\n padding: 0 16px 16px;\n animation: slideDown 0.2s ease-out;\n}\n\n@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.feedback-divider {\n height: 1px;\n background: var(--suite-run-border);\n margin-bottom: 16px;\n}\n\n.feedback-section {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.feedback-label {\n font-size: 14px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.inline-rating {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.rating-numbers {\n display: flex;\n gap: 6px;\n flex-wrap: wrap;\n}\n\n.rating-btn {\n width: 36px;\n height: 36px;\n border: 2px solid var(--suite-run-border);\n border-radius: 8px;\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-text-secondary);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.rating-btn:hover,\n.rating-btn.hover {\n transform: scale(1.1);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n}\n\n.rating-btn.low:hover,\n.rating-btn.low.hover {\n border-color: var(--suite-run-danger);\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.rating-btn.mid:hover,\n.rating-btn.mid.hover {\n border-color: var(--suite-run-warning);\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.rating-btn.high:hover,\n.rating-btn.high.hover {\n border-color: var(--suite-run-success);\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.rating-btn.selected {\n transform: scale(1.1);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n}\n\n.rating-btn.selected.low {\n border-color: var(--suite-run-danger);\n background: var(--suite-run-danger);\n color: white;\n}\n\n.rating-btn.selected.mid {\n border-color: var(--suite-run-warning);\n background: var(--suite-run-warning);\n color: white;\n}\n\n.rating-btn.selected.high {\n border-color: var(--suite-run-success);\n background: var(--suite-run-success);\n color: white;\n}\n\n.rating-info {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 14px;\n background: var(--suite-run-neutral-light);\n border-radius: 8px;\n}\n\n.rating-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--suite-run-text);\n}\n\n.rating-label-text {\n font-size: 13px;\n color: var(--suite-run-text-secondary);\n}\n\n.correctness-row {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.correctness-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--suite-run-text);\n}\n\n.correctness-options {\n display: flex;\n gap: 16px;\n}\n\n.radio-opt {\n display: flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--suite-run-text-secondary);\n}\n\n.radio-opt input[type=\"radio\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n}\n\n.comments-row {\n width: 100%;\n}\n\n.feedback-textarea {\n width: 100%;\n padding: 12px;\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n}\n\n.feedback-textarea:focus {\n outline: none;\n border-color: var(--suite-run-primary);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n\n.feedback-actions {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n padding-top: 8px;\n}\n\n/* ===================================\n Mobile Responsive Updates\n =================================== */\n@media (max-width: 768px) {\n .tags-bar {\n padding: 8px 12px;\n }\n\n .tags-bar-content {\n gap: 8px;\n }\n\n .tag-inline {\n padding: 3px 8px;\n font-size: 10px;\n }\n\n .tags-editor-panel {\n margin-top: 12px;\n }\n\n .tags-editor-body {\n padding: 12px;\n }\n\n .tags-editor-footer {\n padding: 10px 12px;\n }\n\n .runs-toolbar {\n flex-direction: column;\n align-items: stretch;\n }\n\n .run-filters {\n justify-content: center;\n }\n\n .runs-actions {\n justify-content: center;\n }\n\n .rating-numbers {\n justify-content: center;\n }\n\n .rating-btn {\n width: 32px;\n height: 32px;\n font-size: 12px;\n }\n\n .correctness-row {\n flex-direction: column;\n align-items: flex-start;\n gap: 8px;\n }\n\n .feedback-actions {\n flex-direction: column;\n }\n\n .feedback-actions button {\n width: 100%;\n }\n}\n\n/* ===================================\n Animations\n =================================== */\n@keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n\n.result-hero.running .result-hero-icon {\n animation: pulse 2s ease-in-out infinite;\n}\n\n/* Tab content fade in */\n.overview-tab,\n.runs-tab,\n.details-tab,\n.analytics-tab {\n animation: fadeIn 0.3s ease;\n}\n\n/* ===================================\n Analytics Tab\n =================================== */\n.analytics-tab {\n max-width: 1200px;\n margin: 0 auto;\n width: 100%;\n display: flex;\n flex-direction: column;\n gap: 24px;\n}\n\n.analytics-section {\n background: var(--suite-run-card);\n border-radius: var(--suite-run-radius);\n padding: 24px;\n box-shadow: var(--suite-run-shadow);\n}\n\n.analytics-section h3 {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--suite-run-text);\n padding-bottom: 12px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.analytics-section h3 i {\n color: var(--suite-run-primary);\n}\n\n.analytics-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: 16px;\n margin-bottom: 20px;\n padding-bottom: 12px;\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.analytics-header h3 {\n margin: 0;\n padding: 0;\n border: none;\n}\n\n.analytics-legend {\n display: flex;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 500;\n}\n\n.legend-item.passed {\n color: var(--suite-run-success);\n}\n\n.legend-item.failed {\n color: var(--suite-run-danger);\n}\n\n.legend-item.error {\n color: var(--suite-run-warning);\n}\n\n.legend-item.skipped {\n color: var(--suite-run-neutral);\n}\n\n/* Performance Matrix */\n.performance-matrix {\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.matrix-row {\n display: grid;\n grid-template-columns: 2fr 120px 150px 100px 100px;\n border-bottom: 1px solid var(--suite-run-border);\n transition: var(--suite-run-transition);\n cursor: pointer;\n}\n\n.matrix-row:last-child {\n border-bottom: none;\n}\n\n.matrix-row:hover:not(.matrix-header-row) {\n background: var(--suite-run-primary-light);\n}\n\n.matrix-row.passed {\n border-left: 4px solid var(--suite-run-success);\n}\n\n.matrix-row.failed {\n border-left: 4px solid var(--suite-run-danger);\n}\n\n.matrix-row.error {\n border-left: 4px solid var(--suite-run-warning);\n}\n\n.matrix-row.skipped {\n border-left: 4px solid var(--suite-run-neutral);\n}\n\n.matrix-header-row {\n background: var(--suite-run-neutral-light);\n font-weight: 600;\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n cursor: default;\n}\n\n.matrix-cell {\n padding: 12px 16px;\n display: flex;\n align-items: center;\n}\n\n.test-name-cell {\n gap: 12px;\n}\n\n.test-sequence {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--suite-run-neutral-light);\n border-radius: 50%;\n font-size: 11px;\n font-weight: 600;\n color: var(--suite-run-text-secondary);\n flex-shrink: 0;\n}\n\n.test-name {\n font-weight: 500;\n color: var(--suite-run-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.status-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n}\n\n.status-indicator.status-passed {\n color: var(--suite-run-success);\n}\n\n.status-indicator.status-failed {\n color: var(--suite-run-danger);\n}\n\n.status-indicator.status-error {\n color: var(--suite-run-warning);\n}\n\n.status-indicator.status-skipped {\n color: var(--suite-run-neutral);\n}\n\n.status-indicator.status-pending {\n color: var(--suite-run-info);\n}\n\n.status-indicator.status-running {\n color: var(--suite-run-primary);\n}\n\n.score-bar {\n position: relative;\n width: 100%;\n height: 20px;\n background: var(--suite-run-neutral-light);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.score-fill {\n height: 100%;\n border-radius: 10px;\n transition: width 0.3s ease;\n}\n\n.score-fill.high {\n background: linear-gradient(90deg, var(--suite-run-success) 0%, #34d399 100%);\n}\n\n.score-fill.medium {\n background: linear-gradient(90deg, var(--suite-run-warning) 0%, #fbbf24 100%);\n}\n\n.score-fill.low {\n background: linear-gradient(90deg, var(--suite-run-danger) 0%, #f87171 100%);\n}\n\n.score-text {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n font-size: 11px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.na-value {\n color: var(--suite-run-text-secondary);\n opacity: 0.6;\n}\n\n/* Summary Statistics Grid */\n.stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 16px;\n}\n\n.stat-card {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 20px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border: 1px solid var(--suite-run-border);\n border-radius: 12px;\n transition: var(--suite-run-transition);\n}\n\n.stat-card:hover {\n transform: translateY(-2px);\n box-shadow: var(--suite-run-shadow);\n}\n\n.stat-icon {\n width: 48px;\n height: 48px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 12px;\n font-size: 20px;\n}\n\n.stat-icon.passed {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.stat-icon.failed {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.stat-icon.score {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.stat-icon.duration {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n.stat-icon.cost {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.stat-content {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.stat-card .stat-value {\n font-size: 24px;\n font-weight: 700;\n color: var(--suite-run-text);\n}\n\n.stat-card .stat-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.stat-percent {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n/* Responsive Analytics */\n@media (max-width: 768px) {\n .analytics-header {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .matrix-row {\n grid-template-columns: 1fr;\n gap: 8px;\n padding: 12px;\n }\n\n .matrix-header-row {\n display: none;\n }\n\n .matrix-cell {\n padding: 4px 0;\n }\n\n .test-name-cell::before,\n .status-cell::before,\n .score-cell::before,\n .duration-cell::before,\n .cost-cell::before {\n font-size: 10px;\n font-weight: 600;\n color: var(--suite-run-text-secondary);\n text-transform: uppercase;\n margin-right: 8px;\n min-width: 80px;\n }\n\n .status-cell::before { content: 'Status:'; }\n .score-cell::before { content: 'Score:'; }\n .duration-cell::before { content: 'Duration:'; }\n .cost-cell::before { content: 'Cost:'; }\n\n .stats-grid {\n grid-template-columns: 1fr 1fr;\n }\n\n .stat-card {\n padding: 16px;\n }\n\n .stat-icon {\n width: 40px;\n height: 40px;\n font-size: 16px;\n }\n\n .stat-card .stat-value {\n font-size: 20px;\n }\n}\n\n/* Focus States for Accessibility */\n.tab:focus-visible,\n.test-run-item:focus-visible,\nbutton:focus-visible {\n outline: 2px solid var(--suite-run-primary);\n outline-offset: 2px;\n}\n\n/* ===================================\n Analytics Loading State\n =================================== */\n.analytics-loading {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 60px 20px;\n color: var(--suite-run-text-secondary);\n}\n\n.analytics-loading i {\n font-size: 32px;\n color: var(--suite-run-primary);\n}\n\n/* ===================================\n Results Table\n =================================== */\n.results-table-wrapper {\n border: 1px solid var(--suite-run-border);\n border-radius: 8px;\n overflow: hidden;\n}\n\n.results-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n}\n\n.results-table thead {\n background: var(--suite-run-neutral-light);\n}\n\n.results-table th {\n padding: 12px 16px;\n text-align: left;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--suite-run-text-secondary);\n border-bottom: 1px solid var(--suite-run-border);\n}\n\n.results-table td {\n padding: 12px 16px;\n border-bottom: 1px solid #f1f5f9;\n vertical-align: middle;\n}\n\n.results-table tbody tr:last-child td {\n border-bottom: none;\n}\n\n/* Column widths - Fixed columns fit content, name column takes remainder (max 50%) */\n.seq-col {\n width: 40px;\n min-width: 40px;\n text-align: center;\n white-space: nowrap;\n}\n\n.name-col {\n /* Take remaining space, but cap at 50% of table width */\n width: auto;\n max-width: 50%;\n}\n\n.status-col {\n width: 1%; /* Shrink to fit content */\n white-space: nowrap;\n}\n\n.score-col {\n width: 1%; /* Shrink to fit content */\n min-width: 120px; /* Score bar needs some minimum width */\n white-space: nowrap;\n}\n\n.duration-col {\n width: 1%; /* Shrink to fit content */\n white-space: nowrap;\n text-align: right;\n}\n\n.cost-col {\n width: 1%; /* Shrink to fit content */\n white-space: nowrap;\n text-align: right;\n}\n\n/* Result Row */\n.result-row {\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.result-row:hover {\n background: var(--suite-run-primary-light);\n}\n\n.result-row.row-passed {\n border-left: 4px solid var(--suite-run-success);\n}\n\n.result-row.row-failed {\n border-left: 4px solid var(--suite-run-danger);\n}\n\n.result-row.row-error {\n border-left: 4px solid var(--suite-run-warning);\n}\n\n.result-row.row-skipped {\n border-left: 4px solid var(--suite-run-neutral);\n}\n\n/* Test Name Wrapper */\n.test-name-wrapper {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.test-name-wrapper .test-name {\n font-weight: 500;\n color: var(--suite-run-text);\n}\n\n.test-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n/* Score Display */\n.score-display {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.score-bar-mini {\n flex: 1;\n height: 6px;\n background: var(--suite-run-neutral-light);\n border-radius: 3px;\n overflow: hidden;\n min-width: 60px;\n}\n\n.score-bar-mini .score-fill {\n height: 100%;\n border-radius: 3px;\n transition: width 0.3s ease;\n}\n\n.score-bar-mini .score-fill.high {\n background: var(--suite-run-success);\n}\n\n.score-bar-mini .score-fill.medium {\n background: var(--suite-run-warning);\n}\n\n.score-bar-mini .score-fill.low {\n background: var(--suite-run-danger);\n}\n\n.score-display .score-text {\n position: static;\n transform: none;\n font-size: 12px;\n font-weight: 600;\n color: var(--suite-run-text);\n min-width: 35px;\n text-align: right;\n}\n\n/* Status Badge in Table */\n.results-table .status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n}\n\n.results-table .status-badge.status-passed {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.results-table .status-badge.status-failed {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.results-table .status-badge.status-error {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.results-table .status-badge.status-skipped {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\n}\n\n.results-table .status-badge.status-pending {\n background: var(--suite-run-info-light);\n color: var(--suite-run-info);\n}\n\n.results-table .status-badge.status-running {\n background: var(--suite-run-primary-light);\n color: var(--suite-run-primary);\n}\n\n/* Responsive Results Table */\n@media (max-width: 768px) {\n .results-table-wrapper {\n overflow-x: auto;\n }\n\n .results-table {\n min-width: 600px;\n }\n\n .results-table th,\n .results-table td {\n padding: 10px 12px;\n }\n\n .name-col {\n min-width: 150px;\n }\n}\n\n/* ===================================\n High Contrast Mode\n =================================== */\n@media (prefers-contrast: high) {\n .status-badge,\n .status-inline {\n border: 2px solid currentColor;\n }\n\n .test-run-item {\n border-width: 2px;\n }\n\n .tab.active {\n border-bottom-width: 4px;\n }\n}\n\n/* ===================================\n Evaluation Summary\n =================================== */\n.evaluation-summary {\n margin-top: 20px;\n}\n\n.eval-summary-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 16px;\n}\n\n.eval-summary-card {\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n overflow: hidden;\n transition: var(--suite-run-transition);\n}\n\n.eval-summary-card:hover {\n box-shadow: var(--suite-run-shadow);\n}\n\n.eval-card-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n background: var(--suite-run-neutral-light);\n border-bottom: 1px solid var(--suite-run-border);\n font-size: 13px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.eval-card-header i {\n color: var(--suite-run-primary);\n}\n\n.eval-card-body {\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.eval-stat-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n}\n\n.eval-stat-label {\n font-size: 12px;\n color: var(--suite-run-text-secondary);\n}\n\n.eval-stat-value {\n font-size: 14px;\n font-weight: 600;\n color: var(--suite-run-text);\n}\n\n.eval-stat-value.correct {\n color: var(--suite-run-success);\n}\n\n.eval-stat-value.incorrect {\n color: var(--suite-run-danger);\n font-weight: 500;\n font-size: 12px;\n}\n\n.eval-stat-value.error {\n color: var(--suite-run-danger);\n}\n\n.eval-stat-value.timeout {\n color: var(--suite-run-warning);\n}\n\n.eval-card-footer {\n padding: 10px 16px;\n background: var(--suite-run-warning-light);\n border-top: 1px solid rgba(245, 158, 11, 0.2);\n}\n\n.pending-badge {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 500;\n color: var(--suite-run-warning);\n}\n\n.pending-badge i {\n font-size: 11px;\n}\n\n/* ===================================\n Needs Review Section\n =================================== */\n.needs-review-section {\n background: var(--suite-run-card);\n border: 1px solid var(--suite-run-border);\n border-radius: var(--suite-run-radius);\n overflow: hidden;\n}\n\n.needs-review-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 14px 20px;\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n border-bottom: 1px solid rgba(245, 158, 11, 0.3);\n}\n\n.needs-review-header h3 {\n margin: 0;\n font-size: 14px;\n font-weight: 600;\n color: #92400e;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.needs-review-header h3 i {\n font-size: 16px;\n}\n\n.review-count {\n font-size: 12px;\n font-weight: 500;\n color: #92400e;\n background: rgba(255, 255, 255, 0.6);\n padding: 2px 10px;\n border-radius: 12px;\n}\n\n.needs-review-list {\n padding: 8px;\n}\n\n.review-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n border-radius: 8px;\n cursor: pointer;\n transition: var(--suite-run-transition);\n}\n\n.review-item:hover {\n background: var(--suite-run-primary-light);\n}\n\n.review-item-icon {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 50%;\n font-size: 14px;\n flex-shrink: 0;\n}\n\n.review-item.high-priority .review-item-icon {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.review-item.medium-priority .review-item-icon {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.review-item:not(.high-priority):not(.medium-priority) .review-item-icon {\n background: var(--suite-run-neutral-light);\n color: var(--suite-run-neutral);\n}\n\n.review-item-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.review-item-name {\n font-size: 13px;\n font-weight: 500;\n color: var(--suite-run-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.review-item-reason {\n font-size: 11px;\n color: var(--suite-run-text-secondary);\n}\n\n.review-item-action {\n color: var(--suite-run-text-secondary);\n font-size: 12px;\n}\n\n.review-item:hover .review-item-action {\n color: var(--suite-run-primary);\n}\n\n.review-more {\n display: flex;\n justify-content: center;\n padding: 8px;\n border-top: 1px solid var(--suite-run-border);\n}\n\n/* Mobile Responsive for Evaluation */\n@media (max-width: 768px) {\n .eval-summary-grid {\n grid-template-columns: 1fr;\n }\n\n .eval-card-header {\n padding: 10px 14px;\n font-size: 12px;\n }\n\n .eval-card-body {\n padding: 12px 14px;\n }\n\n .needs-review-header {\n padding: 12px 16px;\n }\n\n .needs-review-header h3 {\n font-size: 13px;\n }\n\n .review-item {\n padding: 10px 12px;\n }\n\n .review-item-icon {\n width: 28px;\n height: 28px;\n font-size: 12px;\n }\n}\n\n/* ===================================\n Feedback Column in Analytics Table\n =================================== */\n.feedback-col {\n width: 1%; /* Shrink to fit content */\n white-space: nowrap;\n text-align: center;\n}\n\n.feedback-display {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n}\n\n.feedback-rating {\n font-size: 13px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 4px;\n background: var(--suite-run-neutral-light);\n}\n\n.feedback-rating.low {\n background: var(--suite-run-danger-light);\n color: var(--suite-run-danger);\n}\n\n.feedback-rating.mid {\n background: var(--suite-run-warning-light);\n color: var(--suite-run-warning);\n}\n\n.feedback-rating.high {\n background: var(--suite-run-success-light);\n color: var(--suite-run-success);\n}\n\n.feedback-correctness i {\n font-size: 12px;\n}\n\n.feedback-correctness i.correct {\n color: var(--suite-run-success);\n}\n\n.feedback-correctness i.incorrect {\n color: var(--suite-run-danger);\n}\n\n.na-value.needs-review {\n color: var(--suite-run-warning);\n opacity: 0.7;\n}\n\n.na-value.needs-review i {\n font-size: 14px;\n}\n"] }]
|
|
2275
|
+
}], () => [{ type: i0.ElementRef }, { type: i1.SharedService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i3.TestingDialogService }, { type: i3.EvaluationPreferencesService }], { handleKeyboardShortcut: [{
|
|
2276
|
+
type: HostListener,
|
|
2277
|
+
args: ['document:keydown', ['$event']]
|
|
2278
|
+
}] }); })();
|
|
2279
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TestSuiteRunFormComponentExtended, { className: "TestSuiteRunFormComponentExtended", filePath: "src/lib/custom/Tests/test-suite-run-form.component.ts", lineNumber: 34 }); })();
|
|
567
2280
|
export function LoadTestSuiteRunFormComponentExtended() {
|
|
568
2281
|
// Prevents tree-shaking
|
|
569
2282
|
}
|