@memberjunction/ng-dashboards 2.117.0 → 2.118.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/Testing/components/testing-analytics.component.d.ts +56 -0
  2. package/dist/Testing/components/testing-analytics.component.d.ts.map +1 -0
  3. package/dist/Testing/components/testing-analytics.component.js +746 -0
  4. package/dist/Testing/components/testing-analytics.component.js.map +1 -0
  5. package/dist/Testing/components/testing-execution.component.d.ts +59 -0
  6. package/dist/Testing/components/testing-execution.component.d.ts.map +1 -0
  7. package/dist/Testing/components/testing-execution.component.js +649 -0
  8. package/dist/Testing/components/testing-execution.component.js.map +1 -0
  9. package/dist/Testing/components/testing-feedback.component.d.ts +55 -0
  10. package/dist/Testing/components/testing-feedback.component.d.ts.map +1 -0
  11. package/dist/Testing/components/testing-feedback.component.js +789 -0
  12. package/dist/Testing/components/testing-feedback.component.js.map +1 -0
  13. package/dist/Testing/components/testing-overview.component.d.ts +30 -0
  14. package/dist/Testing/components/testing-overview.component.d.ts.map +1 -0
  15. package/dist/Testing/components/testing-overview.component.js +342 -0
  16. package/dist/Testing/components/testing-overview.component.js.map +1 -0
  17. package/dist/Testing/components/testing-version-comparison.component.d.ts +58 -0
  18. package/dist/Testing/components/testing-version-comparison.component.d.ts.map +1 -0
  19. package/dist/Testing/components/testing-version-comparison.component.js +801 -0
  20. package/dist/Testing/components/testing-version-comparison.component.js.map +1 -0
  21. package/dist/Testing/components/widgets/cost-display.component.d.ts +16 -0
  22. package/dist/Testing/components/widgets/cost-display.component.d.ts.map +1 -0
  23. package/dist/Testing/components/widgets/cost-display.component.js +88 -0
  24. package/dist/Testing/components/widgets/cost-display.component.js.map +1 -0
  25. package/dist/Testing/components/widgets/oracle-breakdown-table.component.d.ts +20 -0
  26. package/dist/Testing/components/widgets/oracle-breakdown-table.component.d.ts.map +1 -0
  27. package/dist/Testing/components/widgets/oracle-breakdown-table.component.js +280 -0
  28. package/dist/Testing/components/widgets/oracle-breakdown-table.component.js.map +1 -0
  29. package/dist/Testing/components/widgets/score-indicator.component.d.ts +13 -0
  30. package/dist/Testing/components/widgets/score-indicator.component.d.ts.map +1 -0
  31. package/dist/Testing/components/widgets/score-indicator.component.js +93 -0
  32. package/dist/Testing/components/widgets/score-indicator.component.js.map +1 -0
  33. package/dist/Testing/components/widgets/suite-tree.component.d.ts +28 -0
  34. package/dist/Testing/components/widgets/suite-tree.component.d.ts.map +1 -0
  35. package/dist/Testing/components/widgets/suite-tree.component.js +275 -0
  36. package/dist/Testing/components/widgets/suite-tree.component.js.map +1 -0
  37. package/dist/Testing/components/widgets/test-run-detail-panel.component.d.ts +34 -0
  38. package/dist/Testing/components/widgets/test-run-detail-panel.component.d.ts.map +1 -0
  39. package/dist/Testing/components/widgets/test-run-detail-panel.component.js +373 -0
  40. package/dist/Testing/components/widgets/test-run-detail-panel.component.js.map +1 -0
  41. package/dist/Testing/components/widgets/test-run-dialog.component.d.ts +63 -0
  42. package/dist/Testing/components/widgets/test-run-dialog.component.d.ts.map +1 -0
  43. package/dist/Testing/components/widgets/test-run-dialog.component.js +989 -0
  44. package/dist/Testing/components/widgets/test-run-dialog.component.js.map +1 -0
  45. package/dist/Testing/components/widgets/test-status-badge.component.d.ts +10 -0
  46. package/dist/Testing/components/widgets/test-status-badge.component.d.ts.map +1 -0
  47. package/dist/Testing/components/widgets/test-status-badge.component.js +68 -0
  48. package/dist/Testing/components/widgets/test-status-badge.component.js.map +1 -0
  49. package/dist/Testing/services/testing-instrumentation.service.d.ts +152 -0
  50. package/dist/Testing/services/testing-instrumentation.service.d.ts.map +1 -0
  51. package/dist/Testing/services/testing-instrumentation.service.js +579 -0
  52. package/dist/Testing/services/testing-instrumentation.service.js.map +1 -0
  53. package/dist/Testing/testing-dashboard.component.d.ts +52 -0
  54. package/dist/Testing/testing-dashboard.component.d.ts.map +1 -0
  55. package/dist/Testing/testing-dashboard.component.js +273 -0
  56. package/dist/Testing/testing-dashboard.component.js.map +1 -0
  57. package/dist/module.d.ts +33 -20
  58. package/dist/module.d.ts.map +1 -1
  59. package/dist/module.js +55 -6
  60. package/dist/module.js.map +1 -1
  61. package/dist/public-api.d.ts +1 -0
  62. package/dist/public-api.d.ts.map +1 -1
  63. package/dist/public-api.js +3 -0
  64. package/dist/public-api.js.map +1 -1
  65. package/package.json +12 -10
@@ -0,0 +1,789 @@
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';
5
+ import { SharedService } from '@memberjunction/ng-shared';
6
+ import * as i0 from "@angular/core";
7
+ import * as i1 from "../services/testing-instrumentation.service";
8
+ import * as i2 from "@angular/common";
9
+ import * as i3 from "@angular/forms";
10
+ import * as i4 from "./widgets/test-status-badge.component";
11
+ import * as i5 from "./widgets/score-indicator.component";
12
+ const _forTrack0 = ($index, $item) => $item.testRunID;
13
+ const _c0 = () => [];
14
+ function TestingFeedbackComponent_div_6_Template(rf, ctx) { if (rf & 1) {
15
+ i0.ɵɵelementStart(0, "div", 52)(1, "span", 53);
16
+ i0.ɵɵtext(2);
17
+ i0.ɵɵpipe(3, "async");
18
+ i0.ɵɵelementEnd();
19
+ i0.ɵɵelementStart(4, "span", 54);
20
+ i0.ɵɵtext(5, "Pending Review");
21
+ i0.ɵɵelementEnd()();
22
+ } if (rf & 2) {
23
+ const ctx_r0 = i0.ɵɵnextContext();
24
+ i0.ɵɵadvance(2);
25
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(3, 1, ctx_r0.pendingCount$));
26
+ } }
27
+ function TestingFeedbackComponent_button_41_Template(rf, ctx) { if (rf & 1) {
28
+ const _r2 = i0.ɵɵgetCurrentView();
29
+ i0.ɵɵelementStart(0, "button", 55);
30
+ 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()); });
31
+ i0.ɵɵelement(1, "i", 56);
32
+ i0.ɵɵelementEnd();
33
+ } }
34
+ function TestingFeedbackComponent_For_97_Conditional_23_Template(rf, ctx) { if (rf & 1) {
35
+ const _r5 = i0.ɵɵgetCurrentView();
36
+ i0.ɵɵelementStart(0, "div", 71)(1, "div", 72)(2, "div", 73)(3, "h4");
37
+ i0.ɵɵtext(4, "Provide Your Feedback");
38
+ i0.ɵɵelementEnd();
39
+ i0.ɵɵelementStart(5, "div", 74)(6, "div", 75)(7, "label");
40
+ i0.ɵɵtext(8, "Human Rating (1-10)");
41
+ i0.ɵɵelementEnd();
42
+ i0.ɵɵelementStart(9, "input", 76);
43
+ 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); });
44
+ i0.ɵɵelementEnd()();
45
+ i0.ɵɵelementStart(10, "div", 75)(11, "label");
46
+ i0.ɵɵtext(12, "Is Automated Result Correct?");
47
+ i0.ɵɵelementEnd();
48
+ i0.ɵɵelementStart(13, "div", 77)(14, "label", 78)(15, "input", 79);
49
+ 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); });
50
+ i0.ɵɵelementEnd();
51
+ i0.ɵɵelementStart(16, "span");
52
+ i0.ɵɵtext(17, "Yes, the automated assessment is correct");
53
+ i0.ɵɵelementEnd()()()()();
54
+ i0.ɵɵelementStart(18, "div", 75)(19, "label");
55
+ i0.ɵɵtext(20, "Comments / Notes");
56
+ i0.ɵɵelementEnd();
57
+ i0.ɵɵelementStart(21, "textarea", 80);
58
+ 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); });
59
+ i0.ɵɵelementEnd()();
60
+ i0.ɵɵelementStart(22, "div", 81)(23, "button", 82);
61
+ 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)); });
62
+ i0.ɵɵelement(24, "i", 83);
63
+ i0.ɵɵtext(25, " Submit Feedback ");
64
+ i0.ɵɵelementEnd();
65
+ i0.ɵɵelementStart(26, "button", 84);
66
+ 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)); });
67
+ i0.ɵɵelement(27, "i", 85);
68
+ i0.ɵɵtext(28, " Skip for Now ");
69
+ i0.ɵɵelementEnd()()();
70
+ i0.ɵɵelementStart(29, "div", 86)(30, "h4");
71
+ i0.ɵɵtext(31, "Test Context");
72
+ i0.ɵɵelementEnd();
73
+ i0.ɵɵelementStart(32, "div", 87)(33, "div", 88)(34, "span", 89);
74
+ i0.ɵɵtext(35, "Test Run ID");
75
+ i0.ɵɵelementEnd();
76
+ i0.ɵɵelementStart(36, "span", 90);
77
+ i0.ɵɵtext(37);
78
+ i0.ɵɵelementEnd()();
79
+ i0.ɵɵelementStart(38, "div", 88)(39, "span", 89);
80
+ i0.ɵɵtext(40, "Automated Score");
81
+ i0.ɵɵelementEnd();
82
+ i0.ɵɵelementStart(41, "span", 90);
83
+ i0.ɵɵelement(42, "app-score-indicator", 91);
84
+ i0.ɵɵelementEnd()();
85
+ i0.ɵɵelementStart(43, "div", 88)(44, "span", 89);
86
+ i0.ɵɵtext(45, "Status");
87
+ i0.ɵɵelementEnd();
88
+ i0.ɵɵelementStart(46, "span", 90);
89
+ i0.ɵɵelement(47, "app-test-status-badge", 66);
90
+ i0.ɵɵelementEnd()();
91
+ i0.ɵɵelementStart(48, "div", 88)(49, "span", 89);
92
+ i0.ɵɵtext(50, "Run Date");
93
+ i0.ɵɵelementEnd();
94
+ i0.ɵɵelementStart(51, "span", 90);
95
+ i0.ɵɵtext(52);
96
+ i0.ɵɵpipe(53, "date");
97
+ i0.ɵɵelementEnd()()();
98
+ i0.ɵɵelementStart(54, "button", 92);
99
+ 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)); });
100
+ i0.ɵɵelement(55, "i", 93);
101
+ i0.ɵɵtext(56, " View Full Test Details ");
102
+ i0.ɵɵelementEnd()()()();
103
+ } if (rf & 2) {
104
+ const item_r4 = i0.ɵɵnextContext().$implicit;
105
+ const ctx_r0 = i0.ɵɵnextContext();
106
+ i0.ɵɵadvance(9);
107
+ i0.ɵɵtwoWayProperty("ngModel", item_r4.feedbackRating);
108
+ i0.ɵɵadvance(6);
109
+ i0.ɵɵtwoWayProperty("ngModel", item_r4.feedbackIsCorrect);
110
+ i0.ɵɵadvance(6);
111
+ i0.ɵɵtwoWayProperty("ngModel", item_r4.feedbackComments);
112
+ i0.ɵɵadvance(16);
113
+ i0.ɵɵtextInterpolate(item_r4.testRunID);
114
+ i0.ɵɵadvance(5);
115
+ i0.ɵɵproperty("score", item_r4.automatedScore)("showBar", true);
116
+ i0.ɵɵadvance(5);
117
+ i0.ɵɵproperty("status", ctx_r0.getTestStatus(item_r4.automatedStatus));
118
+ i0.ɵɵadvance(5);
119
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(53, 8, item_r4.runDateTime, "medium"));
120
+ } }
121
+ function TestingFeedbackComponent_For_97_Template(rf, ctx) { if (rf & 1) {
122
+ const _r3 = i0.ɵɵgetCurrentView();
123
+ i0.ɵɵelementStart(0, "div", 57)(1, "div", 58);
124
+ 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)); });
125
+ i0.ɵɵelementStart(2, "div", 59)(3, "div", 60);
126
+ i0.ɵɵtext(4);
127
+ i0.ɵɵelementEnd();
128
+ i0.ɵɵelementStart(5, "div", 61)(6, "span", 62);
129
+ i0.ɵɵelement(7, "i", 63);
130
+ i0.ɵɵtext(8);
131
+ i0.ɵɵpipe(9, "date");
132
+ i0.ɵɵelementEnd();
133
+ i0.ɵɵelementStart(10, "span", 64);
134
+ i0.ɵɵtext(11, " Automated Score: ");
135
+ i0.ɵɵelementStart(12, "strong");
136
+ i0.ɵɵtext(13);
137
+ i0.ɵɵelementEnd()();
138
+ i0.ɵɵelementStart(14, "span", 65);
139
+ i0.ɵɵtext(15, " Status: ");
140
+ i0.ɵɵelement(16, "app-test-status-badge", 66);
141
+ i0.ɵɵelementEnd()()();
142
+ i0.ɵɵelementStart(17, "div", 67)(18, "span", 68);
143
+ i0.ɵɵelement(19, "i", 69);
144
+ i0.ɵɵtext(20);
145
+ i0.ɵɵelementEnd()();
146
+ i0.ɵɵelementStart(21, "button", 70);
147
+ i0.ɵɵelement(22, "i", 69);
148
+ i0.ɵɵelementEnd()();
149
+ i0.ɵɵtemplate(23, TestingFeedbackComponent_For_97_Conditional_23_Template, 57, 11, "div", 71);
150
+ i0.ɵɵelementEnd();
151
+ } if (rf & 2) {
152
+ const item_r4 = ctx.$implicit;
153
+ const ctx_r0 = i0.ɵɵnextContext();
154
+ i0.ɵɵclassProp("expanded", ctx_r0.expandedItem === item_r4.testRunID);
155
+ i0.ɵɵadvance(4);
156
+ i0.ɵɵtextInterpolate(item_r4.testName);
157
+ i0.ɵɵadvance(4);
158
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(9, 20, item_r4.runDateTime, "short"), " ");
159
+ i0.ɵɵadvance(5);
160
+ i0.ɵɵtextInterpolate(item_r4.automatedScore.toFixed(4));
161
+ i0.ɵɵadvance(3);
162
+ i0.ɵɵproperty("status", ctx_r0.getTestStatus(item_r4.automatedStatus));
163
+ i0.ɵɵadvance(2);
164
+ i0.ɵɵclassMap(item_r4.reason);
165
+ i0.ɵɵadvance();
166
+ 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");
167
+ i0.ɵɵadvance();
168
+ i0.ɵɵtextInterpolate1(" ", ctx_r0.formatReason(item_r4.reason), " ");
169
+ i0.ɵɵadvance(2);
170
+ i0.ɵɵclassProp("fa-chevron-down", ctx_r0.expandedItem !== item_r4.testRunID)("fa-chevron-up", ctx_r0.expandedItem === item_r4.testRunID);
171
+ i0.ɵɵadvance();
172
+ i0.ɵɵconditional(ctx_r0.expandedItem === item_r4.testRunID ? 23 : -1);
173
+ } }
174
+ function TestingFeedbackComponent_ForEmpty_98_Template(rf, ctx) { if (rf & 1) {
175
+ i0.ɵɵelementStart(0, "div", 44);
176
+ i0.ɵɵelement(1, "i", 94);
177
+ i0.ɵɵelementStart(2, "h3");
178
+ i0.ɵɵtext(3, "All Caught Up!");
179
+ i0.ɵɵelementEnd();
180
+ i0.ɵɵelementStart(4, "p");
181
+ i0.ɵɵtext(5, "No tests currently require feedback review.");
182
+ i0.ɵɵelementEnd()();
183
+ } }
184
+ export class TestingFeedbackComponent {
185
+ instrumentationService;
186
+ cdr;
187
+ initialState;
188
+ stateChange = new EventEmitter();
189
+ destroy$ = new Subject();
190
+ filters = {
191
+ status: 'pending',
192
+ reason: 'all',
193
+ searchText: ''
194
+ };
195
+ sortBy = 'priority';
196
+ expandedItem = null;
197
+ pendingFeedback$;
198
+ filteredFeedback$;
199
+ pendingCount$;
200
+ discrepancyCount$;
201
+ reviewedCount$;
202
+ accuracyRate$;
203
+ totalFeedback$;
204
+ avgRating$;
205
+ agreementRate$;
206
+ disagreementRate$;
207
+ constructor(instrumentationService, cdr) {
208
+ this.instrumentationService = instrumentationService;
209
+ this.cdr = cdr;
210
+ }
211
+ ngOnInit() {
212
+ this.setupObservables();
213
+ if (this.initialState) {
214
+ this.filters = { ...this.filters, ...this.initialState.filters };
215
+ this.sortBy = this.initialState.sortBy || 'priority';
216
+ }
217
+ }
218
+ ngOnDestroy() {
219
+ this.destroy$.next();
220
+ this.destroy$.complete();
221
+ }
222
+ setupObservables() {
223
+ this.pendingFeedback$ = this.instrumentationService.pendingFeedback$.pipe(map(feedback => feedback.map(f => ({
224
+ ...f,
225
+ feedbackRating: 5,
226
+ feedbackIsCorrect: true,
227
+ feedbackComments: ''
228
+ }))), takeUntil(this.destroy$));
229
+ this.filteredFeedback$ = this.pendingFeedback$.pipe(map(feedback => this.filterAndSort(feedback)));
230
+ this.pendingCount$ = this.pendingFeedback$.pipe(map(feedback => feedback.length));
231
+ this.discrepancyCount$ = this.pendingFeedback$.pipe(map(feedback => feedback.filter(f => f.reason === 'high-score-failed' || f.reason === 'low-score-passed').length));
232
+ // Load real feedback statistics from the service
233
+ const feedbackStats$ = this.instrumentationService.feedbackStats$;
234
+ this.reviewedCount$ = feedbackStats$.pipe(map(stats => stats.reviewedCount), takeUntil(this.destroy$));
235
+ this.accuracyRate$ = feedbackStats$.pipe(map(stats => stats.accuracyRate), takeUntil(this.destroy$));
236
+ this.totalFeedback$ = feedbackStats$.pipe(map(stats => stats.totalFeedback), takeUntil(this.destroy$));
237
+ this.avgRating$ = feedbackStats$.pipe(map(stats => stats.avgRating), takeUntil(this.destroy$));
238
+ this.agreementRate$ = feedbackStats$.pipe(map(stats => stats.agreementRate), takeUntil(this.destroy$));
239
+ this.disagreementRate$ = feedbackStats$.pipe(map(stats => stats.disagreementRate), takeUntil(this.destroy$));
240
+ }
241
+ filterAndSort(feedback) {
242
+ let filtered = [...feedback];
243
+ // Note: 'reviewed' status would need to query Test Run Feedback entity separately
244
+ // For now, we only show pending items (all items from pendingFeedback$ are pending by definition)
245
+ if (this.filters.status === 'reviewed') {
246
+ filtered = []; // No reviewed items in this stream
247
+ }
248
+ if (this.filters.reason !== 'all') {
249
+ filtered = filtered.filter(f => f.reason === this.filters.reason);
250
+ }
251
+ if (this.filters.searchText) {
252
+ const searchLower = this.filters.searchText.toLowerCase();
253
+ filtered = filtered.filter(f => f.testName.toLowerCase().includes(searchLower));
254
+ }
255
+ filtered.sort((a, b) => {
256
+ if (this.sortBy === 'date') {
257
+ return b.runDateTime.getTime() - a.runDateTime.getTime();
258
+ }
259
+ else if (this.sortBy === 'priority') {
260
+ const priorityOrder = { 'high-score-failed': 1, 'low-score-passed': 2, 'no-feedback': 3 };
261
+ return (priorityOrder[a.reason] || 99) -
262
+ (priorityOrder[b.reason] || 99);
263
+ }
264
+ else {
265
+ return a.testName.localeCompare(b.testName);
266
+ }
267
+ });
268
+ return filtered;
269
+ }
270
+ onFilterChange() {
271
+ this.emitStateChange();
272
+ this.cdr.markForCheck();
273
+ }
274
+ clearSearch() {
275
+ this.filters.searchText = '';
276
+ this.onFilterChange();
277
+ }
278
+ onSortChange() {
279
+ this.emitStateChange();
280
+ this.cdr.markForCheck();
281
+ }
282
+ toggleExpanded(testRunID) {
283
+ this.expandedItem = this.expandedItem === testRunID ? null : testRunID;
284
+ }
285
+ submitFeedback(item) {
286
+ console.log('Submit feedback:', item);
287
+ this.expandedItem = null;
288
+ this.cdr.markForCheck();
289
+ }
290
+ skipFeedback(item) {
291
+ console.log('Skip feedback:', item);
292
+ this.expandedItem = null;
293
+ this.cdr.markForCheck();
294
+ }
295
+ viewFullDetails(item) {
296
+ SharedService.Instance.OpenEntityRecord('MJ: Test Runs', CompositeKey.FromID(item.testRunID));
297
+ }
298
+ refresh() {
299
+ this.instrumentationService.refresh();
300
+ }
301
+ formatReason(reason) {
302
+ switch (reason) {
303
+ case 'no-feedback': return 'No Feedback';
304
+ case 'high-score-failed': return 'High Score but Failed';
305
+ case 'low-score-passed': return 'Low Score but Passed';
306
+ default: return reason;
307
+ }
308
+ }
309
+ getTestStatus(status) {
310
+ // Convert automatedStatus string to TestStatus type
311
+ return status;
312
+ }
313
+ emitStateChange() {
314
+ this.stateChange.emit({
315
+ filters: this.filters,
316
+ sortBy: this.sortBy
317
+ });
318
+ }
319
+ static ɵfac = function TestingFeedbackComponent_Factory(t) { return new (t || TestingFeedbackComponent)(i0.ɵɵdirectiveInject(i1.TestingInstrumentationService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
320
+ 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) {
321
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h2");
322
+ i0.ɵɵelement(4, "i", 3);
323
+ i0.ɵɵtext(5, " Human Feedback Review ");
324
+ i0.ɵɵelementEnd();
325
+ i0.ɵɵtemplate(6, TestingFeedbackComponent_div_6_Template, 6, 3, "div", 4);
326
+ i0.ɵɵpipe(7, "async");
327
+ i0.ɵɵelementEnd();
328
+ i0.ɵɵelementStart(8, "div", 5)(9, "button", 6);
329
+ i0.ɵɵlistener("click", function TestingFeedbackComponent_Template_button_click_9_listener() { return ctx.refresh(); });
330
+ i0.ɵɵelement(10, "i", 7);
331
+ i0.ɵɵtext(11, " Refresh ");
332
+ i0.ɵɵelementEnd()()();
333
+ i0.ɵɵelementStart(12, "div", 8)(13, "div", 9)(14, "label");
334
+ i0.ɵɵtext(15, "Status");
335
+ i0.ɵɵelementEnd();
336
+ i0.ɵɵelementStart(16, "select", 10);
337
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_select_ngModelChange_16_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.status, $event) || (ctx.filters.status = $event); return $event; });
338
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_Template_select_change_16_listener() { return ctx.onFilterChange(); });
339
+ i0.ɵɵelementStart(17, "option", 11);
340
+ i0.ɵɵtext(18, "All");
341
+ i0.ɵɵelementEnd();
342
+ i0.ɵɵelementStart(19, "option", 12);
343
+ i0.ɵɵtext(20, "Pending Review");
344
+ i0.ɵɵelementEnd();
345
+ i0.ɵɵelementStart(21, "option", 13);
346
+ i0.ɵɵtext(22, "Reviewed");
347
+ i0.ɵɵelementEnd()()();
348
+ i0.ɵɵelementStart(23, "div", 9)(24, "label");
349
+ i0.ɵɵtext(25, "Reason");
350
+ i0.ɵɵelementEnd();
351
+ i0.ɵɵelementStart(26, "select", 10);
352
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_select_ngModelChange_26_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.reason, $event) || (ctx.filters.reason = $event); return $event; });
353
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_Template_select_change_26_listener() { return ctx.onFilterChange(); });
354
+ i0.ɵɵelementStart(27, "option", 11);
355
+ i0.ɵɵtext(28, "All Reasons");
356
+ i0.ɵɵelementEnd();
357
+ i0.ɵɵelementStart(29, "option", 14);
358
+ i0.ɵɵtext(30, "No Feedback");
359
+ i0.ɵɵelementEnd();
360
+ i0.ɵɵelementStart(31, "option", 15);
361
+ i0.ɵɵtext(32, "High Score but Failed");
362
+ i0.ɵɵelementEnd();
363
+ i0.ɵɵelementStart(33, "option", 16);
364
+ i0.ɵɵtext(34, "Low Score but Passed");
365
+ i0.ɵɵelementEnd()()();
366
+ i0.ɵɵelementStart(35, "div", 17)(36, "label");
367
+ i0.ɵɵtext(37, "Search");
368
+ i0.ɵɵelementEnd();
369
+ i0.ɵɵelementStart(38, "div", 18);
370
+ i0.ɵɵelement(39, "i", 19);
371
+ i0.ɵɵelementStart(40, "input", 20);
372
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_input_ngModelChange_40_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.filters.searchText, $event) || (ctx.filters.searchText = $event); return $event; });
373
+ i0.ɵɵlistener("input", function TestingFeedbackComponent_Template_input_input_40_listener() { return ctx.onFilterChange(); });
374
+ i0.ɵɵelementEnd();
375
+ i0.ɵɵtemplate(41, TestingFeedbackComponent_button_41_Template, 2, 0, "button", 21);
376
+ i0.ɵɵelementEnd()()();
377
+ i0.ɵɵelementStart(42, "div", 22)(43, "div", 23)(44, "div", 24);
378
+ i0.ɵɵelement(45, "i", 25);
379
+ i0.ɵɵelementEnd();
380
+ i0.ɵɵelementStart(46, "div", 26)(47, "div", 27);
381
+ i0.ɵɵtext(48);
382
+ i0.ɵɵpipe(49, "async");
383
+ i0.ɵɵelementEnd();
384
+ i0.ɵɵelementStart(50, "div", 28);
385
+ i0.ɵɵtext(51, "Pending Review");
386
+ i0.ɵɵelementEnd()()();
387
+ i0.ɵɵelementStart(52, "div", 23)(53, "div", 29);
388
+ i0.ɵɵelement(54, "i", 30);
389
+ i0.ɵɵelementEnd();
390
+ i0.ɵɵelementStart(55, "div", 26)(56, "div", 27);
391
+ i0.ɵɵtext(57);
392
+ i0.ɵɵpipe(58, "async");
393
+ i0.ɵɵelementEnd();
394
+ i0.ɵɵelementStart(59, "div", 28);
395
+ i0.ɵɵtext(60, "Score Discrepancies");
396
+ i0.ɵɵelementEnd()()();
397
+ i0.ɵɵelementStart(61, "div", 23)(62, "div", 31);
398
+ i0.ɵɵelement(63, "i", 32);
399
+ i0.ɵɵelementEnd();
400
+ i0.ɵɵelementStart(64, "div", 26)(65, "div", 27);
401
+ i0.ɵɵtext(66);
402
+ i0.ɵɵpipe(67, "async");
403
+ i0.ɵɵelementEnd();
404
+ i0.ɵɵelementStart(68, "div", 28);
405
+ i0.ɵɵtext(69, "Reviewed");
406
+ i0.ɵɵelementEnd()()();
407
+ i0.ɵɵelementStart(70, "div", 23)(71, "div", 33);
408
+ i0.ɵɵelement(72, "i", 34);
409
+ i0.ɵɵelementEnd();
410
+ i0.ɵɵelementStart(73, "div", 26)(74, "div", 27);
411
+ i0.ɵɵtext(75);
412
+ i0.ɵɵpipe(76, "async");
413
+ i0.ɵɵpipe(77, "number");
414
+ i0.ɵɵelementEnd();
415
+ i0.ɵɵelementStart(78, "div", 28);
416
+ i0.ɵɵtext(79, "Human-AI Agreement");
417
+ i0.ɵɵelementEnd()()()();
418
+ i0.ɵɵelementStart(80, "div", 35)(81, "div", 36)(82, "h3");
419
+ i0.ɵɵelement(83, "i", 37);
420
+ i0.ɵɵtext(84, " Tests Requiring Review ");
421
+ i0.ɵɵelementEnd();
422
+ i0.ɵɵelementStart(85, "div", 38)(86, "label");
423
+ i0.ɵɵtext(87, "Sort by:");
424
+ i0.ɵɵelementEnd();
425
+ i0.ɵɵelementStart(88, "select", 10);
426
+ i0.ɵɵtwoWayListener("ngModelChange", function TestingFeedbackComponent_Template_select_ngModelChange_88_listener($event) { i0.ɵɵtwoWayBindingSet(ctx.sortBy, $event) || (ctx.sortBy = $event); return $event; });
427
+ i0.ɵɵlistener("change", function TestingFeedbackComponent_Template_select_change_88_listener() { return ctx.onSortChange(); });
428
+ i0.ɵɵelementStart(89, "option", 39);
429
+ i0.ɵɵtext(90, "Date");
430
+ i0.ɵɵelementEnd();
431
+ i0.ɵɵelementStart(91, "option", 40);
432
+ i0.ɵɵtext(92, "Priority");
433
+ i0.ɵɵelementEnd();
434
+ i0.ɵɵelementStart(93, "option", 41);
435
+ i0.ɵɵtext(94, "Test Name");
436
+ i0.ɵɵelementEnd()()()();
437
+ i0.ɵɵelementStart(95, "div", 42);
438
+ i0.ɵɵrepeaterCreate(96, TestingFeedbackComponent_For_97_Template, 24, 23, "div", 43, _forTrack0, false, TestingFeedbackComponent_ForEmpty_98_Template, 6, 0, "div", 44);
439
+ i0.ɵɵpipe(99, "async");
440
+ i0.ɵɵelementEnd()();
441
+ i0.ɵɵelementStart(100, "div", 45)(101, "div", 46)(102, "h3");
442
+ i0.ɵɵelement(103, "i", 47);
443
+ i0.ɵɵtext(104, " Feedback Statistics ");
444
+ i0.ɵɵelementEnd();
445
+ i0.ɵɵelementStart(105, "div", 48)(106, "div", 49)(107, "div", 50);
446
+ i0.ɵɵtext(108, "Total Feedback Submitted");
447
+ i0.ɵɵelementEnd();
448
+ i0.ɵɵelementStart(109, "div", 51);
449
+ i0.ɵɵtext(110);
450
+ i0.ɵɵpipe(111, "async");
451
+ i0.ɵɵelementEnd()();
452
+ i0.ɵɵelementStart(112, "div", 49)(113, "div", 50);
453
+ i0.ɵɵtext(114, "Avg Rating");
454
+ i0.ɵɵelementEnd();
455
+ i0.ɵɵelementStart(115, "div", 51);
456
+ i0.ɵɵtext(116);
457
+ i0.ɵɵpipe(117, "async");
458
+ i0.ɵɵpipe(118, "number");
459
+ i0.ɵɵelementEnd()();
460
+ i0.ɵɵelementStart(119, "div", 49)(120, "div", 50);
461
+ i0.ɵɵtext(121, "Agreement Rate");
462
+ i0.ɵɵelementEnd();
463
+ i0.ɵɵelementStart(122, "div", 51);
464
+ i0.ɵɵtext(123);
465
+ i0.ɵɵpipe(124, "async");
466
+ i0.ɵɵpipe(125, "number");
467
+ i0.ɵɵelementEnd()();
468
+ i0.ɵɵelementStart(126, "div", 49)(127, "div", 50);
469
+ i0.ɵɵtext(128, "Disagreement Rate");
470
+ i0.ɵɵelementEnd();
471
+ i0.ɵɵelementStart(129, "div", 51);
472
+ i0.ɵɵtext(130);
473
+ i0.ɵɵpipe(131, "async");
474
+ i0.ɵɵpipe(132, "number");
475
+ i0.ɵɵelementEnd()()()()()();
476
+ } if (rf & 2) {
477
+ let tmp_10_0;
478
+ i0.ɵɵadvance(6);
479
+ i0.ɵɵproperty("ngIf", i0.ɵɵpipeBind1(7, 15, ctx.pendingCount$) || 0 > 0);
480
+ i0.ɵɵadvance(10);
481
+ i0.ɵɵtwoWayProperty("ngModel", ctx.filters.status);
482
+ i0.ɵɵadvance(10);
483
+ i0.ɵɵtwoWayProperty("ngModel", ctx.filters.reason);
484
+ i0.ɵɵadvance(14);
485
+ i0.ɵɵtwoWayProperty("ngModel", ctx.filters.searchText);
486
+ i0.ɵɵadvance();
487
+ i0.ɵɵproperty("ngIf", ctx.filters.searchText);
488
+ i0.ɵɵadvance(7);
489
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(49, 17, ctx.pendingCount$) || 0);
490
+ i0.ɵɵadvance(9);
491
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(58, 19, ctx.discrepancyCount$) || 0);
492
+ i0.ɵɵadvance(9);
493
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(67, 21, ctx.reviewedCount$) || 0);
494
+ i0.ɵɵadvance(9);
495
+ i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(77, 25, i0.ɵɵpipeBind1(76, 23, ctx.accuracyRate$) || 0, "1.1-1"), "%");
496
+ i0.ɵɵadvance(13);
497
+ i0.ɵɵtwoWayProperty("ngModel", ctx.sortBy);
498
+ i0.ɵɵadvance(8);
499
+ i0.ɵɵrepeater((tmp_10_0 = i0.ɵɵpipeBind1(99, 28, ctx.filteredFeedback$)) !== null && tmp_10_0 !== undefined ? tmp_10_0 : i0.ɵɵpureFunction0(47, _c0));
500
+ i0.ɵɵadvance(14);
501
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(111, 30, ctx.totalFeedback$) || 0);
502
+ i0.ɵɵadvance(6);
503
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(118, 34, i0.ɵɵpipeBind1(117, 32, ctx.avgRating$) || 0, "1.1-1"));
504
+ i0.ɵɵadvance(7);
505
+ i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(125, 39, i0.ɵɵpipeBind1(124, 37, ctx.agreementRate$) || 0, "1.1-1"), "%");
506
+ i0.ɵɵadvance(7);
507
+ i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind2(132, 44, i0.ɵɵpipeBind1(131, 42, ctx.disagreementRate$) || 0, "1.1-1"), "%");
508
+ } }, 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, i5.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 });
509
+ }
510
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TestingFeedbackComponent, [{
511
+ type: Component,
512
+ args: [{ selector: 'app-testing-feedback', changeDetection: ChangeDetectionStrategy.OnPush, template: `
513
+ <div class="testing-feedback">
514
+ <div class="feedback-header">
515
+ <div class="header-left">
516
+ <h2>
517
+ <i class="fa-solid fa-clipboard-check"></i>
518
+ Human Feedback Review
519
+ </h2>
520
+ <div class="pending-badge" *ngIf="(pendingCount$ | async) || 0 > 0">
521
+ <span class="badge-count">{{ (pendingCount$ | async) }}</span>
522
+ <span class="badge-text">Pending Review</span>
523
+ </div>
524
+ </div>
525
+ <div class="header-actions">
526
+ <button class="action-btn" (click)="refresh()">
527
+ <i class="fa-solid fa-refresh"></i>
528
+ Refresh
529
+ </button>
530
+ </div>
531
+ </div>
532
+
533
+ <!-- Filters -->
534
+ <div class="feedback-filters">
535
+ <div class="filter-group">
536
+ <label>Status</label>
537
+ <select [(ngModel)]="filters.status" (change)="onFilterChange()">
538
+ <option value="all">All</option>
539
+ <option value="pending">Pending Review</option>
540
+ <option value="reviewed">Reviewed</option>
541
+ </select>
542
+ </div>
543
+ <div class="filter-group">
544
+ <label>Reason</label>
545
+ <select [(ngModel)]="filters.reason" (change)="onFilterChange()">
546
+ <option value="all">All Reasons</option>
547
+ <option value="no-feedback">No Feedback</option>
548
+ <option value="high-score-failed">High Score but Failed</option>
549
+ <option value="low-score-passed">Low Score but Passed</option>
550
+ </select>
551
+ </div>
552
+ <div class="filter-group search">
553
+ <label>Search</label>
554
+ <div class="search-input-wrapper">
555
+ <i class="fa-solid fa-search"></i>
556
+ <input
557
+ type="text"
558
+ [(ngModel)]="filters.searchText"
559
+ (input)="onFilterChange()"
560
+ placeholder="Search tests..."
561
+ />
562
+ <button
563
+ class="clear-btn"
564
+ *ngIf="filters.searchText"
565
+ (click)="clearSearch()"
566
+ >
567
+ <i class="fa-solid fa-times"></i>
568
+ </button>
569
+ </div>
570
+ </div>
571
+ </div>
572
+
573
+ <!-- Summary Cards -->
574
+ <div class="feedback-summary">
575
+ <div class="summary-card">
576
+ <div class="summary-icon pending">
577
+ <i class="fa-solid fa-hourglass-half"></i>
578
+ </div>
579
+ <div class="summary-content">
580
+ <div class="summary-value">{{ (pendingCount$ | async) || 0 }}</div>
581
+ <div class="summary-label">Pending Review</div>
582
+ </div>
583
+ </div>
584
+ <div class="summary-card">
585
+ <div class="summary-icon discrepancy">
586
+ <i class="fa-solid fa-triangle-exclamation"></i>
587
+ </div>
588
+ <div class="summary-content">
589
+ <div class="summary-value">{{ (discrepancyCount$ | async) || 0 }}</div>
590
+ <div class="summary-label">Score Discrepancies</div>
591
+ </div>
592
+ </div>
593
+ <div class="summary-card">
594
+ <div class="summary-icon reviewed">
595
+ <i class="fa-solid fa-check-circle"></i>
596
+ </div>
597
+ <div class="summary-content">
598
+ <div class="summary-value">{{ (reviewedCount$ | async) || 0 }}</div>
599
+ <div class="summary-label">Reviewed</div>
600
+ </div>
601
+ </div>
602
+ <div class="summary-card">
603
+ <div class="summary-icon accuracy">
604
+ <i class="fa-solid fa-bullseye"></i>
605
+ </div>
606
+ <div class="summary-content">
607
+ <div class="summary-value">{{ (accuracyRate$ | async) || 0 | number:'1.1-1' }}%</div>
608
+ <div class="summary-label">Human-AI Agreement</div>
609
+ </div>
610
+ </div>
611
+ </div>
612
+
613
+ <!-- Pending Reviews List -->
614
+ <div class="feedback-content">
615
+ <div class="content-header">
616
+ <h3>
617
+ <i class="fa-solid fa-list-check"></i>
618
+ Tests Requiring Review
619
+ </h3>
620
+ <div class="sort-controls">
621
+ <label>Sort by:</label>
622
+ <select [(ngModel)]="sortBy" (change)="onSortChange()">
623
+ <option value="date">Date</option>
624
+ <option value="priority">Priority</option>
625
+ <option value="test-name">Test Name</option>
626
+ </select>
627
+ </div>
628
+ </div>
629
+
630
+ <div class="feedback-list">
631
+ @for (item of (filteredFeedback$ | async) ?? []; track item.testRunID) {
632
+ <div class="feedback-item" [class.expanded]="expandedItem === item.testRunID">
633
+ <div class="item-header" (click)="toggleExpanded(item.testRunID)">
634
+ <div class="item-main">
635
+ <div class="item-title">{{ item.testName }}</div>
636
+ <div class="item-meta">
637
+ <span class="meta-date">
638
+ <i class="fa-solid fa-clock"></i>
639
+ {{ item.runDateTime | date:'short' }}
640
+ </span>
641
+ <span class="meta-score">
642
+ Automated Score: <strong>{{ item.automatedScore.toFixed(4) }}</strong>
643
+ </span>
644
+ <span class="meta-status">
645
+ Status: <app-test-status-badge [status]="getTestStatus(item.automatedStatus)"></app-test-status-badge>
646
+ </span>
647
+ </div>
648
+ </div>
649
+ <div class="item-reason">
650
+ <span class="reason-badge" [class]="item.reason">
651
+ <i class="fa-solid" [class.fa-circle-info]="item.reason === 'no-feedback'"
652
+ [class.fa-arrow-up]="item.reason === 'high-score-failed'"
653
+ [class.fa-arrow-down]="item.reason === 'low-score-passed'"></i>
654
+ {{ formatReason(item.reason) }}
655
+ </span>
656
+ </div>
657
+ <button class="expand-btn">
658
+ <i class="fa-solid" [class.fa-chevron-down]="expandedItem !== item.testRunID"
659
+ [class.fa-chevron-up]="expandedItem === item.testRunID"></i>
660
+ </button>
661
+ </div>
662
+
663
+ @if (expandedItem === item.testRunID) {
664
+ <div class="item-content">
665
+ <div class="feedback-form">
666
+ <div class="form-section">
667
+ <h4>Provide Your Feedback</h4>
668
+ <div class="form-row">
669
+ <div class="form-group">
670
+ <label>Human Rating (1-10)</label>
671
+ <input
672
+ type="number"
673
+ [(ngModel)]="item.feedbackRating"
674
+ min="1"
675
+ max="10"
676
+ class="rating-input"
677
+ placeholder="Rate 1-10"
678
+ />
679
+ </div>
680
+ <div class="form-group">
681
+ <label>Is Automated Result Correct?</label>
682
+ <div class="checkbox-group">
683
+ <label class="checkbox-label">
684
+ <input type="checkbox" [(ngModel)]="item.feedbackIsCorrect" />
685
+ <span>Yes, the automated assessment is correct</span>
686
+ </label>
687
+ </div>
688
+ </div>
689
+ </div>
690
+ <div class="form-group">
691
+ <label>Comments / Notes</label>
692
+ <textarea
693
+ [(ngModel)]="item.feedbackComments"
694
+ rows="4"
695
+ class="comments-textarea"
696
+ placeholder="Provide detailed feedback about this test result..."
697
+ ></textarea>
698
+ </div>
699
+ <div class="form-actions">
700
+ <button class="submit-btn" (click)="submitFeedback(item)">
701
+ <i class="fa-solid fa-paper-plane"></i>
702
+ Submit Feedback
703
+ </button>
704
+ <button class="skip-btn" (click)="skipFeedback(item)">
705
+ <i class="fa-solid fa-forward"></i>
706
+ Skip for Now
707
+ </button>
708
+ </div>
709
+ </div>
710
+
711
+ <div class="context-section">
712
+ <h4>Test Context</h4>
713
+ <div class="context-details">
714
+ <div class="detail-item">
715
+ <span class="detail-label">Test Run ID</span>
716
+ <span class="detail-value">{{ item.testRunID }}</span>
717
+ </div>
718
+ <div class="detail-item">
719
+ <span class="detail-label">Automated Score</span>
720
+ <span class="detail-value">
721
+ <app-score-indicator [score]="item.automatedScore" [showBar]="true"></app-score-indicator>
722
+ </span>
723
+ </div>
724
+ <div class="detail-item">
725
+ <span class="detail-label">Status</span>
726
+ <span class="detail-value">
727
+ <app-test-status-badge [status]="getTestStatus(item.automatedStatus)"></app-test-status-badge>
728
+ </span>
729
+ </div>
730
+ <div class="detail-item">
731
+ <span class="detail-label">Run Date</span>
732
+ <span class="detail-value">{{ item.runDateTime | date:'medium' }}</span>
733
+ </div>
734
+ </div>
735
+ <button class="view-details-btn" (click)="viewFullDetails(item)">
736
+ <i class="fa-solid fa-external-link"></i>
737
+ View Full Test Details
738
+ </button>
739
+ </div>
740
+ </div>
741
+ </div>
742
+ }
743
+ </div>
744
+ } @empty {
745
+ <div class="empty-state">
746
+ <i class="fa-solid fa-check-double"></i>
747
+ <h3>All Caught Up!</h3>
748
+ <p>No tests currently require feedback review.</p>
749
+ </div>
750
+ }
751
+ </div>
752
+ </div>
753
+
754
+ <!-- Feedback Statistics -->
755
+ <div class="feedback-stats">
756
+ <div class="stats-section">
757
+ <h3>
758
+ <i class="fa-solid fa-chart-pie"></i>
759
+ Feedback Statistics
760
+ </h3>
761
+ <div class="stats-grid">
762
+ <div class="stat-card">
763
+ <div class="stat-label">Total Feedback Submitted</div>
764
+ <div class="stat-value">{{ (totalFeedback$ | async) || 0 }}</div>
765
+ </div>
766
+ <div class="stat-card">
767
+ <div class="stat-label">Avg Rating</div>
768
+ <div class="stat-value">{{ (avgRating$ | async) || 0 | number:'1.1-1' }}</div>
769
+ </div>
770
+ <div class="stat-card">
771
+ <div class="stat-label">Agreement Rate</div>
772
+ <div class="stat-value">{{ (agreementRate$ | async) || 0 | number:'1.1-1' }}%</div>
773
+ </div>
774
+ <div class="stat-card">
775
+ <div class="stat-label">Disagreement Rate</div>
776
+ <div class="stat-value">{{ (disagreementRate$ | async) || 0 | number:'1.1-1' }}%</div>
777
+ </div>
778
+ </div>
779
+ </div>
780
+ </div>
781
+ </div>
782
+ `, 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 "] }]
783
+ }], () => [{ type: i1.TestingInstrumentationService }, { type: i0.ChangeDetectorRef }], { initialState: [{
784
+ type: Input
785
+ }], stateChange: [{
786
+ type: Output
787
+ }] }); })();
788
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TestingFeedbackComponent, { className: "TestingFeedbackComponent", filePath: "src/Testing/components/testing-feedback.component.ts", lineNumber: 919 }); })();
789
+ //# sourceMappingURL=testing-feedback.component.js.map