@memberjunction/ng-dashboards 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.
Files changed (22) hide show
  1. package/dist/Testing/components/testing-execution.component.d.ts +16 -5
  2. package/dist/Testing/components/testing-execution.component.d.ts.map +1 -1
  3. package/dist/Testing/components/testing-execution.component.js +452 -273
  4. package/dist/Testing/components/testing-execution.component.js.map +1 -1
  5. package/dist/Testing/components/testing-feedback.component.d.ts +70 -14
  6. package/dist/Testing/components/testing-feedback.component.d.ts.map +1 -1
  7. package/dist/Testing/components/testing-feedback.component.js +1177 -479
  8. package/dist/Testing/components/testing-feedback.component.js.map +1 -1
  9. package/dist/Testing/components/testing-overview.component.d.ts.map +1 -1
  10. package/dist/Testing/components/testing-overview.component.js +182 -162
  11. package/dist/Testing/components/testing-overview.component.js.map +1 -1
  12. package/dist/Testing/components/testing-version-comparison.component.d.ts +4 -0
  13. package/dist/Testing/components/testing-version-comparison.component.d.ts.map +1 -1
  14. package/dist/Testing/components/testing-version-comparison.component.js +19 -5
  15. package/dist/Testing/components/testing-version-comparison.component.js.map +1 -1
  16. package/dist/Testing/services/testing-instrumentation.service.d.ts +47 -1
  17. package/dist/Testing/services/testing-instrumentation.service.d.ts.map +1 -1
  18. package/dist/Testing/services/testing-instrumentation.service.js +243 -60
  19. package/dist/Testing/services/testing-instrumentation.service.js.map +1 -1
  20. package/dist/Testing/testing-dashboard.component.js +36 -34
  21. package/dist/Testing/testing-dashboard.component.js.map +1 -1
  22. package/package.json +27 -27
@@ -1,178 +1,241 @@
1
1
  import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
2
- import { Subject } from 'rxjs';
3
- import { takeUntil, map } from 'rxjs/operators';
4
- import { CompositeKey } from '@memberjunction/core';
2
+ import { BehaviorSubject, Observable, Subject, combineLatest } from 'rxjs';
3
+ import { takeUntil, map, shareReplay, switchMap } from 'rxjs/operators';
4
+ import { CompositeKey, Metadata, RunView } from '@memberjunction/core';
5
5
  import { SharedService } from '@memberjunction/ng-shared';
6
6
  import * as i0 from "@angular/core";
7
7
  import * as i1 from "../services/testing-instrumentation.service";
8
8
  import * as i2 from "@angular/common";
9
9
  import * as i3 from "@angular/forms";
10
- import * as i4 from "@memberjunction/ng-testing";
11
- const _forTrack0 = ($index, $item) => $item.testRunID;
12
- const _c0 = () => [];
13
- function TestingFeedbackComponent_div_6_Template(rf, ctx) { if (rf & 1) {
14
- i0.ɵɵelementStart(0, "div", 52)(1, "span", 53);
15
- i0.ɵɵtext(2);
16
- i0.ɵɵpipe(3, "async");
10
+ const _c0 = () => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
11
+ function TestingFeedbackComponent_div_6_span_1_Template(rf, ctx) { if (rf & 1) {
12
+ i0.ɵɵelementStart(0, "span", 48);
13
+ i0.ɵɵtext(1);
17
14
  i0.ɵɵelementEnd();
18
- i0.ɵɵelementStart(4, "span", 54);
19
- i0.ɵɵtext(5, "Pending Review");
15
+ } if (rf & 2) {
16
+ const count_r1 = i0.ɵɵnextContext().ngIf;
17
+ i0.ɵɵadvance();
18
+ i0.ɵɵtextInterpolate(count_r1);
19
+ } }
20
+ function TestingFeedbackComponent_div_6_Template(rf, ctx) { if (rf & 1) {
21
+ i0.ɵɵelementStart(0, "div", 45);
22
+ i0.ɵɵtemplate(1, TestingFeedbackComponent_div_6_span_1_Template, 2, 1, "span", 46);
23
+ i0.ɵɵelementStart(2, "span", 47);
24
+ i0.ɵɵtext(3);
20
25
  i0.ɵɵelementEnd()();
21
26
  } if (rf & 2) {
22
- const ctx_r0 = i0.ɵɵnextContext();
27
+ const count_r1 = ctx.ngIf;
28
+ i0.ɵɵadvance();
29
+ i0.ɵɵproperty("ngIf", count_r1 > 0);
23
30
  i0.ɵɵadvance(2);
24
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(3, 1, ctx_r0.pendingCount$));
31
+ i0.ɵɵtextInterpolate(count_r1 > 0 ? "Pending Review" : "All Reviewed");
25
32
  } }
26
- function TestingFeedbackComponent_button_41_Template(rf, ctx) { if (rf & 1) {
33
+ function TestingFeedbackComponent_div_64_Template(rf, ctx) { if (rf & 1) {
27
34
  const _r2 = i0.ɵɵgetCurrentView();
28
- i0.ɵɵelementStart(0, "button", 55);
29
- i0.ɵɵlistener("click", function TestingFeedbackComponent_button_41_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.clearSearch()); });
30
- i0.ɵɵelement(1, "i", 56);
35
+ i0.ɵɵelementStart(0, "div", 27)(1, "label");
36
+ i0.ɵɵtext(2, "Reason");
37
+ i0.ɵɵelementEnd();
38
+ i0.ɵɵelementStart(3, "select", 28);
39
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_div_64_Template_select_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.filters.reason, $event) || (ctx_r2.filters.reason = $event); return i0.ɵɵresetView($event); });
40
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_div_64_Template_select_change_3_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onFilterChange()); });
41
+ i0.ɵɵelementStart(4, "option", 49);
42
+ i0.ɵɵtext(5, "All Reasons");
31
43
  i0.ɵɵelementEnd();
44
+ i0.ɵɵelementStart(6, "option", 50);
45
+ i0.ɵɵtext(7, "No Feedback");
46
+ i0.ɵɵelementEnd();
47
+ i0.ɵɵelementStart(8, "option", 51);
48
+ i0.ɵɵtext(9, "High Score but Failed");
49
+ i0.ɵɵelementEnd();
50
+ i0.ɵɵelementStart(10, "option", 52);
51
+ i0.ɵɵtext(11, "Low Score but Passed");
52
+ i0.ɵɵelementEnd()()();
53
+ } if (rf & 2) {
54
+ const ctx_r2 = i0.ɵɵnextContext();
55
+ i0.ɵɵadvance(3);
56
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r2.filters.reason);
32
57
  } }
33
- function TestingFeedbackComponent_For_97_Conditional_23_Template(rf, ctx) { if (rf & 1) {
34
- const _r5 = i0.ɵɵgetCurrentView();
35
- i0.ɵɵelementStart(0, "div", 71)(1, "div", 72)(2, "div", 73)(3, "h4");
36
- i0.ɵɵtext(4, "Provide Your Feedback");
58
+ function TestingFeedbackComponent_div_65_option_6_Template(rf, ctx) { if (rf & 1) {
59
+ i0.ɵɵelementStart(0, "option", 53);
60
+ i0.ɵɵtext(1);
61
+ i0.ɵɵelementEnd();
62
+ } if (rf & 2) {
63
+ const suite_r5 = ctx.$implicit;
64
+ i0.ɵɵproperty("ngValue", suite_r5.ID);
65
+ i0.ɵɵadvance();
66
+ i0.ɵɵtextInterpolate(suite_r5.Name);
67
+ } }
68
+ function TestingFeedbackComponent_div_65_Template(rf, ctx) { if (rf & 1) {
69
+ const _r4 = i0.ɵɵgetCurrentView();
70
+ i0.ɵɵelementStart(0, "div", 27)(1, "label");
71
+ i0.ɵɵtext(2, "Test Suite");
37
72
  i0.ɵɵelementEnd();
38
- i0.ɵɵelementStart(5, "div", 74)(6, "div", 75)(7, "label");
39
- i0.ɵɵtext(8, "Human Rating (1-10)");
73
+ i0.ɵɵelementStart(3, "select", 28);
74
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_div_65_Template_select_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.filters.suiteId, $event) || (ctx_r2.filters.suiteId = $event); return i0.ɵɵresetView($event); });
75
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_div_65_Template_select_change_3_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onFilterChange()); });
76
+ i0.ɵɵelementStart(4, "option", 53);
77
+ i0.ɵɵtext(5, "All Suites");
40
78
  i0.ɵɵelementEnd();
41
- i0.ɵɵelementStart(9, "input", 76);
42
- i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_For_97_Conditional_23_Template_input_ngModelChange_9_listener($event) { i0.ɵɵrestoreView(_r5); const item_r4 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(item_r4.feedbackRating, $event) || (item_r4.feedbackRating = $event); return i0.ɵɵresetView($event); });
79
+ i0.ɵɵtemplate(6, TestingFeedbackComponent_div_65_option_6_Template, 2, 2, "option", 54);
80
+ i0.ɵɵpipe(7, "async");
43
81
  i0.ɵɵelementEnd()();
44
- i0.ɵɵelementStart(10, "div", 75)(11, "label");
45
- i0.ɵɵtext(12, "Is Automated Result Correct?");
82
+ } if (rf & 2) {
83
+ const ctx_r2 = i0.ɵɵnextContext();
84
+ i0.ɵɵadvance(3);
85
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r2.filters.suiteId);
86
+ i0.ɵɵadvance();
87
+ i0.ɵɵproperty("ngValue", null);
88
+ i0.ɵɵadvance(2);
89
+ i0.ɵɵproperty("ngForOf", i0.ɵɵpipeBind1(7, 3, ctx_r2.testSuites$));
90
+ } }
91
+ function TestingFeedbackComponent_button_72_Template(rf, ctx) { if (rf & 1) {
92
+ const _r6 = i0.ɵɵgetCurrentView();
93
+ i0.ɵɵelementStart(0, "button", 55);
94
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_button_72_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.clearSearch()); });
95
+ i0.ɵɵelement(1, "i", 56);
46
96
  i0.ɵɵelementEnd();
47
- i0.ɵɵelementStart(13, "div", 77)(14, "label", 78)(15, "input", 79);
48
- i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_For_97_Conditional_23_Template_input_ngModelChange_15_listener($event) { i0.ɵɵrestoreView(_r5); const item_r4 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(item_r4.feedbackIsCorrect, $event) || (item_r4.feedbackIsCorrect = $event); return i0.ɵɵresetView($event); });
97
+ } }
98
+ function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_button_9_Template(rf, ctx) { if (rf & 1) {
99
+ const _r11 = i0.ɵɵgetCurrentView();
100
+ i0.ɵɵelementStart(0, "button", 101);
101
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_button_9_Template_button_click_0_listener() { const star_r12 = i0.ɵɵrestoreView(_r11).$implicit; const item_r9 = i0.ɵɵnextContext(2).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.setRating(item_r9, star_r12)); });
102
+ i0.ɵɵelement(1, "i", 102);
49
103
  i0.ɵɵelementEnd();
50
- i0.ɵɵelementStart(16, "span");
51
- i0.ɵɵtext(17, "Yes, the automated assessment is correct");
52
- i0.ɵɵelementEnd()()()()();
53
- i0.ɵɵelementStart(18, "div", 75)(19, "label");
54
- i0.ɵɵtext(20, "Comments / Notes");
104
+ } if (rf & 2) {
105
+ const star_r12 = ctx.$implicit;
106
+ const item_r9 = i0.ɵɵnextContext(2).$implicit;
107
+ i0.ɵɵclassProp("filled", star_r12 <= item_r9.feedbackRating);
108
+ } }
109
+ function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_Template(rf, ctx) { if (rf & 1) {
110
+ const _r10 = i0.ɵɵgetCurrentView();
111
+ i0.ɵɵelementStart(0, "div", 82)(1, "div", 83)(2, "div", 84)(3, "h4");
112
+ i0.ɵɵtext(4, "Provide Your Feedback");
55
113
  i0.ɵɵelementEnd();
56
- i0.ɵɵelementStart(21, "textarea", 80);
57
- i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_For_97_Conditional_23_Template_textarea_ngModelChange_21_listener($event) { i0.ɵɵrestoreView(_r5); const item_r4 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(item_r4.feedbackComments, $event) || (item_r4.feedbackComments = $event); return i0.ɵɵresetView($event); });
58
- i0.ɵɵelementEnd()();
59
- i0.ɵɵelementStart(22, "div", 81)(23, "button", 82);
60
- i0.ɵɵlistener("click", function TestingFeedbackComponent_For_97_Conditional_23_Template_button_click_23_listener() { i0.ɵɵrestoreView(_r5); const item_r4 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.submitFeedback(item_r4)); });
61
- i0.ɵɵelement(24, "i", 83);
62
- i0.ɵɵtext(25, " Submit Feedback ");
63
- i0.ɵɵelementEnd();
64
- i0.ɵɵelementStart(26, "button", 84);
65
- i0.ɵɵlistener("click", function TestingFeedbackComponent_For_97_Conditional_23_Template_button_click_26_listener() { i0.ɵɵrestoreView(_r5); const item_r4 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.skipFeedback(item_r4)); });
66
- i0.ɵɵelement(27, "i", 85);
67
- i0.ɵɵtext(28, " Skip for Now ");
68
- i0.ɵɵelementEnd()()();
69
- i0.ɵɵelementStart(29, "div", 86)(30, "h4");
70
- i0.ɵɵtext(31, "Test Context");
114
+ i0.ɵɵelementStart(5, "div", 85)(6, "label");
115
+ i0.ɵɵtext(7, "Human Rating");
71
116
  i0.ɵɵelementEnd();
72
- i0.ɵɵelementStart(32, "div", 87)(33, "div", 88)(34, "span", 89);
73
- i0.ɵɵtext(35, "Test Run ID");
117
+ i0.ɵɵelementStart(8, "div", 86);
118
+ i0.ɵɵtemplate(9, TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_button_9_Template, 2, 2, "button", 87);
119
+ i0.ɵɵelementStart(10, "span", 88);
120
+ i0.ɵɵtext(11);
121
+ i0.ɵɵelementEnd()()();
122
+ i0.ɵɵelementStart(12, "div", 89)(13, "label");
123
+ i0.ɵɵtext(14, "Is the Automated Result Correct?");
74
124
  i0.ɵɵelementEnd();
75
- i0.ɵɵelementStart(36, "span", 90);
76
- i0.ɵɵtext(37);
77
- i0.ɵɵelementEnd()();
78
- i0.ɵɵelementStart(38, "div", 88)(39, "span", 89);
79
- i0.ɵɵtext(40, "Automated Score");
125
+ i0.ɵɵelementStart(15, "div", 90)(16, "button", 91);
126
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_Template_button_click_16_listener() { i0.ɵɵrestoreView(_r10); const item_r9 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.setCorrectness(item_r9, true)); });
127
+ i0.ɵɵelement(17, "i", 92);
128
+ i0.ɵɵtext(18, " Correct ");
80
129
  i0.ɵɵelementEnd();
81
- i0.ɵɵelementStart(41, "span", 90);
82
- i0.ɵɵelement(42, "app-score-indicator", 91);
83
- i0.ɵɵelementEnd()();
84
- i0.ɵɵelementStart(43, "div", 88)(44, "span", 89);
85
- i0.ɵɵtext(45, "Status");
130
+ i0.ɵɵelementStart(19, "button", 93);
131
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r10); const item_r9 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.setCorrectness(item_r9, false)); });
132
+ i0.ɵɵelement(20, "i", 56);
133
+ i0.ɵɵtext(21, " Incorrect ");
134
+ i0.ɵɵelementEnd()()();
135
+ i0.ɵɵelementStart(22, "div", 94)(23, "label");
136
+ i0.ɵɵtext(24, "Comments / Correction Notes");
86
137
  i0.ɵɵelementEnd();
87
- i0.ɵɵelementStart(46, "span", 90);
88
- i0.ɵɵelement(47, "app-test-status-badge", 66);
138
+ i0.ɵɵelementStart(25, "textarea", 95);
139
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_Template_textarea_ngModelChange_25_listener($event) { i0.ɵɵrestoreView(_r10); const item_r9 = i0.ɵɵnextContext().$implicit; i0.ɵɵtwoWayBindingSet(item_r9.feedbackComments, $event) || (item_r9.feedbackComments = $event); return i0.ɵɵresetView($event); });
89
140
  i0.ɵɵelementEnd()();
90
- i0.ɵɵelementStart(48, "div", 88)(49, "span", 89);
91
- i0.ɵɵtext(50, "Run Date");
141
+ i0.ɵɵelementStart(26, "div", 96)(27, "button", 97);
142
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_Template_button_click_27_listener() { i0.ɵɵrestoreView(_r10); const item_r9 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.submitFeedback(item_r9)); });
143
+ i0.ɵɵelement(28, "i", 98);
144
+ i0.ɵɵtext(29);
92
145
  i0.ɵɵelementEnd();
93
- i0.ɵɵelementStart(51, "span", 90);
94
- i0.ɵɵtext(52);
95
- i0.ɵɵpipe(53, "date");
96
- i0.ɵɵelementEnd()()();
97
- i0.ɵɵelementStart(54, "button", 92);
98
- i0.ɵɵlistener("click", function TestingFeedbackComponent_For_97_Conditional_23_Template_button_click_54_listener() { i0.ɵɵrestoreView(_r5); const item_r4 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.viewFullDetails(item_r4)); });
99
- i0.ɵɵelement(55, "i", 93);
100
- i0.ɵɵtext(56, " View Full Test Details ");
101
- i0.ɵɵelementEnd()()()();
146
+ i0.ɵɵelementStart(30, "button", 99);
147
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_Template_button_click_30_listener() { i0.ɵɵrestoreView(_r10); const item_r9 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.viewFullDetails(item_r9)); });
148
+ i0.ɵɵelement(31, "i", 100);
149
+ i0.ɵɵtext(32, " View Full Details ");
150
+ i0.ɵɵelementEnd()()()()();
102
151
  } if (rf & 2) {
103
- const item_r4 = i0.ɵɵnextContext().$implicit;
104
- const ctx_r0 = i0.ɵɵnextContext();
152
+ const item_r9 = i0.ɵɵnextContext().$implicit;
153
+ const ctx_r2 = i0.ɵɵnextContext(4);
154
+ i0.ɵɵproperty("@slideDown", undefined);
105
155
  i0.ɵɵadvance(9);
106
- i0.ɵɵtwoWayProperty("ngModel", item_r4.feedbackRating);
107
- i0.ɵɵadvance(6);
108
- i0.ɵɵtwoWayProperty("ngModel", item_r4.feedbackIsCorrect);
109
- i0.ɵɵadvance(6);
110
- i0.ɵɵtwoWayProperty("ngModel", item_r4.feedbackComments);
111
- i0.ɵɵadvance(16);
112
- i0.ɵɵtextInterpolate(item_r4.testRunID);
113
- i0.ɵɵadvance(5);
114
- i0.ɵɵproperty("score", item_r4.automatedScore)("showBar", true);
115
- i0.ɵɵadvance(5);
116
- i0.ɵɵproperty("status", ctx_r0.getTestStatus(item_r4.automatedStatus));
156
+ i0.ɵɵproperty("ngForOf", i0.ɵɵpureFunction0(10, _c0));
157
+ i0.ɵɵadvance(2);
158
+ i0.ɵɵtextInterpolate1("", item_r9.feedbackRating, "/10");
117
159
  i0.ɵɵadvance(5);
118
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(53, 8, item_r4.runDateTime, "medium"));
160
+ i0.ɵɵclassProp("active", item_r9.feedbackIsCorrect === true);
161
+ i0.ɵɵadvance(3);
162
+ i0.ɵɵclassProp("active", item_r9.feedbackIsCorrect === false);
163
+ i0.ɵɵadvance(6);
164
+ i0.ɵɵtwoWayProperty("ngModel", item_r9.feedbackComments);
165
+ i0.ɵɵadvance(2);
166
+ i0.ɵɵproperty("disabled", ctx_r2.isSubmitting);
167
+ i0.ɵɵadvance(2);
168
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.isSubmitting ? "Submitting..." : "Submit Feedback", " ");
119
169
  } }
120
- function TestingFeedbackComponent_For_97_Template(rf, ctx) { if (rf & 1) {
121
- const _r3 = i0.ɵɵgetCurrentView();
122
- i0.ɵɵelementStart(0, "div", 57)(1, "div", 58);
123
- i0.ɵɵlistener("click", function TestingFeedbackComponent_For_97_Template_div_click_1_listener() { const item_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.toggleExpanded(item_r4.testRunID)); });
124
- i0.ɵɵelementStart(2, "div", 59)(3, "div", 60);
170
+ function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_Template(rf, ctx) { if (rf & 1) {
171
+ const _r8 = i0.ɵɵgetCurrentView();
172
+ i0.ɵɵelementStart(0, "div", 68)(1, "div", 69);
173
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_Template_div_click_1_listener() { const item_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.toggleExpanded(item_r9.testRunID)); });
174
+ i0.ɵɵelementStart(2, "div", 70)(3, "div", 71);
125
175
  i0.ɵɵtext(4);
126
176
  i0.ɵɵelementEnd();
127
- i0.ɵɵelementStart(5, "div", 61)(6, "span", 62);
128
- i0.ɵɵelement(7, "i", 63);
177
+ i0.ɵɵelementStart(5, "div", 72)(6, "span", 73);
178
+ i0.ɵɵelement(7, "i", 74);
129
179
  i0.ɵɵtext(8);
130
180
  i0.ɵɵpipe(9, "date");
131
181
  i0.ɵɵelementEnd();
132
- i0.ɵɵelementStart(10, "span", 64);
133
- i0.ɵɵtext(11, " Automated Score: ");
182
+ i0.ɵɵelementStart(10, "span", 75);
183
+ i0.ɵɵtext(11, " Score: ");
134
184
  i0.ɵɵelementStart(12, "strong");
135
185
  i0.ɵɵtext(13);
136
- i0.ɵɵelementEnd()();
137
- i0.ɵɵelementStart(14, "span", 65);
138
- i0.ɵɵtext(15, " Status: ");
139
- i0.ɵɵelement(16, "app-test-status-badge", 66);
186
+ i0.ɵɵelementEnd();
187
+ i0.ɵɵtext(14, "/10 ");
188
+ i0.ɵɵelementEnd();
189
+ i0.ɵɵelementStart(15, "span", 76);
190
+ i0.ɵɵtext(16);
140
191
  i0.ɵɵelementEnd()()();
141
- i0.ɵɵelementStart(17, "div", 67)(18, "span", 68);
142
- i0.ɵɵelement(19, "i", 69);
192
+ i0.ɵɵelementStart(17, "div", 77)(18, "span", 78);
193
+ i0.ɵɵelement(19, "i", 79);
143
194
  i0.ɵɵtext(20);
144
195
  i0.ɵɵelementEnd()();
145
- i0.ɵɵelementStart(21, "button", 70);
146
- i0.ɵɵelement(22, "i", 69);
196
+ i0.ɵɵelementStart(21, "button", 80);
197
+ i0.ɵɵelement(22, "i", 79);
147
198
  i0.ɵɵelementEnd()();
148
- i0.ɵɵtemplate(23, TestingFeedbackComponent_For_97_Conditional_23_Template, 57, 11, "div", 71);
199
+ i0.ɵɵtemplate(23, TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_div_23_Template, 33, 11, "div", 81);
149
200
  i0.ɵɵelementEnd();
150
201
  } if (rf & 2) {
151
- const item_r4 = ctx.$implicit;
152
- const ctx_r0 = i0.ɵɵnextContext();
153
- i0.ɵɵclassProp("expanded", ctx_r0.expandedItem === item_r4.testRunID);
202
+ const item_r9 = ctx.$implicit;
203
+ const ctx_r2 = i0.ɵɵnextContext(4);
204
+ i0.ɵɵclassProp("expanded", ctx_r2.expandedItem === item_r9.testRunID);
154
205
  i0.ɵɵadvance(4);
155
- i0.ɵɵtextInterpolate(item_r4.testName);
206
+ i0.ɵɵtextInterpolate(item_r9.testName);
156
207
  i0.ɵɵadvance(4);
157
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(9, 20, item_r4.runDateTime, "short"), " ");
208
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(9, 22, item_r9.runDateTime, "short"), " ");
158
209
  i0.ɵɵadvance(5);
159
- i0.ɵɵtextInterpolate(item_r4.automatedScore.toFixed(4));
160
- i0.ɵɵadvance(3);
161
- i0.ɵɵproperty("status", ctx_r0.getTestStatus(item_r4.automatedStatus));
210
+ i0.ɵɵtextInterpolate((item_r9.automatedScore * 10).toFixed(2));
211
+ i0.ɵɵadvance(2);
212
+ i0.ɵɵclassMap("status-" + item_r9.automatedStatus.toLowerCase());
213
+ i0.ɵɵadvance();
214
+ i0.ɵɵtextInterpolate1(" ", item_r9.automatedStatus, " ");
162
215
  i0.ɵɵadvance(2);
163
- i0.ɵɵclassMap(item_r4.reason);
216
+ i0.ɵɵclassMap(item_r9.reason);
164
217
  i0.ɵɵadvance();
165
- i0.ɵɵclassProp("fa-circle-info", item_r4.reason === "no-feedback")("fa-arrow-up", item_r4.reason === "high-score-failed")("fa-arrow-down", item_r4.reason === "low-score-passed");
218
+ i0.ɵɵclassProp("fa-circle-info", item_r9.reason === "no-feedback")("fa-arrow-up", item_r9.reason === "high-score-failed")("fa-arrow-down", item_r9.reason === "low-score-passed");
166
219
  i0.ɵɵadvance();
167
- i0.ɵɵtextInterpolate1(" ", ctx_r0.formatReason(item_r4.reason), " ");
220
+ i0.ɵɵtextInterpolate1(" ", ctx_r2.formatReason(item_r9.reason), " ");
168
221
  i0.ɵɵadvance(2);
169
- i0.ɵɵclassProp("fa-chevron-down", ctx_r0.expandedItem !== item_r4.testRunID)("fa-chevron-up", ctx_r0.expandedItem === item_r4.testRunID);
222
+ i0.ɵɵclassProp("fa-chevron-down", ctx_r2.expandedItem !== item_r9.testRunID)("fa-chevron-up", ctx_r2.expandedItem === item_r9.testRunID);
170
223
  i0.ɵɵadvance();
171
- i0.ɵɵconditional(ctx_r0.expandedItem === item_r4.testRunID ? 23 : -1);
224
+ i0.ɵɵproperty("ngIf", ctx_r2.expandedItem === item_r9.testRunID);
172
225
  } }
173
- function TestingFeedbackComponent_ForEmpty_98_Template(rf, ctx) { if (rf & 1) {
174
- i0.ɵɵelementStart(0, "div", 44);
175
- i0.ɵɵelement(1, "i", 94);
226
+ function TestingFeedbackComponent_div_73_div_15_ng_container_1_Template(rf, ctx) { if (rf & 1) {
227
+ i0.ɵɵelementContainerStart(0);
228
+ i0.ɵɵtemplate(1, TestingFeedbackComponent_div_73_div_15_ng_container_1_div_1_Template, 24, 25, "div", 67);
229
+ i0.ɵɵelementContainerEnd();
230
+ } if (rf & 2) {
231
+ const items_r13 = i0.ɵɵnextContext().ngIf;
232
+ const ctx_r2 = i0.ɵɵnextContext(2);
233
+ i0.ɵɵadvance();
234
+ i0.ɵɵproperty("ngForOf", items_r13)("ngForTrackBy", ctx_r2.trackByTestRunId);
235
+ } }
236
+ function TestingFeedbackComponent_div_73_div_15_ng_template_2_Template(rf, ctx) { if (rf & 1) {
237
+ i0.ɵɵelementStart(0, "div", 103);
238
+ i0.ɵɵelement(1, "i", 104);
176
239
  i0.ɵɵelementStart(2, "h3");
177
240
  i0.ɵɵtext(3, "All Caught Up!");
178
241
  i0.ɵɵelementEnd();
@@ -180,85 +243,536 @@ function TestingFeedbackComponent_ForEmpty_98_Template(rf, ctx) { if (rf & 1) {
180
243
  i0.ɵɵtext(5, "No tests currently require feedback review.");
181
244
  i0.ɵɵelementEnd()();
182
245
  } }
246
+ function TestingFeedbackComponent_div_73_div_15_Template(rf, ctx) { if (rf & 1) {
247
+ i0.ɵɵelementStart(0, "div", 65);
248
+ i0.ɵɵtemplate(1, TestingFeedbackComponent_div_73_div_15_ng_container_1_Template, 2, 2, "ng-container", 66)(2, TestingFeedbackComponent_div_73_div_15_ng_template_2_Template, 6, 0, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
249
+ i0.ɵɵelementEnd();
250
+ } if (rf & 2) {
251
+ const items_r13 = ctx.ngIf;
252
+ const emptyPending_r14 = i0.ɵɵreference(3);
253
+ i0.ɵɵadvance();
254
+ i0.ɵɵproperty("ngIf", items_r13.length > 0)("ngIfElse", emptyPending_r14);
255
+ } }
256
+ function TestingFeedbackComponent_div_73_Template(rf, ctx) { if (rf & 1) {
257
+ const _r7 = i0.ɵɵgetCurrentView();
258
+ i0.ɵɵelementStart(0, "div", 57)(1, "div", 58)(2, "h3");
259
+ i0.ɵɵelement(3, "i", 59);
260
+ i0.ɵɵtext(4, " Tests Requiring Review ");
261
+ i0.ɵɵelementEnd();
262
+ i0.ɵɵelementStart(5, "div", 60)(6, "label");
263
+ i0.ɵɵtext(7, "Sort by:");
264
+ i0.ɵɵelementEnd();
265
+ i0.ɵɵelementStart(8, "select", 28);
266
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_div_73_Template_select_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.sortBy, $event) || (ctx_r2.sortBy = $event); return i0.ɵɵresetView($event); });
267
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_div_73_Template_select_change_8_listener() { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onSortChange()); });
268
+ i0.ɵɵelementStart(9, "option", 61);
269
+ i0.ɵɵtext(10, "Date");
270
+ i0.ɵɵelementEnd();
271
+ i0.ɵɵelementStart(11, "option", 62);
272
+ i0.ɵɵtext(12, "Priority");
273
+ i0.ɵɵelementEnd();
274
+ i0.ɵɵelementStart(13, "option", 63);
275
+ i0.ɵɵtext(14, "Test Name");
276
+ i0.ɵɵelementEnd()()()();
277
+ i0.ɵɵtemplate(15, TestingFeedbackComponent_div_73_div_15_Template, 4, 2, "div", 64);
278
+ i0.ɵɵpipe(16, "async");
279
+ i0.ɵɵelementEnd();
280
+ } if (rf & 2) {
281
+ const ctx_r2 = i0.ɵɵnextContext();
282
+ i0.ɵɵadvance(8);
283
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r2.sortBy);
284
+ i0.ɵɵadvance(7);
285
+ i0.ɵɵproperty("ngIf", i0.ɵɵpipeBind1(16, 2, ctx_r2.filteredPending$));
286
+ } }
287
+ function TestingFeedbackComponent_div_74_div_15_ng_container_1_div_1_i_15_Template(rf, ctx) { if (rf & 1) {
288
+ i0.ɵɵelement(0, "i", 102);
289
+ } if (rf & 2) {
290
+ const s_r17 = ctx.$implicit;
291
+ const item_r18 = i0.ɵɵnextContext().$implicit;
292
+ i0.ɵɵclassProp("filled", s_r17 <= item_r18.rating);
293
+ } }
294
+ function TestingFeedbackComponent_div_74_div_15_ng_container_1_div_1_div_24_Template(rf, ctx) { if (rf & 1) {
295
+ i0.ɵɵelementStart(0, "div", 124)(1, "p");
296
+ i0.ɵɵtext(2);
297
+ i0.ɵɵelementEnd()();
298
+ } if (rf & 2) {
299
+ const item_r18 = i0.ɵɵnextContext().$implicit;
300
+ i0.ɵɵadvance(2);
301
+ i0.ɵɵtextInterpolate(item_r18.comments);
302
+ } }
303
+ function TestingFeedbackComponent_div_74_div_15_ng_container_1_div_1_Template(rf, ctx) { if (rf & 1) {
304
+ const _r16 = i0.ɵɵgetCurrentView();
305
+ i0.ɵɵelementStart(0, "div", 108)(1, "div", 109)(2, "div", 110)(3, "div", 111);
306
+ i0.ɵɵtext(4);
307
+ i0.ɵɵelementEnd();
308
+ i0.ɵɵelementStart(5, "div", 112)(6, "span", 113);
309
+ i0.ɵɵelement(7, "i", 114);
310
+ i0.ɵɵtext(8);
311
+ i0.ɵɵelementEnd();
312
+ i0.ɵɵelementStart(9, "span", 73);
313
+ i0.ɵɵelement(10, "i", 115);
314
+ i0.ɵɵtext(11);
315
+ i0.ɵɵpipe(12, "date");
316
+ i0.ɵɵelementEnd()()();
317
+ i0.ɵɵelementStart(13, "div", 116)(14, "div", 117);
318
+ i0.ɵɵtemplate(15, TestingFeedbackComponent_div_74_div_15_ng_container_1_div_1_i_15_Template, 1, 2, "i", 118);
319
+ i0.ɵɵelementEnd();
320
+ i0.ɵɵelementStart(16, "span", 119);
321
+ i0.ɵɵtext(17);
322
+ i0.ɵɵelementEnd()();
323
+ i0.ɵɵelementStart(18, "div", 120)(19, "span", 121);
324
+ i0.ɵɵelement(20, "i", 79);
325
+ i0.ɵɵtext(21);
326
+ i0.ɵɵelementEnd()();
327
+ i0.ɵɵelementStart(22, "button", 122);
328
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_74_div_15_ng_container_1_div_1_Template_button_click_22_listener() { const item_r18 = i0.ɵɵrestoreView(_r16).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.viewTestRun(item_r18.testRunID)); });
329
+ i0.ɵɵelement(23, "i", 100);
330
+ i0.ɵɵelementEnd()();
331
+ i0.ɵɵtemplate(24, TestingFeedbackComponent_div_74_div_15_ng_container_1_div_1_div_24_Template, 3, 1, "div", 123);
332
+ i0.ɵɵelementEnd();
333
+ } if (rf & 2) {
334
+ const item_r18 = ctx.$implicit;
335
+ i0.ɵɵadvance(4);
336
+ i0.ɵɵtextInterpolate(item_r18.testName);
337
+ i0.ɵɵadvance(4);
338
+ i0.ɵɵtextInterpolate1(" ", item_r18.reviewerName, " ");
339
+ i0.ɵɵadvance(3);
340
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(12, 15, item_r18.reviewedAt, "short"), " ");
341
+ i0.ɵɵadvance(4);
342
+ i0.ɵɵproperty("ngForOf", i0.ɵɵpureFunction0(18, _c0));
343
+ i0.ɵɵadvance(2);
344
+ i0.ɵɵtextInterpolate1("", item_r18.rating, "/10");
345
+ i0.ɵɵadvance(2);
346
+ i0.ɵɵclassProp("correct", item_r18.isCorrect)("incorrect", !item_r18.isCorrect);
347
+ i0.ɵɵadvance();
348
+ i0.ɵɵclassProp("fa-check", item_r18.isCorrect)("fa-times", !item_r18.isCorrect);
349
+ i0.ɵɵadvance();
350
+ i0.ɵɵtextInterpolate1(" ", item_r18.isCorrect ? "Correct" : "Incorrect", " ");
351
+ i0.ɵɵadvance(3);
352
+ i0.ɵɵproperty("ngIf", item_r18.comments);
353
+ } }
354
+ function TestingFeedbackComponent_div_74_div_15_ng_container_1_Template(rf, ctx) { if (rf & 1) {
355
+ i0.ɵɵelementContainerStart(0);
356
+ i0.ɵɵtemplate(1, TestingFeedbackComponent_div_74_div_15_ng_container_1_div_1_Template, 25, 19, "div", 107);
357
+ i0.ɵɵelementContainerEnd();
358
+ } if (rf & 2) {
359
+ const items_r19 = i0.ɵɵnextContext().ngIf;
360
+ const ctx_r2 = i0.ɵɵnextContext(2);
361
+ i0.ɵɵadvance();
362
+ i0.ɵɵproperty("ngForOf", items_r19)("ngForTrackBy", ctx_r2.trackByReviewedId);
363
+ } }
364
+ function TestingFeedbackComponent_div_74_div_15_ng_template_2_Template(rf, ctx) { if (rf & 1) {
365
+ i0.ɵɵelementStart(0, "div", 125);
366
+ i0.ɵɵelement(1, "i", 126);
367
+ i0.ɵɵelementStart(2, "h3");
368
+ i0.ɵɵtext(3, "No Reviews Yet");
369
+ i0.ɵɵelementEnd();
370
+ i0.ɵɵelementStart(4, "p");
371
+ i0.ɵɵtext(5, "No feedback has been submitted yet. Start by reviewing pending tests.");
372
+ i0.ɵɵelementEnd()();
373
+ } }
374
+ function TestingFeedbackComponent_div_74_div_15_Template(rf, ctx) { if (rf & 1) {
375
+ i0.ɵɵelementStart(0, "div", 65);
376
+ i0.ɵɵtemplate(1, TestingFeedbackComponent_div_74_div_15_ng_container_1_Template, 2, 2, "ng-container", 66)(2, TestingFeedbackComponent_div_74_div_15_ng_template_2_Template, 6, 0, "ng-template", null, 1, i0.ɵɵtemplateRefExtractor);
377
+ i0.ɵɵelementEnd();
378
+ } if (rf & 2) {
379
+ const items_r19 = ctx.ngIf;
380
+ const emptyReviewed_r20 = i0.ɵɵreference(3);
381
+ i0.ɵɵadvance();
382
+ i0.ɵɵproperty("ngIf", items_r19.length > 0)("ngIfElse", emptyReviewed_r20);
383
+ } }
384
+ function TestingFeedbackComponent_div_74_Template(rf, ctx) { if (rf & 1) {
385
+ const _r15 = i0.ɵɵgetCurrentView();
386
+ i0.ɵɵelementStart(0, "div", 57)(1, "div", 58)(2, "h3");
387
+ i0.ɵɵelement(3, "i", 105);
388
+ i0.ɵɵtext(4, " Reviewed Feedback History ");
389
+ i0.ɵɵelementEnd();
390
+ i0.ɵɵelementStart(5, "div", 60)(6, "label");
391
+ i0.ɵɵtext(7, "Sort by:");
392
+ i0.ɵɵelementEnd();
393
+ i0.ɵɵelementStart(8, "select", 28);
394
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_div_74_Template_select_ngModelChange_8_listener($event) { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.reviewedSortBy, $event) || (ctx_r2.reviewedSortBy = $event); return i0.ɵɵresetView($event); });
395
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_div_74_Template_select_change_8_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onReviewedSortChange()); });
396
+ i0.ɵɵelementStart(9, "option", 61);
397
+ i0.ɵɵtext(10, "Review Date");
398
+ i0.ɵɵelementEnd();
399
+ i0.ɵɵelementStart(11, "option", 106);
400
+ i0.ɵɵtext(12, "Rating");
401
+ i0.ɵɵelementEnd();
402
+ i0.ɵɵelementStart(13, "option", 63);
403
+ i0.ɵɵtext(14, "Test Name");
404
+ i0.ɵɵelementEnd()()()();
405
+ i0.ɵɵtemplate(15, TestingFeedbackComponent_div_74_div_15_Template, 4, 2, "div", 64);
406
+ i0.ɵɵpipe(16, "async");
407
+ i0.ɵɵelementEnd();
408
+ } if (rf & 2) {
409
+ const ctx_r2 = i0.ɵɵnextContext();
410
+ i0.ɵɵadvance(8);
411
+ i0.ɵɵtwoWayProperty("ngModel", ctx_r2.reviewedSortBy);
412
+ i0.ɵɵadvance(7);
413
+ i0.ɵɵproperty("ngIf", i0.ɵɵpipeBind1(16, 2, ctx_r2.filteredReviewed$));
414
+ } }
415
+ function TestingFeedbackComponent_div_75_div_5_ng_container_1_div_1_Template(rf, ctx) { if (rf & 1) {
416
+ const _r21 = i0.ɵɵgetCurrentView();
417
+ i0.ɵɵelementStart(0, "div", 130);
418
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_div_75_div_5_ng_container_1_div_1_Template_div_click_0_listener() { const suite_r22 = i0.ɵɵrestoreView(_r21).$implicit; const ctx_r2 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r2.selectSuite(suite_r22.suiteId)); });
419
+ i0.ɵɵelementStart(1, "div", 131)(2, "div", 132);
420
+ i0.ɵɵelement(3, "i", 22);
421
+ i0.ɵɵelementEnd();
422
+ i0.ɵɵelementStart(4, "div", 133)(5, "h4");
423
+ i0.ɵɵtext(6);
424
+ i0.ɵɵelementEnd();
425
+ i0.ɵɵelementStart(7, "div", 134)(8, "span");
426
+ i0.ɵɵtext(9);
427
+ i0.ɵɵelementEnd()()()();
428
+ i0.ɵɵelementStart(10, "div", 135)(11, "div", 136)(12, "div", 137);
429
+ i0.ɵɵtext(13);
430
+ i0.ɵɵelementEnd();
431
+ i0.ɵɵelementStart(14, "div", 43);
432
+ i0.ɵɵtext(15, "Pending");
433
+ i0.ɵɵelementEnd()();
434
+ i0.ɵɵelementStart(16, "div", 136)(17, "div", 138);
435
+ i0.ɵɵtext(18);
436
+ i0.ɵɵelementEnd();
437
+ i0.ɵɵelementStart(19, "div", 43);
438
+ i0.ɵɵtext(20, "Reviewed");
439
+ i0.ɵɵelementEnd()();
440
+ i0.ɵɵelementStart(21, "div", 136)(22, "div", 44);
441
+ i0.ɵɵtext(23);
442
+ i0.ɵɵpipe(24, "number");
443
+ i0.ɵɵelementEnd();
444
+ i0.ɵɵelementStart(25, "div", 43);
445
+ i0.ɵɵtext(26, "Avg Rating");
446
+ i0.ɵɵelementEnd()();
447
+ i0.ɵɵelementStart(27, "div", 136)(28, "div", 44);
448
+ i0.ɵɵtext(29);
449
+ i0.ɵɵpipe(30, "number");
450
+ i0.ɵɵelementEnd();
451
+ i0.ɵɵelementStart(31, "div", 43);
452
+ i0.ɵɵtext(32, "Agreement");
453
+ i0.ɵɵelementEnd()();
454
+ i0.ɵɵelementStart(33, "div", 136)(34, "div", 44);
455
+ i0.ɵɵtext(35);
456
+ i0.ɵɵpipe(36, "number");
457
+ i0.ɵɵelementEnd();
458
+ i0.ɵɵelementStart(37, "div", 43);
459
+ i0.ɵɵtext(38, "Pass Rate");
460
+ i0.ɵɵelementEnd()()();
461
+ i0.ɵɵelement(39, "i", 139);
462
+ i0.ɵɵelementEnd();
463
+ } if (rf & 2) {
464
+ const suite_r22 = ctx.$implicit;
465
+ i0.ɵɵadvance(6);
466
+ i0.ɵɵtextInterpolate(suite_r22.suiteName);
467
+ i0.ɵɵadvance(3);
468
+ i0.ɵɵtextInterpolate1("", suite_r22.totalRuns, " test runs");
469
+ i0.ɵɵadvance(4);
470
+ i0.ɵɵtextInterpolate(suite_r22.pendingCount);
471
+ i0.ɵɵadvance(5);
472
+ i0.ɵɵtextInterpolate(suite_r22.reviewedCount);
473
+ i0.ɵɵadvance(5);
474
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(24, 15, suite_r22.avgRating, "1.1-1"));
475
+ i0.ɵɵadvance(5);
476
+ i0.ɵɵclassProp("good", suite_r22.agreementRate >= 70)("bad", suite_r22.agreementRate < 50);
477
+ i0.ɵɵadvance();
478
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(30, 18, suite_r22.agreementRate, "1.0-0"), "% ");
479
+ i0.ɵɵadvance(5);
480
+ i0.ɵɵclassProp("good", suite_r22.passRate >= 80)("bad", suite_r22.passRate < 50);
481
+ i0.ɵɵadvance();
482
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(36, 21, suite_r22.passRate, "1.0-0"), "% ");
483
+ } }
484
+ function TestingFeedbackComponent_div_75_div_5_ng_container_1_Template(rf, ctx) { if (rf & 1) {
485
+ i0.ɵɵelementContainerStart(0);
486
+ i0.ɵɵtemplate(1, TestingFeedbackComponent_div_75_div_5_ng_container_1_div_1_Template, 40, 24, "div", 129);
487
+ i0.ɵɵelementContainerEnd();
488
+ } if (rf & 2) {
489
+ const suites_r23 = i0.ɵɵnextContext().ngIf;
490
+ const ctx_r2 = i0.ɵɵnextContext(2);
491
+ i0.ɵɵadvance();
492
+ i0.ɵɵproperty("ngForOf", suites_r23)("ngForTrackBy", ctx_r2.trackBySuiteId);
493
+ } }
494
+ function TestingFeedbackComponent_div_75_div_5_ng_template_2_Template(rf, ctx) { if (rf & 1) {
495
+ i0.ɵɵelementStart(0, "div", 125);
496
+ i0.ɵɵelement(1, "i", 22);
497
+ i0.ɵɵelementStart(2, "h3");
498
+ i0.ɵɵtext(3, "No Test Suites");
499
+ i0.ɵɵelementEnd();
500
+ i0.ɵɵelementStart(4, "p");
501
+ i0.ɵɵtext(5, "No test suites have been created yet.");
502
+ i0.ɵɵelementEnd()();
503
+ } }
504
+ function TestingFeedbackComponent_div_75_div_5_Template(rf, ctx) { if (rf & 1) {
505
+ i0.ɵɵelementStart(0, "div", 128);
506
+ i0.ɵɵtemplate(1, TestingFeedbackComponent_div_75_div_5_ng_container_1_Template, 2, 2, "ng-container", 66)(2, TestingFeedbackComponent_div_75_div_5_ng_template_2_Template, 6, 0, "ng-template", null, 2, i0.ɵɵtemplateRefExtractor);
507
+ i0.ɵɵelementEnd();
508
+ } if (rf & 2) {
509
+ const suites_r23 = ctx.ngIf;
510
+ const emptySuites_r24 = i0.ɵɵreference(3);
511
+ i0.ɵɵadvance();
512
+ i0.ɵɵproperty("ngIf", suites_r23.length > 0)("ngIfElse", emptySuites_r24);
513
+ } }
514
+ function TestingFeedbackComponent_div_75_Template(rf, ctx) { if (rf & 1) {
515
+ i0.ɵɵelementStart(0, "div", 57)(1, "div", 58)(2, "h3");
516
+ i0.ɵɵelement(3, "i", 22);
517
+ i0.ɵɵtext(4, " Feedback by Test Suite ");
518
+ i0.ɵɵelementEnd()();
519
+ i0.ɵɵtemplate(5, TestingFeedbackComponent_div_75_div_5_Template, 4, 2, "div", 127);
520
+ i0.ɵɵpipe(6, "async");
521
+ i0.ɵɵelementEnd();
522
+ } if (rf & 2) {
523
+ const ctx_r2 = i0.ɵɵnextContext();
524
+ i0.ɵɵadvance(5);
525
+ i0.ɵɵproperty("ngIf", i0.ɵɵpipeBind1(6, 1, ctx_r2.suiteAggregations$));
526
+ } }
183
527
  export class TestingFeedbackComponent {
184
528
  instrumentationService;
185
529
  cdr;
186
530
  initialState;
187
531
  stateChange = new EventEmitter();
188
532
  destroy$ = new Subject();
533
+ filterTrigger$ = new BehaviorSubject(undefined);
534
+ metadata = new Metadata();
535
+ viewMode = 'pending';
536
+ isRefreshing = false;
537
+ isSubmitting = false;
538
+ expandedItem = null;
189
539
  filters = {
190
- status: 'pending',
540
+ status: 'all',
191
541
  reason: 'all',
542
+ suiteId: null,
192
543
  searchText: ''
193
544
  };
194
- sortBy = 'priority';
195
- expandedItem = null;
196
- pendingFeedback$;
197
- filteredFeedback$;
545
+ sortBy = 'date';
546
+ reviewedSortBy = 'date';
547
+ // Observables
198
548
  pendingCount$;
199
- discrepancyCount$;
200
549
  reviewedCount$;
550
+ suiteCount$;
201
551
  accuracyRate$;
202
552
  totalFeedback$;
203
553
  avgRating$;
204
554
  agreementRate$;
205
- disagreementRate$;
555
+ discrepancyCount$;
556
+ filteredPending$;
557
+ filteredReviewed$;
558
+ suiteAggregations$;
559
+ testSuites$;
560
+ // Local data cache for filtering
561
+ pendingData = [];
562
+ reviewedData = [];
206
563
  constructor(instrumentationService, cdr) {
207
564
  this.instrumentationService = instrumentationService;
208
565
  this.cdr = cdr;
209
566
  }
210
567
  ngOnInit() {
211
- this.setupObservables();
212
568
  if (this.initialState) {
213
- this.filters = { ...this.filters, ...this.initialState.filters };
214
- this.sortBy = this.initialState.sortBy || 'priority';
569
+ if (this.initialState.filters) {
570
+ this.filters = { ...this.filters, ...this.initialState.filters };
571
+ }
572
+ if (this.initialState.viewMode) {
573
+ this.viewMode = this.initialState.viewMode;
574
+ }
575
+ if (this.initialState.sortBy) {
576
+ this.sortBy = this.initialState.sortBy;
577
+ }
215
578
  }
579
+ this.setupObservables();
580
+ this.loadTestSuites();
216
581
  }
217
582
  ngOnDestroy() {
218
583
  this.destroy$.next();
219
584
  this.destroy$.complete();
220
585
  }
221
586
  setupObservables() {
222
- this.pendingFeedback$ = this.instrumentationService.pendingFeedback$.pipe(map(feedback => feedback.map(f => ({
223
- ...f,
224
- feedbackRating: 5,
225
- feedbackIsCorrect: true,
226
- feedbackComments: ''
227
- }))), takeUntil(this.destroy$));
228
- this.filteredFeedback$ = this.pendingFeedback$.pipe(map(feedback => this.filterAndSort(feedback)));
229
- this.pendingCount$ = this.pendingFeedback$.pipe(map(feedback => feedback.length));
230
- this.discrepancyCount$ = this.pendingFeedback$.pipe(map(feedback => feedback.filter(f => f.reason === 'high-score-failed' || f.reason === 'low-score-passed').length));
231
- // Load real feedback statistics from the service
232
- const feedbackStats$ = this.instrumentationService.feedbackStats$;
233
- this.reviewedCount$ = feedbackStats$.pipe(map(stats => stats.reviewedCount), takeUntil(this.destroy$));
234
- this.accuracyRate$ = feedbackStats$.pipe(map(stats => stats.accuracyRate), takeUntil(this.destroy$));
235
- this.totalFeedback$ = feedbackStats$.pipe(map(stats => stats.totalFeedback), takeUntil(this.destroy$));
236
- this.avgRating$ = feedbackStats$.pipe(map(stats => stats.avgRating), takeUntil(this.destroy$));
237
- this.agreementRate$ = feedbackStats$.pipe(map(stats => stats.agreementRate), takeUntil(this.destroy$));
238
- this.disagreementRate$ = feedbackStats$.pipe(map(stats => stats.disagreementRate), takeUntil(this.destroy$));
587
+ // Stats from service
588
+ const feedbackStats$ = this.instrumentationService.feedbackStats$.pipe(takeUntil(this.destroy$), shareReplay(1));
589
+ this.pendingCount$ = this.instrumentationService.pendingFeedback$.pipe(map(items => items.length), takeUntil(this.destroy$));
590
+ this.reviewedCount$ = feedbackStats$.pipe(map(stats => stats.reviewedCount));
591
+ this.accuracyRate$ = feedbackStats$.pipe(map(stats => stats.accuracyRate));
592
+ this.totalFeedback$ = feedbackStats$.pipe(map(stats => stats.totalFeedback));
593
+ this.avgRating$ = feedbackStats$.pipe(map(stats => stats.avgRating));
594
+ this.agreementRate$ = feedbackStats$.pipe(map(stats => stats.agreementRate));
595
+ this.discrepancyCount$ = this.instrumentationService.pendingFeedback$.pipe(map(items => items.filter(f => f.reason === 'high-score-failed' || f.reason === 'low-score-passed').length), takeUntil(this.destroy$));
596
+ // Filtered pending items
597
+ this.filteredPending$ = combineLatest([
598
+ this.instrumentationService.pendingFeedback$,
599
+ this.filterTrigger$
600
+ ]).pipe(map(([items]) => {
601
+ const enhanced = items.map(f => ({
602
+ ...f,
603
+ feedbackRating: 5,
604
+ feedbackIsCorrect: true,
605
+ feedbackComments: ''
606
+ }));
607
+ this.pendingData = enhanced;
608
+ return this.filterAndSortPending(enhanced);
609
+ }), takeUntil(this.destroy$));
610
+ // Load and filter reviewed feedback
611
+ this.filteredReviewed$ = combineLatest([
612
+ this.loadReviewedFeedback(),
613
+ this.filterTrigger$
614
+ ]).pipe(map(([items]) => {
615
+ this.reviewedData = items;
616
+ return this.filterAndSortReviewed(items);
617
+ }), takeUntil(this.destroy$));
618
+ // Suite aggregations
619
+ this.suiteAggregations$ = this.loadSuiteAggregations().pipe(takeUntil(this.destroy$));
620
+ this.suiteCount$ = this.suiteAggregations$.pipe(map(suites => suites.length));
239
621
  }
240
- filterAndSort(feedback) {
241
- let filtered = [...feedback];
242
- // Note: 'reviewed' status would need to query Test Run Feedback entity separately
243
- // For now, we only show pending items (all items from pendingFeedback$ are pending by definition)
244
- if (this.filters.status === 'reviewed') {
245
- filtered = []; // No reviewed items in this stream
246
- }
622
+ async loadTestSuites() {
623
+ const rv = new RunView();
624
+ const result = await rv.RunView({
625
+ EntityName: 'MJ: Test Suites',
626
+ ExtraFilter: "Status = 'Active'",
627
+ OrderBy: 'Name',
628
+ ResultType: 'entity_object'
629
+ });
630
+ this.testSuites$ = new BehaviorSubject(result.Results || []).asObservable();
631
+ this.cdr.markForCheck();
632
+ }
633
+ loadReviewedFeedback() {
634
+ return combineLatest([
635
+ this.instrumentationService.dateRange$,
636
+ this.instrumentationService.isLoading$
637
+ ]).pipe(switchMap(([dateRange]) => {
638
+ return new Observable(observer => {
639
+ this.loadReviewedFeedbackAsync(dateRange.start, dateRange.end).then(data => {
640
+ observer.next(data);
641
+ observer.complete();
642
+ }, error => observer.error(error));
643
+ });
644
+ }), shareReplay(1));
645
+ }
646
+ async loadReviewedFeedbackAsync(start, end) {
647
+ const rv = new RunView();
648
+ const result = await rv.RunView({
649
+ EntityName: 'MJ: Test Run Feedbacks',
650
+ ExtraFilter: `__mj_CreatedAt >= '${start.toISOString()}' AND __mj_CreatedAt <= '${end.toISOString()}'`,
651
+ OrderBy: '__mj_CreatedAt DESC',
652
+ MaxRows: 500,
653
+ ResultType: 'entity_object'
654
+ });
655
+ const feedbacks = result.Results || [];
656
+ // Get test run details for each feedback
657
+ if (feedbacks.length === 0)
658
+ return [];
659
+ const testRunIds = feedbacks.map(f => f.TestRunID);
660
+ const testRunResult = await rv.RunView({
661
+ EntityName: 'MJ: Test Runs',
662
+ ExtraFilter: `ID IN ('${testRunIds.join("','")}')`,
663
+ ResultType: 'entity_object'
664
+ });
665
+ const testRunMap = new Map();
666
+ (testRunResult.Results || []).forEach(tr => testRunMap.set(tr.ID, tr));
667
+ return feedbacks.map(f => {
668
+ const testRun = testRunMap.get(f.TestRunID);
669
+ return {
670
+ id: f.ID,
671
+ testRunID: f.TestRunID,
672
+ testName: testRun?.Test || 'Unknown Test',
673
+ rating: f.Rating || 0,
674
+ isCorrect: f.IsCorrect ?? true,
675
+ comments: f.CorrectionSummary || '',
676
+ reviewerName: f.ReviewerUser || 'Unknown',
677
+ reviewedAt: f.__mj_CreatedAt ? new Date(f.__mj_CreatedAt) : new Date(),
678
+ automatedScore: testRun?.Score || 0,
679
+ automatedStatus: testRun?.Status || 'Unknown'
680
+ };
681
+ });
682
+ }
683
+ loadSuiteAggregations() {
684
+ return combineLatest([
685
+ this.instrumentationService.dateRange$,
686
+ this.instrumentationService.isLoading$
687
+ ]).pipe(switchMap(([dateRange]) => {
688
+ return new Observable(observer => {
689
+ this.loadSuiteAggregationsAsync(dateRange.start, dateRange.end).then(data => {
690
+ observer.next(data);
691
+ observer.complete();
692
+ }, error => observer.error(error));
693
+ });
694
+ }), shareReplay(1));
695
+ }
696
+ async loadSuiteAggregationsAsync(start, end) {
697
+ const rv = new RunView();
698
+ // Get all test suites
699
+ const suitesResult = await rv.RunView({
700
+ EntityName: 'MJ: Test Suites',
701
+ ExtraFilter: "Status = 'Active'",
702
+ ResultType: 'entity_object'
703
+ });
704
+ const suites = suitesResult.Results || [];
705
+ if (suites.length === 0)
706
+ return [];
707
+ // Get test runs in date range
708
+ const runsResult = await rv.RunView({
709
+ EntityName: 'MJ: Test Runs',
710
+ ExtraFilter: `StartedAt >= '${start.toISOString()}' AND StartedAt <= '${end.toISOString()}'`,
711
+ ResultType: 'entity_object'
712
+ });
713
+ const runs = runsResult.Results || [];
714
+ // Get feedback in date range
715
+ const feedbackResult = await rv.RunView({
716
+ EntityName: 'MJ: Test Run Feedbacks',
717
+ ExtraFilter: `__mj_CreatedAt >= '${start.toISOString()}'`,
718
+ ResultType: 'entity_object'
719
+ });
720
+ const feedbacks = feedbackResult.Results || [];
721
+ const feedbackMap = new Map();
722
+ feedbacks.forEach(f => feedbackMap.set(f.TestRunID, f));
723
+ // Aggregate by suite (simplified - would need TestSuiteTest join for accuracy)
724
+ const aggregations = suites.map(suite => {
725
+ // Filter runs by test suite (simplified)
726
+ const suiteRuns = runs; // In reality, need to join through TestSuiteTest
727
+ const totalRuns = suiteRuns.length;
728
+ const passedRuns = suiteRuns.filter(r => r.Status === 'Passed').length;
729
+ const reviewedRuns = suiteRuns.filter(r => feedbackMap.has(r.ID));
730
+ const reviewedCount = reviewedRuns.length;
731
+ const pendingCount = totalRuns - reviewedCount;
732
+ const ratings = reviewedRuns
733
+ .map(r => feedbackMap.get(r.ID)?.Rating || 0)
734
+ .filter(r => r > 0);
735
+ const avgRating = ratings.length > 0
736
+ ? ratings.reduce((sum, r) => sum + r, 0) / ratings.length
737
+ : 0;
738
+ const correctCount = reviewedRuns
739
+ .filter(r => feedbackMap.get(r.ID)?.IsCorrect === true).length;
740
+ const agreementRate = reviewedCount > 0
741
+ ? (correctCount / reviewedCount) * 100
742
+ : 0;
743
+ const passRate = totalRuns > 0 ? (passedRuns / totalRuns) * 100 : 0;
744
+ return {
745
+ suiteId: suite.ID,
746
+ suiteName: suite.Name,
747
+ totalRuns,
748
+ reviewedCount,
749
+ pendingCount,
750
+ avgRating,
751
+ agreementRate,
752
+ passRate
753
+ };
754
+ });
755
+ return aggregations.sort((a, b) => b.pendingCount - a.pendingCount);
756
+ }
757
+ filterAndSortPending(items) {
758
+ let filtered = [...items];
759
+ // Filter by reason
247
760
  if (this.filters.reason !== 'all') {
248
761
  filtered = filtered.filter(f => f.reason === this.filters.reason);
249
762
  }
763
+ // Filter by search text
250
764
  if (this.filters.searchText) {
251
765
  const searchLower = this.filters.searchText.toLowerCase();
252
766
  filtered = filtered.filter(f => f.testName.toLowerCase().includes(searchLower));
253
767
  }
768
+ // Sort
254
769
  filtered.sort((a, b) => {
255
770
  if (this.sortBy === 'date') {
256
771
  return b.runDateTime.getTime() - a.runDateTime.getTime();
257
772
  }
258
773
  else if (this.sortBy === 'priority') {
259
774
  const priorityOrder = { 'high-score-failed': 1, 'low-score-passed': 2, 'no-feedback': 3 };
260
- return (priorityOrder[a.reason] || 99) -
261
- (priorityOrder[b.reason] || 99);
775
+ return (priorityOrder[a.reason] || 99) - (priorityOrder[b.reason] || 99);
262
776
  }
263
777
  else {
264
778
  return a.testName.localeCompare(b.testName);
@@ -266,280 +780,399 @@ export class TestingFeedbackComponent {
266
780
  });
267
781
  return filtered;
268
782
  }
269
- onFilterChange() {
783
+ filterAndSortReviewed(items) {
784
+ let filtered = [...items];
785
+ // Filter by search text
786
+ if (this.filters.searchText) {
787
+ const searchLower = this.filters.searchText.toLowerCase();
788
+ filtered = filtered.filter(f => f.testName.toLowerCase().includes(searchLower) ||
789
+ f.reviewerName.toLowerCase().includes(searchLower));
790
+ }
791
+ // Sort
792
+ filtered.sort((a, b) => {
793
+ if (this.reviewedSortBy === 'date') {
794
+ return b.reviewedAt.getTime() - a.reviewedAt.getTime();
795
+ }
796
+ else if (this.reviewedSortBy === 'rating') {
797
+ return b.rating - a.rating;
798
+ }
799
+ else {
800
+ return a.testName.localeCompare(b.testName);
801
+ }
802
+ });
803
+ return filtered;
804
+ }
805
+ // Event handlers
806
+ setViewMode(mode) {
807
+ this.viewMode = mode;
808
+ this.expandedItem = null;
270
809
  this.emitStateChange();
271
810
  this.cdr.markForCheck();
272
811
  }
273
- clearSearch() {
274
- this.filters.searchText = '';
275
- this.onFilterChange();
812
+ onViewModeChange() {
813
+ this.expandedItem = null;
814
+ this.emitStateChange();
815
+ this.cdr.markForCheck();
816
+ }
817
+ onFilterChange() {
818
+ this.filterTrigger$.next();
819
+ this.emitStateChange();
820
+ this.cdr.markForCheck();
276
821
  }
277
822
  onSortChange() {
823
+ this.filterTrigger$.next();
278
824
  this.emitStateChange();
279
825
  this.cdr.markForCheck();
280
826
  }
827
+ onReviewedSortChange() {
828
+ this.filterTrigger$.next();
829
+ this.cdr.markForCheck();
830
+ }
831
+ clearSearch() {
832
+ this.filters.searchText = '';
833
+ this.onFilterChange();
834
+ }
281
835
  toggleExpanded(testRunID) {
282
836
  this.expandedItem = this.expandedItem === testRunID ? null : testRunID;
283
837
  }
284
- submitFeedback(item) {
285
- console.log('Submit feedback:', item);
286
- this.expandedItem = null;
287
- this.cdr.markForCheck();
838
+ setRating(item, rating) {
839
+ item.feedbackRating = rating;
288
840
  }
289
- skipFeedback(item) {
290
- console.log('Skip feedback:', item);
291
- this.expandedItem = null;
841
+ setCorrectness(item, isCorrect) {
842
+ item.feedbackIsCorrect = isCorrect;
843
+ }
844
+ async submitFeedback(item) {
845
+ if (this.isSubmitting)
846
+ return;
847
+ this.isSubmitting = true;
292
848
  this.cdr.markForCheck();
849
+ try {
850
+ const success = await this.instrumentationService.submitFeedback(item.testRunID, item.feedbackRating, item.feedbackIsCorrect, item.feedbackComments);
851
+ if (success) {
852
+ this.expandedItem = null;
853
+ // Refresh will happen via the service
854
+ }
855
+ else {
856
+ console.error('Failed to submit feedback');
857
+ }
858
+ }
859
+ catch (error) {
860
+ console.error('Error submitting feedback:', error);
861
+ }
862
+ finally {
863
+ this.isSubmitting = false;
864
+ this.cdr.markForCheck();
865
+ }
293
866
  }
294
867
  viewFullDetails(item) {
295
868
  SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(item.testRunID));
296
869
  }
870
+ viewTestRun(testRunId) {
871
+ SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(testRunId));
872
+ }
873
+ selectSuite(suiteId) {
874
+ this.filters.suiteId = suiteId;
875
+ this.viewMode = 'pending';
876
+ this.onFilterChange();
877
+ }
297
878
  refresh() {
879
+ this.isRefreshing = true;
880
+ this.cdr.markForCheck();
298
881
  this.instrumentationService.refresh();
882
+ setTimeout(() => {
883
+ this.isRefreshing = false;
884
+ this.cdr.markForCheck();
885
+ }, 1500);
299
886
  }
300
887
  formatReason(reason) {
301
888
  switch (reason) {
302
889
  case 'no-feedback': return 'No Feedback';
303
- case 'high-score-failed': return 'High Score but Failed';
304
- case 'low-score-passed': return 'Low Score but Passed';
890
+ case 'high-score-failed': return 'High Score Failed';
891
+ case 'low-score-passed': return 'Low Score Passed';
305
892
  default: return reason;
306
893
  }
307
894
  }
308
- getTestStatus(status) {
309
- // Convert automatedStatus string to TestStatus type
310
- return status;
895
+ // Track by functions
896
+ trackByTestRunId(index, item) {
897
+ return item.testRunID;
898
+ }
899
+ trackByReviewedId(index, item) {
900
+ return item.id;
901
+ }
902
+ trackBySuiteId(index, item) {
903
+ return item.suiteId;
311
904
  }
312
905
  emitStateChange() {
313
906
  this.stateChange.emit({
314
907
  filters: this.filters,
908
+ viewMode: this.viewMode,
315
909
  sortBy: this.sortBy
316
910
  });
317
911
  }
318
912
  static ɵfac = function TestingFeedbackComponent_Factory(t) { return new (t || TestingFeedbackComponent)(i0.ɵɵdirectiveInject(i1.TestingInstrumentationService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
319
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestingFeedbackComponent, selectors: [["app-testing-feedback"]], inputs: { initialState: "initialState" }, outputs: { stateChange: "stateChange" }, decls: 133, vars: 48, consts: [[1, "testing-feedback"], [1, "feedback-header"], [1, "header-left"], [1, "fa-solid", "fa-clipboard-check"], ["class", "pending-badge", 4, "ngIf"], [1, "header-actions"], [1, "action-btn", 3, "click"], [1, "fa-solid", "fa-refresh"], [1, "feedback-filters"], [1, "filter-group"], [3, "ngModelChange", "change", "ngModel"], ["value", "all"], ["value", "pending"], ["value", "reviewed"], ["value", "no-feedback"], ["value", "high-score-failed"], ["value", "low-score-passed"], [1, "filter-group", "search"], [1, "search-input-wrapper"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Search tests...", 3, "ngModelChange", "input", "ngModel"], ["class", "clear-btn", 3, "click", 4, "ngIf"], [1, "feedback-summary"], [1, "summary-card"], [1, "summary-icon", "pending"], [1, "fa-solid", "fa-hourglass-half"], [1, "summary-content"], [1, "summary-value"], [1, "summary-label"], [1, "summary-icon", "discrepancy"], [1, "fa-solid", "fa-triangle-exclamation"], [1, "summary-icon", "reviewed"], [1, "fa-solid", "fa-check-circle"], [1, "summary-icon", "accuracy"], [1, "fa-solid", "fa-bullseye"], [1, "feedback-content"], [1, "content-header"], [1, "fa-solid", "fa-list-check"], [1, "sort-controls"], ["value", "date"], ["value", "priority"], ["value", "test-name"], [1, "feedback-list"], [1, "feedback-item", 3, "expanded"], [1, "empty-state"], [1, "feedback-stats"], [1, "stats-section"], [1, "fa-solid", "fa-chart-pie"], [1, "stats-grid"], [1, "stat-card"], [1, "stat-label"], [1, "stat-value"], [1, "pending-badge"], [1, "badge-count"], [1, "badge-text"], [1, "clear-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "feedback-item"], [1, "item-header", 3, "click"], [1, "item-main"], [1, "item-title"], [1, "item-meta"], [1, "meta-date"], [1, "fa-solid", "fa-clock"], [1, "meta-score"], [1, "meta-status"], [3, "status"], [1, "item-reason"], [1, "reason-badge"], [1, "fa-solid"], [1, "expand-btn"], [1, "item-content"], [1, "feedback-form"], [1, "form-section"], [1, "form-row"], [1, "form-group"], ["type", "number", "min", "1", "max", "10", "placeholder", "Rate 1-10", 1, "rating-input", 3, "ngModelChange", "ngModel"], [1, "checkbox-group"], [1, "checkbox-label"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], ["rows", "4", "placeholder", "Provide detailed feedback about this test result...", 1, "comments-textarea", 3, "ngModelChange", "ngModel"], [1, "form-actions"], [1, "submit-btn", 3, "click"], [1, "fa-solid", "fa-paper-plane"], [1, "skip-btn", 3, "click"], [1, "fa-solid", "fa-forward"], [1, "context-section"], [1, "context-details"], [1, "detail-item"], [1, "detail-label"], [1, "detail-value"], [3, "score", "showBar"], [1, "view-details-btn", 3, "click"], [1, "fa-solid", "fa-external-link"], [1, "fa-solid", "fa-check-double"]], template: function TestingFeedbackComponent_Template(rf, ctx) { if (rf & 1) {
320
- i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h2");
321
- i0.ɵɵelement(4, "i", 3);
913
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TestingFeedbackComponent, selectors: [["app-testing-feedback"]], inputs: { initialState: "initialState" }, outputs: { stateChange: "stateChange" }, decls: 107, vars: 54, consts: [["emptyPending", ""], ["emptyReviewed", ""], ["emptySuites", ""], [1, "testing-feedback"], [1, "feedback-header"], [1, "header-left"], [1, "fa-solid", "fa-clipboard-check"], ["class", "pending-badge", 4, "ngIf"], [1, "header-actions"], [1, "action-btn", "refresh-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], [1, "feedback-summary"], [1, "summary-card", "clickable", 3, "click"], [1, "summary-icon", "pending"], [1, "fa-solid", "fa-hourglass-half"], [1, "summary-content"], [1, "summary-value"], [1, "summary-label"], [1, "fa-solid", "fa-chevron-right", "summary-arrow"], [1, "summary-icon", "reviewed"], [1, "fa-solid", "fa-check-circle"], [1, "summary-icon", "suites"], [1, "fa-solid", "fa-layer-group"], [1, "summary-card"], [1, "summary-icon", "accuracy"], [1, "fa-solid", "fa-bullseye"], [1, "feedback-filters"], [1, "filter-group"], [3, "ngModelChange", "change", "ngModel"], ["value", "pending"], ["value", "reviewed"], ["value", "suites"], ["class", "filter-group", 4, "ngIf"], [1, "filter-group", "search"], [1, "search-input-wrapper"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Search tests...", 3, "ngModelChange", "input", "ngModel"], ["class", "clear-btn", 3, "click", 4, "ngIf"], ["class", "feedback-content", 4, "ngIf"], [1, "feedback-stats"], [1, "fa-solid", "fa-chart-pie"], [1, "stats-grid"], [1, "stat-card"], [1, "stat-label"], [1, "stat-value"], [1, "pending-badge"], ["class", "badge-count", 4, "ngIf"], [1, "badge-text"], [1, "badge-count"], ["value", "all"], ["value", "no-feedback"], ["value", "high-score-failed"], ["value", "low-score-passed"], [3, "ngValue"], [3, "ngValue", 4, "ngFor", "ngForOf"], [1, "clear-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "feedback-content"], [1, "content-header"], [1, "fa-solid", "fa-list-check"], [1, "sort-controls"], ["value", "date"], ["value", "priority"], ["value", "test-name"], ["class", "feedback-list", 4, "ngIf"], [1, "feedback-list"], [4, "ngIf", "ngIfElse"], ["class", "feedback-item", 3, "expanded", 4, "ngFor", "ngForOf", "ngForTrackBy"], [1, "feedback-item"], [1, "item-header", 3, "click"], [1, "item-main"], [1, "item-title"], [1, "item-meta"], [1, "meta-date"], [1, "fa-solid", "fa-clock"], [1, "meta-score"], [1, "meta-status"], [1, "item-reason"], [1, "reason-badge"], [1, "fa-solid"], [1, "expand-btn"], ["class", "item-content", 4, "ngIf"], [1, "item-content"], [1, "feedback-form"], [1, "form-section"], [1, "rating-section"], [1, "rating-stars-input"], ["class", "star-btn", 3, "filled", "click", 4, "ngFor", "ngForOf"], [1, "rating-display"], [1, "correctness-section"], [1, "correctness-buttons"], [1, "correctness-btn", "correct", 3, "click"], [1, "fa-solid", "fa-check"], [1, "correctness-btn", "incorrect", 3, "click"], [1, "form-group"], ["rows", "3", "placeholder", "Explain your assessment or provide correction notes...", 1, "comments-textarea", 3, "ngModelChange", "ngModel"], [1, "form-actions"], [1, "submit-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-paper-plane"], [1, "view-btn", 3, "click"], [1, "fa-solid", "fa-external-link"], [1, "star-btn", 3, "click"], [1, "fa-solid", "fa-star"], [1, "empty-state", "success"], [1, "fa-solid", "fa-check-double"], [1, "fa-solid", "fa-history"], ["value", "rating"], ["class", "reviewed-item", 4, "ngFor", "ngForOf", "ngForTrackBy"], [1, "reviewed-item"], [1, "reviewed-header"], [1, "reviewed-main"], [1, "reviewed-title"], [1, "reviewed-meta"], [1, "meta-reviewer"], [1, "fa-solid", "fa-user"], [1, "fa-solid", "fa-calendar"], [1, "reviewed-rating"], [1, "rating-stars"], ["class", "fa-solid fa-star", 3, "filled", 4, "ngFor", "ngForOf"], [1, "rating-text"], [1, "reviewed-verdict"], [1, "verdict-badge"], [1, "view-btn-small", 3, "click"], ["class", "reviewed-comments", 4, "ngIf"], [1, "reviewed-comments"], [1, "empty-state"], [1, "fa-solid", "fa-clipboard"], ["class", "suites-list", 4, "ngIf"], [1, "suites-list"], ["class", "suite-card", 3, "click", 4, "ngFor", "ngForOf", "ngForTrackBy"], [1, "suite-card", 3, "click"], [1, "suite-header"], [1, "suite-icon"], [1, "suite-info"], [1, "suite-meta"], [1, "suite-stats"], [1, "suite-stat"], [1, "stat-value", "pending"], [1, "stat-value", "reviewed"], [1, "fa-solid", "fa-chevron-right", "suite-arrow"]], template: function TestingFeedbackComponent_Template(rf, ctx) { if (rf & 1) {
914
+ i0.ɵɵelementStart(0, "div", 3)(1, "div", 4)(2, "div", 5)(3, "h2");
915
+ i0.ɵɵelement(4, "i", 6);
322
916
  i0.ɵɵtext(5, " Human Feedback Review ");
323
917
  i0.ɵɵelementEnd();
324
- i0.ɵɵtemplate(6, TestingFeedbackComponent_div_6_Template, 6, 3, "div", 4);
918
+ i0.ɵɵtemplate(6, TestingFeedbackComponent_div_6_Template, 4, 2, "div", 7);
325
919
  i0.ɵɵpipe(7, "async");
326
920
  i0.ɵɵelementEnd();
327
- i0.ɵɵelementStart(8, "div", 5)(9, "button", 6);
921
+ i0.ɵɵelementStart(8, "div", 8)(9, "button", 9);
328
922
  i0.ɵɵlistener("click", function TestingFeedbackComponent_Template_button_click_9_listener() { return ctx.refresh(); });
329
- i0.ɵɵelement(10, "i", 7);
330
- i0.ɵɵtext(11, " Refresh ");
923
+ i0.ɵɵelement(10, "i", 10);
924
+ i0.ɵɵtext(11);
331
925
  i0.ɵɵelementEnd()()();
332
- i0.ɵɵelementStart(12, "div", 8)(13, "div", 9)(14, "label");
333
- i0.ɵɵtext(15, "Status");
926
+ i0.ɵɵelementStart(12, "div", 11)(13, "div", 12);
927
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_Template_div_click_13_listener() { return ctx.setViewMode("pending"); });
928
+ i0.ɵɵelementStart(14, "div", 13);
929
+ i0.ɵɵelement(15, "i", 14);
334
930
  i0.ɵɵelementEnd();
335
- i0.ɵɵelementStart(16, "select", 10);
336
- i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_select_ngModelChange_16_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.status, $event) || (ctx.filters.status = $event); return $event; });
337
- i0.ɵɵlistener("change", function TestingFeedbackComponent_Template_select_change_16_listener() { return ctx.onFilterChange(); });
338
- i0.ɵɵelementStart(17, "option", 11);
339
- i0.ɵɵtext(18, "All");
931
+ i0.ɵɵelementStart(16, "div", 15)(17, "div", 16);
932
+ i0.ɵɵtext(18);
933
+ i0.ɵɵpipe(19, "async");
340
934
  i0.ɵɵelementEnd();
341
- i0.ɵɵelementStart(19, "option", 12);
342
- i0.ɵɵtext(20, "Pending Review");
935
+ i0.ɵɵelementStart(20, "div", 17);
936
+ i0.ɵɵtext(21, "Pending Review");
937
+ i0.ɵɵelementEnd()();
938
+ i0.ɵɵelement(22, "i", 18);
343
939
  i0.ɵɵelementEnd();
344
- i0.ɵɵelementStart(21, "option", 13);
345
- i0.ɵɵtext(22, "Reviewed");
346
- i0.ɵɵelementEnd()()();
347
- i0.ɵɵelementStart(23, "div", 9)(24, "label");
348
- i0.ɵɵtext(25, "Reason");
940
+ i0.ɵɵelementStart(23, "div", 12);
941
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_Template_div_click_23_listener() { return ctx.setViewMode("reviewed"); });
942
+ i0.ɵɵelementStart(24, "div", 19);
943
+ i0.ɵɵelement(25, "i", 20);
349
944
  i0.ɵɵelementEnd();
350
- i0.ɵɵelementStart(26, "select", 10);
351
- i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_select_ngModelChange_26_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.reason, $event) || (ctx.filters.reason = $event); return $event; });
352
- i0.ɵɵlistener("change", function TestingFeedbackComponent_Template_select_change_26_listener() { return ctx.onFilterChange(); });
353
- i0.ɵɵelementStart(27, "option", 11);
354
- i0.ɵɵtext(28, "All Reasons");
945
+ i0.ɵɵelementStart(26, "div", 15)(27, "div", 16);
946
+ i0.ɵɵtext(28);
947
+ i0.ɵɵpipe(29, "async");
355
948
  i0.ɵɵelementEnd();
356
- i0.ɵɵelementStart(29, "option", 14);
357
- i0.ɵɵtext(30, "No Feedback");
949
+ i0.ɵɵelementStart(30, "div", 17);
950
+ i0.ɵɵtext(31, "Reviewed");
951
+ i0.ɵɵelementEnd()();
952
+ i0.ɵɵelement(32, "i", 18);
358
953
  i0.ɵɵelementEnd();
359
- i0.ɵɵelementStart(31, "option", 15);
360
- i0.ɵɵtext(32, "High Score but Failed");
954
+ i0.ɵɵelementStart(33, "div", 12);
955
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_Template_div_click_33_listener() { return ctx.setViewMode("suites"); });
956
+ i0.ɵɵelementStart(34, "div", 21);
957
+ i0.ɵɵelement(35, "i", 22);
361
958
  i0.ɵɵelementEnd();
362
- i0.ɵɵelementStart(33, "option", 16);
363
- i0.ɵɵtext(34, "Low Score but Passed");
364
- i0.ɵɵelementEnd()()();
365
- i0.ɵɵelementStart(35, "div", 17)(36, "label");
366
- i0.ɵɵtext(37, "Search");
959
+ i0.ɵɵelementStart(36, "div", 15)(37, "div", 16);
960
+ i0.ɵɵtext(38);
961
+ i0.ɵɵpipe(39, "async");
367
962
  i0.ɵɵelementEnd();
368
- i0.ɵɵelementStart(38, "div", 18);
369
- i0.ɵɵelement(39, "i", 19);
370
- i0.ɵɵelementStart(40, "input", 20);
371
- i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_input_ngModelChange_40_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.searchText, $event) || (ctx.filters.searchText = $event); return $event; });
372
- i0.ɵɵlistener("input", function TestingFeedbackComponent_Template_input_input_40_listener() { return ctx.onFilterChange(); });
963
+ i0.ɵɵelementStart(40, "div", 17);
964
+ i0.ɵɵtext(41, "Test Suites");
965
+ i0.ɵɵelementEnd()();
966
+ i0.ɵɵelement(42, "i", 18);
373
967
  i0.ɵɵelementEnd();
374
- i0.ɵɵtemplate(41, TestingFeedbackComponent_button_41_Template, 2, 0, "button", 21);
375
- i0.ɵɵelementEnd()()();
376
- i0.ɵɵelementStart(42, "div", 22)(43, "div", 23)(44, "div", 24);
968
+ i0.ɵɵelementStart(43, "div", 23)(44, "div", 24);
377
969
  i0.ɵɵelement(45, "i", 25);
378
970
  i0.ɵɵelementEnd();
379
- i0.ɵɵelementStart(46, "div", 26)(47, "div", 27);
971
+ i0.ɵɵelementStart(46, "div", 15)(47, "div", 16);
380
972
  i0.ɵɵtext(48);
381
973
  i0.ɵɵpipe(49, "async");
974
+ i0.ɵɵpipe(50, "number");
382
975
  i0.ɵɵelementEnd();
383
- i0.ɵɵelementStart(50, "div", 28);
384
- i0.ɵɵtext(51, "Pending Review");
385
- i0.ɵɵelementEnd()()();
386
- i0.ɵɵelementStart(52, "div", 23)(53, "div", 29);
387
- i0.ɵɵelement(54, "i", 30);
388
- i0.ɵɵelementEnd();
389
- i0.ɵɵelementStart(55, "div", 26)(56, "div", 27);
390
- i0.ɵɵtext(57);
391
- i0.ɵɵpipe(58, "async");
976
+ i0.ɵɵelementStart(51, "div", 17);
977
+ i0.ɵɵtext(52, "Human-AI Agreement");
978
+ i0.ɵɵelementEnd()()()();
979
+ i0.ɵɵelementStart(53, "div", 26)(54, "div", 27)(55, "label");
980
+ i0.ɵɵtext(56, "View");
392
981
  i0.ɵɵelementEnd();
393
- i0.ɵɵelementStart(59, "div", 28);
394
- i0.ɵɵtext(60, "Score Discrepancies");
395
- i0.ɵɵelementEnd()()();
396
- i0.ɵɵelementStart(61, "div", 23)(62, "div", 31);
397
- i0.ɵɵelement(63, "i", 32);
982
+ i0.ɵɵelementStart(57, "select", 28);
983
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_select_ngModelChange_57_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.viewMode, $event) || (ctx.viewMode = $event); return $event; });
984
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_Template_select_change_57_listener() { return ctx.onViewModeChange(); });
985
+ i0.ɵɵelementStart(58, "option", 29);
986
+ i0.ɵɵtext(59, "Pending Reviews");
398
987
  i0.ɵɵelementEnd();
399
- i0.ɵɵelementStart(64, "div", 26)(65, "div", 27);
400
- i0.ɵɵtext(66);
401
- i0.ɵɵpipe(67, "async");
988
+ i0.ɵɵelementStart(60, "option", 30);
989
+ i0.ɵɵtext(61, "Reviewed Feedback");
402
990
  i0.ɵɵelementEnd();
403
- i0.ɵɵelementStart(68, "div", 28);
404
- i0.ɵɵtext(69, "Reviewed");
991
+ i0.ɵɵelementStart(62, "option", 31);
992
+ i0.ɵɵtext(63, "By Test Suite");
405
993
  i0.ɵɵelementEnd()()();
406
- i0.ɵɵelementStart(70, "div", 23)(71, "div", 33);
407
- i0.ɵɵelement(72, "i", 34);
408
- i0.ɵɵelementEnd();
409
- i0.ɵɵelementStart(73, "div", 26)(74, "div", 27);
410
- i0.ɵɵtext(75);
411
- i0.ɵɵpipe(76, "async");
412
- i0.ɵɵpipe(77, "number");
413
- i0.ɵɵelementEnd();
414
- i0.ɵɵelementStart(78, "div", 28);
415
- i0.ɵɵtext(79, "Human-AI Agreement");
416
- i0.ɵɵelementEnd()()()();
417
- i0.ɵɵelementStart(80, "div", 35)(81, "div", 36)(82, "h3");
418
- i0.ɵɵelement(83, "i", 37);
419
- i0.ɵɵtext(84, " Tests Requiring Review ");
420
- i0.ɵɵelementEnd();
421
- i0.ɵɵelementStart(85, "div", 38)(86, "label");
422
- i0.ɵɵtext(87, "Sort by:");
994
+ i0.ɵɵtemplate(64, TestingFeedbackComponent_div_64_Template, 12, 1, "div", 32)(65, TestingFeedbackComponent_div_65_Template, 8, 5, "div", 32);
995
+ i0.ɵɵelementStart(66, "div", 33)(67, "label");
996
+ i0.ɵɵtext(68, "Search");
423
997
  i0.ɵɵelementEnd();
424
- i0.ɵɵelementStart(88, "select", 10);
425
- i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_select_ngModelChange_88_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.sortBy, $event) || (ctx.sortBy = $event); return $event; });
426
- i0.ɵɵlistener("change", function TestingFeedbackComponent_Template_select_change_88_listener() { return ctx.onSortChange(); });
427
- i0.ɵɵelementStart(89, "option", 39);
428
- i0.ɵɵtext(90, "Date");
998
+ i0.ɵɵelementStart(69, "div", 34);
999
+ i0.ɵɵelement(70, "i", 35);
1000
+ i0.ɵɵelementStart(71, "input", 36);
1001
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_input_ngModelChange_71_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.searchText, $event) || (ctx.filters.searchText = $event); return $event; });
1002
+ i0.ɵɵlistener("input", function TestingFeedbackComponent_Template_input_input_71_listener() { return ctx.onFilterChange(); });
429
1003
  i0.ɵɵelementEnd();
430
- i0.ɵɵelementStart(91, "option", 40);
431
- i0.ɵɵtext(92, "Priority");
432
- i0.ɵɵelementEnd();
433
- i0.ɵɵelementStart(93, "option", 41);
434
- i0.ɵɵtext(94, "Test Name");
435
- i0.ɵɵelementEnd()()()();
436
- i0.ɵɵelementStart(95, "div", 42);
437
- i0.ɵɵrepeaterCreate(96, TestingFeedbackComponent_For_97_Template, 24, 23, "div", 43, _forTrack0, false, TestingFeedbackComponent_ForEmpty_98_Template, 6, 0, "div", 44);
438
- i0.ɵɵpipe(99, "async");
439
- i0.ɵɵelementEnd()();
440
- i0.ɵɵelementStart(100, "div", 45)(101, "div", 46)(102, "h3");
441
- i0.ɵɵelement(103, "i", 47);
442
- i0.ɵɵtext(104, " Feedback Statistics ");
1004
+ i0.ɵɵtemplate(72, TestingFeedbackComponent_button_72_Template, 2, 0, "button", 37);
1005
+ i0.ɵɵelementEnd()()();
1006
+ i0.ɵɵtemplate(73, TestingFeedbackComponent_div_73_Template, 17, 4, "div", 38)(74, TestingFeedbackComponent_div_74_Template, 17, 4, "div", 38)(75, TestingFeedbackComponent_div_75_Template, 7, 3, "div", 38);
1007
+ i0.ɵɵelementStart(76, "div", 39)(77, "h3");
1008
+ i0.ɵɵelement(78, "i", 40);
1009
+ i0.ɵɵtext(79, " Feedback Statistics ");
443
1010
  i0.ɵɵelementEnd();
444
- i0.ɵɵelementStart(105, "div", 48)(106, "div", 49)(107, "div", 50);
445
- i0.ɵɵtext(108, "Total Feedback Submitted");
1011
+ i0.ɵɵelementStart(80, "div", 41)(81, "div", 42)(82, "div", 43);
1012
+ i0.ɵɵtext(83, "Total Feedback");
446
1013
  i0.ɵɵelementEnd();
447
- i0.ɵɵelementStart(109, "div", 51);
448
- i0.ɵɵtext(110);
449
- i0.ɵɵpipe(111, "async");
1014
+ i0.ɵɵelementStart(84, "div", 44);
1015
+ i0.ɵɵtext(85);
1016
+ i0.ɵɵpipe(86, "async");
450
1017
  i0.ɵɵelementEnd()();
451
- i0.ɵɵelementStart(112, "div", 49)(113, "div", 50);
452
- i0.ɵɵtext(114, "Avg Rating");
1018
+ i0.ɵɵelementStart(87, "div", 42)(88, "div", 43);
1019
+ i0.ɵɵtext(89, "Avg Rating");
453
1020
  i0.ɵɵelementEnd();
454
- i0.ɵɵelementStart(115, "div", 51);
455
- i0.ɵɵtext(116);
456
- i0.ɵɵpipe(117, "async");
457
- i0.ɵɵpipe(118, "number");
1021
+ i0.ɵɵelementStart(90, "div", 44);
1022
+ i0.ɵɵtext(91);
1023
+ i0.ɵɵpipe(92, "async");
1024
+ i0.ɵɵpipe(93, "number");
458
1025
  i0.ɵɵelementEnd()();
459
- i0.ɵɵelementStart(119, "div", 49)(120, "div", 50);
460
- i0.ɵɵtext(121, "Agreement Rate");
1026
+ i0.ɵɵelementStart(94, "div", 42)(95, "div", 43);
1027
+ i0.ɵɵtext(96, "Agreement Rate");
461
1028
  i0.ɵɵelementEnd();
462
- i0.ɵɵelementStart(122, "div", 51);
463
- i0.ɵɵtext(123);
464
- i0.ɵɵpipe(124, "async");
465
- i0.ɵɵpipe(125, "number");
1029
+ i0.ɵɵelementStart(97, "div", 44);
1030
+ i0.ɵɵtext(98);
1031
+ i0.ɵɵpipe(99, "async");
1032
+ i0.ɵɵpipe(100, "number");
466
1033
  i0.ɵɵelementEnd()();
467
- i0.ɵɵelementStart(126, "div", 49)(127, "div", 50);
468
- i0.ɵɵtext(128, "Disagreement Rate");
1034
+ i0.ɵɵelementStart(101, "div", 42)(102, "div", 43);
1035
+ i0.ɵɵtext(103, "Discrepancy Count");
469
1036
  i0.ɵɵelementEnd();
470
- i0.ɵɵelementStart(129, "div", 51);
471
- i0.ɵɵtext(130);
472
- i0.ɵɵpipe(131, "async");
473
- i0.ɵɵpipe(132, "number");
474
- i0.ɵɵelementEnd()()()()()();
1037
+ i0.ɵɵelementStart(104, "div", 44);
1038
+ i0.ɵɵtext(105);
1039
+ i0.ɵɵpipe(106, "async");
1040
+ i0.ɵɵelementEnd()()()()();
475
1041
  } if (rf & 2) {
1042
+ let tmp_5_0;
1043
+ let tmp_7_0;
1044
+ let tmp_9_0;
476
1045
  let tmp_10_0;
1046
+ let tmp_19_0;
1047
+ let tmp_20_0;
1048
+ let tmp_21_0;
1049
+ let tmp_22_0;
477
1050
  i0.ɵɵadvance(6);
478
- i0.ɵɵproperty("ngIf", i0.ɵɵpipeBind1(7, 15, ctx.pendingCount$) || 0 > 0);
479
- i0.ɵɵadvance(10);
480
- i0.ɵɵtwoWayProperty("ngModel", ctx.filters.status);
1051
+ i0.ɵɵproperty("ngIf", i0.ɵɵpipeBind1(7, 27, ctx.pendingCount$));
1052
+ i0.ɵɵadvance(3);
1053
+ i0.ɵɵproperty("disabled", ctx.isRefreshing);
1054
+ i0.ɵɵadvance();
1055
+ i0.ɵɵclassProp("fa-spin", ctx.isRefreshing);
1056
+ i0.ɵɵadvance();
1057
+ i0.ɵɵtextInterpolate1(" ", ctx.isRefreshing ? "Refreshing..." : "Refresh", " ");
1058
+ i0.ɵɵadvance(2);
1059
+ i0.ɵɵclassProp("active", ctx.viewMode === "pending");
1060
+ i0.ɵɵadvance(5);
1061
+ i0.ɵɵtextInterpolate((tmp_5_0 = i0.ɵɵpipeBind1(19, 29, ctx.pendingCount$)) !== null && tmp_5_0 !== undefined ? tmp_5_0 : 0);
1062
+ i0.ɵɵadvance(5);
1063
+ i0.ɵɵclassProp("active", ctx.viewMode === "reviewed");
1064
+ i0.ɵɵadvance(5);
1065
+ i0.ɵɵtextInterpolate((tmp_7_0 = i0.ɵɵpipeBind1(29, 31, ctx.reviewedCount$)) !== null && tmp_7_0 !== undefined ? tmp_7_0 : 0);
1066
+ i0.ɵɵadvance(5);
1067
+ i0.ɵɵclassProp("active", ctx.viewMode === "suites");
1068
+ i0.ɵɵadvance(5);
1069
+ i0.ɵɵtextInterpolate((tmp_9_0 = i0.ɵɵpipeBind1(39, 33, ctx.suiteCount$)) !== null && tmp_9_0 !== undefined ? tmp_9_0 : 0);
481
1070
  i0.ɵɵadvance(10);
482
- i0.ɵɵtwoWayProperty("ngModel", ctx.filters.reason);
483
- i0.ɵɵadvance(14);
1071
+ i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(50, 37, (tmp_10_0 = i0.ɵɵpipeBind1(49, 35, ctx.accuracyRate$)) !== null && tmp_10_0 !== undefined ? tmp_10_0 : 0, "1.1-1"), "%");
1072
+ i0.ɵɵadvance(9);
1073
+ i0.ɵɵtwoWayProperty("ngModel", ctx.viewMode);
1074
+ i0.ɵɵadvance(7);
1075
+ i0.ɵɵproperty("ngIf", ctx.viewMode === "pending");
1076
+ i0.ɵɵadvance();
1077
+ i0.ɵɵproperty("ngIf", ctx.viewMode !== "suites");
1078
+ i0.ɵɵadvance(6);
484
1079
  i0.ɵɵtwoWayProperty("ngModel", ctx.filters.searchText);
485
1080
  i0.ɵɵadvance();
486
1081
  i0.ɵɵproperty("ngIf", ctx.filters.searchText);
487
- i0.ɵɵadvance(7);
488
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(49, 17, ctx.pendingCount$) || 0);
489
- i0.ɵɵadvance(9);
490
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(58, 19, ctx.discrepancyCount$) || 0);
491
- i0.ɵɵadvance(9);
492
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(67, 21, ctx.reviewedCount$) || 0);
493
- i0.ɵɵadvance(9);
494
- i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(77, 25, i0.ɵɵpipeBind1(76, 23, ctx.accuracyRate$) || 0, "1.1-1"), "%");
495
- i0.ɵɵadvance(13);
496
- i0.ɵɵtwoWayProperty("ngModel", ctx.sortBy);
497
- i0.ɵɵadvance(8);
498
- i0.ɵɵrepeater((tmp_10_0 = i0.ɵɵpipeBind1(99, 28, ctx.filteredFeedback$)) !== null && tmp_10_0 !== undefined ? tmp_10_0 : i0.ɵɵpureFunction0(47, _c0));
499
- i0.ɵɵadvance(14);
500
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(111, 30, ctx.totalFeedback$) || 0);
1082
+ i0.ɵɵadvance();
1083
+ i0.ɵɵproperty("ngIf", ctx.viewMode === "pending");
1084
+ i0.ɵɵadvance();
1085
+ i0.ɵɵproperty("ngIf", ctx.viewMode === "reviewed");
1086
+ i0.ɵɵadvance();
1087
+ i0.ɵɵproperty("ngIf", ctx.viewMode === "suites");
1088
+ i0.ɵɵadvance(10);
1089
+ i0.ɵɵtextInterpolate((tmp_19_0 = i0.ɵɵpipeBind1(86, 40, ctx.totalFeedback$)) !== null && tmp_19_0 !== undefined ? tmp_19_0 : 0);
501
1090
  i0.ɵɵadvance(6);
502
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(118, 34, i0.ɵɵpipeBind1(117, 32, ctx.avgRating$) || 0, "1.1-1"));
1091
+ i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(93, 44, (tmp_20_0 = i0.ɵɵpipeBind1(92, 42, ctx.avgRating$)) !== null && tmp_20_0 !== undefined ? tmp_20_0 : 0, "1.1-1"), "/10");
503
1092
  i0.ɵɵadvance(7);
504
- i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(125, 39, i0.ɵɵpipeBind1(124, 37, ctx.agreementRate$) || 0, "1.1-1"), "%");
1093
+ i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(100, 49, (tmp_21_0 = i0.ɵɵpipeBind1(99, 47, ctx.agreementRate$)) !== null && tmp_21_0 !== undefined ? tmp_21_0 : 0, "1.1-1"), "%");
505
1094
  i0.ɵɵadvance(7);
506
- i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(132, 44, i0.ɵɵpipeBind1(131, 42, ctx.disagreementRate$) || 0, "1.1-1"), "%");
507
- } }, dependencies: [i2.NgIf, i3.NgSelectOption, i3.ɵNgSelectMultipleOption, i3.DefaultValueAccessor, i3.NumberValueAccessor, i3.CheckboxControlValueAccessor, i3.SelectControlValueAccessor, i3.NgControlStatus, i3.MinValidator, i3.MaxValidator, i3.NgModel, i4.TestStatusBadgeComponent, i4.ScoreIndicatorComponent, i2.AsyncPipe, i2.DecimalPipe, i2.DatePipe], styles: [".testing-feedback[_ngcontent-%COMP%] {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background: #f8f9fa;\n }\n\n .feedback-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 24px;\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .header-left[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-left[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .pending-badge[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: #fff3e0;\n border: 2px solid #ff9800;\n border-radius: 20px;\n }\n\n .badge-count[_ngcontent-%COMP%] {\n background: #ff9800;\n color: white;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n }\n\n .badge-text[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: #ff9800;\n }\n\n .action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: 1px solid #ddd;\n border-radius: 4px;\n background: white;\n color: #666;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .action-btn[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n }\n\n .feedback-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n margin-bottom: 20px;\n background: white;\n padding: 16px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 150px;\n }\n\n .filter-group.search[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .filter-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n }\n\n .filter-group[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n background: white;\n }\n\n .search-input-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-input-wrapper[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n color: #999;\n font-size: 12px;\n }\n\n .search-input-wrapper[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n flex: 1;\n padding: 8px 40px 8px 36px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n }\n\n .clear-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n background: none;\n border: none;\n color: #999;\n cursor: pointer;\n padding: 4px;\n }\n\n .clear-btn[_ngcontent-%COMP%]:hover {\n color: #333;\n }\n\n .feedback-summary[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 16px;\n margin-bottom: 24px;\n }\n\n .summary-card[_ngcontent-%COMP%] {\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .summary-icon[_ngcontent-%COMP%] {\n width: 56px;\n height: 56px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n color: white;\n }\n\n .summary-icon.pending[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);\n }\n\n .summary-icon.discrepancy[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%);\n }\n\n .summary-icon.reviewed[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #4caf50 0%, #388e3c 100%);\n }\n\n .summary-icon.accuracy[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);\n }\n\n .summary-content[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .summary-value[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: #333;\n line-height: 1;\n margin-bottom: 6px;\n }\n\n .summary-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #666;\n font-weight: 600;\n text-transform: uppercase;\n }\n\n .feedback-content[_ngcontent-%COMP%] {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n margin-bottom: 24px;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 20px;\n background: #f8f9fa;\n border-bottom: 2px solid #e0e0e0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .content-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .content-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .sort-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #666;\n }\n\n .sort-controls[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n padding: 6px 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n }\n\n .feedback-list[_ngcontent-%COMP%] {\n max-height: 800px;\n overflow-y: auto;\n }\n\n .feedback-item[_ngcontent-%COMP%] {\n border-bottom: 1px solid #f0f0f0;\n transition: all 0.3s ease;\n }\n\n .feedback-item.expanded[_ngcontent-%COMP%] {\n background: #f8f9fa;\n }\n\n .item-header[_ngcontent-%COMP%] {\n padding: 20px;\n display: flex;\n align-items: center;\n gap: 16px;\n cursor: pointer;\n transition: background 0.2s ease;\n }\n\n .item-header[_ngcontent-%COMP%]:hover {\n background: rgba(33, 150, 243, 0.05);\n }\n\n .item-main[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .item-title[_ngcontent-%COMP%] {\n font-size: 15px;\n font-weight: 600;\n color: #333;\n margin-bottom: 8px;\n }\n\n .item-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #666;\n }\n\n .item-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .item-reason[_ngcontent-%COMP%] {\n min-width: 180px;\n }\n\n .reason-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .reason-badge.no-feedback[_ngcontent-%COMP%] {\n background: #e3f2fd;\n color: #2196f3;\n }\n\n .reason-badge.high-score-failed[_ngcontent-%COMP%] {\n background: #ffebee;\n color: #f44336;\n }\n\n .reason-badge.low-score-passed[_ngcontent-%COMP%] {\n background: #fff3e0;\n color: #ff9800;\n }\n\n .expand-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: #666;\n cursor: pointer;\n padding: 8px;\n border-radius: 4px;\n transition: all 0.2s ease;\n font-size: 16px;\n }\n\n .expand-btn[_ngcontent-%COMP%]:hover {\n background: #e0e0e0;\n }\n\n .item-content[_ngcontent-%COMP%] {\n padding: 20px;\n border-top: 1px solid #e0e0e0;\n animation: _ngcontent-%COMP%_slideDown 0.3s ease;\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-form[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 2fr 1fr;\n gap: 24px;\n }\n\n .form-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%], \n .context-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n padding-bottom: 12px;\n border-bottom: 2px solid #f0f0f0;\n }\n\n .form-row[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 1fr 2fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n .form-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .form-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: #666;\n }\n\n .rating-input[_ngcontent-%COMP%] {\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n }\n\n .checkbox-group[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n }\n\n .checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #333;\n cursor: pointer;\n }\n\n .checkbox-label[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n }\n\n .comments-textarea[_ngcontent-%COMP%] {\n padding: 10px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n font-family: inherit;\n resize: vertical;\n }\n\n .form-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n margin-top: 16px;\n }\n\n .submit-btn[_ngcontent-%COMP%], \n .skip-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .submit-btn[_ngcontent-%COMP%] {\n background: #2196f3;\n color: white;\n }\n\n .submit-btn[_ngcontent-%COMP%]:hover {\n background: #1976d2;\n }\n\n .skip-btn[_ngcontent-%COMP%] {\n background: #f5f5f5;\n color: #666;\n }\n\n .skip-btn[_ngcontent-%COMP%]:hover {\n background: #e0e0e0;\n }\n\n .context-details[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin-bottom: 16px;\n }\n\n .detail-item[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px;\n background: white;\n border-radius: 4px;\n border: 1px solid #e0e0e0;\n }\n\n .detail-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n }\n\n .detail-value[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n color: #333;\n }\n\n .view-details-btn[_ngcontent-%COMP%] {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 10px;\n border: 1px solid #2196f3;\n border-radius: 4px;\n background: white;\n color: #2196f3;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .view-details-btn[_ngcontent-%COMP%]:hover {\n background: #e3f2fd;\n }\n\n .empty-state[_ngcontent-%COMP%] {\n padding: 80px 20px;\n text-align: center;\n color: #999;\n }\n\n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 64px;\n margin-bottom: 20px;\n opacity: 0.3;\n color: #4caf50;\n }\n\n .empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 20px;\n color: #666;\n margin: 0 0 12px 0;\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin: 0;\n }\n\n .feedback-stats[_ngcontent-%COMP%] {\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .feedback-stats[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n padding-bottom: 12px;\n border-bottom: 2px solid #f0f0f0;\n }\n\n .feedback-stats[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196f3;\n }\n\n .stats-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n }\n\n .stat-card[_ngcontent-%COMP%] {\n background: #f8f9fa;\n padding: 16px;\n border-radius: 6px;\n text-align: center;\n }\n\n .stat-label[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n margin-bottom: 8px;\n }\n\n .stat-value[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: #333;\n }\n\n @media (max-width: 1200px) {\n .feedback-form[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .form-row[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n }"], changeDetection: 0 });
1095
+ i0.ɵɵtextInterpolate((tmp_22_0 = i0.ɵɵpipeBind1(106, 52, ctx.discrepancyCount$)) !== null && tmp_22_0 !== undefined ? tmp_22_0 : 0);
1096
+ } }, dependencies: [i2.NgForOf, i2.NgIf, i3.NgSelectOption, i3.ɵNgSelectMultipleOption, i3.DefaultValueAccessor, i3.SelectControlValueAccessor, i3.NgControlStatus, i3.NgModel, i2.AsyncPipe, i2.DecimalPipe, i2.DatePipe], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n }\n\n .testing-feedback[_ngcontent-%COMP%] {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background: #f8f9fa;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n \n\n .feedback-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n background: white;\n padding: 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n }\n\n .header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .header-left[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 22px;\n font-weight: 700;\n color: #1e293b;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-left[_ngcontent-%COMP%] h2[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #3b82f6;\n }\n\n .pending-badge[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 14px;\n background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);\n border: 1px solid #fb923c;\n border-radius: 20px;\n }\n\n .badge-count[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);\n color: white;\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n }\n\n .badge-text[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: #ea580c;\n }\n\n .action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n background: white;\n color: #64748b;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .action-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f8fafc;\n border-color: #cbd5e1;\n }\n\n .action-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n \n\n .feedback-summary[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n margin-bottom: 20px;\n }\n\n .summary-card[_ngcontent-%COMP%] {\n background: white;\n padding: 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n align-items: center;\n gap: 16px;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .summary-card.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n }\n\n .summary-card.clickable[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);\n }\n\n .summary-card.active[_ngcontent-%COMP%] {\n border: 2px solid #3b82f6;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n }\n\n .summary-icon[_ngcontent-%COMP%] {\n width: 52px;\n height: 52px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n color: white;\n flex-shrink: 0;\n }\n\n .summary-icon.pending[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);\n }\n\n .summary-icon.reviewed[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);\n }\n\n .summary-icon.suites[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n }\n\n .summary-icon.accuracy[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);\n }\n\n .summary-content[_ngcontent-%COMP%] {\n flex: 1;\n }\n\n .summary-value[_ngcontent-%COMP%] {\n font-size: 28px;\n font-weight: 700;\n color: #1e293b;\n line-height: 1;\n margin-bottom: 4px;\n }\n\n .summary-label[_ngcontent-%COMP%] {\n font-size: 11px;\n color: #64748b;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .summary-arrow[_ngcontent-%COMP%] {\n color: #94a3b8;\n font-size: 14px;\n }\n\n \n\n .feedback-filters[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n margin-bottom: 20px;\n background: white;\n padding: 16px 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n flex-wrap: wrap;\n }\n\n .filter-group[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 140px;\n }\n\n .filter-group.search[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 200px;\n }\n\n .filter-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .filter-group[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n padding: 10px 12px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 13px;\n background: white;\n color: #1e293b;\n cursor: pointer;\n }\n\n .filter-group[_ngcontent-%COMP%] select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .search-input-wrapper[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-input-wrapper[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n color: #94a3b8;\n font-size: 13px;\n }\n\n .search-input-wrapper[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n flex: 1;\n padding: 10px 40px 10px 36px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 13px;\n }\n\n .search-input-wrapper[_ngcontent-%COMP%] input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .clear-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 6px;\n border-radius: 4px;\n }\n\n .clear-btn[_ngcontent-%COMP%]:hover {\n color: #64748b;\n background: #f1f5f9;\n }\n\n \n\n .feedback-content[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n margin-bottom: 20px;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 20px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-bottom: 1px solid #e2e8f0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .content-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #1e293b;\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .content-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #3b82f6;\n }\n\n .sort-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #64748b;\n }\n\n .sort-controls[_ngcontent-%COMP%] select[_ngcontent-%COMP%] {\n padding: 6px 10px;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n font-size: 12px;\n background: white;\n }\n\n \n\n .feedback-list[_ngcontent-%COMP%] {\n max-height: 600px;\n overflow-y: auto;\n }\n\n .feedback-item[_ngcontent-%COMP%] {\n border-bottom: 1px solid #f1f5f9;\n transition: all 0.2s ease;\n }\n\n .feedback-item.expanded[_ngcontent-%COMP%] {\n background: #f8fafc;\n }\n\n .item-header[_ngcontent-%COMP%] {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 16px;\n cursor: pointer;\n transition: background 0.2s ease;\n }\n\n .item-header[_ngcontent-%COMP%]:hover {\n background: rgba(59, 130, 246, 0.04);\n }\n\n .item-main[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n\n .item-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 6px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .item-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #64748b;\n flex-wrap: wrap;\n }\n\n .item-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .meta-status[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n font-size: 11px;\n }\n\n .meta-status.status-passed[_ngcontent-%COMP%] { background: #dcfce7; color: #16a34a; }\n .meta-status.status-failed[_ngcontent-%COMP%] { background: #fee2e2; color: #dc2626; }\n .meta-status.status-error[_ngcontent-%COMP%] { background: #fef3c7; color: #d97706; }\n .meta-status.status-running[_ngcontent-%COMP%] { background: #dbeafe; color: #2563eb; }\n\n .item-reason[_ngcontent-%COMP%] {\n flex-shrink: 0;\n }\n\n .reason-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .reason-badge.no-feedback[_ngcontent-%COMP%] {\n background: #dbeafe;\n color: #2563eb;\n }\n\n .reason-badge.high-score-failed[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #dc2626;\n }\n\n .reason-badge.low-score-passed[_ngcontent-%COMP%] {\n background: #fef3c7;\n color: #d97706;\n }\n\n .expand-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 8px;\n border-radius: 6px;\n transition: all 0.2s ease;\n font-size: 14px;\n }\n\n .expand-btn[_ngcontent-%COMP%]:hover {\n background: #e2e8f0;\n color: #64748b;\n }\n\n \n\n .item-content[_ngcontent-%COMP%] {\n padding: 20px;\n border-top: 1px solid #e2e8f0;\n background: white;\n }\n\n .feedback-form[_ngcontent-%COMP%] {\n max-width: 600px;\n }\n\n .form-section[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 20px 0;\n font-size: 15px;\n font-weight: 600;\n color: #1e293b;\n }\n\n .rating-section[_ngcontent-%COMP%], \n .correctness-section[_ngcontent-%COMP%] {\n margin-bottom: 20px;\n }\n\n .rating-section[_ngcontent-%COMP%] label[_ngcontent-%COMP%], \n .correctness-section[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n margin-bottom: 10px;\n }\n\n .rating-stars-input[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .star-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n font-size: 22px;\n color: #e2e8f0;\n cursor: pointer;\n padding: 2px;\n transition: all 0.15s ease;\n }\n\n .star-btn[_ngcontent-%COMP%]:hover {\n transform: scale(1.2);\n }\n\n .star-btn.filled[_ngcontent-%COMP%] {\n color: #f59e0b;\n }\n\n .rating-display[_ngcontent-%COMP%] {\n margin-left: 12px;\n font-size: 16px;\n font-weight: 700;\n color: #1e293b;\n }\n\n .correctness-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n }\n\n .correctness-btn[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 20px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n background: white;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .correctness-btn.correct[_ngcontent-%COMP%]:hover, \n .correctness-btn.correct.active[_ngcontent-%COMP%] {\n border-color: #22c55e;\n background: #f0fdf4;\n color: #16a34a;\n }\n\n .correctness-btn.incorrect[_ngcontent-%COMP%]:hover, \n .correctness-btn.incorrect.active[_ngcontent-%COMP%] {\n border-color: #ef4444;\n background: #fef2f2;\n color: #dc2626;\n }\n\n .form-group[_ngcontent-%COMP%] {\n margin-bottom: 16px;\n }\n\n .form-group[_ngcontent-%COMP%] label[_ngcontent-%COMP%] {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n margin-bottom: 8px;\n }\n\n .comments-textarea[_ngcontent-%COMP%] {\n width: 100%;\n padding: 12px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n }\n\n .comments-textarea[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .form-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n margin-top: 20px;\n }\n\n .submit-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n border-radius: 8px;\n background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);\n color: white;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .submit-btn[_ngcontent-%COMP%]:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n }\n\n .submit-btn[_ngcontent-%COMP%]:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .view-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 20px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n background: white;\n color: #64748b;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .view-btn[_ngcontent-%COMP%]:hover {\n border-color: #cbd5e1;\n background: #f8fafc;\n }\n\n \n\n .reviewed-item[_ngcontent-%COMP%] {\n padding: 16px 20px;\n border-bottom: 1px solid #f1f5f9;\n }\n\n .reviewed-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .reviewed-main[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n\n .reviewed-title[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 4px;\n }\n\n .reviewed-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #64748b;\n }\n\n .reviewed-meta[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .reviewed-rating[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n }\n\n .rating-stars[_ngcontent-%COMP%] {\n display: flex;\n gap: 2px;\n }\n\n .rating-stars[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #e2e8f0;\n }\n\n .rating-stars[_ngcontent-%COMP%] i.filled[_ngcontent-%COMP%] {\n color: #f59e0b;\n }\n\n .rating-text[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n }\n\n .reviewed-verdict[_ngcontent-%COMP%] {\n flex-shrink: 0;\n }\n\n .verdict-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .verdict-badge.correct[_ngcontent-%COMP%] {\n background: #dcfce7;\n color: #16a34a;\n }\n\n .verdict-badge.incorrect[_ngcontent-%COMP%] {\n background: #fee2e2;\n color: #dc2626;\n }\n\n .view-btn-small[_ngcontent-%COMP%] {\n background: none;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 8px;\n color: #64748b;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .view-btn-small[_ngcontent-%COMP%]:hover {\n background: #f8fafc;\n border-color: #cbd5e1;\n }\n\n .reviewed-comments[_ngcontent-%COMP%] {\n margin-top: 12px;\n padding: 12px;\n background: #f8fafc;\n border-radius: 8px;\n border-left: 3px solid #3b82f6;\n }\n\n .reviewed-comments[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n color: #475569;\n line-height: 1.5;\n }\n\n \n\n .suites-list[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .suite-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 20px;\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n margin-bottom: 12px;\n }\n\n .suite-card[_ngcontent-%COMP%]:hover {\n border-color: #3b82f6;\n background: white;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n }\n\n .suite-card[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n }\n\n .suite-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 14px;\n flex: 1;\n min-width: 0;\n }\n\n .suite-icon[_ngcontent-%COMP%] {\n width: 44px;\n height: 44px;\n border-radius: 10px;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 18px;\n flex-shrink: 0;\n }\n\n .suite-info[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 4px 0;\n font-size: 15px;\n font-weight: 600;\n color: #1e293b;\n }\n\n .suite-meta[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #64748b;\n }\n\n .suite-stats[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n }\n\n .suite-stat[_ngcontent-%COMP%] {\n text-align: center;\n min-width: 60px;\n }\n\n .suite-stat[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: #1e293b;\n }\n\n .suite-stat[_ngcontent-%COMP%] .stat-value.pending[_ngcontent-%COMP%] {\n color: #f97316;\n }\n\n .suite-stat[_ngcontent-%COMP%] .stat-value.reviewed[_ngcontent-%COMP%] {\n color: #22c55e;\n }\n\n .suite-stat[_ngcontent-%COMP%] .stat-value.good[_ngcontent-%COMP%] {\n color: #22c55e;\n }\n\n .suite-stat[_ngcontent-%COMP%] .stat-value.bad[_ngcontent-%COMP%] {\n color: #ef4444;\n }\n\n .suite-stat[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 10px;\n color: #94a3b8;\n font-weight: 600;\n text-transform: uppercase;\n }\n\n .suite-arrow[_ngcontent-%COMP%] {\n color: #94a3b8;\n font-size: 14px;\n }\n\n \n\n .empty-state[_ngcontent-%COMP%] {\n padding: 60px 20px;\n text-align: center;\n }\n\n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 56px;\n margin-bottom: 16px;\n color: #cbd5e1;\n }\n\n .empty-state.success[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #22c55e;\n }\n\n .empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 18px;\n color: #475569;\n margin: 0 0 8px 0;\n font-weight: 600;\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n color: #94a3b8;\n margin: 0;\n }\n\n \n\n .feedback-stats[_ngcontent-%COMP%] {\n background: white;\n padding: 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n }\n\n .feedback-stats[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #1e293b;\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .feedback-stats[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #3b82f6;\n }\n\n .stats-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 16px;\n }\n\n .stat-card[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n padding: 16px;\n border-radius: 10px;\n text-align: center;\n }\n\n .stat-card[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n font-size: 10px;\n font-weight: 700;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n }\n\n .stat-card[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 24px;\n font-weight: 700;\n color: #1e293b;\n }\n\n \n\n @media (max-width: 1024px) {\n .feedback-summary[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .suite-stats[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n gap: 12px;\n }\n }\n\n @media (max-width: 768px) {\n .testing-feedback[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .feedback-header[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 16px;\n align-items: flex-start;\n }\n\n .feedback-summary[_ngcontent-%COMP%] {\n grid-template-columns: 1fr 1fr;\n }\n\n .summary-card[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .summary-value[_ngcontent-%COMP%] {\n font-size: 22px;\n }\n\n .feedback-filters[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .filter-group[_ngcontent-%COMP%] {\n min-width: 100%;\n }\n\n .item-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .item-reason[_ngcontent-%COMP%] {\n width: 100%;\n margin-top: 8px;\n }\n\n .correctness-buttons[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .form-actions[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .reviewed-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .suite-card[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .suite-stats[_ngcontent-%COMP%] {\n width: 100%;\n justify-content: space-between;\n }\n }"], data: { animation: [] }, changeDetection: 0 });
508
1097
  }
509
1098
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TestingFeedbackComponent, [{
510
1099
  type: Component,
511
1100
  args: [{ selector: 'app-testing-feedback', changeDetection: ChangeDetectionStrategy.OnPush, template: `
512
1101
  <div class="testing-feedback">
1102
+ <!-- Header -->
513
1103
  <div class="feedback-header">
514
1104
  <div class="header-left">
515
1105
  <h2>
516
1106
  <i class="fa-solid fa-clipboard-check"></i>
517
1107
  Human Feedback Review
518
1108
  </h2>
519
- <div class="pending-badge" *ngIf="(pendingCount$ | async) || 0 > 0">
520
- <span class="badge-count">{{ (pendingCount$ | async) }}</span>
521
- <span class="badge-text">Pending Review</span>
1109
+ <div class="pending-badge" *ngIf="(pendingCount$ | async) as count">
1110
+ <span class="badge-count" *ngIf="count > 0">{{ count }}</span>
1111
+ <span class="badge-text">{{ count > 0 ? 'Pending Review' : 'All Reviewed' }}</span>
522
1112
  </div>
523
1113
  </div>
524
1114
  <div class="header-actions">
525
- <button class="action-btn" (click)="refresh()">
526
- <i class="fa-solid fa-refresh"></i>
527
- Refresh
1115
+ <button class="action-btn refresh-btn" (click)="refresh()" [disabled]="isRefreshing">
1116
+ <i class="fa-solid fa-refresh" [class.fa-spin]="isRefreshing"></i>
1117
+ {{ isRefreshing ? 'Refreshing...' : 'Refresh' }}
528
1118
  </button>
529
1119
  </div>
530
1120
  </div>
531
1121
 
532
- <!-- Filters -->
1122
+ <!-- KPI Summary Cards - Clickable -->
1123
+ <div class="feedback-summary">
1124
+ <div class="summary-card clickable" [class.active]="viewMode === 'pending'" (click)="setViewMode('pending')">
1125
+ <div class="summary-icon pending">
1126
+ <i class="fa-solid fa-hourglass-half"></i>
1127
+ </div>
1128
+ <div class="summary-content">
1129
+ <div class="summary-value">{{ (pendingCount$ | async) ?? 0 }}</div>
1130
+ <div class="summary-label">Pending Review</div>
1131
+ </div>
1132
+ <i class="fa-solid fa-chevron-right summary-arrow"></i>
1133
+ </div>
1134
+ <div class="summary-card clickable" [class.active]="viewMode === 'reviewed'" (click)="setViewMode('reviewed')">
1135
+ <div class="summary-icon reviewed">
1136
+ <i class="fa-solid fa-check-circle"></i>
1137
+ </div>
1138
+ <div class="summary-content">
1139
+ <div class="summary-value">{{ (reviewedCount$ | async) ?? 0 }}</div>
1140
+ <div class="summary-label">Reviewed</div>
1141
+ </div>
1142
+ <i class="fa-solid fa-chevron-right summary-arrow"></i>
1143
+ </div>
1144
+ <div class="summary-card clickable" [class.active]="viewMode === 'suites'" (click)="setViewMode('suites')">
1145
+ <div class="summary-icon suites">
1146
+ <i class="fa-solid fa-layer-group"></i>
1147
+ </div>
1148
+ <div class="summary-content">
1149
+ <div class="summary-value">{{ (suiteCount$ | async) ?? 0 }}</div>
1150
+ <div class="summary-label">Test Suites</div>
1151
+ </div>
1152
+ <i class="fa-solid fa-chevron-right summary-arrow"></i>
1153
+ </div>
1154
+ <div class="summary-card">
1155
+ <div class="summary-icon accuracy">
1156
+ <i class="fa-solid fa-bullseye"></i>
1157
+ </div>
1158
+ <div class="summary-content">
1159
+ <div class="summary-value">{{ (accuracyRate$ | async) ?? 0 | number:'1.1-1' }}%</div>
1160
+ <div class="summary-label">Human-AI Agreement</div>
1161
+ </div>
1162
+ </div>
1163
+ </div>
1164
+
1165
+ <!-- Filters Bar -->
533
1166
  <div class="feedback-filters">
534
1167
  <div class="filter-group">
535
- <label>Status</label>
536
- <select [(ngModel)]="filters.status" (change)="onFilterChange()">
537
- <option value="all">All</option>
538
- <option value="pending">Pending Review</option>
539
- <option value="reviewed">Reviewed</option>
1168
+ <label>View</label>
1169
+ <select [(ngModel)]="viewMode" (change)="onViewModeChange()">
1170
+ <option value="pending">Pending Reviews</option>
1171
+ <option value="reviewed">Reviewed Feedback</option>
1172
+ <option value="suites">By Test Suite</option>
540
1173
  </select>
541
1174
  </div>
542
- <div class="filter-group">
1175
+ <div class="filter-group" *ngIf="viewMode === 'pending'">
543
1176
  <label>Reason</label>
544
1177
  <select [(ngModel)]="filters.reason" (change)="onFilterChange()">
545
1178
  <option value="all">All Reasons</option>
@@ -548,6 +1181,13 @@ export class TestingFeedbackComponent {
548
1181
  <option value="low-score-passed">Low Score but Passed</option>
549
1182
  </select>
550
1183
  </div>
1184
+ <div class="filter-group" *ngIf="viewMode !== 'suites'">
1185
+ <label>Test Suite</label>
1186
+ <select [(ngModel)]="filters.suiteId" (change)="onFilterChange()">
1187
+ <option [ngValue]="null">All Suites</option>
1188
+ <option *ngFor="let suite of testSuites$ | async" [ngValue]="suite.ID">{{ suite.Name }}</option>
1189
+ </select>
1190
+ </div>
551
1191
  <div class="filter-group search">
552
1192
  <label>Search</label>
553
1193
  <div class="search-input-wrapper">
@@ -558,59 +1198,15 @@ export class TestingFeedbackComponent {
558
1198
  (input)="onFilterChange()"
559
1199
  placeholder="Search tests..."
560
1200
  />
561
- <button
562
- class="clear-btn"
563
- *ngIf="filters.searchText"
564
- (click)="clearSearch()"
565
- >
1201
+ <button class="clear-btn" *ngIf="filters.searchText" (click)="clearSearch()">
566
1202
  <i class="fa-solid fa-times"></i>
567
1203
  </button>
568
1204
  </div>
569
1205
  </div>
570
1206
  </div>
571
1207
 
572
- <!-- Summary Cards -->
573
- <div class="feedback-summary">
574
- <div class="summary-card">
575
- <div class="summary-icon pending">
576
- <i class="fa-solid fa-hourglass-half"></i>
577
- </div>
578
- <div class="summary-content">
579
- <div class="summary-value">{{ (pendingCount$ | async) || 0 }}</div>
580
- <div class="summary-label">Pending Review</div>
581
- </div>
582
- </div>
583
- <div class="summary-card">
584
- <div class="summary-icon discrepancy">
585
- <i class="fa-solid fa-triangle-exclamation"></i>
586
- </div>
587
- <div class="summary-content">
588
- <div class="summary-value">{{ (discrepancyCount$ | async) || 0 }}</div>
589
- <div class="summary-label">Score Discrepancies</div>
590
- </div>
591
- </div>
592
- <div class="summary-card">
593
- <div class="summary-icon reviewed">
594
- <i class="fa-solid fa-check-circle"></i>
595
- </div>
596
- <div class="summary-content">
597
- <div class="summary-value">{{ (reviewedCount$ | async) || 0 }}</div>
598
- <div class="summary-label">Reviewed</div>
599
- </div>
600
- </div>
601
- <div class="summary-card">
602
- <div class="summary-icon accuracy">
603
- <i class="fa-solid fa-bullseye"></i>
604
- </div>
605
- <div class="summary-content">
606
- <div class="summary-value">{{ (accuracyRate$ | async) || 0 | number:'1.1-1' }}%</div>
607
- <div class="summary-label">Human-AI Agreement</div>
608
- </div>
609
- </div>
610
- </div>
611
-
612
- <!-- Pending Reviews List -->
613
- <div class="feedback-content">
1208
+ <!-- Pending Reviews View -->
1209
+ <div class="feedback-content" *ngIf="viewMode === 'pending'">
614
1210
  <div class="content-header">
615
1211
  <h3>
616
1212
  <i class="fa-solid fa-list-check"></i>
@@ -626,9 +1222,10 @@ export class TestingFeedbackComponent {
626
1222
  </div>
627
1223
  </div>
628
1224
 
629
- <div class="feedback-list">
630
- @for (item of (filteredFeedback$ | async) ?? []; track item.testRunID) {
631
- <div class="feedback-item" [class.expanded]="expandedItem === item.testRunID">
1225
+ <div class="feedback-list" *ngIf="(filteredPending$ | async) as items">
1226
+ <ng-container *ngIf="items.length > 0; else emptyPending">
1227
+ <div class="feedback-item" *ngFor="let item of items; trackBy: trackByTestRunId"
1228
+ [class.expanded]="expandedItem === item.testRunID">
632
1229
  <div class="item-header" (click)="toggleExpanded(item.testRunID)">
633
1230
  <div class="item-main">
634
1231
  <div class="item-title">{{ item.testName }}</div>
@@ -638,10 +1235,10 @@ export class TestingFeedbackComponent {
638
1235
  {{ item.runDateTime | date:'short' }}
639
1236
  </span>
640
1237
  <span class="meta-score">
641
- Automated Score: <strong>{{ item.automatedScore.toFixed(4) }}</strong>
1238
+ Score: <strong>{{ (item.automatedScore * 10).toFixed(2) }}</strong>/10
642
1239
  </span>
643
- <span class="meta-status">
644
- Status: <app-test-status-badge [status]="getTestStatus(item.automatedStatus)"></app-test-status-badge>
1240
+ <span class="meta-status" [class]="'status-' + item.automatedStatus.toLowerCase()">
1241
+ {{ item.automatedStatus }}
645
1242
  </span>
646
1243
  </div>
647
1244
  </div>
@@ -659,130 +1256,231 @@ export class TestingFeedbackComponent {
659
1256
  </button>
660
1257
  </div>
661
1258
 
662
- @if (expandedItem === item.testRunID) {
663
- <div class="item-content">
664
- <div class="feedback-form">
665
- <div class="form-section">
666
- <h4>Provide Your Feedback</h4>
667
- <div class="form-row">
668
- <div class="form-group">
669
- <label>Human Rating (1-10)</label>
670
- <input
671
- type="number"
672
- [(ngModel)]="item.feedbackRating"
673
- min="1"
674
- max="10"
675
- class="rating-input"
676
- placeholder="Rate 1-10"
677
- />
678
- </div>
679
- <div class="form-group">
680
- <label>Is Automated Result Correct?</label>
681
- <div class="checkbox-group">
682
- <label class="checkbox-label">
683
- <input type="checkbox" [(ngModel)]="item.feedbackIsCorrect" />
684
- <span>Yes, the automated assessment is correct</span>
685
- </label>
686
- </div>
687
- </div>
688
- </div>
689
- <div class="form-group">
690
- <label>Comments / Notes</label>
691
- <textarea
692
- [(ngModel)]="item.feedbackComments"
693
- rows="4"
694
- class="comments-textarea"
695
- placeholder="Provide detailed feedback about this test result..."
696
- ></textarea>
1259
+ <div class="item-content" *ngIf="expandedItem === item.testRunID" [@slideDown]>
1260
+ <div class="feedback-form">
1261
+ <div class="form-section">
1262
+ <h4>Provide Your Feedback</h4>
1263
+ <div class="rating-section">
1264
+ <label>Human Rating</label>
1265
+ <div class="rating-stars-input">
1266
+ <button *ngFor="let star of [1,2,3,4,5,6,7,8,9,10]"
1267
+ class="star-btn"
1268
+ [class.filled]="star <= item.feedbackRating"
1269
+ (click)="setRating(item, star)">
1270
+ <i class="fa-solid fa-star"></i>
1271
+ </button>
1272
+ <span class="rating-display">{{ item.feedbackRating }}/10</span>
697
1273
  </div>
698
- <div class="form-actions">
699
- <button class="submit-btn" (click)="submitFeedback(item)">
700
- <i class="fa-solid fa-paper-plane"></i>
701
- Submit Feedback
1274
+ </div>
1275
+ <div class="correctness-section">
1276
+ <label>Is the Automated Result Correct?</label>
1277
+ <div class="correctness-buttons">
1278
+ <button class="correctness-btn correct" [class.active]="item.feedbackIsCorrect === true"
1279
+ (click)="setCorrectness(item, true)">
1280
+ <i class="fa-solid fa-check"></i>
1281
+ Correct
702
1282
  </button>
703
- <button class="skip-btn" (click)="skipFeedback(item)">
704
- <i class="fa-solid fa-forward"></i>
705
- Skip for Now
1283
+ <button class="correctness-btn incorrect" [class.active]="item.feedbackIsCorrect === false"
1284
+ (click)="setCorrectness(item, false)">
1285
+ <i class="fa-solid fa-times"></i>
1286
+ Incorrect
706
1287
  </button>
707
1288
  </div>
708
1289
  </div>
709
-
710
- <div class="context-section">
711
- <h4>Test Context</h4>
712
- <div class="context-details">
713
- <div class="detail-item">
714
- <span class="detail-label">Test Run ID</span>
715
- <span class="detail-value">{{ item.testRunID }}</span>
716
- </div>
717
- <div class="detail-item">
718
- <span class="detail-label">Automated Score</span>
719
- <span class="detail-value">
720
- <app-score-indicator [score]="item.automatedScore" [showBar]="true"></app-score-indicator>
721
- </span>
722
- </div>
723
- <div class="detail-item">
724
- <span class="detail-label">Status</span>
725
- <span class="detail-value">
726
- <app-test-status-badge [status]="getTestStatus(item.automatedStatus)"></app-test-status-badge>
727
- </span>
728
- </div>
729
- <div class="detail-item">
730
- <span class="detail-label">Run Date</span>
731
- <span class="detail-value">{{ item.runDateTime | date:'medium' }}</span>
732
- </div>
733
- </div>
734
- <button class="view-details-btn" (click)="viewFullDetails(item)">
1290
+ <div class="form-group">
1291
+ <label>Comments / Correction Notes</label>
1292
+ <textarea
1293
+ [(ngModel)]="item.feedbackComments"
1294
+ rows="3"
1295
+ class="comments-textarea"
1296
+ placeholder="Explain your assessment or provide correction notes..."
1297
+ ></textarea>
1298
+ </div>
1299
+ <div class="form-actions">
1300
+ <button class="submit-btn" (click)="submitFeedback(item)" [disabled]="isSubmitting">
1301
+ <i class="fa-solid fa-paper-plane"></i>
1302
+ {{ isSubmitting ? 'Submitting...' : 'Submit Feedback' }}
1303
+ </button>
1304
+ <button class="view-btn" (click)="viewFullDetails(item)">
735
1305
  <i class="fa-solid fa-external-link"></i>
736
- View Full Test Details
1306
+ View Full Details
737
1307
  </button>
738
1308
  </div>
739
1309
  </div>
740
1310
  </div>
741
- }
1311
+ </div>
742
1312
  </div>
743
- } @empty {
744
- <div class="empty-state">
1313
+ </ng-container>
1314
+ <ng-template #emptyPending>
1315
+ <div class="empty-state success">
745
1316
  <i class="fa-solid fa-check-double"></i>
746
1317
  <h3>All Caught Up!</h3>
747
1318
  <p>No tests currently require feedback review.</p>
748
1319
  </div>
749
- }
1320
+ </ng-template>
750
1321
  </div>
751
1322
  </div>
752
1323
 
753
- <!-- Feedback Statistics -->
754
- <div class="feedback-stats">
755
- <div class="stats-section">
1324
+ <!-- Reviewed Feedback View -->
1325
+ <div class="feedback-content" *ngIf="viewMode === 'reviewed'">
1326
+ <div class="content-header">
756
1327
  <h3>
757
- <i class="fa-solid fa-chart-pie"></i>
758
- Feedback Statistics
1328
+ <i class="fa-solid fa-history"></i>
1329
+ Reviewed Feedback History
759
1330
  </h3>
760
- <div class="stats-grid">
761
- <div class="stat-card">
762
- <div class="stat-label">Total Feedback Submitted</div>
763
- <div class="stat-value">{{ (totalFeedback$ | async) || 0 }}</div>
1331
+ <div class="sort-controls">
1332
+ <label>Sort by:</label>
1333
+ <select [(ngModel)]="reviewedSortBy" (change)="onReviewedSortChange()">
1334
+ <option value="date">Review Date</option>
1335
+ <option value="rating">Rating</option>
1336
+ <option value="test-name">Test Name</option>
1337
+ </select>
1338
+ </div>
1339
+ </div>
1340
+
1341
+ <div class="feedback-list" *ngIf="(filteredReviewed$ | async) as items">
1342
+ <ng-container *ngIf="items.length > 0; else emptyReviewed">
1343
+ <div class="reviewed-item" *ngFor="let item of items; trackBy: trackByReviewedId">
1344
+ <div class="reviewed-header">
1345
+ <div class="reviewed-main">
1346
+ <div class="reviewed-title">{{ item.testName }}</div>
1347
+ <div class="reviewed-meta">
1348
+ <span class="meta-reviewer">
1349
+ <i class="fa-solid fa-user"></i>
1350
+ {{ item.reviewerName }}
1351
+ </span>
1352
+ <span class="meta-date">
1353
+ <i class="fa-solid fa-calendar"></i>
1354
+ {{ item.reviewedAt | date:'short' }}
1355
+ </span>
1356
+ </div>
1357
+ </div>
1358
+ <div class="reviewed-rating">
1359
+ <div class="rating-stars">
1360
+ <i class="fa-solid fa-star" *ngFor="let s of [1,2,3,4,5,6,7,8,9,10]"
1361
+ [class.filled]="s <= item.rating"></i>
1362
+ </div>
1363
+ <span class="rating-text">{{ item.rating }}/10</span>
1364
+ </div>
1365
+ <div class="reviewed-verdict">
1366
+ <span class="verdict-badge" [class.correct]="item.isCorrect" [class.incorrect]="!item.isCorrect">
1367
+ <i class="fa-solid" [class.fa-check]="item.isCorrect" [class.fa-times]="!item.isCorrect"></i>
1368
+ {{ item.isCorrect ? 'Correct' : 'Incorrect' }}
1369
+ </span>
1370
+ </div>
1371
+ <button class="view-btn-small" (click)="viewTestRun(item.testRunID)">
1372
+ <i class="fa-solid fa-external-link"></i>
1373
+ </button>
1374
+ </div>
1375
+ <div class="reviewed-comments" *ngIf="item.comments">
1376
+ <p>{{ item.comments }}</p>
1377
+ </div>
764
1378
  </div>
765
- <div class="stat-card">
766
- <div class="stat-label">Avg Rating</div>
767
- <div class="stat-value">{{ (avgRating$ | async) || 0 | number:'1.1-1' }}</div>
1379
+ </ng-container>
1380
+ <ng-template #emptyReviewed>
1381
+ <div class="empty-state">
1382
+ <i class="fa-solid fa-clipboard"></i>
1383
+ <h3>No Reviews Yet</h3>
1384
+ <p>No feedback has been submitted yet. Start by reviewing pending tests.</p>
768
1385
  </div>
769
- <div class="stat-card">
770
- <div class="stat-label">Agreement Rate</div>
771
- <div class="stat-value">{{ (agreementRate$ | async) || 0 | number:'1.1-1' }}%</div>
1386
+ </ng-template>
1387
+ </div>
1388
+ </div>
1389
+
1390
+ <!-- Test Suite Aggregation View -->
1391
+ <div class="feedback-content" *ngIf="viewMode === 'suites'">
1392
+ <div class="content-header">
1393
+ <h3>
1394
+ <i class="fa-solid fa-layer-group"></i>
1395
+ Feedback by Test Suite
1396
+ </h3>
1397
+ </div>
1398
+
1399
+ <div class="suites-list" *ngIf="(suiteAggregations$ | async) as suites">
1400
+ <ng-container *ngIf="suites.length > 0; else emptySuites">
1401
+ <div class="suite-card" *ngFor="let suite of suites; trackBy: trackBySuiteId"
1402
+ (click)="selectSuite(suite.suiteId)">
1403
+ <div class="suite-header">
1404
+ <div class="suite-icon">
1405
+ <i class="fa-solid fa-layer-group"></i>
1406
+ </div>
1407
+ <div class="suite-info">
1408
+ <h4>{{ suite.suiteName }}</h4>
1409
+ <div class="suite-meta">
1410
+ <span>{{ suite.totalRuns }} test runs</span>
1411
+ </div>
1412
+ </div>
1413
+ </div>
1414
+ <div class="suite-stats">
1415
+ <div class="suite-stat">
1416
+ <div class="stat-value pending">{{ suite.pendingCount }}</div>
1417
+ <div class="stat-label">Pending</div>
1418
+ </div>
1419
+ <div class="suite-stat">
1420
+ <div class="stat-value reviewed">{{ suite.reviewedCount }}</div>
1421
+ <div class="stat-label">Reviewed</div>
1422
+ </div>
1423
+ <div class="suite-stat">
1424
+ <div class="stat-value">{{ suite.avgRating | number:'1.1-1' }}</div>
1425
+ <div class="stat-label">Avg Rating</div>
1426
+ </div>
1427
+ <div class="suite-stat">
1428
+ <div class="stat-value" [class.good]="suite.agreementRate >= 70" [class.bad]="suite.agreementRate < 50">
1429
+ {{ suite.agreementRate | number:'1.0-0' }}%
1430
+ </div>
1431
+ <div class="stat-label">Agreement</div>
1432
+ </div>
1433
+ <div class="suite-stat">
1434
+ <div class="stat-value" [class.good]="suite.passRate >= 80" [class.bad]="suite.passRate < 50">
1435
+ {{ suite.passRate | number:'1.0-0' }}%
1436
+ </div>
1437
+ <div class="stat-label">Pass Rate</div>
1438
+ </div>
1439
+ </div>
1440
+ <i class="fa-solid fa-chevron-right suite-arrow"></i>
772
1441
  </div>
773
- <div class="stat-card">
774
- <div class="stat-label">Disagreement Rate</div>
775
- <div class="stat-value">{{ (disagreementRate$ | async) || 0 | number:'1.1-1' }}%</div>
1442
+ </ng-container>
1443
+ <ng-template #emptySuites>
1444
+ <div class="empty-state">
1445
+ <i class="fa-solid fa-layer-group"></i>
1446
+ <h3>No Test Suites</h3>
1447
+ <p>No test suites have been created yet.</p>
776
1448
  </div>
1449
+ </ng-template>
1450
+ </div>
1451
+ </div>
1452
+
1453
+ <!-- Summary Statistics -->
1454
+ <div class="feedback-stats">
1455
+ <h3>
1456
+ <i class="fa-solid fa-chart-pie"></i>
1457
+ Feedback Statistics
1458
+ </h3>
1459
+ <div class="stats-grid">
1460
+ <div class="stat-card">
1461
+ <div class="stat-label">Total Feedback</div>
1462
+ <div class="stat-value">{{ (totalFeedback$ | async) ?? 0 }}</div>
1463
+ </div>
1464
+ <div class="stat-card">
1465
+ <div class="stat-label">Avg Rating</div>
1466
+ <div class="stat-value">{{ (avgRating$ | async) ?? 0 | number:'1.1-1' }}/10</div>
1467
+ </div>
1468
+ <div class="stat-card">
1469
+ <div class="stat-label">Agreement Rate</div>
1470
+ <div class="stat-value">{{ (agreementRate$ | async) ?? 0 | number:'1.1-1' }}%</div>
1471
+ </div>
1472
+ <div class="stat-card">
1473
+ <div class="stat-label">Discrepancy Count</div>
1474
+ <div class="stat-value">{{ (discrepancyCount$ | async) ?? 0 }}</div>
777
1475
  </div>
778
1476
  </div>
779
1477
  </div>
780
1478
  </div>
781
- `, styles: ["\n .testing-feedback {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background: #f8f9fa;\n }\n\n .feedback-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 24px;\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .header-left {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .header-left h2 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-left h2 i {\n color: #2196f3;\n }\n\n .pending-badge {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: #fff3e0;\n border: 2px solid #ff9800;\n border-radius: 20px;\n }\n\n .badge-count {\n background: #ff9800;\n color: white;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n }\n\n .badge-text {\n font-size: 12px;\n font-weight: 600;\n color: #ff9800;\n }\n\n .action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: 1px solid #ddd;\n border-radius: 4px;\n background: white;\n color: #666;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .action-btn:hover {\n background: #f5f5f5;\n }\n\n .feedback-filters {\n display: flex;\n gap: 16px;\n margin-bottom: 20px;\n background: white;\n padding: 16px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .filter-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 150px;\n }\n\n .filter-group.search {\n flex: 1;\n }\n\n .filter-group label {\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n }\n\n .filter-group select {\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n background: white;\n }\n\n .search-input-wrapper {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-input-wrapper i {\n position: absolute;\n left: 12px;\n color: #999;\n font-size: 12px;\n }\n\n .search-input-wrapper input {\n flex: 1;\n padding: 8px 40px 8px 36px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n }\n\n .clear-btn {\n position: absolute;\n right: 8px;\n background: none;\n border: none;\n color: #999;\n cursor: pointer;\n padding: 4px;\n }\n\n .clear-btn:hover {\n color: #333;\n }\n\n .feedback-summary {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 16px;\n margin-bottom: 24px;\n }\n\n .summary-card {\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .summary-icon {\n width: 56px;\n height: 56px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 24px;\n color: white;\n }\n\n .summary-icon.pending {\n background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);\n }\n\n .summary-icon.discrepancy {\n background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%);\n }\n\n .summary-icon.reviewed {\n background: linear-gradient(135deg, #4caf50 0%, #388e3c 100%);\n }\n\n .summary-icon.accuracy {\n background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%);\n }\n\n .summary-content {\n flex: 1;\n }\n\n .summary-value {\n font-size: 28px;\n font-weight: 700;\n color: #333;\n line-height: 1;\n margin-bottom: 6px;\n }\n\n .summary-label {\n font-size: 11px;\n color: #666;\n font-weight: 600;\n text-transform: uppercase;\n }\n\n .feedback-content {\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n margin-bottom: 24px;\n }\n\n .content-header {\n padding: 20px;\n background: #f8f9fa;\n border-bottom: 2px solid #e0e0e0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .content-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .content-header h3 i {\n color: #2196f3;\n }\n\n .sort-controls {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #666;\n }\n\n .sort-controls select {\n padding: 6px 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 12px;\n }\n\n .feedback-list {\n max-height: 800px;\n overflow-y: auto;\n }\n\n .feedback-item {\n border-bottom: 1px solid #f0f0f0;\n transition: all 0.3s ease;\n }\n\n .feedback-item.expanded {\n background: #f8f9fa;\n }\n\n .item-header {\n padding: 20px;\n display: flex;\n align-items: center;\n gap: 16px;\n cursor: pointer;\n transition: background 0.2s ease;\n }\n\n .item-header:hover {\n background: rgba(33, 150, 243, 0.05);\n }\n\n .item-main {\n flex: 1;\n }\n\n .item-title {\n font-size: 15px;\n font-weight: 600;\n color: #333;\n margin-bottom: 8px;\n }\n\n .item-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #666;\n }\n\n .item-meta span {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .item-reason {\n min-width: 180px;\n }\n\n .reason-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .reason-badge.no-feedback {\n background: #e3f2fd;\n color: #2196f3;\n }\n\n .reason-badge.high-score-failed {\n background: #ffebee;\n color: #f44336;\n }\n\n .reason-badge.low-score-passed {\n background: #fff3e0;\n color: #ff9800;\n }\n\n .expand-btn {\n background: none;\n border: none;\n color: #666;\n cursor: pointer;\n padding: 8px;\n border-radius: 4px;\n transition: all 0.2s ease;\n font-size: 16px;\n }\n\n .expand-btn:hover {\n background: #e0e0e0;\n }\n\n .item-content {\n padding: 20px;\n border-top: 1px solid #e0e0e0;\n animation: slideDown 0.3s ease;\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-form {\n display: grid;\n grid-template-columns: 2fr 1fr;\n gap: 24px;\n }\n\n .form-section h4,\n .context-section h4 {\n margin: 0 0 16px 0;\n font-size: 14px;\n font-weight: 600;\n color: #333;\n padding-bottom: 12px;\n border-bottom: 2px solid #f0f0f0;\n }\n\n .form-row {\n display: grid;\n grid-template-columns: 1fr 2fr;\n gap: 16px;\n margin-bottom: 16px;\n }\n\n .form-group {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .form-group label {\n font-size: 12px;\n font-weight: 600;\n color: #666;\n }\n\n .rating-input {\n padding: 8px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 14px;\n }\n\n .checkbox-group {\n display: flex;\n align-items: center;\n }\n\n .checkbox-label {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n color: #333;\n cursor: pointer;\n }\n\n .checkbox-label input[type=\"checkbox\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n }\n\n .comments-textarea {\n padding: 10px 12px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n font-family: inherit;\n resize: vertical;\n }\n\n .form-actions {\n display: flex;\n gap: 12px;\n margin-top: 16px;\n }\n\n .submit-btn,\n .skip-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .submit-btn {\n background: #2196f3;\n color: white;\n }\n\n .submit-btn:hover {\n background: #1976d2;\n }\n\n .skip-btn {\n background: #f5f5f5;\n color: #666;\n }\n\n .skip-btn:hover {\n background: #e0e0e0;\n }\n\n .context-details {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin-bottom: 16px;\n }\n\n .detail-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 10px;\n background: white;\n border-radius: 4px;\n border: 1px solid #e0e0e0;\n }\n\n .detail-label {\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n }\n\n .detail-value {\n font-size: 13px;\n font-weight: 500;\n color: #333;\n }\n\n .view-details-btn {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 10px;\n border: 1px solid #2196f3;\n border-radius: 4px;\n background: white;\n color: #2196f3;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .view-details-btn:hover {\n background: #e3f2fd;\n }\n\n .empty-state {\n padding: 80px 20px;\n text-align: center;\n color: #999;\n }\n\n .empty-state i {\n font-size: 64px;\n margin-bottom: 20px;\n opacity: 0.3;\n color: #4caf50;\n }\n\n .empty-state h3 {\n font-size: 20px;\n color: #666;\n margin: 0 0 12px 0;\n }\n\n .empty-state p {\n font-size: 14px;\n margin: 0;\n }\n\n .feedback-stats {\n background: white;\n padding: 20px;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n .feedback-stats h3 {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #333;\n display: flex;\n align-items: center;\n gap: 8px;\n padding-bottom: 12px;\n border-bottom: 2px solid #f0f0f0;\n }\n\n .feedback-stats h3 i {\n color: #2196f3;\n }\n\n .stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n }\n\n .stat-card {\n background: #f8f9fa;\n padding: 16px;\n border-radius: 6px;\n text-align: center;\n }\n\n .stat-label {\n font-size: 11px;\n font-weight: 600;\n color: #666;\n text-transform: uppercase;\n margin-bottom: 8px;\n }\n\n .stat-value {\n font-size: 24px;\n font-weight: 700;\n color: #333;\n }\n\n @media (max-width: 1200px) {\n .feedback-form {\n grid-template-columns: 1fr;\n }\n\n .form-row {\n grid-template-columns: 1fr;\n }\n }\n "] }]
1479
+ `, animations: [], styles: ["\n :host {\n display: block;\n height: 100%;\n }\n\n .testing-feedback {\n padding: 20px;\n height: 100%;\n overflow-y: auto;\n background: #f8f9fa;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n }\n\n /* Header */\n .feedback-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n background: white;\n padding: 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n }\n\n .header-left {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .header-left h2 {\n margin: 0;\n font-size: 22px;\n font-weight: 700;\n color: #1e293b;\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .header-left h2 i {\n color: #3b82f6;\n }\n\n .pending-badge {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 14px;\n background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 100%);\n border: 1px solid #fb923c;\n border-radius: 20px;\n }\n\n .badge-count {\n background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);\n color: white;\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n }\n\n .badge-text {\n font-size: 12px;\n font-weight: 600;\n color: #ea580c;\n }\n\n .action-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n background: white;\n color: #64748b;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .action-btn:hover:not(:disabled) {\n background: #f8fafc;\n border-color: #cbd5e1;\n }\n\n .action-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n /* Summary Cards */\n .feedback-summary {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 16px;\n margin-bottom: 20px;\n }\n\n .summary-card {\n background: white;\n padding: 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n align-items: center;\n gap: 16px;\n transition: all 0.2s ease;\n position: relative;\n }\n\n .summary-card.clickable {\n cursor: pointer;\n }\n\n .summary-card.clickable:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);\n }\n\n .summary-card.active {\n border: 2px solid #3b82f6;\n background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);\n }\n\n .summary-icon {\n width: 52px;\n height: 52px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 22px;\n color: white;\n flex-shrink: 0;\n }\n\n .summary-icon.pending {\n background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);\n }\n\n .summary-icon.reviewed {\n background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);\n }\n\n .summary-icon.suites {\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n }\n\n .summary-icon.accuracy {\n background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);\n }\n\n .summary-content {\n flex: 1;\n }\n\n .summary-value {\n font-size: 28px;\n font-weight: 700;\n color: #1e293b;\n line-height: 1;\n margin-bottom: 4px;\n }\n\n .summary-label {\n font-size: 11px;\n color: #64748b;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .summary-arrow {\n color: #94a3b8;\n font-size: 14px;\n }\n\n /* Filters */\n .feedback-filters {\n display: flex;\n gap: 16px;\n margin-bottom: 20px;\n background: white;\n padding: 16px 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n flex-wrap: wrap;\n }\n\n .filter-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-width: 140px;\n }\n\n .filter-group.search {\n flex: 1;\n min-width: 200px;\n }\n\n .filter-group label {\n font-size: 10px;\n font-weight: 700;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .filter-group select {\n padding: 10px 12px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 13px;\n background: white;\n color: #1e293b;\n cursor: pointer;\n }\n\n .filter-group select:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .search-input-wrapper {\n position: relative;\n display: flex;\n align-items: center;\n }\n\n .search-input-wrapper > i {\n position: absolute;\n left: 12px;\n color: #94a3b8;\n font-size: 13px;\n }\n\n .search-input-wrapper input {\n flex: 1;\n padding: 10px 40px 10px 36px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 13px;\n }\n\n .search-input-wrapper input:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .clear-btn {\n position: absolute;\n right: 8px;\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 6px;\n border-radius: 4px;\n }\n\n .clear-btn:hover {\n color: #64748b;\n background: #f1f5f9;\n }\n\n /* Content Area */\n .feedback-content {\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n margin-bottom: 20px;\n }\n\n .content-header {\n padding: 20px;\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n border-bottom: 1px solid #e2e8f0;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n\n .content-header h3 {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: #1e293b;\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .content-header h3 i {\n color: #3b82f6;\n }\n\n .sort-controls {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: #64748b;\n }\n\n .sort-controls select {\n padding: 6px 10px;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n font-size: 12px;\n background: white;\n }\n\n /* Feedback List */\n .feedback-list {\n max-height: 600px;\n overflow-y: auto;\n }\n\n .feedback-item {\n border-bottom: 1px solid #f1f5f9;\n transition: all 0.2s ease;\n }\n\n .feedback-item.expanded {\n background: #f8fafc;\n }\n\n .item-header {\n padding: 16px 20px;\n display: flex;\n align-items: center;\n gap: 16px;\n cursor: pointer;\n transition: background 0.2s ease;\n }\n\n .item-header:hover {\n background: rgba(59, 130, 246, 0.04);\n }\n\n .item-main {\n flex: 1;\n min-width: 0;\n }\n\n .item-title {\n font-size: 14px;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 6px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .item-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #64748b;\n flex-wrap: wrap;\n }\n\n .item-meta span {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .meta-status {\n padding: 2px 8px;\n border-radius: 4px;\n font-weight: 600;\n font-size: 11px;\n }\n\n .meta-status.status-passed { background: #dcfce7; color: #16a34a; }\n .meta-status.status-failed { background: #fee2e2; color: #dc2626; }\n .meta-status.status-error { background: #fef3c7; color: #d97706; }\n .meta-status.status-running { background: #dbeafe; color: #2563eb; }\n\n .item-reason {\n flex-shrink: 0;\n }\n\n .reason-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .reason-badge.no-feedback {\n background: #dbeafe;\n color: #2563eb;\n }\n\n .reason-badge.high-score-failed {\n background: #fee2e2;\n color: #dc2626;\n }\n\n .reason-badge.low-score-passed {\n background: #fef3c7;\n color: #d97706;\n }\n\n .expand-btn {\n background: none;\n border: none;\n color: #94a3b8;\n cursor: pointer;\n padding: 8px;\n border-radius: 6px;\n transition: all 0.2s ease;\n font-size: 14px;\n }\n\n .expand-btn:hover {\n background: #e2e8f0;\n color: #64748b;\n }\n\n /* Expanded Content */\n .item-content {\n padding: 20px;\n border-top: 1px solid #e2e8f0;\n background: white;\n }\n\n .feedback-form {\n max-width: 600px;\n }\n\n .form-section h4 {\n margin: 0 0 20px 0;\n font-size: 15px;\n font-weight: 600;\n color: #1e293b;\n }\n\n .rating-section,\n .correctness-section {\n margin-bottom: 20px;\n }\n\n .rating-section label,\n .correctness-section label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n margin-bottom: 10px;\n }\n\n .rating-stars-input {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .star-btn {\n background: none;\n border: none;\n font-size: 22px;\n color: #e2e8f0;\n cursor: pointer;\n padding: 2px;\n transition: all 0.15s ease;\n }\n\n .star-btn:hover {\n transform: scale(1.2);\n }\n\n .star-btn.filled {\n color: #f59e0b;\n }\n\n .rating-display {\n margin-left: 12px;\n font-size: 16px;\n font-weight: 700;\n color: #1e293b;\n }\n\n .correctness-buttons {\n display: flex;\n gap: 12px;\n }\n\n .correctness-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 20px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n background: white;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .correctness-btn.correct:hover,\n .correctness-btn.correct.active {\n border-color: #22c55e;\n background: #f0fdf4;\n color: #16a34a;\n }\n\n .correctness-btn.incorrect:hover,\n .correctness-btn.incorrect.active {\n border-color: #ef4444;\n background: #fef2f2;\n color: #dc2626;\n }\n\n .form-group {\n margin-bottom: 16px;\n }\n\n .form-group label {\n display: block;\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n margin-bottom: 8px;\n }\n\n .comments-textarea {\n width: 100%;\n padding: 12px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n font-size: 14px;\n font-family: inherit;\n resize: vertical;\n min-height: 80px;\n }\n\n .comments-textarea:focus {\n outline: none;\n border-color: #3b82f6;\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n }\n\n .form-actions {\n display: flex;\n gap: 12px;\n margin-top: 20px;\n }\n\n .submit-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 24px;\n border: none;\n border-radius: 8px;\n background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);\n color: white;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .submit-btn:hover:not(:disabled) {\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);\n }\n\n .submit-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n }\n\n .view-btn {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 20px;\n border: 1px solid #e2e8f0;\n border-radius: 8px;\n background: white;\n color: #64748b;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .view-btn:hover {\n border-color: #cbd5e1;\n background: #f8fafc;\n }\n\n /* Reviewed Items */\n .reviewed-item {\n padding: 16px 20px;\n border-bottom: 1px solid #f1f5f9;\n }\n\n .reviewed-header {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .reviewed-main {\n flex: 1;\n min-width: 0;\n }\n\n .reviewed-title {\n font-size: 14px;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 4px;\n }\n\n .reviewed-meta {\n display: flex;\n gap: 16px;\n font-size: 12px;\n color: #64748b;\n }\n\n .reviewed-meta span {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n\n .reviewed-rating {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n }\n\n .rating-stars {\n display: flex;\n gap: 2px;\n }\n\n .rating-stars i {\n font-size: 12px;\n color: #e2e8f0;\n }\n\n .rating-stars i.filled {\n color: #f59e0b;\n }\n\n .rating-text {\n font-size: 12px;\n font-weight: 600;\n color: #64748b;\n }\n\n .reviewed-verdict {\n flex-shrink: 0;\n }\n\n .verdict-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border-radius: 16px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .verdict-badge.correct {\n background: #dcfce7;\n color: #16a34a;\n }\n\n .verdict-badge.incorrect {\n background: #fee2e2;\n color: #dc2626;\n }\n\n .view-btn-small {\n background: none;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n padding: 8px;\n color: #64748b;\n cursor: pointer;\n transition: all 0.2s ease;\n }\n\n .view-btn-small:hover {\n background: #f8fafc;\n border-color: #cbd5e1;\n }\n\n .reviewed-comments {\n margin-top: 12px;\n padding: 12px;\n background: #f8fafc;\n border-radius: 8px;\n border-left: 3px solid #3b82f6;\n }\n\n .reviewed-comments p {\n margin: 0;\n font-size: 13px;\n color: #475569;\n line-height: 1.5;\n }\n\n /* Suite Cards */\n .suites-list {\n padding: 16px;\n }\n\n .suite-card {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 20px;\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n margin-bottom: 12px;\n }\n\n .suite-card:hover {\n border-color: #3b82f6;\n background: white;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n }\n\n .suite-card:last-child {\n margin-bottom: 0;\n }\n\n .suite-header {\n display: flex;\n align-items: center;\n gap: 14px;\n flex: 1;\n min-width: 0;\n }\n\n .suite-icon {\n width: 44px;\n height: 44px;\n border-radius: 10px;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-size: 18px;\n flex-shrink: 0;\n }\n\n .suite-info h4 {\n margin: 0 0 4px 0;\n font-size: 15px;\n font-weight: 600;\n color: #1e293b;\n }\n\n .suite-meta {\n font-size: 12px;\n color: #64748b;\n }\n\n .suite-stats {\n display: flex;\n gap: 20px;\n }\n\n .suite-stat {\n text-align: center;\n min-width: 60px;\n }\n\n .suite-stat .stat-value {\n font-size: 18px;\n font-weight: 700;\n color: #1e293b;\n }\n\n .suite-stat .stat-value.pending {\n color: #f97316;\n }\n\n .suite-stat .stat-value.reviewed {\n color: #22c55e;\n }\n\n .suite-stat .stat-value.good {\n color: #22c55e;\n }\n\n .suite-stat .stat-value.bad {\n color: #ef4444;\n }\n\n .suite-stat .stat-label {\n font-size: 10px;\n color: #94a3b8;\n font-weight: 600;\n text-transform: uppercase;\n }\n\n .suite-arrow {\n color: #94a3b8;\n font-size: 14px;\n }\n\n /* Empty States */\n .empty-state {\n padding: 60px 20px;\n text-align: center;\n }\n\n .empty-state i {\n font-size: 56px;\n margin-bottom: 16px;\n color: #cbd5e1;\n }\n\n .empty-state.success i {\n color: #22c55e;\n }\n\n .empty-state h3 {\n font-size: 18px;\n color: #475569;\n margin: 0 0 8px 0;\n font-weight: 600;\n }\n\n .empty-state p {\n font-size: 14px;\n color: #94a3b8;\n margin: 0;\n }\n\n /* Statistics */\n .feedback-stats {\n background: white;\n padding: 20px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n }\n\n .feedback-stats h3 {\n margin: 0 0 20px 0;\n font-size: 16px;\n font-weight: 600;\n color: #1e293b;\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .feedback-stats h3 i {\n color: #3b82f6;\n }\n\n .stats-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 16px;\n }\n\n .stat-card {\n background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);\n padding: 16px;\n border-radius: 10px;\n text-align: center;\n }\n\n .stat-card .stat-label {\n font-size: 10px;\n font-weight: 700;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n }\n\n .stat-card .stat-value {\n font-size: 24px;\n font-weight: 700;\n color: #1e293b;\n }\n\n /* Responsive */\n @media (max-width: 1024px) {\n .feedback-summary {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .suite-stats {\n flex-wrap: wrap;\n gap: 12px;\n }\n }\n\n @media (max-width: 768px) {\n .testing-feedback {\n padding: 16px;\n }\n\n .feedback-header {\n flex-direction: column;\n gap: 16px;\n align-items: flex-start;\n }\n\n .feedback-summary {\n grid-template-columns: 1fr 1fr;\n }\n\n .summary-card {\n padding: 16px;\n }\n\n .summary-value {\n font-size: 22px;\n }\n\n .feedback-filters {\n flex-direction: column;\n }\n\n .filter-group {\n min-width: 100%;\n }\n\n .item-header {\n flex-wrap: wrap;\n }\n\n .item-reason {\n width: 100%;\n margin-top: 8px;\n }\n\n .correctness-buttons {\n flex-direction: column;\n }\n\n .form-actions {\n flex-direction: column;\n }\n\n .reviewed-header {\n flex-wrap: wrap;\n }\n\n .suite-card {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .suite-stats {\n width: 100%;\n justify-content: space-between;\n }\n }\n "] }]
782
1480
  }], () => [{ type: i1.TestingInstrumentationService }, { type: i0.ChangeDetectorRef }], { initialState: [{
783
1481
  type: Input
784
1482
  }], stateChange: [{
785
1483
  type: Output
786
1484
  }] }); })();
787
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TestingFeedbackComponent, { className: "TestingFeedbackComponent", filePath: "src/Testing/components/testing-feedback.component.ts", lineNumber: 921 }); })();
1485
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TestingFeedbackComponent, { className: "TestingFeedbackComponent", filePath: "src/Testing/components/testing-feedback.component.ts", lineNumber: 1431 }); })();
788
1486
  //# sourceMappingURL=testing-feedback.component.js.map