@memberjunction/ng-core-entity-forms 2.129.0 → 2.130.1
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 +96 -9
- package/dist/lib/custom/Tests/test-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-form.component.js +1529 -277
- package/dist/lib/custom/Tests/test-form.component.js.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.d.ts +50 -9
- package/dist/lib/custom/Tests/test-run-form.component.d.ts.map +1 -1
- package/dist/lib/custom/Tests/test-run-form.component.js +1079 -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 +228 -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 +3309 -201
- 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 +88 -3
- 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 +1976 -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,1310 @@ 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, viewContainerRef) {
|
|
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;
|
|
1362
|
+
this.viewContainerRef = viewContainerRef;
|
|
258
1363
|
this.destroy$ = new Subject();
|
|
259
1364
|
// UI state
|
|
260
1365
|
this.activeTab = 'overview';
|
|
261
1366
|
this.loading = false;
|
|
1367
|
+
this.loadingTestRuns = false;
|
|
1368
|
+
this.loadingFeedbacks = false;
|
|
262
1369
|
this.error = null;
|
|
263
1370
|
this.testRunsLoaded = false;
|
|
1371
|
+
this.feedbacksLoaded = false;
|
|
1372
|
+
this.isRefreshing = false;
|
|
1373
|
+
this.autoRefreshEnabled = false;
|
|
264
1374
|
// Related entities
|
|
265
1375
|
this.testSuite = null;
|
|
266
1376
|
this.testRuns = [];
|
|
1377
|
+
this.feedbacks = new Map();
|
|
1378
|
+
// Tags
|
|
1379
|
+
this.tags = [];
|
|
1380
|
+
this.newTag = '';
|
|
1381
|
+
this.editingTags = false;
|
|
1382
|
+
this.savingTags = false;
|
|
1383
|
+
// Inline feedback
|
|
1384
|
+
this.expandedRunId = null;
|
|
1385
|
+
this.inlineRating = 0;
|
|
1386
|
+
this.inlineHoverRating = 0;
|
|
1387
|
+
this.inlineIsCorrect = null;
|
|
1388
|
+
this.inlineComments = '';
|
|
1389
|
+
this.savingInlineFeedback = false;
|
|
1390
|
+
// Filter for test runs
|
|
1391
|
+
this.runStatusFilter = null;
|
|
1392
|
+
// Keyboard shortcuts
|
|
1393
|
+
this.keyboardShortcutsEnabled = true;
|
|
1394
|
+
this.showShortcuts = false; // Hidden by default
|
|
1395
|
+
this.shortcutsSettingEntity = null;
|
|
1396
|
+
this.metadata = new Metadata();
|
|
1397
|
+
// Evaluation system
|
|
1398
|
+
this.evalPreferences = {
|
|
1399
|
+
showExecution: true,
|
|
1400
|
+
showHuman: true,
|
|
1401
|
+
showAuto: false
|
|
1402
|
+
};
|
|
1403
|
+
this.testRunsWithFeedback = [];
|
|
1404
|
+
this.evaluationMetrics = null;
|
|
1405
|
+
this.needsReviewItems = [];
|
|
267
1406
|
}
|
|
268
1407
|
async ngOnInit() {
|
|
269
1408
|
await super.ngOnInit();
|
|
1409
|
+
this.loadShortcutsSetting();
|
|
1410
|
+
// Subscribe to evaluation preferences
|
|
1411
|
+
this.evalPrefsService.preferences$
|
|
1412
|
+
.pipe(takeUntil(this.destroy$))
|
|
1413
|
+
.subscribe(prefs => {
|
|
1414
|
+
this.evalPreferences = prefs;
|
|
1415
|
+
this.cdr.markForCheck();
|
|
1416
|
+
});
|
|
270
1417
|
if (this.record && this.record.ID) {
|
|
271
1418
|
await this.loadRelatedData();
|
|
1419
|
+
this.parseTags();
|
|
1420
|
+
// Auto-refresh for running suite executions
|
|
1421
|
+
if (this.record.Status === 'Running' || this.record.Status === 'Pending') {
|
|
1422
|
+
this.startAutoRefresh();
|
|
1423
|
+
}
|
|
272
1424
|
}
|
|
273
1425
|
}
|
|
1426
|
+
parseTags() {
|
|
1427
|
+
this.tags = TagsHelper.parseTags(this.record.Tags);
|
|
1428
|
+
}
|
|
274
1429
|
ngOnDestroy() {
|
|
275
1430
|
this.destroy$.next();
|
|
276
1431
|
this.destroy$.complete();
|
|
277
1432
|
}
|
|
1433
|
+
// Keyboard shortcuts
|
|
1434
|
+
handleKeyboardShortcut(event) {
|
|
1435
|
+
if (!this.keyboardShortcutsEnabled)
|
|
1436
|
+
return;
|
|
1437
|
+
// Cmd/Ctrl + R: Refresh
|
|
1438
|
+
if ((event.metaKey || event.ctrlKey) && event.key === 'r' && !event.shiftKey) {
|
|
1439
|
+
event.preventDefault();
|
|
1440
|
+
this.refresh();
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
// Cmd/Ctrl + Shift + R: Re-run suite
|
|
1444
|
+
if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'r') {
|
|
1445
|
+
event.preventDefault();
|
|
1446
|
+
this.reRunSuite();
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
// Number keys for tabs (1-4)
|
|
1450
|
+
if (!event.metaKey && !event.ctrlKey && !event.altKey) {
|
|
1451
|
+
switch (event.key) {
|
|
1452
|
+
case '1':
|
|
1453
|
+
this.changeTab('overview');
|
|
1454
|
+
break;
|
|
1455
|
+
case '2':
|
|
1456
|
+
this.changeTab('runs');
|
|
1457
|
+
break;
|
|
1458
|
+
case '3':
|
|
1459
|
+
this.changeTab('details');
|
|
1460
|
+
break;
|
|
1461
|
+
case '4':
|
|
1462
|
+
this.changeTab('analytics');
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
startAutoRefresh() {
|
|
1468
|
+
this.autoRefreshEnabled = true;
|
|
1469
|
+
interval(5000)
|
|
1470
|
+
.pipe(takeUntil(this.destroy$))
|
|
1471
|
+
.subscribe(() => {
|
|
1472
|
+
if (this.autoRefreshEnabled && (this.record.Status === 'Running' || this.record.Status === 'Pending')) {
|
|
1473
|
+
this.silentRefresh();
|
|
1474
|
+
}
|
|
1475
|
+
else {
|
|
1476
|
+
this.autoRefreshEnabled = false;
|
|
1477
|
+
}
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
async silentRefresh() {
|
|
1481
|
+
try {
|
|
1482
|
+
await this.record.Load(this.record.ID);
|
|
1483
|
+
this.cdr.markForCheck();
|
|
1484
|
+
}
|
|
1485
|
+
catch {
|
|
1486
|
+
// Silently fail on auto-refresh
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
278
1489
|
async loadRelatedData() {
|
|
279
1490
|
this.loading = true;
|
|
1491
|
+
this.error = null;
|
|
280
1492
|
try {
|
|
281
1493
|
// Load test suite
|
|
282
1494
|
if (this.record.SuiteID) {
|
|
@@ -290,16 +1502,22 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
290
1502
|
}
|
|
291
1503
|
catch (error) {
|
|
292
1504
|
console.error('Error loading related data:', error);
|
|
293
|
-
this.error = 'Failed to load related data';
|
|
1505
|
+
this.error = 'Failed to load related data. Click to retry.';
|
|
294
1506
|
}
|
|
295
1507
|
finally {
|
|
296
1508
|
this.loading = false;
|
|
297
1509
|
this.cdr.markForCheck();
|
|
298
1510
|
}
|
|
299
1511
|
}
|
|
1512
|
+
async retryLoad() {
|
|
1513
|
+
this.error = null;
|
|
1514
|
+
await this.loadRelatedData();
|
|
1515
|
+
}
|
|
300
1516
|
async loadTestRuns() {
|
|
301
1517
|
if (this.testRunsLoaded)
|
|
302
1518
|
return;
|
|
1519
|
+
this.loadingTestRuns = true;
|
|
1520
|
+
this.cdr.markForCheck();
|
|
303
1521
|
try {
|
|
304
1522
|
const rv = new RunView();
|
|
305
1523
|
const result = await rv.RunView({
|
|
@@ -312,40 +1530,51 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
312
1530
|
this.testRuns = result.Results || [];
|
|
313
1531
|
}
|
|
314
1532
|
this.testRunsLoaded = true;
|
|
315
|
-
|
|
1533
|
+
// Also load feedbacks for these runs
|
|
1534
|
+
if (this.testRuns.length > 0) {
|
|
1535
|
+
await this.loadFeedbacks();
|
|
1536
|
+
}
|
|
316
1537
|
}
|
|
317
1538
|
catch (error) {
|
|
318
1539
|
console.error('Error loading test runs:', error);
|
|
1540
|
+
SharedService.Instance.CreateSimpleNotification('Failed to load test runs', 'error', 3000);
|
|
1541
|
+
}
|
|
1542
|
+
finally {
|
|
1543
|
+
this.loadingTestRuns = false;
|
|
1544
|
+
this.cdr.markForCheck();
|
|
319
1545
|
}
|
|
320
1546
|
}
|
|
321
1547
|
changeTab(tab) {
|
|
322
1548
|
this.activeTab = tab;
|
|
323
1549
|
// Lazy load tabs
|
|
324
|
-
if (tab === 'runs' && !this.testRunsLoaded) {
|
|
1550
|
+
if ((tab === 'runs' || tab === 'analytics') && !this.testRunsLoaded) {
|
|
325
1551
|
this.loadTestRuns();
|
|
326
1552
|
}
|
|
327
1553
|
this.cdr.markForCheck();
|
|
328
1554
|
}
|
|
329
1555
|
getStatusColor() {
|
|
330
1556
|
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 '#
|
|
1557
|
+
case 'Completed': return '#10b981';
|
|
1558
|
+
case 'Failed': return '#ef4444';
|
|
1559
|
+
case 'Running': return '#3b82f6';
|
|
1560
|
+
case 'Pending': return '#8b5cf6';
|
|
1561
|
+
case 'Cancelled': return '#6b7280';
|
|
1562
|
+
default: return '#9ca3af';
|
|
337
1563
|
}
|
|
338
1564
|
}
|
|
339
1565
|
getStatusIcon() {
|
|
340
1566
|
switch (this.record.Status) {
|
|
341
1567
|
case 'Completed': return 'fa-check-circle';
|
|
342
1568
|
case 'Failed': return 'fa-times-circle';
|
|
343
|
-
case 'Running': return 'fa-
|
|
344
|
-
case 'Pending': return 'fa-
|
|
1569
|
+
case 'Running': return 'fa-circle-notch fa-spin';
|
|
1570
|
+
case 'Pending': return 'fa-hourglass-half';
|
|
345
1571
|
case 'Cancelled': return 'fa-ban';
|
|
346
1572
|
default: return 'fa-question-circle';
|
|
347
1573
|
}
|
|
348
1574
|
}
|
|
1575
|
+
getStatusClass() {
|
|
1576
|
+
return `status-${this.record.Status?.toLowerCase() || 'unknown'}`;
|
|
1577
|
+
}
|
|
349
1578
|
calculateDuration() {
|
|
350
1579
|
if (!this.record.TotalDurationSeconds)
|
|
351
1580
|
return 'N/A';
|
|
@@ -373,6 +1602,25 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
373
1602
|
return 0;
|
|
374
1603
|
return (passed / total) * 100;
|
|
375
1604
|
}
|
|
1605
|
+
getRelativeTime(date) {
|
|
1606
|
+
if (!date)
|
|
1607
|
+
return 'N/A';
|
|
1608
|
+
const d = new Date(date);
|
|
1609
|
+
const now = new Date();
|
|
1610
|
+
const diffMs = now.getTime() - d.getTime();
|
|
1611
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
1612
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
1613
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
1614
|
+
if (diffMins < 1)
|
|
1615
|
+
return 'Just now';
|
|
1616
|
+
if (diffMins < 60)
|
|
1617
|
+
return `${diffMins}m ago`;
|
|
1618
|
+
if (diffHours < 24)
|
|
1619
|
+
return `${diffHours}h ago`;
|
|
1620
|
+
if (diffDays < 7)
|
|
1621
|
+
return `${diffDays}d ago`;
|
|
1622
|
+
return d.toLocaleDateString();
|
|
1623
|
+
}
|
|
376
1624
|
openTestSuite() {
|
|
377
1625
|
if (this.testSuite) {
|
|
378
1626
|
SharedService.Instance.OpenEntityRecord('MJ: Test Suites', CompositeKey.FromID(this.testSuite.ID));
|
|
@@ -381,136 +1629,572 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
381
1629
|
openTestRun(runId) {
|
|
382
1630
|
SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(runId));
|
|
383
1631
|
}
|
|
1632
|
+
async reRunSuite() {
|
|
1633
|
+
if (!this.record.SuiteID) {
|
|
1634
|
+
SharedService.Instance.CreateSimpleNotification('Cannot re-run: Suite ID not available', 'error', 3000);
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
this.testingDialogService.OpenSuiteDialog(this.record.SuiteID, this.viewContainerRef);
|
|
1638
|
+
}
|
|
384
1639
|
async refresh() {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
await this.
|
|
1640
|
+
this.isRefreshing = true;
|
|
1641
|
+
this.cdr.markForCheck();
|
|
1642
|
+
try {
|
|
1643
|
+
await this.record.Load(this.record.ID);
|
|
1644
|
+
await this.loadRelatedData();
|
|
1645
|
+
// Reset lazy-loaded data
|
|
1646
|
+
if (this.testRunsLoaded) {
|
|
1647
|
+
this.testRunsLoaded = false;
|
|
1648
|
+
this.testRuns = [];
|
|
1649
|
+
await this.loadTestRuns();
|
|
1650
|
+
}
|
|
1651
|
+
SharedService.Instance.CreateSimpleNotification('Refreshed successfully', 'success', 2000);
|
|
1652
|
+
}
|
|
1653
|
+
catch {
|
|
1654
|
+
SharedService.Instance.CreateSimpleNotification('Failed to refresh', 'error', 3000);
|
|
1655
|
+
}
|
|
1656
|
+
finally {
|
|
1657
|
+
this.isRefreshing = false;
|
|
1658
|
+
this.cdr.markForCheck();
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
getRunStatusColor(status) {
|
|
1662
|
+
switch (status) {
|
|
1663
|
+
case 'Passed': return '#10b981';
|
|
1664
|
+
case 'Failed': return '#ef4444';
|
|
1665
|
+
case 'Error': return '#f59e0b';
|
|
1666
|
+
case 'Timeout': return '#f97316';
|
|
1667
|
+
case 'Running': return '#3b82f6';
|
|
1668
|
+
case 'Pending': return '#8b5cf6';
|
|
1669
|
+
case 'Skipped': return '#6b7280';
|
|
1670
|
+
default: return '#9ca3af';
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
getRunStatusIcon(status) {
|
|
1674
|
+
switch (status) {
|
|
1675
|
+
case 'Passed': return 'fa-check';
|
|
1676
|
+
case 'Failed': return 'fa-times';
|
|
1677
|
+
case 'Error': return 'fa-exclamation';
|
|
1678
|
+
case 'Timeout': return 'fa-clock';
|
|
1679
|
+
case 'Running': return 'fa-circle-notch fa-spin';
|
|
1680
|
+
case 'Pending': return 'fa-hourglass-half';
|
|
1681
|
+
case 'Skipped': return 'fa-forward';
|
|
1682
|
+
default: return 'fa-question';
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
// ===========================
|
|
1686
|
+
// Tag Management
|
|
1687
|
+
// ===========================
|
|
1688
|
+
startEditingTags() {
|
|
1689
|
+
this.editingTags = true;
|
|
1690
|
+
this.cdr.markForCheck();
|
|
1691
|
+
}
|
|
1692
|
+
cancelEditingTags() {
|
|
1693
|
+
this.editingTags = false;
|
|
1694
|
+
this.newTag = '';
|
|
1695
|
+
this.parseTags(); // Reset to original
|
|
1696
|
+
this.cdr.markForCheck();
|
|
1697
|
+
}
|
|
1698
|
+
addTag() {
|
|
1699
|
+
const tag = this.newTag.trim();
|
|
1700
|
+
if (tag && !this.tags.includes(tag)) {
|
|
1701
|
+
this.tags = [...this.tags, tag];
|
|
1702
|
+
this.newTag = '';
|
|
1703
|
+
this.cdr.markForCheck();
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
removeTag(tag) {
|
|
1707
|
+
this.tags = this.tags.filter(t => t !== tag);
|
|
1708
|
+
this.cdr.markForCheck();
|
|
1709
|
+
}
|
|
1710
|
+
async saveTags() {
|
|
1711
|
+
// Auto-add any pending tag in the input before saving
|
|
1712
|
+
const pendingTag = this.newTag.trim();
|
|
1713
|
+
if (pendingTag && !this.tags.includes(pendingTag)) {
|
|
1714
|
+
this.tags = [...this.tags, pendingTag];
|
|
1715
|
+
this.newTag = '';
|
|
1716
|
+
}
|
|
1717
|
+
this.savingTags = true;
|
|
1718
|
+
this.cdr.markForCheck();
|
|
1719
|
+
try {
|
|
1720
|
+
this.record.Tags = TagsHelper.toJson(this.tags);
|
|
1721
|
+
const result = await this.record.Save();
|
|
1722
|
+
if (result) {
|
|
1723
|
+
this.editingTags = false;
|
|
1724
|
+
SharedService.Instance.CreateSimpleNotification('Tags saved successfully', 'success', 2000);
|
|
1725
|
+
}
|
|
1726
|
+
else {
|
|
1727
|
+
SharedService.Instance.CreateSimpleNotification(this.record.LatestResult?.Message || 'Failed to save tags', 'error', 3000);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
catch (error) {
|
|
1731
|
+
SharedService.Instance.CreateSimpleNotification('Failed to save tags', 'error', 3000);
|
|
1732
|
+
}
|
|
1733
|
+
finally {
|
|
1734
|
+
this.savingTags = false;
|
|
1735
|
+
this.cdr.markForCheck();
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
// ===========================
|
|
1739
|
+
// Test Run Filtering
|
|
1740
|
+
// ===========================
|
|
1741
|
+
setRunStatusFilter(status) {
|
|
1742
|
+
this.runStatusFilter = status;
|
|
1743
|
+
this.cdr.markForCheck();
|
|
1744
|
+
}
|
|
1745
|
+
getFilteredTestRuns() {
|
|
1746
|
+
if (!this.runStatusFilter)
|
|
1747
|
+
return this.testRuns;
|
|
1748
|
+
return this.testRuns.filter(run => run.Status === this.runStatusFilter);
|
|
1749
|
+
}
|
|
1750
|
+
getRunCountByStatus(status) {
|
|
1751
|
+
return this.testRuns.filter(run => run.Status === status).length;
|
|
1752
|
+
}
|
|
1753
|
+
// ===========================
|
|
1754
|
+
// Inline Feedback
|
|
1755
|
+
// ===========================
|
|
1756
|
+
async loadFeedbacks() {
|
|
1757
|
+
if (this.feedbacksLoaded)
|
|
1758
|
+
return;
|
|
1759
|
+
this.loadingFeedbacks = true;
|
|
1760
|
+
this.cdr.markForCheck();
|
|
1761
|
+
try {
|
|
1762
|
+
const testRunIds = this.testRuns.map(r => `'${r.ID}'`).join(',');
|
|
1763
|
+
if (!testRunIds)
|
|
1764
|
+
return;
|
|
1765
|
+
const rv = new RunView();
|
|
1766
|
+
const result = await rv.RunView({
|
|
1767
|
+
EntityName: 'MJ: Test Run Feedbacks',
|
|
1768
|
+
ExtraFilter: `TestRunID IN (${testRunIds})`,
|
|
1769
|
+
ResultType: 'entity_object'
|
|
1770
|
+
});
|
|
1771
|
+
if (result.Success && result.Results) {
|
|
1772
|
+
this.feedbacks.clear();
|
|
1773
|
+
for (const feedback of result.Results) {
|
|
1774
|
+
this.feedbacks.set(feedback.TestRunID, feedback);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
// Build TestRunWithFeedback array and calculate metrics
|
|
1778
|
+
this.buildTestRunsWithFeedback();
|
|
1779
|
+
this.feedbacksLoaded = true;
|
|
1780
|
+
}
|
|
1781
|
+
catch (error) {
|
|
1782
|
+
console.error('Error loading feedbacks:', error);
|
|
1783
|
+
}
|
|
1784
|
+
finally {
|
|
1785
|
+
this.loadingFeedbacks = false;
|
|
1786
|
+
this.cdr.markForCheck();
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
/**
|
|
1790
|
+
* Build TestRunWithFeedback array from testRuns and feedbacks
|
|
1791
|
+
*/
|
|
1792
|
+
buildTestRunsWithFeedback() {
|
|
1793
|
+
this.testRunsWithFeedback = this.testRuns.map(run => {
|
|
1794
|
+
const feedback = this.feedbacks.get(run.ID);
|
|
1795
|
+
return {
|
|
1796
|
+
id: run.ID,
|
|
1797
|
+
testId: run.TestID,
|
|
1798
|
+
testName: run.Test || 'Unknown Test',
|
|
1799
|
+
executionStatus: normalizeExecutionStatus(run.Status || 'Completed'),
|
|
1800
|
+
originalStatus: run.Status || 'Completed',
|
|
1801
|
+
duration: (run.DurationSeconds || 0) * 1000, // Convert to ms
|
|
1802
|
+
cost: run.CostUSD || 0,
|
|
1803
|
+
runDateTime: run.StartedAt ? new Date(run.StartedAt) : new Date(),
|
|
1804
|
+
autoScore: run.Score,
|
|
1805
|
+
passedChecks: null,
|
|
1806
|
+
failedChecks: null,
|
|
1807
|
+
totalChecks: null,
|
|
1808
|
+
humanRating: feedback?.Rating || null,
|
|
1809
|
+
humanIsCorrect: feedback?.IsCorrect ?? null,
|
|
1810
|
+
humanComments: feedback?.CorrectionSummary || null,
|
|
1811
|
+
hasHumanFeedback: !!feedback,
|
|
1812
|
+
feedbackId: feedback?.ID || null,
|
|
1813
|
+
tags: TagsHelper.parseTags(run.Tags),
|
|
1814
|
+
targetType: null,
|
|
1815
|
+
targetLogID: null
|
|
1816
|
+
};
|
|
1817
|
+
});
|
|
1818
|
+
// Calculate metrics
|
|
1819
|
+
this.evaluationMetrics = calculateEvaluationMetrics(this.testRunsWithFeedback);
|
|
1820
|
+
// Get items needing review
|
|
1821
|
+
this.needsReviewItems = getNeedsReviewItems(this.testRunsWithFeedback);
|
|
1822
|
+
}
|
|
1823
|
+
toggleRunExpanded(runId) {
|
|
1824
|
+
if (this.expandedRunId === runId) {
|
|
1825
|
+
this.expandedRunId = null;
|
|
1826
|
+
}
|
|
1827
|
+
else {
|
|
1828
|
+
this.expandedRunId = runId;
|
|
1829
|
+
this.initializeInlineFeedback(runId);
|
|
1830
|
+
}
|
|
1831
|
+
this.cdr.markForCheck();
|
|
1832
|
+
}
|
|
1833
|
+
initializeInlineFeedback(runId) {
|
|
1834
|
+
const existingFeedback = this.feedbacks.get(runId);
|
|
1835
|
+
if (existingFeedback) {
|
|
1836
|
+
this.inlineRating = existingFeedback.Rating || 0;
|
|
1837
|
+
this.inlineIsCorrect = existingFeedback.IsCorrect;
|
|
1838
|
+
this.inlineComments = existingFeedback.CorrectionSummary || '';
|
|
1839
|
+
}
|
|
1840
|
+
else {
|
|
1841
|
+
this.inlineRating = 0;
|
|
1842
|
+
this.inlineIsCorrect = null;
|
|
1843
|
+
this.inlineComments = '';
|
|
1844
|
+
}
|
|
1845
|
+
this.inlineHoverRating = 0;
|
|
1846
|
+
}
|
|
1847
|
+
setInlineRating(value) {
|
|
1848
|
+
this.inlineRating = value;
|
|
1849
|
+
this.cdr.markForCheck();
|
|
1850
|
+
}
|
|
1851
|
+
getInlineRatingLabel() {
|
|
1852
|
+
if (this.inlineRating <= 3)
|
|
1853
|
+
return 'Poor';
|
|
1854
|
+
if (this.inlineRating <= 5)
|
|
1855
|
+
return 'Below Average';
|
|
1856
|
+
if (this.inlineRating <= 6)
|
|
1857
|
+
return 'Average';
|
|
1858
|
+
if (this.inlineRating <= 7)
|
|
1859
|
+
return 'Good';
|
|
1860
|
+
if (this.inlineRating <= 8)
|
|
1861
|
+
return 'Very Good';
|
|
1862
|
+
if (this.inlineRating <= 9)
|
|
1863
|
+
return 'Excellent';
|
|
1864
|
+
return 'Outstanding';
|
|
1865
|
+
}
|
|
1866
|
+
canSubmitInlineFeedback() {
|
|
1867
|
+
return this.inlineRating > 0 && this.inlineComments.trim().length > 0;
|
|
1868
|
+
}
|
|
1869
|
+
async saveInlineFeedback() {
|
|
1870
|
+
if (!this.expandedRunId || !this.canSubmitInlineFeedback())
|
|
1871
|
+
return;
|
|
1872
|
+
this.savingInlineFeedback = true;
|
|
1873
|
+
this.cdr.markForCheck();
|
|
1874
|
+
try {
|
|
1875
|
+
const md = new Metadata();
|
|
1876
|
+
const currentUser = md.CurrentUser;
|
|
1877
|
+
let feedback = this.feedbacks.get(this.expandedRunId);
|
|
1878
|
+
if (!feedback) {
|
|
1879
|
+
feedback = await md.GetEntityObject('MJ: Test Run Feedbacks', currentUser);
|
|
1880
|
+
feedback.TestRunID = this.expandedRunId;
|
|
1881
|
+
feedback.ReviewerUserID = currentUser.ID;
|
|
1882
|
+
}
|
|
1883
|
+
feedback.Rating = this.inlineRating;
|
|
1884
|
+
feedback.IsCorrect = this.inlineIsCorrect;
|
|
1885
|
+
feedback.CorrectionSummary = this.inlineComments.trim() || null;
|
|
1886
|
+
const result = await feedback.Save();
|
|
1887
|
+
if (result) {
|
|
1888
|
+
this.feedbacks.set(this.expandedRunId, feedback);
|
|
1889
|
+
// Rebuild the metrics after feedback update
|
|
1890
|
+
this.buildTestRunsWithFeedback();
|
|
1891
|
+
SharedService.Instance.CreateSimpleNotification('Feedback saved', 'success', 2000);
|
|
1892
|
+
this.expandedRunId = null;
|
|
1893
|
+
}
|
|
1894
|
+
else {
|
|
1895
|
+
SharedService.Instance.CreateSimpleNotification(feedback.LatestResult?.Message || 'Failed to save feedback', 'error', 3000);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
catch (error) {
|
|
1899
|
+
SharedService.Instance.CreateSimpleNotification('Failed to save feedback', 'error', 3000);
|
|
1900
|
+
}
|
|
1901
|
+
finally {
|
|
1902
|
+
this.savingInlineFeedback = false;
|
|
1903
|
+
this.cdr.markForCheck();
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
hasFeedback(runId) {
|
|
1907
|
+
return this.feedbacks.has(runId);
|
|
1908
|
+
}
|
|
1909
|
+
getFeedbackRating(runId) {
|
|
1910
|
+
return this.feedbacks.get(runId)?.Rating || 0;
|
|
1911
|
+
}
|
|
1912
|
+
/**
|
|
1913
|
+
* Get TestRunWithFeedback by run ID for template binding
|
|
1914
|
+
*/
|
|
1915
|
+
getRunWithFeedback(runId) {
|
|
1916
|
+
return this.testRunsWithFeedback.find(r => r.id === runId);
|
|
1917
|
+
}
|
|
1918
|
+
/**
|
|
1919
|
+
* Get the human correctness status for a run
|
|
1920
|
+
*/
|
|
1921
|
+
getHumanIsCorrect(runId) {
|
|
1922
|
+
return this.feedbacks.get(runId)?.IsCorrect ?? null;
|
|
1923
|
+
}
|
|
1924
|
+
// ===========================
|
|
1925
|
+
// Run Tags
|
|
1926
|
+
// ===========================
|
|
1927
|
+
getRunTags(run) {
|
|
1928
|
+
return TagsHelper.parseTags(run.Tags);
|
|
1929
|
+
}
|
|
1930
|
+
// ===========================
|
|
1931
|
+
// Keyboard Shortcuts Settings
|
|
1932
|
+
// ===========================
|
|
1933
|
+
/**
|
|
1934
|
+
* Load keyboard shortcuts visibility setting from user settings
|
|
1935
|
+
*/
|
|
1936
|
+
loadShortcutsSetting() {
|
|
1937
|
+
try {
|
|
1938
|
+
const engine = UserInfoEngine.Instance;
|
|
1939
|
+
const setting = engine.UserSettings.find(s => s.Setting === SHORTCUTS_SETTINGS_KEY);
|
|
1940
|
+
if (setting) {
|
|
1941
|
+
this.shortcutsSettingEntity = setting;
|
|
1942
|
+
this.showShortcuts = setting.Value === 'true';
|
|
1943
|
+
}
|
|
1944
|
+
else {
|
|
1945
|
+
// Default to hidden
|
|
1946
|
+
this.showShortcuts = false;
|
|
1947
|
+
}
|
|
1948
|
+
this.cdr.markForCheck();
|
|
1949
|
+
}
|
|
1950
|
+
catch (error) {
|
|
1951
|
+
console.warn('Failed to load shortcuts setting:', error);
|
|
389
1952
|
}
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* Toggle keyboard shortcuts visibility and save preference
|
|
1956
|
+
*/
|
|
1957
|
+
async toggleShortcuts() {
|
|
1958
|
+
this.showShortcuts = !this.showShortcuts;
|
|
390
1959
|
this.cdr.markForCheck();
|
|
1960
|
+
try {
|
|
1961
|
+
const userId = this.metadata.CurrentUser?.ID;
|
|
1962
|
+
if (!userId)
|
|
1963
|
+
return;
|
|
1964
|
+
if (!this.shortcutsSettingEntity) {
|
|
1965
|
+
const engine = UserInfoEngine.Instance;
|
|
1966
|
+
const setting = engine.UserSettings.find(s => s.Setting === SHORTCUTS_SETTINGS_KEY);
|
|
1967
|
+
if (setting) {
|
|
1968
|
+
this.shortcutsSettingEntity = setting;
|
|
1969
|
+
}
|
|
1970
|
+
else {
|
|
1971
|
+
this.shortcutsSettingEntity = await this.metadata.GetEntityObject('MJ: User Settings');
|
|
1972
|
+
this.shortcutsSettingEntity.UserID = userId;
|
|
1973
|
+
this.shortcutsSettingEntity.Setting = SHORTCUTS_SETTINGS_KEY;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
this.shortcutsSettingEntity.Value = this.showShortcuts ? 'true' : 'false';
|
|
1977
|
+
await this.shortcutsSettingEntity.Save();
|
|
1978
|
+
}
|
|
1979
|
+
catch (error) {
|
|
1980
|
+
console.warn('Failed to save shortcuts setting:', error);
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
// ===========================
|
|
1984
|
+
// Analytics Calculations
|
|
1985
|
+
// ===========================
|
|
1986
|
+
getPassedCount() {
|
|
1987
|
+
return this.testRuns.filter(r => r.Status === 'Passed').length;
|
|
1988
|
+
}
|
|
1989
|
+
getFailedCount() {
|
|
1990
|
+
return this.testRuns.filter(r => r.Status === 'Failed' || r.Status === 'Error').length;
|
|
1991
|
+
}
|
|
1992
|
+
getPassedPercent() {
|
|
1993
|
+
if (this.testRuns.length === 0)
|
|
1994
|
+
return 0;
|
|
1995
|
+
return (this.getPassedCount() / this.testRuns.length) * 100;
|
|
1996
|
+
}
|
|
1997
|
+
getFailedPercent() {
|
|
1998
|
+
if (this.testRuns.length === 0)
|
|
1999
|
+
return 0;
|
|
2000
|
+
return (this.getFailedCount() / this.testRuns.length) * 100;
|
|
2001
|
+
}
|
|
2002
|
+
getAverageScore() {
|
|
2003
|
+
const runsWithScore = this.testRuns.filter(r => r.Score != null);
|
|
2004
|
+
if (runsWithScore.length === 0)
|
|
2005
|
+
return 0;
|
|
2006
|
+
const sum = runsWithScore.reduce((acc, r) => acc + (r.Score || 0), 0);
|
|
2007
|
+
return sum / runsWithScore.length;
|
|
2008
|
+
}
|
|
2009
|
+
getAverageDuration() {
|
|
2010
|
+
const runsWithDuration = this.testRuns.filter(r => r.DurationSeconds != null);
|
|
2011
|
+
if (runsWithDuration.length === 0)
|
|
2012
|
+
return 0;
|
|
2013
|
+
const sum = runsWithDuration.reduce((acc, r) => acc + (r.DurationSeconds || 0), 0);
|
|
2014
|
+
return sum / runsWithDuration.length;
|
|
2015
|
+
}
|
|
2016
|
+
getTotalCost() {
|
|
2017
|
+
return this.testRuns.reduce((acc, r) => acc + (r.CostUSD || 0), 0);
|
|
2018
|
+
}
|
|
2019
|
+
// ===========================
|
|
2020
|
+
// Export
|
|
2021
|
+
// ===========================
|
|
2022
|
+
exportToCSV() {
|
|
2023
|
+
const headers = ['Test Name', 'Status', 'Score', 'Duration (s)', 'Cost (USD)', 'Started At', 'Tags'];
|
|
2024
|
+
const rows = this.testRuns.map(run => [
|
|
2025
|
+
run.Test || '',
|
|
2026
|
+
run.Status || '',
|
|
2027
|
+
run.Score?.toFixed(4) || '',
|
|
2028
|
+
run.DurationSeconds?.toFixed(2) || '',
|
|
2029
|
+
run.CostUSD?.toFixed(6) || '',
|
|
2030
|
+
run.StartedAt ? new Date(run.StartedAt).toISOString() : '',
|
|
2031
|
+
this.getRunTags(run).join('; ')
|
|
2032
|
+
]);
|
|
2033
|
+
const csvContent = [headers, ...rows]
|
|
2034
|
+
.map(row => row.map(cell => `"${cell}"`).join(','))
|
|
2035
|
+
.join('\n');
|
|
2036
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
2037
|
+
const link = document.createElement('a');
|
|
2038
|
+
link.href = URL.createObjectURL(blob);
|
|
2039
|
+
link.download = `test-suite-run-${this.record.ID.substring(0, 8)}-results.csv`;
|
|
2040
|
+
link.click();
|
|
2041
|
+
URL.revokeObjectURL(link.href);
|
|
2042
|
+
SharedService.Instance.CreateSimpleNotification('Export complete', 'success', 2000);
|
|
391
2043
|
}
|
|
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"]],
|
|
2044
|
+
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), i0.ɵɵdirectiveInject(i0.ViewContainerRef)); }; }
|
|
2045
|
+
static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestSuiteRunFormComponentExtended, selectors: [["mj-test-suite-run-form"]], hostBindings: function TestSuiteRunFormComponentExtended_HostBindings(rf, ctx) { if (rf & 1) {
|
|
2046
|
+
i0.ɵɵlistener("keydown", function TestSuiteRunFormComponentExtended_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, false, i0.ɵɵresolveDocument);
|
|
2047
|
+
} }, 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
2048
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
|
|
395
2049
|
i0.ɵɵtemplate(2, TestSuiteRunFormComponentExtended_div_2_Template, 7, 2, "div", 2);
|
|
396
2050
|
i0.ɵɵelementStart(3, "div", 3)(4, "div", 4)(5, "div", 5);
|
|
397
2051
|
i0.ɵɵelement(6, "i", 6);
|
|
398
2052
|
i0.ɵɵelementEnd();
|
|
399
2053
|
i0.ɵɵelementStart(7, "div", 7)(8, "h1");
|
|
400
|
-
i0.ɵɵtext(9, "
|
|
2054
|
+
i0.ɵɵtext(9, "Suite Run");
|
|
401
2055
|
i0.ɵɵelementEnd();
|
|
402
2056
|
i0.ɵɵelementStart(10, "div", 8)(11, "span", 9);
|
|
403
|
-
i0.ɵɵelement(12, "i",
|
|
2057
|
+
i0.ɵɵelement(12, "i", 6);
|
|
404
2058
|
i0.ɵɵtext(13);
|
|
405
2059
|
i0.ɵɵelementEnd();
|
|
406
|
-
i0.ɵɵtemplate(14, TestSuiteRunFormComponentExtended_span_14_Template,
|
|
2060
|
+
i0.ɵɵtemplate(14, TestSuiteRunFormComponentExtended_span_14_Template, 3, 1, "span", 10)(15, TestSuiteRunFormComponentExtended_span_15_Template, 3, 1, "span", 11);
|
|
407
2061
|
i0.ɵɵelementEnd()()();
|
|
408
|
-
i0.ɵɵelementStart(16, "div",
|
|
409
|
-
i0.ɵɵ
|
|
410
|
-
i0.ɵɵ
|
|
2062
|
+
i0.ɵɵelementStart(16, "div", 12);
|
|
2063
|
+
i0.ɵɵelement(17, "app-evaluation-mode-toggle");
|
|
2064
|
+
i0.ɵɵtemplate(18, TestSuiteRunFormComponentExtended_button_18_Template, 3, 0, "button", 13);
|
|
2065
|
+
i0.ɵɵelementStart(19, "button", 14);
|
|
2066
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_19_listener() { return ctx.refresh(); });
|
|
2067
|
+
i0.ɵɵelement(20, "i", 6);
|
|
2068
|
+
i0.ɵɵtext(21);
|
|
411
2069
|
i0.ɵɵelementEnd()()();
|
|
412
|
-
i0.ɵɵelementStart(
|
|
413
|
-
i0.ɵɵ
|
|
2070
|
+
i0.ɵɵelementStart(22, "div", 15)(23, "div", 16)(24, "div", 17);
|
|
2071
|
+
i0.ɵɵelement(25, "i", 18);
|
|
414
2072
|
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");
|
|
2073
|
+
i0.ɵɵelementStart(26, "div", 19)(27, "div", 20);
|
|
2074
|
+
i0.ɵɵtext(28);
|
|
421
2075
|
i0.ɵɵelementEnd();
|
|
422
|
-
i0.ɵɵelementStart(29, "div",
|
|
423
|
-
i0.ɵɵtext(30);
|
|
424
|
-
i0.ɵɵ
|
|
425
|
-
i0.ɵɵ
|
|
426
|
-
i0.ɵɵ
|
|
427
|
-
i0.ɵɵtext(34, "Duration");
|
|
2076
|
+
i0.ɵɵelementStart(29, "div", 21);
|
|
2077
|
+
i0.ɵɵtext(30, "Duration");
|
|
2078
|
+
i0.ɵɵelementEnd()()();
|
|
2079
|
+
i0.ɵɵelementStart(31, "div", 16)(32, "div", 17);
|
|
2080
|
+
i0.ɵɵelement(33, "i", 22);
|
|
428
2081
|
i0.ɵɵelementEnd();
|
|
429
|
-
i0.ɵɵelementStart(35, "div",
|
|
2082
|
+
i0.ɵɵelementStart(34, "div", 19)(35, "div", 20);
|
|
430
2083
|
i0.ɵɵtext(36);
|
|
431
|
-
i0.ɵɵelementEnd()();
|
|
432
|
-
i0.ɵɵelementStart(37, "div", 16)(38, "div", 17);
|
|
433
|
-
i0.ɵɵtext(39, "Pass Rate");
|
|
434
2084
|
i0.ɵɵelementEnd();
|
|
435
|
-
i0.ɵɵelementStart(
|
|
436
|
-
i0.ɵɵtext(
|
|
437
|
-
i0.ɵɵelementEnd()();
|
|
438
|
-
i0.ɵɵelementStart(
|
|
439
|
-
i0.ɵɵ
|
|
2085
|
+
i0.ɵɵelementStart(37, "div", 21);
|
|
2086
|
+
i0.ɵɵtext(38, "Pass Rate");
|
|
2087
|
+
i0.ɵɵelementEnd()()();
|
|
2088
|
+
i0.ɵɵelementStart(39, "div", 16)(40, "div", 17);
|
|
2089
|
+
i0.ɵɵelement(41, "i", 23);
|
|
2090
|
+
i0.ɵɵelementEnd();
|
|
2091
|
+
i0.ɵɵelementStart(42, "div", 19)(43, "div", 20);
|
|
2092
|
+
i0.ɵɵtext(44);
|
|
440
2093
|
i0.ɵɵelementEnd();
|
|
441
|
-
i0.ɵɵelementStart(45, "div",
|
|
442
|
-
i0.ɵɵtext(46);
|
|
2094
|
+
i0.ɵɵelementStart(45, "div", 21);
|
|
2095
|
+
i0.ɵɵtext(46, "Total Cost");
|
|
443
2096
|
i0.ɵɵelementEnd()()();
|
|
444
|
-
i0.ɵɵelementStart(47, "div",
|
|
445
|
-
i0.ɵɵelement(49, "i",
|
|
446
|
-
i0.ɵɵ
|
|
447
|
-
i0.ɵɵ
|
|
2097
|
+
i0.ɵɵelementStart(47, "div", 16)(48, "div", 17);
|
|
2098
|
+
i0.ɵɵelement(49, "i", 24);
|
|
2099
|
+
i0.ɵɵelementEnd();
|
|
2100
|
+
i0.ɵɵelementStart(50, "div", 19)(51, "div", 20);
|
|
2101
|
+
i0.ɵɵtext(52);
|
|
448
2102
|
i0.ɵɵelementEnd();
|
|
449
|
-
i0.ɵɵelementStart(
|
|
450
|
-
i0.ɵɵtext(
|
|
451
|
-
i0.ɵɵelementEnd()();
|
|
452
|
-
i0.ɵɵelementStart(
|
|
453
|
-
i0.ɵɵelement(
|
|
454
|
-
i0.ɵɵ
|
|
455
|
-
i0.ɵɵ
|
|
2103
|
+
i0.ɵɵelementStart(53, "div", 21);
|
|
2104
|
+
i0.ɵɵtext(54, "Started");
|
|
2105
|
+
i0.ɵɵelementEnd()()()();
|
|
2106
|
+
i0.ɵɵelementStart(55, "div", 25)(56, "div", 26)(57, "div", 27);
|
|
2107
|
+
i0.ɵɵelement(58, "i", 28);
|
|
2108
|
+
i0.ɵɵelementEnd();
|
|
2109
|
+
i0.ɵɵelementStart(59, "div", 29)(60, "span", 30);
|
|
2110
|
+
i0.ɵɵtext(61);
|
|
456
2111
|
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);
|
|
2112
|
+
i0.ɵɵelementStart(62, "span", 31);
|
|
2113
|
+
i0.ɵɵtext(63, "Passed");
|
|
2114
|
+
i0.ɵɵelementEnd()()();
|
|
2115
|
+
i0.ɵɵelementStart(64, "div", 32)(65, "div", 27);
|
|
2116
|
+
i0.ɵɵelement(66, "i", 33);
|
|
464
2117
|
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);
|
|
2118
|
+
i0.ɵɵelementStart(67, "div", 29)(68, "span", 30);
|
|
471
2119
|
i0.ɵɵtext(69);
|
|
472
2120
|
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.ɵɵ
|
|
2121
|
+
i0.ɵɵelementStart(70, "span", 31);
|
|
2122
|
+
i0.ɵɵtext(71, "Failed");
|
|
2123
|
+
i0.ɵɵelementEnd()()();
|
|
2124
|
+
i0.ɵɵelementStart(72, "div", 34)(73, "div", 27);
|
|
2125
|
+
i0.ɵɵelement(74, "i", 35);
|
|
2126
|
+
i0.ɵɵelementEnd();
|
|
2127
|
+
i0.ɵɵelementStart(75, "div", 29)(76, "span", 30);
|
|
2128
|
+
i0.ɵɵtext(77);
|
|
2129
|
+
i0.ɵɵelementEnd();
|
|
2130
|
+
i0.ɵɵelementStart(78, "span", 31);
|
|
2131
|
+
i0.ɵɵtext(79, "Errors");
|
|
2132
|
+
i0.ɵɵelementEnd()()();
|
|
2133
|
+
i0.ɵɵelementStart(80, "div", 36)(81, "div", 27);
|
|
2134
|
+
i0.ɵɵelement(82, "i", 37);
|
|
2135
|
+
i0.ɵɵelementEnd();
|
|
2136
|
+
i0.ɵɵelementStart(83, "div", 29)(84, "span", 30);
|
|
2137
|
+
i0.ɵɵtext(85);
|
|
480
2138
|
i0.ɵɵelementEnd();
|
|
481
|
-
i0.ɵɵelementStart(
|
|
482
|
-
i0.ɵɵtext(
|
|
2139
|
+
i0.ɵɵelementStart(86, "span", 31);
|
|
2140
|
+
i0.ɵɵtext(87, "Skipped");
|
|
2141
|
+
i0.ɵɵelementEnd()()();
|
|
2142
|
+
i0.ɵɵelementStart(88, "div", 38)(89, "div", 27);
|
|
2143
|
+
i0.ɵɵelement(90, "i", 39);
|
|
2144
|
+
i0.ɵɵelementEnd();
|
|
2145
|
+
i0.ɵɵelementStart(91, "div", 29)(92, "span", 30);
|
|
2146
|
+
i0.ɵɵtext(93);
|
|
2147
|
+
i0.ɵɵelementEnd();
|
|
2148
|
+
i0.ɵɵelementStart(94, "span", 31);
|
|
2149
|
+
i0.ɵɵtext(95, "Total");
|
|
483
2150
|
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");
|
|
2151
|
+
i0.ɵɵtemplate(96, TestSuiteRunFormComponentExtended_div_96_Template, 9, 2, "div", 40)(97, TestSuiteRunFormComponentExtended_div_97_Template, 19, 7, "div", 41);
|
|
2152
|
+
i0.ɵɵelementEnd();
|
|
2153
|
+
i0.ɵɵelementStart(98, "div", 42)(99, "div", 43)(100, "button", 44);
|
|
2154
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_100_listener() { return ctx.changeTab("overview"); });
|
|
2155
|
+
i0.ɵɵelement(101, "i", 45);
|
|
2156
|
+
i0.ɵɵtext(102, " Overview ");
|
|
495
2157
|
i0.ɵɵelementEnd();
|
|
496
|
-
i0.ɵɵ
|
|
2158
|
+
i0.ɵɵelementStart(103, "button", 44);
|
|
2159
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_103_listener() { return ctx.changeTab("runs"); });
|
|
2160
|
+
i0.ɵɵelement(104, "i", 39);
|
|
2161
|
+
i0.ɵɵtext(105, " Test Runs ");
|
|
2162
|
+
i0.ɵɵtemplate(106, TestSuiteRunFormComponentExtended_span_106_Template, 2, 1, "span", 46);
|
|
497
2163
|
i0.ɵɵelementEnd();
|
|
498
|
-
i0.ɵɵelementStart(
|
|
499
|
-
i0.ɵɵlistener("click", function
|
|
500
|
-
i0.ɵɵelement(
|
|
501
|
-
i0.ɵɵ
|
|
502
|
-
i0.ɵɵ
|
|
2164
|
+
i0.ɵɵelementStart(107, "button", 44);
|
|
2165
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_107_listener() { return ctx.changeTab("details"); });
|
|
2166
|
+
i0.ɵɵelement(108, "i", 47);
|
|
2167
|
+
i0.ɵɵtext(109, " Details ");
|
|
2168
|
+
i0.ɵɵelementEnd();
|
|
2169
|
+
i0.ɵɵelementStart(110, "button", 48);
|
|
2170
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_110_listener() { return ctx.changeTab("analytics"); });
|
|
2171
|
+
i0.ɵɵelement(111, "i", 49);
|
|
2172
|
+
i0.ɵɵtext(112, " Analytics ");
|
|
2173
|
+
i0.ɵɵelementEnd();
|
|
2174
|
+
i0.ɵɵelementStart(113, "button", 50);
|
|
2175
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_113_listener() { return ctx.changeTab("execution"); });
|
|
2176
|
+
i0.ɵɵelement(114, "i", 51);
|
|
2177
|
+
i0.ɵɵelementStart(115, "span");
|
|
2178
|
+
i0.ɵɵtext(116, "Execution");
|
|
503
2179
|
i0.ɵɵelementEnd()()()();
|
|
504
|
-
i0.ɵɵelementStart(
|
|
505
|
-
i0.ɵɵtemplate(
|
|
506
|
-
i0.ɵɵelementEnd()
|
|
2180
|
+
i0.ɵɵelementStart(117, "div", 52);
|
|
2181
|
+
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);
|
|
2182
|
+
i0.ɵɵelementEnd();
|
|
2183
|
+
i0.ɵɵelementStart(123, "button", 58);
|
|
2184
|
+
i0.ɵɵlistener("click", function TestSuiteRunFormComponentExtended_Template_button_click_123_listener() { return ctx.toggleShortcuts(); });
|
|
2185
|
+
i0.ɵɵelement(124, "i", 59);
|
|
2186
|
+
i0.ɵɵelementEnd();
|
|
2187
|
+
i0.ɵɵtemplate(125, TestSuiteRunFormComponentExtended_div_125_Template, 34, 0, "div", 60);
|
|
2188
|
+
i0.ɵɵelementEnd();
|
|
507
2189
|
} if (rf & 2) {
|
|
508
2190
|
i0.ɵɵadvance(2);
|
|
509
2191
|
i0.ɵɵproperty("ngIf", ctx.testSuite);
|
|
510
2192
|
i0.ɵɵadvance(3);
|
|
511
2193
|
i0.ɵɵstyleProp("background-color", ctx.getStatusColor());
|
|
512
|
-
i0.ɵɵadvance(
|
|
513
|
-
i0.ɵɵ
|
|
2194
|
+
i0.ɵɵadvance();
|
|
2195
|
+
i0.ɵɵproperty("ngClass", ctx.getStatusIcon());
|
|
2196
|
+
i0.ɵɵadvance(5);
|
|
2197
|
+
i0.ɵɵproperty("ngClass", ctx.getStatusClass());
|
|
514
2198
|
i0.ɵɵadvance();
|
|
515
2199
|
i0.ɵɵproperty("ngClass", ctx.getStatusIcon());
|
|
516
2200
|
i0.ɵɵadvance();
|
|
@@ -519,41 +2203,68 @@ let TestSuiteRunFormComponentExtended = class TestSuiteRunFormComponentExtended
|
|
|
519
2203
|
i0.ɵɵproperty("ngIf", ctx.record.Environment);
|
|
520
2204
|
i0.ɵɵadvance();
|
|
521
2205
|
i0.ɵɵproperty("ngIf", ctx.record.TriggerType);
|
|
522
|
-
i0.ɵɵadvance(
|
|
523
|
-
i0.ɵɵ
|
|
524
|
-
i0.ɵɵadvance(
|
|
525
|
-
i0.ɵɵ
|
|
526
|
-
i0.ɵɵadvance(
|
|
2206
|
+
i0.ɵɵadvance(3);
|
|
2207
|
+
i0.ɵɵproperty("ngIf", ctx.record.SuiteID);
|
|
2208
|
+
i0.ɵɵadvance();
|
|
2209
|
+
i0.ɵɵproperty("disabled", ctx.isRefreshing);
|
|
2210
|
+
i0.ɵɵadvance();
|
|
2211
|
+
i0.ɵɵproperty("ngClass", ctx.isRefreshing ? "fa-sync fa-spin" : "fa-sync");
|
|
2212
|
+
i0.ɵɵadvance();
|
|
2213
|
+
i0.ɵɵtextInterpolate1(" ", ctx.isRefreshing ? "Refreshing..." : "Refresh", " ");
|
|
2214
|
+
i0.ɵɵadvance(7);
|
|
527
2215
|
i0.ɵɵtextInterpolate(ctx.calculateDuration());
|
|
528
|
-
i0.ɵɵadvance(
|
|
2216
|
+
i0.ɵɵadvance(8);
|
|
529
2217
|
i0.ɵɵtextInterpolate1("", ctx.getPassRate().toFixed(1), "%");
|
|
530
|
-
i0.ɵɵadvance(
|
|
2218
|
+
i0.ɵɵadvance(8);
|
|
531
2219
|
i0.ɵɵtextInterpolate(ctx.formatCost(ctx.record.TotalCostUSD));
|
|
532
|
-
i0.ɵɵadvance(
|
|
2220
|
+
i0.ɵɵadvance(8);
|
|
2221
|
+
i0.ɵɵtextInterpolate(ctx.getRelativeTime(ctx.record.StartedAt));
|
|
2222
|
+
i0.ɵɵadvance(9);
|
|
533
2223
|
i0.ɵɵtextInterpolate(ctx.record.PassedTests || 0);
|
|
534
|
-
i0.ɵɵadvance(
|
|
2224
|
+
i0.ɵɵadvance(8);
|
|
535
2225
|
i0.ɵɵtextInterpolate(ctx.record.FailedTests || 0);
|
|
536
|
-
i0.ɵɵadvance(
|
|
537
|
-
i0.ɵɵtextInterpolate(ctx.record.SkippedTests || 0);
|
|
538
|
-
i0.ɵɵadvance(6);
|
|
2226
|
+
i0.ɵɵadvance(8);
|
|
539
2227
|
i0.ɵɵtextInterpolate(ctx.record.ErrorTests || 0);
|
|
540
|
-
i0.ɵɵadvance(
|
|
2228
|
+
i0.ɵɵadvance(8);
|
|
2229
|
+
i0.ɵɵtextInterpolate(ctx.record.SkippedTests || 0);
|
|
2230
|
+
i0.ɵɵadvance(8);
|
|
541
2231
|
i0.ɵɵtextInterpolate(ctx.record.TotalTests || 0);
|
|
542
|
-
i0.ɵɵadvance(
|
|
2232
|
+
i0.ɵɵadvance(3);
|
|
2233
|
+
i0.ɵɵproperty("ngIf", !ctx.editingTags);
|
|
2234
|
+
i0.ɵɵadvance();
|
|
2235
|
+
i0.ɵɵproperty("ngIf", ctx.editingTags);
|
|
2236
|
+
i0.ɵɵadvance(3);
|
|
543
2237
|
i0.ɵɵclassProp("active", ctx.activeTab === "overview");
|
|
544
|
-
i0.ɵɵ
|
|
2238
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "overview");
|
|
2239
|
+
i0.ɵɵadvance(3);
|
|
545
2240
|
i0.ɵɵclassProp("active", ctx.activeTab === "runs");
|
|
546
|
-
i0.ɵɵ
|
|
2241
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "runs");
|
|
2242
|
+
i0.ɵɵadvance(3);
|
|
547
2243
|
i0.ɵɵproperty("ngIf", ctx.testRunsLoaded);
|
|
548
2244
|
i0.ɵɵadvance();
|
|
549
2245
|
i0.ɵɵclassProp("active", ctx.activeTab === "details");
|
|
2246
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "details");
|
|
2247
|
+
i0.ɵɵadvance(3);
|
|
2248
|
+
i0.ɵɵclassProp("active", ctx.activeTab === "analytics");
|
|
2249
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "analytics");
|
|
2250
|
+
i0.ɵɵadvance(3);
|
|
2251
|
+
i0.ɵɵclassProp("active", ctx.activeTab === "execution");
|
|
2252
|
+
i0.ɵɵattribute("aria-selected", ctx.activeTab === "execution");
|
|
550
2253
|
i0.ɵɵadvance(5);
|
|
551
2254
|
i0.ɵɵproperty("ngIf", ctx.activeTab === "overview");
|
|
552
2255
|
i0.ɵɵadvance();
|
|
553
2256
|
i0.ɵɵproperty("ngIf", ctx.activeTab === "runs");
|
|
554
2257
|
i0.ɵɵadvance();
|
|
555
2258
|
i0.ɵɵproperty("ngIf", ctx.activeTab === "details");
|
|
556
|
-
|
|
2259
|
+
i0.ɵɵadvance();
|
|
2260
|
+
i0.ɵɵproperty("ngIf", ctx.activeTab === "analytics");
|
|
2261
|
+
i0.ɵɵadvance();
|
|
2262
|
+
i0.ɵɵproperty("ngIf", ctx.activeTab === "execution");
|
|
2263
|
+
i0.ɵɵadvance();
|
|
2264
|
+
i0.ɵɵproperty("title", ctx.showShortcuts ? "Hide keyboard shortcuts" : "Show keyboard shortcuts");
|
|
2265
|
+
i0.ɵɵadvance(2);
|
|
2266
|
+
i0.ɵɵproperty("ngIf", ctx.showShortcuts);
|
|
2267
|
+
} }, 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
2268
|
};
|
|
558
2269
|
TestSuiteRunFormComponentExtended = __decorate([
|
|
559
2270
|
RegisterClass(BaseFormComponent, 'MJ: Test Suite Runs')
|
|
@@ -561,9 +2272,12 @@ TestSuiteRunFormComponentExtended = __decorate([
|
|
|
561
2272
|
export { TestSuiteRunFormComponentExtended };
|
|
562
2273
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TestSuiteRunFormComponentExtended, [{
|
|
563
2274
|
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
|
-
|
|
2275
|
+
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"] }]
|
|
2276
|
+
}], () => [{ type: i0.ElementRef }, { type: i1.SharedService }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i0.ChangeDetectorRef }, { type: i3.TestingDialogService }, { type: i3.EvaluationPreferencesService }, { type: i0.ViewContainerRef }], { handleKeyboardShortcut: [{
|
|
2277
|
+
type: HostListener,
|
|
2278
|
+
args: ['document:keydown', ['$event']]
|
|
2279
|
+
}] }); })();
|
|
2280
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TestSuiteRunFormComponentExtended, { className: "TestSuiteRunFormComponentExtended", filePath: "src/lib/custom/Tests/test-suite-run-form.component.ts", lineNumber: 34 }); })();
|
|
567
2281
|
export function LoadTestSuiteRunFormComponentExtended() {
|
|
568
2282
|
// Prevents tree-shaking
|
|
569
2283
|
}
|