@memberjunction/ng-dashboards 5.23.0 → 5.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +677 -5
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +6879 -1873
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +46 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +758 -491
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +19 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +410 -208
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +17 -17
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/Integration/components/activity/activity.component.d.ts.map +1 -1
- package/dist/Integration/components/activity/activity.component.js +1 -0
- package/dist/Integration/components/activity/activity.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +1 -0
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.d.ts.map +1 -1
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js +1 -0
- package/dist/Integration/components/mapping-workspace/mapping-workspace.component.js.map +1 -1
- package/dist/Integration/components/overview/overview.component.d.ts.map +1 -1
- package/dist/Integration/components/overview/overview.component.js +1 -0
- package/dist/Integration/components/overview/overview.component.js.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.d.ts.map +1 -1
- package/dist/Integration/components/pipelines/pipelines.component.js +1 -0
- package/dist/Integration/components/pipelines/pipelines.component.js.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.d.ts.map +1 -1
- package/dist/Integration/components/schedules/schedules.component.js +1 -0
- package/dist/Integration/components/schedules/schedules.component.js.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts +411 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +4266 -0
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +35 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +186 -13
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +1 -0
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +188 -165
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts +75 -0
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js +601 -0
- package/dist/KnowledgeHub/components/scheduling/scheduling-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts +93 -12
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js +637 -107
- package/dist/KnowledgeHub/components/search/knowledge-search-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/index.d.ts +2 -0
- package/dist/KnowledgeHub/index.d.ts.map +1 -1
- package/dist/KnowledgeHub/index.js +2 -0
- package/dist/KnowledgeHub/index.js.map +1 -1
- package/dist/__tests__/analytics-resource.test.d.ts +2 -0
- package/dist/__tests__/analytics-resource.test.d.ts.map +1 -0
- package/dist/__tests__/analytics-resource.test.js +181 -0
- package/dist/__tests__/analytics-resource.test.js.map +1 -0
- package/dist/__tests__/scheduling.test.d.ts +2 -0
- package/dist/__tests__/scheduling.test.d.ts.map +1 -0
- package/dist/__tests__/scheduling.test.js +205 -0
- package/dist/__tests__/scheduling.test.js.map +1 -0
- package/dist/ai-dashboards.module.d.ts +18 -14
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +25 -5
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/dist/shared/entity-field-display.d.ts +44 -0
- package/dist/shared/entity-field-display.d.ts.map +1 -0
- package/dist/shared/entity-field-display.js +118 -0
- package/dist/shared/entity-field-display.js.map +1 -0
- package/package.json +47 -46
|
@@ -12,10 +12,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
12
12
|
* Supports triggering new detection runs with real-time progress via
|
|
13
13
|
* GraphQL subscriptions.
|
|
14
14
|
*/
|
|
15
|
-
import { Component, ChangeDetectorRef, Input, inject, ViewEncapsulation } from '@angular/core';
|
|
15
|
+
import { Component, ChangeDetectorRef, Input, inject, ViewEncapsulation, HostListener } from '@angular/core';
|
|
16
16
|
import { Subject } from 'rxjs';
|
|
17
17
|
import { debounceTime, takeUntil } from 'rxjs/operators';
|
|
18
|
-
import { CompositeKey, Metadata, RecordMergeRequest, RunView } from '@memberjunction/core';
|
|
18
|
+
import { CompositeKey, LogStatus, Metadata, RecordMergeRequest, RunView } from '@memberjunction/core';
|
|
19
19
|
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
20
20
|
import { KnowledgeHubMetadataEngine } from '@memberjunction/core-entities';
|
|
21
21
|
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
@@ -41,15 +41,15 @@ function DuplicateDetectionResourceComponent_For_12_Template(rf, ctx) { if (rf &
|
|
|
41
41
|
i0.ɵɵtextInterpolate2("", doc_r1.Name, " (", doc_r1.EntityName, ")");
|
|
42
42
|
} }
|
|
43
43
|
function DuplicateDetectionResourceComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
44
|
-
i0.ɵɵelement(0, "i",
|
|
44
|
+
i0.ɵɵelement(0, "i", 34);
|
|
45
45
|
i0.ɵɵtext(1, " Detecting... ");
|
|
46
46
|
} }
|
|
47
47
|
function DuplicateDetectionResourceComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
48
|
-
i0.ɵɵelement(0, "i",
|
|
48
|
+
i0.ɵɵelement(0, "i", 35);
|
|
49
49
|
i0.ɵɵtext(1, " Run Detection ");
|
|
50
50
|
} }
|
|
51
51
|
function DuplicateDetectionResourceComponent_Conditional_16_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
52
|
-
i0.ɵɵelementStart(0, "span",
|
|
52
|
+
i0.ɵɵelementStart(0, "span", 41);
|
|
53
53
|
i0.ɵɵtext(1);
|
|
54
54
|
i0.ɵɵelementEnd();
|
|
55
55
|
} if (rf & 2) {
|
|
@@ -58,17 +58,17 @@ function DuplicateDetectionResourceComponent_Conditional_16_Conditional_9_Templa
|
|
|
58
58
|
i0.ɵɵtextInterpolate(ctx_r1.DetectionCurrentItem);
|
|
59
59
|
} }
|
|
60
60
|
function DuplicateDetectionResourceComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
61
|
-
i0.ɵɵelementStart(0, "div", 11)(1, "div",
|
|
62
|
-
i0.ɵɵelement(3, "i",
|
|
61
|
+
i0.ɵɵelementStart(0, "div", 11)(1, "div", 36)(2, "span", 37);
|
|
62
|
+
i0.ɵɵelement(3, "i", 34);
|
|
63
63
|
i0.ɵɵtext(4);
|
|
64
64
|
i0.ɵɵelementEnd();
|
|
65
|
-
i0.ɵɵelementStart(5, "span",
|
|
65
|
+
i0.ɵɵelementStart(5, "span", 38);
|
|
66
66
|
i0.ɵɵtext(6);
|
|
67
67
|
i0.ɵɵelementEnd()();
|
|
68
|
-
i0.ɵɵelementStart(7, "div",
|
|
69
|
-
i0.ɵɵelement(8, "div",
|
|
68
|
+
i0.ɵɵelementStart(7, "div", 39);
|
|
69
|
+
i0.ɵɵelement(8, "div", 40);
|
|
70
70
|
i0.ɵɵelementEnd();
|
|
71
|
-
i0.ɵɵconditionalCreate(9, DuplicateDetectionResourceComponent_Conditional_16_Conditional_9_Template, 2, 1, "span",
|
|
71
|
+
i0.ɵɵconditionalCreate(9, DuplicateDetectionResourceComponent_Conditional_16_Conditional_9_Template, 2, 1, "span", 41);
|
|
72
72
|
i0.ɵɵelementEnd();
|
|
73
73
|
} if (rf & 2) {
|
|
74
74
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -83,28 +83,28 @@ function DuplicateDetectionResourceComponent_Conditional_16_Template(rf, ctx) {
|
|
|
83
83
|
} }
|
|
84
84
|
function DuplicateDetectionResourceComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
85
85
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
86
|
-
i0.ɵɵelementStart(0, "div", 12)(1, "div",
|
|
87
|
-
i0.ɵɵelement(3, "i",
|
|
86
|
+
i0.ɵɵelementStart(0, "div", 12)(1, "div", 42)(2, "label", 43);
|
|
87
|
+
i0.ɵɵelement(3, "i", 44);
|
|
88
88
|
i0.ɵɵtext(4, " Potential Match ");
|
|
89
|
-
i0.ɵɵelementStart(5, "span",
|
|
89
|
+
i0.ɵɵelementStart(5, "span", 45);
|
|
90
90
|
i0.ɵɵtext(6);
|
|
91
91
|
i0.ɵɵelementEnd()();
|
|
92
|
-
i0.ɵɵelementStart(7, "input",
|
|
92
|
+
i0.ɵɵelementStart(7, "input", 46);
|
|
93
93
|
i0.ɵɵlistener("input", function DuplicateDetectionResourceComponent_Conditional_17_Template_input_input_7_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnPotentialThresholdChanged($event.target.value / 100)); });
|
|
94
94
|
i0.ɵɵelementEnd();
|
|
95
|
-
i0.ɵɵelementStart(8, "span",
|
|
95
|
+
i0.ɵɵelementStart(8, "span", 47);
|
|
96
96
|
i0.ɵɵtext(9, "Score above which duplicates are flagged for review");
|
|
97
97
|
i0.ɵɵelementEnd()();
|
|
98
|
-
i0.ɵɵelementStart(10, "div",
|
|
99
|
-
i0.ɵɵelement(12, "i",
|
|
98
|
+
i0.ɵɵelementStart(10, "div", 42)(11, "label", 43);
|
|
99
|
+
i0.ɵɵelement(12, "i", 48);
|
|
100
100
|
i0.ɵɵtext(13, " Absolute Match ");
|
|
101
|
-
i0.ɵɵelementStart(14, "span",
|
|
101
|
+
i0.ɵɵelementStart(14, "span", 45);
|
|
102
102
|
i0.ɵɵtext(15);
|
|
103
103
|
i0.ɵɵelementEnd()();
|
|
104
|
-
i0.ɵɵelementStart(16, "input",
|
|
104
|
+
i0.ɵɵelementStart(16, "input", 46);
|
|
105
105
|
i0.ɵɵlistener("input", function DuplicateDetectionResourceComponent_Conditional_17_Template_input_input_16_listener($event) { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnAbsoluteThresholdChanged($event.target.value / 100)); });
|
|
106
106
|
i0.ɵɵelementEnd();
|
|
107
|
-
i0.ɵɵelementStart(17, "span",
|
|
107
|
+
i0.ɵɵelementStart(17, "span", 47);
|
|
108
108
|
i0.ɵɵtext(18, "Score above which duplicates are auto-confirmed");
|
|
109
109
|
i0.ɵɵelementEnd()()();
|
|
110
110
|
} if (rf & 2) {
|
|
@@ -135,32 +135,43 @@ function DuplicateDetectionResourceComponent_For_44_Template(rf, ctx) { if (rf &
|
|
|
135
135
|
} }
|
|
136
136
|
function DuplicateDetectionResourceComponent_Conditional_61_Template(rf, ctx) { if (rf & 1) {
|
|
137
137
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
138
|
-
i0.ɵɵelementStart(0, "button",
|
|
138
|
+
i0.ɵɵelementStart(0, "button", 49);
|
|
139
139
|
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_61_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ClearFilters()); });
|
|
140
|
-
i0.ɵɵelement(1, "i",
|
|
140
|
+
i0.ɵɵelement(1, "i", 50);
|
|
141
141
|
i0.ɵɵtext(2, " Clear Filters ");
|
|
142
142
|
i0.ɵɵelementEnd();
|
|
143
143
|
} }
|
|
144
144
|
function DuplicateDetectionResourceComponent_Conditional_62_Template(rf, ctx) { if (rf & 1) {
|
|
145
145
|
i0.ɵɵelementStart(0, "div", 28);
|
|
146
|
-
i0.ɵɵelement(1, "
|
|
146
|
+
i0.ɵɵelement(1, "i", 51);
|
|
147
|
+
i0.ɵɵtext(2, " Merging is not available for this entity. Detection results are read-only. ");
|
|
147
148
|
i0.ɵɵelementEnd();
|
|
148
149
|
} }
|
|
149
150
|
function DuplicateDetectionResourceComponent_Conditional_63_Template(rf, ctx) { if (rf & 1) {
|
|
150
151
|
i0.ɵɵelementStart(0, "div", 29);
|
|
151
|
-
i0.ɵɵelement(1, "
|
|
152
|
-
i0.ɵɵ
|
|
152
|
+
i0.ɵɵelement(1, "mj-loading", 52);
|
|
153
|
+
i0.ɵɵelementEnd();
|
|
154
|
+
} }
|
|
155
|
+
function DuplicateDetectionResourceComponent_Conditional_64_Template(rf, ctx) { if (rf & 1) {
|
|
156
|
+
i0.ɵɵelementStart(0, "div", 29);
|
|
157
|
+
i0.ɵɵelement(1, "mj-loading", 52);
|
|
158
|
+
i0.ɵɵelementEnd();
|
|
159
|
+
} }
|
|
160
|
+
function DuplicateDetectionResourceComponent_Conditional_65_Template(rf, ctx) { if (rf & 1) {
|
|
161
|
+
i0.ɵɵelementStart(0, "div", 30);
|
|
162
|
+
i0.ɵɵelement(1, "i", 53);
|
|
163
|
+
i0.ɵɵelementStart(2, "p", 54);
|
|
153
164
|
i0.ɵɵtext(3, "No duplicate detection results found.");
|
|
154
165
|
i0.ɵɵelementEnd();
|
|
155
|
-
i0.ɵɵelementStart(4, "p",
|
|
166
|
+
i0.ɵɵelementStart(4, "p", 55);
|
|
156
167
|
i0.ɵɵtext(5, "Select an entity document and click \"Run Detection\" to start.");
|
|
157
168
|
i0.ɵɵelementEnd()();
|
|
158
169
|
} }
|
|
159
|
-
function
|
|
160
|
-
i0.ɵɵelementStart(0, "div",
|
|
170
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_10_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
171
|
+
i0.ɵɵelementStart(0, "div", 86)(1, "span", 88);
|
|
161
172
|
i0.ɵɵtext(2);
|
|
162
173
|
i0.ɵɵelementEnd();
|
|
163
|
-
i0.ɵɵelementStart(3, "span",
|
|
174
|
+
i0.ɵɵelementStart(3, "span", 89);
|
|
164
175
|
i0.ɵɵtext(4);
|
|
165
176
|
i0.ɵɵelementEnd()();
|
|
166
177
|
} if (rf & 2) {
|
|
@@ -170,8 +181,8 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_10_Conditional_1
|
|
|
170
181
|
i0.ɵɵadvance(2);
|
|
171
182
|
i0.ɵɵtextInterpolate(ms_r9.Name);
|
|
172
183
|
} }
|
|
173
|
-
function
|
|
174
|
-
i0.ɵɵelementStart(0, "div",
|
|
184
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_10_Conditional_13_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
185
|
+
i0.ɵɵelementStart(0, "div", 87);
|
|
175
186
|
i0.ɵɵtext(1);
|
|
176
187
|
i0.ɵɵelementEnd();
|
|
177
188
|
} if (rf & 2) {
|
|
@@ -179,10 +190,10 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_10_Conditional_1
|
|
|
179
190
|
i0.ɵɵadvance();
|
|
180
191
|
i0.ɵɵtextInterpolate1("+", group_r8.MatchCount - group_r8.TopMatchSummaries.length, " more");
|
|
181
192
|
} }
|
|
182
|
-
function
|
|
183
|
-
i0.ɵɵelementStart(0, "div",
|
|
184
|
-
i0.ɵɵrepeaterCreate(1,
|
|
185
|
-
i0.ɵɵconditionalCreate(3,
|
|
193
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_10_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
194
|
+
i0.ɵɵelementStart(0, "div", 77);
|
|
195
|
+
i0.ɵɵrepeaterCreate(1, DuplicateDetectionResourceComponent_Conditional_66_For_10_Conditional_13_For_2_Template, 5, 2, "div", 86, _forTrack2);
|
|
196
|
+
i0.ɵɵconditionalCreate(3, DuplicateDetectionResourceComponent_Conditional_66_For_10_Conditional_13_Conditional_3_Template, 2, 1, "div", 87);
|
|
186
197
|
i0.ɵɵelementEnd();
|
|
187
198
|
} if (rf & 2) {
|
|
188
199
|
const group_r8 = i0.ɵɵnextContext().$implicit;
|
|
@@ -191,40 +202,40 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_10_Conditional_1
|
|
|
191
202
|
i0.ɵɵadvance(2);
|
|
192
203
|
i0.ɵɵconditional(group_r8.MatchCount > group_r8.TopMatchSummaries.length ? 3 : -1);
|
|
193
204
|
} }
|
|
194
|
-
function
|
|
205
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_10_Template(rf, ctx) { if (rf & 1) {
|
|
195
206
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
196
|
-
i0.ɵɵelementStart(0, "div",
|
|
197
|
-
i0.ɵɵlistener("dragstart", function
|
|
198
|
-
i0.ɵɵelementStart(1, "div",
|
|
207
|
+
i0.ɵɵelementStart(0, "div", 68);
|
|
208
|
+
i0.ɵɵlistener("dragstart", function DuplicateDetectionResourceComponent_Conditional_66_For_10_Template_div_dragstart_0_listener($event) { const group_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDragStart($event, group_r8)); })("dragend", function DuplicateDetectionResourceComponent_Conditional_66_For_10_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDragEnd()); })("click", function DuplicateDetectionResourceComponent_Conditional_66_For_10_Template_div_click_0_listener() { const group_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OpenComparison(group_r8)); });
|
|
209
|
+
i0.ɵɵelementStart(1, "div", 69)(2, "div", 70)(3, "div", 71);
|
|
199
210
|
i0.ɵɵelement(4, "i");
|
|
200
211
|
i0.ɵɵelementEnd();
|
|
201
|
-
i0.ɵɵelementStart(5, "div",
|
|
212
|
+
i0.ɵɵelementStart(5, "div", 72)(6, "div", 73);
|
|
202
213
|
i0.ɵɵtext(7);
|
|
203
214
|
i0.ɵɵelementEnd();
|
|
204
|
-
i0.ɵɵelementStart(8, "span",
|
|
215
|
+
i0.ɵɵelementStart(8, "span", 74);
|
|
205
216
|
i0.ɵɵtext(9);
|
|
206
217
|
i0.ɵɵelementEnd()()();
|
|
207
|
-
i0.ɵɵelementStart(10, "span",
|
|
218
|
+
i0.ɵɵelementStart(10, "span", 75);
|
|
208
219
|
i0.ɵɵtext(11);
|
|
209
220
|
i0.ɵɵelementEnd()();
|
|
210
|
-
i0.ɵɵelementStart(12, "div",
|
|
211
|
-
i0.ɵɵconditionalCreate(13,
|
|
212
|
-
i0.ɵɵelementStart(14, "div",
|
|
213
|
-
i0.ɵɵelement(16, "i",
|
|
221
|
+
i0.ɵɵelementStart(12, "div", 76);
|
|
222
|
+
i0.ɵɵconditionalCreate(13, DuplicateDetectionResourceComponent_Conditional_66_For_10_Conditional_13_Template, 4, 1, "div", 77);
|
|
223
|
+
i0.ɵɵelementStart(14, "div", 78)(15, "span", 79);
|
|
224
|
+
i0.ɵɵelement(16, "i", 80);
|
|
214
225
|
i0.ɵɵtext(17);
|
|
215
226
|
i0.ɵɵelementEnd();
|
|
216
|
-
i0.ɵɵelementStart(18, "span",
|
|
217
|
-
i0.ɵɵelement(19, "i",
|
|
227
|
+
i0.ɵɵelementStart(18, "span", 79);
|
|
228
|
+
i0.ɵɵelement(19, "i", 81);
|
|
218
229
|
i0.ɵɵtext(20);
|
|
219
230
|
i0.ɵɵelementEnd()()();
|
|
220
|
-
i0.ɵɵelementStart(21, "div",
|
|
221
|
-
i0.ɵɵlistener("click", function
|
|
222
|
-
i0.ɵɵelement(23, "i",
|
|
231
|
+
i0.ɵɵelementStart(21, "div", 82)(22, "button", 83);
|
|
232
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_66_For_10_Template_button_click_22_listener($event) { const group_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.ApproveMatch(group_r8); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
233
|
+
i0.ɵɵelement(23, "i", 84);
|
|
223
234
|
i0.ɵɵtext(24, " Approve ");
|
|
224
235
|
i0.ɵɵelementEnd();
|
|
225
|
-
i0.ɵɵelementStart(25, "button",
|
|
226
|
-
i0.ɵɵlistener("click", function
|
|
227
|
-
i0.ɵɵelement(26, "i",
|
|
236
|
+
i0.ɵɵelementStart(25, "button", 85);
|
|
237
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_66_For_10_Template_button_click_25_listener($event) { const group_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.RejectMatch(group_r8); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
238
|
+
i0.ɵɵelement(26, "i", 50);
|
|
228
239
|
i0.ɵɵtext(27, " Reject ");
|
|
229
240
|
i0.ɵɵelementEnd()()();
|
|
230
241
|
} if (rf & 2) {
|
|
@@ -253,18 +264,18 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_10_Template(rf,
|
|
|
253
264
|
i0.ɵɵadvance(3);
|
|
254
265
|
i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
|
|
255
266
|
} }
|
|
256
|
-
function
|
|
257
|
-
i0.ɵɵelementStart(0, "div",
|
|
258
|
-
i0.ɵɵelement(1, "i",
|
|
267
|
+
function DuplicateDetectionResourceComponent_Conditional_66_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
268
|
+
i0.ɵɵelementStart(0, "div", 63);
|
|
269
|
+
i0.ɵɵelement(1, "i", 65);
|
|
259
270
|
i0.ɵɵelementStart(2, "span");
|
|
260
271
|
i0.ɵɵtext(3, "No pending items");
|
|
261
272
|
i0.ɵɵelementEnd()();
|
|
262
273
|
} }
|
|
263
|
-
function
|
|
264
|
-
i0.ɵɵelementStart(0, "div",
|
|
274
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_21_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
275
|
+
i0.ɵɵelementStart(0, "div", 86)(1, "span", 88);
|
|
265
276
|
i0.ɵɵtext(2);
|
|
266
277
|
i0.ɵɵelementEnd();
|
|
267
|
-
i0.ɵɵelementStart(3, "span",
|
|
278
|
+
i0.ɵɵelementStart(3, "span", 89);
|
|
268
279
|
i0.ɵɵtext(4);
|
|
269
280
|
i0.ɵɵelementEnd()();
|
|
270
281
|
} if (rf & 2) {
|
|
@@ -274,8 +285,8 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_21_Conditional_1
|
|
|
274
285
|
i0.ɵɵadvance(2);
|
|
275
286
|
i0.ɵɵtextInterpolate(ms_r12.Name);
|
|
276
287
|
} }
|
|
277
|
-
function
|
|
278
|
-
i0.ɵɵelementStart(0, "div",
|
|
288
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_21_Conditional_13_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
289
|
+
i0.ɵɵelementStart(0, "div", 87);
|
|
279
290
|
i0.ɵɵtext(1);
|
|
280
291
|
i0.ɵɵelementEnd();
|
|
281
292
|
} if (rf & 2) {
|
|
@@ -283,10 +294,10 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_21_Conditional_1
|
|
|
283
294
|
i0.ɵɵadvance();
|
|
284
295
|
i0.ɵɵtextInterpolate1("+", group_r11.MatchCount - group_r11.TopMatchSummaries.length, " more");
|
|
285
296
|
} }
|
|
286
|
-
function
|
|
287
|
-
i0.ɵɵelementStart(0, "div",
|
|
288
|
-
i0.ɵɵrepeaterCreate(1,
|
|
289
|
-
i0.ɵɵconditionalCreate(3,
|
|
297
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_21_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
298
|
+
i0.ɵɵelementStart(0, "div", 77);
|
|
299
|
+
i0.ɵɵrepeaterCreate(1, DuplicateDetectionResourceComponent_Conditional_66_For_21_Conditional_13_For_2_Template, 5, 2, "div", 86, _forTrack2);
|
|
300
|
+
i0.ɵɵconditionalCreate(3, DuplicateDetectionResourceComponent_Conditional_66_For_21_Conditional_13_Conditional_3_Template, 2, 1, "div", 87);
|
|
290
301
|
i0.ɵɵelementEnd();
|
|
291
302
|
} if (rf & 2) {
|
|
292
303
|
const group_r11 = i0.ɵɵnextContext().$implicit;
|
|
@@ -295,30 +306,30 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_21_Conditional_1
|
|
|
295
306
|
i0.ɵɵadvance(2);
|
|
296
307
|
i0.ɵɵconditional(group_r11.MatchCount > group_r11.TopMatchSummaries.length ? 3 : -1);
|
|
297
308
|
} }
|
|
298
|
-
function
|
|
309
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_21_Template(rf, ctx) { if (rf & 1) {
|
|
299
310
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
300
|
-
i0.ɵɵelementStart(0, "div",
|
|
301
|
-
i0.ɵɵlistener("dragstart", function
|
|
302
|
-
i0.ɵɵelementStart(1, "div",
|
|
311
|
+
i0.ɵɵelementStart(0, "div", 68);
|
|
312
|
+
i0.ɵɵlistener("dragstart", function DuplicateDetectionResourceComponent_Conditional_66_For_21_Template_div_dragstart_0_listener($event) { const group_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDragStart($event, group_r11)); })("dragend", function DuplicateDetectionResourceComponent_Conditional_66_For_21_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDragEnd()); })("click", function DuplicateDetectionResourceComponent_Conditional_66_For_21_Template_div_click_0_listener() { const group_r11 = i0.ɵɵrestoreView(_r10).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OpenComparison(group_r11)); });
|
|
313
|
+
i0.ɵɵelementStart(1, "div", 69)(2, "div", 70)(3, "div", 71);
|
|
303
314
|
i0.ɵɵelement(4, "i");
|
|
304
315
|
i0.ɵɵelementEnd();
|
|
305
|
-
i0.ɵɵelementStart(5, "div",
|
|
316
|
+
i0.ɵɵelementStart(5, "div", 72)(6, "div", 73);
|
|
306
317
|
i0.ɵɵtext(7);
|
|
307
318
|
i0.ɵɵelementEnd();
|
|
308
|
-
i0.ɵɵelementStart(8, "span",
|
|
319
|
+
i0.ɵɵelementStart(8, "span", 74);
|
|
309
320
|
i0.ɵɵtext(9);
|
|
310
321
|
i0.ɵɵelementEnd()()();
|
|
311
|
-
i0.ɵɵelementStart(10, "span",
|
|
322
|
+
i0.ɵɵelementStart(10, "span", 75);
|
|
312
323
|
i0.ɵɵtext(11);
|
|
313
324
|
i0.ɵɵelementEnd()();
|
|
314
|
-
i0.ɵɵelementStart(12, "div",
|
|
315
|
-
i0.ɵɵconditionalCreate(13,
|
|
316
|
-
i0.ɵɵelementStart(14, "div",
|
|
317
|
-
i0.ɵɵelement(16, "i",
|
|
325
|
+
i0.ɵɵelementStart(12, "div", 76);
|
|
326
|
+
i0.ɵɵconditionalCreate(13, DuplicateDetectionResourceComponent_Conditional_66_For_21_Conditional_13_Template, 4, 1, "div", 77);
|
|
327
|
+
i0.ɵɵelementStart(14, "div", 78)(15, "span", 79);
|
|
328
|
+
i0.ɵɵelement(16, "i", 80);
|
|
318
329
|
i0.ɵɵtext(17);
|
|
319
330
|
i0.ɵɵelementEnd();
|
|
320
|
-
i0.ɵɵelementStart(18, "span",
|
|
321
|
-
i0.ɵɵelement(19, "i",
|
|
331
|
+
i0.ɵɵelementStart(18, "span", 79);
|
|
332
|
+
i0.ɵɵelement(19, "i", 81);
|
|
322
333
|
i0.ɵɵtext(20);
|
|
323
334
|
i0.ɵɵelementEnd()()()();
|
|
324
335
|
} if (rf & 2) {
|
|
@@ -343,18 +354,18 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_21_Template(rf,
|
|
|
343
354
|
i0.ɵɵadvance(3);
|
|
344
355
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.FormatDate(group_r11.MatchedAt), " ");
|
|
345
356
|
} }
|
|
346
|
-
function
|
|
347
|
-
i0.ɵɵelementStart(0, "div",
|
|
348
|
-
i0.ɵɵelement(1, "i",
|
|
357
|
+
function DuplicateDetectionResourceComponent_Conditional_66_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
358
|
+
i0.ɵɵelementStart(0, "div", 63);
|
|
359
|
+
i0.ɵɵelement(1, "i", 90);
|
|
349
360
|
i0.ɵɵelementStart(2, "span");
|
|
350
361
|
i0.ɵɵtext(3, "No approved items");
|
|
351
362
|
i0.ɵɵelementEnd()();
|
|
352
363
|
} }
|
|
353
|
-
function
|
|
354
|
-
i0.ɵɵelementStart(0, "div",
|
|
364
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_32_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
365
|
+
i0.ɵɵelementStart(0, "div", 86)(1, "span", 88);
|
|
355
366
|
i0.ɵɵtext(2);
|
|
356
367
|
i0.ɵɵelementEnd();
|
|
357
|
-
i0.ɵɵelementStart(3, "span",
|
|
368
|
+
i0.ɵɵelementStart(3, "span", 89);
|
|
358
369
|
i0.ɵɵtext(4);
|
|
359
370
|
i0.ɵɵelementEnd()();
|
|
360
371
|
} if (rf & 2) {
|
|
@@ -364,8 +375,8 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_32_Conditional_1
|
|
|
364
375
|
i0.ɵɵadvance(2);
|
|
365
376
|
i0.ɵɵtextInterpolate(ms_r15.Name);
|
|
366
377
|
} }
|
|
367
|
-
function
|
|
368
|
-
i0.ɵɵelementStart(0, "div",
|
|
378
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_32_Conditional_13_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
379
|
+
i0.ɵɵelementStart(0, "div", 87);
|
|
369
380
|
i0.ɵɵtext(1);
|
|
370
381
|
i0.ɵɵelementEnd();
|
|
371
382
|
} if (rf & 2) {
|
|
@@ -373,10 +384,10 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_32_Conditional_1
|
|
|
373
384
|
i0.ɵɵadvance();
|
|
374
385
|
i0.ɵɵtextInterpolate1("+", group_r14.MatchCount - group_r14.TopMatchSummaries.length, " more");
|
|
375
386
|
} }
|
|
376
|
-
function
|
|
377
|
-
i0.ɵɵelementStart(0, "div",
|
|
378
|
-
i0.ɵɵrepeaterCreate(1,
|
|
379
|
-
i0.ɵɵconditionalCreate(3,
|
|
387
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_32_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
388
|
+
i0.ɵɵelementStart(0, "div", 77);
|
|
389
|
+
i0.ɵɵrepeaterCreate(1, DuplicateDetectionResourceComponent_Conditional_66_For_32_Conditional_13_For_2_Template, 5, 2, "div", 86, _forTrack2);
|
|
390
|
+
i0.ɵɵconditionalCreate(3, DuplicateDetectionResourceComponent_Conditional_66_For_32_Conditional_13_Conditional_3_Template, 2, 1, "div", 87);
|
|
380
391
|
i0.ɵɵelementEnd();
|
|
381
392
|
} if (rf & 2) {
|
|
382
393
|
const group_r14 = i0.ɵɵnextContext().$implicit;
|
|
@@ -385,30 +396,30 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_32_Conditional_1
|
|
|
385
396
|
i0.ɵɵadvance(2);
|
|
386
397
|
i0.ɵɵconditional(group_r14.MatchCount > group_r14.TopMatchSummaries.length ? 3 : -1);
|
|
387
398
|
} }
|
|
388
|
-
function
|
|
399
|
+
function DuplicateDetectionResourceComponent_Conditional_66_For_32_Template(rf, ctx) { if (rf & 1) {
|
|
389
400
|
const _r13 = i0.ɵɵgetCurrentView();
|
|
390
|
-
i0.ɵɵelementStart(0, "div",
|
|
391
|
-
i0.ɵɵlistener("dragstart", function
|
|
392
|
-
i0.ɵɵelementStart(1, "div",
|
|
401
|
+
i0.ɵɵelementStart(0, "div", 68);
|
|
402
|
+
i0.ɵɵlistener("dragstart", function DuplicateDetectionResourceComponent_Conditional_66_For_32_Template_div_dragstart_0_listener($event) { const group_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDragStart($event, group_r14)); })("dragend", function DuplicateDetectionResourceComponent_Conditional_66_For_32_Template_div_dragend_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDragEnd()); })("click", function DuplicateDetectionResourceComponent_Conditional_66_For_32_Template_div_click_0_listener() { const group_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OpenComparison(group_r14)); });
|
|
403
|
+
i0.ɵɵelementStart(1, "div", 69)(2, "div", 70)(3, "div", 71);
|
|
393
404
|
i0.ɵɵelement(4, "i");
|
|
394
405
|
i0.ɵɵelementEnd();
|
|
395
|
-
i0.ɵɵelementStart(5, "div",
|
|
406
|
+
i0.ɵɵelementStart(5, "div", 72)(6, "div", 73);
|
|
396
407
|
i0.ɵɵtext(7);
|
|
397
408
|
i0.ɵɵelementEnd();
|
|
398
|
-
i0.ɵɵelementStart(8, "span",
|
|
409
|
+
i0.ɵɵelementStart(8, "span", 74);
|
|
399
410
|
i0.ɵɵtext(9);
|
|
400
411
|
i0.ɵɵelementEnd()()();
|
|
401
|
-
i0.ɵɵelementStart(10, "span",
|
|
412
|
+
i0.ɵɵelementStart(10, "span", 75);
|
|
402
413
|
i0.ɵɵtext(11);
|
|
403
414
|
i0.ɵɵelementEnd()();
|
|
404
|
-
i0.ɵɵelementStart(12, "div",
|
|
405
|
-
i0.ɵɵconditionalCreate(13,
|
|
406
|
-
i0.ɵɵelementStart(14, "div",
|
|
407
|
-
i0.ɵɵelement(16, "i",
|
|
415
|
+
i0.ɵɵelementStart(12, "div", 76);
|
|
416
|
+
i0.ɵɵconditionalCreate(13, DuplicateDetectionResourceComponent_Conditional_66_For_32_Conditional_13_Template, 4, 1, "div", 77);
|
|
417
|
+
i0.ɵɵelementStart(14, "div", 78)(15, "span", 79);
|
|
418
|
+
i0.ɵɵelement(16, "i", 80);
|
|
408
419
|
i0.ɵɵtext(17);
|
|
409
420
|
i0.ɵɵelementEnd();
|
|
410
|
-
i0.ɵɵelementStart(18, "span",
|
|
411
|
-
i0.ɵɵelement(19, "i",
|
|
421
|
+
i0.ɵɵelementStart(18, "span", 79);
|
|
422
|
+
i0.ɵɵelement(19, "i", 81);
|
|
412
423
|
i0.ɵɵtext(20);
|
|
413
424
|
i0.ɵɵelementEnd()()()();
|
|
414
425
|
} if (rf & 2) {
|
|
@@ -433,53 +444,53 @@ function DuplicateDetectionResourceComponent_Conditional_64_For_32_Template(rf,
|
|
|
433
444
|
i0.ɵɵadvance(3);
|
|
434
445
|
i0.ɵɵtextInterpolate1(" ", ctx_r1.FormatDate(group_r14.MatchedAt), " ");
|
|
435
446
|
} }
|
|
436
|
-
function
|
|
437
|
-
i0.ɵɵelementStart(0, "div",
|
|
438
|
-
i0.ɵɵelement(1, "i",
|
|
447
|
+
function DuplicateDetectionResourceComponent_Conditional_66_Conditional_33_Template(rf, ctx) { if (rf & 1) {
|
|
448
|
+
i0.ɵɵelementStart(0, "div", 63);
|
|
449
|
+
i0.ɵɵelement(1, "i", 90);
|
|
439
450
|
i0.ɵɵelementStart(2, "span");
|
|
440
451
|
i0.ɵɵtext(3, "No rejected items");
|
|
441
452
|
i0.ɵɵelementEnd()();
|
|
442
453
|
} }
|
|
443
|
-
function
|
|
454
|
+
function DuplicateDetectionResourceComponent_Conditional_66_Template(rf, ctx) { if (rf & 1) {
|
|
444
455
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
445
|
-
i0.ɵɵelementStart(0, "div",
|
|
446
|
-
i0.ɵɵelement(3, "i",
|
|
447
|
-
i0.ɵɵelementStart(4, "span",
|
|
456
|
+
i0.ɵɵelementStart(0, "div", 31)(1, "div", 56)(2, "div", 57);
|
|
457
|
+
i0.ɵɵelement(3, "i", 58);
|
|
458
|
+
i0.ɵɵelementStart(4, "span", 59);
|
|
448
459
|
i0.ɵɵtext(5, "Pending Review");
|
|
449
460
|
i0.ɵɵelementEnd();
|
|
450
|
-
i0.ɵɵelementStart(6, "span",
|
|
461
|
+
i0.ɵɵelementStart(6, "span", 60);
|
|
451
462
|
i0.ɵɵtext(7);
|
|
452
463
|
i0.ɵɵelementEnd()();
|
|
453
|
-
i0.ɵɵelementStart(8, "div",
|
|
454
|
-
i0.ɵɵlistener("dragover", function
|
|
455
|
-
i0.ɵɵrepeaterCreate(9,
|
|
456
|
-
i0.ɵɵconditionalCreate(11,
|
|
464
|
+
i0.ɵɵelementStart(8, "div", 61);
|
|
465
|
+
i0.ɵɵlistener("dragover", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_dragover_8_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragOver($event, "Pending")); })("dragleave", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_dragleave_8_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragLeave($event, "Pending")); })("drop", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_drop_8_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDrop($event, "Pending")); });
|
|
466
|
+
i0.ɵɵrepeaterCreate(9, DuplicateDetectionResourceComponent_Conditional_66_For_10_Template, 28, 14, "div", 62, _forTrack1);
|
|
467
|
+
i0.ɵɵconditionalCreate(11, DuplicateDetectionResourceComponent_Conditional_66_Conditional_11_Template, 4, 0, "div", 63);
|
|
457
468
|
i0.ɵɵelementEnd()();
|
|
458
|
-
i0.ɵɵelementStart(12, "div",
|
|
459
|
-
i0.ɵɵelement(14, "i",
|
|
460
|
-
i0.ɵɵelementStart(15, "span",
|
|
469
|
+
i0.ɵɵelementStart(12, "div", 56)(13, "div", 64);
|
|
470
|
+
i0.ɵɵelement(14, "i", 65);
|
|
471
|
+
i0.ɵɵelementStart(15, "span", 59);
|
|
461
472
|
i0.ɵɵtext(16, "Approved");
|
|
462
473
|
i0.ɵɵelementEnd();
|
|
463
|
-
i0.ɵɵelementStart(17, "span",
|
|
474
|
+
i0.ɵɵelementStart(17, "span", 60);
|
|
464
475
|
i0.ɵɵtext(18);
|
|
465
476
|
i0.ɵɵelementEnd()();
|
|
466
|
-
i0.ɵɵelementStart(19, "div",
|
|
467
|
-
i0.ɵɵlistener("dragover", function
|
|
468
|
-
i0.ɵɵrepeaterCreate(20,
|
|
469
|
-
i0.ɵɵconditionalCreate(22,
|
|
477
|
+
i0.ɵɵelementStart(19, "div", 61);
|
|
478
|
+
i0.ɵɵlistener("dragover", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_dragover_19_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragOver($event, "Approved")); })("dragleave", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_dragleave_19_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragLeave($event, "Approved")); })("drop", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_drop_19_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDrop($event, "Approved")); });
|
|
479
|
+
i0.ɵɵrepeaterCreate(20, DuplicateDetectionResourceComponent_Conditional_66_For_21_Template, 21, 12, "div", 62, _forTrack1);
|
|
480
|
+
i0.ɵɵconditionalCreate(22, DuplicateDetectionResourceComponent_Conditional_66_Conditional_22_Template, 4, 0, "div", 63);
|
|
470
481
|
i0.ɵɵelementEnd()();
|
|
471
|
-
i0.ɵɵelementStart(23, "div",
|
|
472
|
-
i0.ɵɵelement(25, "i",
|
|
473
|
-
i0.ɵɵelementStart(26, "span",
|
|
482
|
+
i0.ɵɵelementStart(23, "div", 56)(24, "div", 66);
|
|
483
|
+
i0.ɵɵelement(25, "i", 67);
|
|
484
|
+
i0.ɵɵelementStart(26, "span", 59);
|
|
474
485
|
i0.ɵɵtext(27, "Rejected");
|
|
475
486
|
i0.ɵɵelementEnd();
|
|
476
|
-
i0.ɵɵelementStart(28, "span",
|
|
487
|
+
i0.ɵɵelementStart(28, "span", 60);
|
|
477
488
|
i0.ɵɵtext(29);
|
|
478
489
|
i0.ɵɵelementEnd()();
|
|
479
|
-
i0.ɵɵelementStart(30, "div",
|
|
480
|
-
i0.ɵɵlistener("dragover", function
|
|
481
|
-
i0.ɵɵrepeaterCreate(31,
|
|
482
|
-
i0.ɵɵconditionalCreate(33,
|
|
490
|
+
i0.ɵɵelementStart(30, "div", 61);
|
|
491
|
+
i0.ɵɵlistener("dragover", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_dragover_30_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragOver($event, "Rejected")); })("dragleave", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_dragleave_30_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDragLeave($event, "Rejected")); })("drop", function DuplicateDetectionResourceComponent_Conditional_66_Template_div_drop_30_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnDrop($event, "Rejected")); });
|
|
492
|
+
i0.ɵɵrepeaterCreate(31, DuplicateDetectionResourceComponent_Conditional_66_For_32_Template, 21, 12, "div", 62, _forTrack1);
|
|
493
|
+
i0.ɵɵconditionalCreate(33, DuplicateDetectionResourceComponent_Conditional_66_Conditional_33_Template, 4, 0, "div", 63);
|
|
483
494
|
i0.ɵɵelementEnd()()();
|
|
484
495
|
} if (rf & 2) {
|
|
485
496
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -508,34 +519,34 @@ function DuplicateDetectionResourceComponent_Conditional_64_Template(rf, ctx) {
|
|
|
508
519
|
i0.ɵɵadvance(2);
|
|
509
520
|
i0.ɵɵconditional(ctx_r1.RejectedGroups.length === 0 ? 33 : -1);
|
|
510
521
|
} }
|
|
511
|
-
function
|
|
512
|
-
i0.ɵɵelementStart(0, "div",
|
|
513
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
522
|
+
function DuplicateDetectionResourceComponent_Conditional_67_Template(rf, ctx) { if (rf & 1) {
|
|
523
|
+
i0.ɵɵelementStart(0, "div", 32);
|
|
524
|
+
i0.ɵɵelement(1, "mj-loading", 91);
|
|
514
525
|
i0.ɵɵelementEnd();
|
|
515
526
|
} }
|
|
516
|
-
function
|
|
517
|
-
i0.ɵɵelementStart(0, "div",
|
|
518
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
527
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
528
|
+
i0.ɵɵelementStart(0, "div", 104);
|
|
529
|
+
i0.ɵɵelement(1, "mj-loading", 130);
|
|
519
530
|
i0.ɵɵelementEnd();
|
|
520
531
|
} }
|
|
521
|
-
function
|
|
522
|
-
i0.ɵɵelementStart(0, "span",
|
|
523
|
-
i0.ɵɵelement(1, "i",
|
|
532
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_44_Template(rf, ctx) { if (rf & 1) {
|
|
533
|
+
i0.ɵɵelementStart(0, "span", 120);
|
|
534
|
+
i0.ɵɵelement(1, "i", 131);
|
|
524
535
|
i0.ɵɵtext(2, " Most deps");
|
|
525
536
|
i0.ɵɵelementEnd();
|
|
526
537
|
} }
|
|
527
|
-
function
|
|
528
|
-
i0.ɵɵelementStart(0, "div",
|
|
529
|
-
i0.ɵɵelement(1, "i",
|
|
538
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
539
|
+
i0.ɵɵelementStart(0, "div", 140);
|
|
540
|
+
i0.ɵɵelement(1, "i", 34);
|
|
530
541
|
i0.ɵɵtext(2, " Loading...");
|
|
531
542
|
i0.ɵɵelementEnd();
|
|
532
543
|
} }
|
|
533
|
-
function
|
|
544
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Conditional_7_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
534
545
|
const _r20 = i0.ɵɵgetCurrentView();
|
|
535
|
-
i0.ɵɵelementStart(0, "div",
|
|
536
|
-
i0.ɵɵlistener("click", function
|
|
537
|
-
i0.ɵɵelement(1, "i",
|
|
538
|
-
i0.ɵɵelementStart(2, "span",
|
|
546
|
+
i0.ɵɵelementStart(0, "div", 142);
|
|
547
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Conditional_7_For_3_Template_div_click_0_listener($event) { const record_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(6); ctx_r1.OpenDepRecord(record_r21); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
548
|
+
i0.ɵɵelement(1, "i", 143);
|
|
549
|
+
i0.ɵɵelementStart(2, "span", 144);
|
|
539
550
|
i0.ɵɵtext(3);
|
|
540
551
|
i0.ɵɵelementEnd()();
|
|
541
552
|
} if (rf & 2) {
|
|
@@ -543,10 +554,10 @@ function DuplicateDetectionResourceComponent_Conditional_66_Conditional_45_Condi
|
|
|
543
554
|
i0.ɵɵadvance(3);
|
|
544
555
|
i0.ɵɵtextInterpolate(record_r21.Name);
|
|
545
556
|
} }
|
|
546
|
-
function
|
|
547
|
-
i0.ɵɵelementStart(0, "div",
|
|
548
|
-
i0.ɵɵconditionalCreate(1,
|
|
549
|
-
i0.ɵɵrepeaterCreate(2,
|
|
557
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
558
|
+
i0.ɵɵelementStart(0, "div", 139);
|
|
559
|
+
i0.ɵɵconditionalCreate(1, DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Conditional_7_Conditional_1_Template, 3, 0, "div", 140);
|
|
560
|
+
i0.ɵɵrepeaterCreate(2, DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Conditional_7_For_3_Template, 4, 1, "div", 141, i0.ɵɵrepeaterTrackByIndex);
|
|
550
561
|
i0.ɵɵelementEnd();
|
|
551
562
|
} if (rf & 2) {
|
|
552
563
|
const dep_r19 = i0.ɵɵnextContext().$implicit;
|
|
@@ -556,18 +567,18 @@ function DuplicateDetectionResourceComponent_Conditional_66_Conditional_45_Condi
|
|
|
556
567
|
i0.ɵɵadvance();
|
|
557
568
|
i0.ɵɵrepeater(ctx_r1.GetDepRecords(0, dep_r19.Entity));
|
|
558
569
|
} }
|
|
559
|
-
function
|
|
570
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
560
571
|
const _r18 = i0.ɵɵgetCurrentView();
|
|
561
|
-
i0.ɵɵelementStart(0, "div",
|
|
562
|
-
i0.ɵɵlistener("click", function
|
|
563
|
-
i0.ɵɵelementStart(2, "span",
|
|
564
|
-
i0.ɵɵelement(3, "i",
|
|
572
|
+
i0.ɵɵelementStart(0, "div", 134)(1, "div", 135);
|
|
573
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Template_div_click_1_listener($event) { const dep_r19 = i0.ɵɵrestoreView(_r18).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); ctx_r1.ToggleDepEntityGroup(0, dep_r19.Entity); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
574
|
+
i0.ɵɵelementStart(2, "span", 136);
|
|
575
|
+
i0.ɵɵelement(3, "i", 137);
|
|
565
576
|
i0.ɵɵtext(4);
|
|
566
577
|
i0.ɵɵelementEnd();
|
|
567
|
-
i0.ɵɵelementStart(5, "span",
|
|
578
|
+
i0.ɵɵelementStart(5, "span", 138);
|
|
568
579
|
i0.ɵɵtext(6);
|
|
569
580
|
i0.ɵɵelementEnd()();
|
|
570
|
-
i0.ɵɵconditionalCreate(7,
|
|
581
|
+
i0.ɵɵconditionalCreate(7, DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Conditional_7_Template, 4, 1, "div", 139);
|
|
571
582
|
i0.ɵɵelementEnd();
|
|
572
583
|
} if (rf & 2) {
|
|
573
584
|
const dep_r19 = ctx.$implicit;
|
|
@@ -581,25 +592,25 @@ function DuplicateDetectionResourceComponent_Conditional_66_Conditional_45_Condi
|
|
|
581
592
|
i0.ɵɵadvance();
|
|
582
593
|
i0.ɵɵconditional(ctx_r1.IsDepEntityGroupExpanded(0, dep_r19.Entity) ? 7 : -1);
|
|
583
594
|
} }
|
|
584
|
-
function
|
|
585
|
-
i0.ɵɵelementStart(0, "div",
|
|
586
|
-
i0.ɵɵrepeaterCreate(1,
|
|
595
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
596
|
+
i0.ɵɵelementStart(0, "div", 133);
|
|
597
|
+
i0.ɵɵrepeaterCreate(1, DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_For_2_Template, 8, 7, "div", 134, _forTrack5);
|
|
587
598
|
i0.ɵɵelementEnd();
|
|
588
599
|
} if (rf & 2) {
|
|
589
600
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
590
601
|
i0.ɵɵadvance();
|
|
591
602
|
i0.ɵɵrepeater(ctx_r1.GetGroupedDeps(0));
|
|
592
603
|
} }
|
|
593
|
-
function
|
|
604
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Template(rf, ctx) { if (rf & 1) {
|
|
594
605
|
const _r17 = i0.ɵɵgetCurrentView();
|
|
595
|
-
i0.ɵɵelementStart(0, "div",
|
|
596
|
-
i0.ɵɵlistener("click", function
|
|
606
|
+
i0.ɵɵelementStart(0, "div", 132);
|
|
607
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleDepsExpanded(0)); });
|
|
597
608
|
i0.ɵɵelementStart(1, "span");
|
|
598
609
|
i0.ɵɵtext(2);
|
|
599
610
|
i0.ɵɵelementEnd();
|
|
600
|
-
i0.ɵɵelement(3, "i",
|
|
611
|
+
i0.ɵɵelement(3, "i", 115);
|
|
601
612
|
i0.ɵɵelementEnd();
|
|
602
|
-
i0.ɵɵconditionalCreate(4,
|
|
613
|
+
i0.ɵɵconditionalCreate(4, DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Conditional_4_Template, 3, 0, "div", 133);
|
|
603
614
|
} if (rf & 2) {
|
|
604
615
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
605
616
|
i0.ɵɵadvance(2);
|
|
@@ -609,24 +620,24 @@ function DuplicateDetectionResourceComponent_Conditional_66_Conditional_45_Templ
|
|
|
609
620
|
i0.ɵɵadvance();
|
|
610
621
|
i0.ɵɵconditional(ctx_r1.IsDepsExpanded(0) ? 4 : -1);
|
|
611
622
|
} }
|
|
612
|
-
function
|
|
613
|
-
i0.ɵɵelementStart(0, "span",
|
|
614
|
-
i0.ɵɵelement(1, "i",
|
|
623
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
624
|
+
i0.ɵɵelementStart(0, "span", 120);
|
|
625
|
+
i0.ɵɵelement(1, "i", 131);
|
|
615
626
|
i0.ɵɵtext(2, " Most deps");
|
|
616
627
|
i0.ɵɵelementEnd();
|
|
617
628
|
} }
|
|
618
|
-
function
|
|
619
|
-
i0.ɵɵelementStart(0, "div",
|
|
620
|
-
i0.ɵɵelement(1, "i",
|
|
629
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
630
|
+
i0.ɵɵelementStart(0, "div", 140);
|
|
631
|
+
i0.ɵɵelement(1, "i", 34);
|
|
621
632
|
i0.ɵɵtext(2, " Loading...");
|
|
622
633
|
i0.ɵɵelementEnd();
|
|
623
634
|
} }
|
|
624
|
-
function
|
|
635
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Conditional_7_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
625
636
|
const _r27 = i0.ɵɵgetCurrentView();
|
|
626
|
-
i0.ɵɵelementStart(0, "div",
|
|
627
|
-
i0.ɵɵlistener("click", function
|
|
628
|
-
i0.ɵɵelement(1, "i",
|
|
629
|
-
i0.ɵɵelementStart(2, "span",
|
|
637
|
+
i0.ɵɵelementStart(0, "div", 142);
|
|
638
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Conditional_7_For_3_Template_div_click_0_listener($event) { const record_r28 = i0.ɵɵrestoreView(_r27).$implicit; const ctx_r1 = i0.ɵɵnextContext(7); ctx_r1.OpenDepRecord(record_r28); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
639
|
+
i0.ɵɵelement(1, "i", 143);
|
|
640
|
+
i0.ɵɵelementStart(2, "span", 144);
|
|
630
641
|
i0.ɵɵtext(3);
|
|
631
642
|
i0.ɵɵelementEnd()();
|
|
632
643
|
} if (rf & 2) {
|
|
@@ -634,341 +645,369 @@ function DuplicateDetectionResourceComponent_Conditional_66_For_47_Conditional_2
|
|
|
634
645
|
i0.ɵɵadvance(3);
|
|
635
646
|
i0.ɵɵtextInterpolate(record_r28.Name);
|
|
636
647
|
} }
|
|
637
|
-
function
|
|
638
|
-
i0.ɵɵelementStart(0, "div",
|
|
639
|
-
i0.ɵɵconditionalCreate(1,
|
|
640
|
-
i0.ɵɵrepeaterCreate(2,
|
|
648
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
649
|
+
i0.ɵɵelementStart(0, "div", 139);
|
|
650
|
+
i0.ɵɵconditionalCreate(1, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Conditional_7_Conditional_1_Template, 3, 0, "div", 140);
|
|
651
|
+
i0.ɵɵrepeaterCreate(2, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Conditional_7_For_3_Template, 4, 1, "div", 141, i0.ɵɵrepeaterTrackByIndex);
|
|
641
652
|
i0.ɵɵelementEnd();
|
|
642
653
|
} if (rf & 2) {
|
|
643
654
|
const dep_r26 = i0.ɵɵnextContext().$implicit;
|
|
644
|
-
const ɵ$
|
|
655
|
+
const ɵ$index_567_r23 = i0.ɵɵnextContext(3).$index;
|
|
645
656
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
646
657
|
i0.ɵɵadvance();
|
|
647
|
-
i0.ɵɵconditional(ctx_r1.IsDepRecordsLoading(ɵ$
|
|
658
|
+
i0.ɵɵconditional(ctx_r1.IsDepRecordsLoading(ɵ$index_567_r23 + 1, dep_r26.Entity) ? 1 : -1);
|
|
648
659
|
i0.ɵɵadvance();
|
|
649
|
-
i0.ɵɵrepeater(ctx_r1.GetDepRecords(ɵ$
|
|
660
|
+
i0.ɵɵrepeater(ctx_r1.GetDepRecords(ɵ$index_567_r23 + 1, dep_r26.Entity));
|
|
650
661
|
} }
|
|
651
|
-
function
|
|
662
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
652
663
|
const _r25 = i0.ɵɵgetCurrentView();
|
|
653
|
-
i0.ɵɵelementStart(0, "div",
|
|
654
|
-
i0.ɵɵlistener("click", function
|
|
655
|
-
i0.ɵɵelementStart(2, "span",
|
|
656
|
-
i0.ɵɵelement(3, "i",
|
|
664
|
+
i0.ɵɵelementStart(0, "div", 134)(1, "div", 135);
|
|
665
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Template_div_click_1_listener($event) { const dep_r26 = i0.ɵɵrestoreView(_r25).$implicit; const ɵ$index_567_r23 = i0.ɵɵnextContext(3).$index; const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.ToggleDepEntityGroup(ɵ$index_567_r23 + 1, dep_r26.Entity); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
666
|
+
i0.ɵɵelementStart(2, "span", 136);
|
|
667
|
+
i0.ɵɵelement(3, "i", 137);
|
|
657
668
|
i0.ɵɵtext(4);
|
|
658
669
|
i0.ɵɵelementEnd();
|
|
659
|
-
i0.ɵɵelementStart(5, "span",
|
|
670
|
+
i0.ɵɵelementStart(5, "span", 138);
|
|
660
671
|
i0.ɵɵtext(6);
|
|
661
672
|
i0.ɵɵelementEnd()();
|
|
662
|
-
i0.ɵɵconditionalCreate(7,
|
|
673
|
+
i0.ɵɵconditionalCreate(7, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Conditional_7_Template, 4, 1, "div", 139);
|
|
663
674
|
i0.ɵɵelementEnd();
|
|
664
675
|
} if (rf & 2) {
|
|
665
676
|
const dep_r26 = ctx.$implicit;
|
|
666
|
-
const ɵ$
|
|
677
|
+
const ɵ$index_567_r23 = i0.ɵɵnextContext(3).$index;
|
|
667
678
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
668
679
|
i0.ɵɵadvance(3);
|
|
669
|
-
i0.ɵɵclassProp("fa-chevron-right", !ctx_r1.IsDepEntityGroupExpanded(ɵ$
|
|
680
|
+
i0.ɵɵclassProp("fa-chevron-right", !ctx_r1.IsDepEntityGroupExpanded(ɵ$index_567_r23 + 1, dep_r26.Entity))("fa-chevron-down", ctx_r1.IsDepEntityGroupExpanded(ɵ$index_567_r23 + 1, dep_r26.Entity));
|
|
670
681
|
i0.ɵɵadvance();
|
|
671
682
|
i0.ɵɵtextInterpolate1(" ", dep_r26.Entity, " ");
|
|
672
683
|
i0.ɵɵadvance(2);
|
|
673
684
|
i0.ɵɵtextInterpolate(dep_r26.Count);
|
|
674
685
|
i0.ɵɵadvance();
|
|
675
|
-
i0.ɵɵconditional(ctx_r1.IsDepEntityGroupExpanded(ɵ$
|
|
686
|
+
i0.ɵɵconditional(ctx_r1.IsDepEntityGroupExpanded(ɵ$index_567_r23 + 1, dep_r26.Entity) ? 7 : -1);
|
|
676
687
|
} }
|
|
677
|
-
function
|
|
678
|
-
i0.ɵɵelementStart(0, "div",
|
|
679
|
-
i0.ɵɵrepeaterCreate(1,
|
|
688
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
689
|
+
i0.ɵɵelementStart(0, "div", 133);
|
|
690
|
+
i0.ɵɵrepeaterCreate(1, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_For_2_Template, 8, 7, "div", 134, _forTrack5);
|
|
680
691
|
i0.ɵɵelementEnd();
|
|
681
692
|
} if (rf & 2) {
|
|
682
|
-
const ɵ$
|
|
693
|
+
const ɵ$index_567_r23 = i0.ɵɵnextContext(2).$index;
|
|
683
694
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
684
695
|
i0.ɵɵadvance();
|
|
685
|
-
i0.ɵɵrepeater(ctx_r1.GetGroupedDeps(ɵ$
|
|
696
|
+
i0.ɵɵrepeater(ctx_r1.GetGroupedDeps(ɵ$index_567_r23 + 1));
|
|
686
697
|
} }
|
|
687
|
-
function
|
|
698
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
688
699
|
const _r24 = i0.ɵɵgetCurrentView();
|
|
689
|
-
i0.ɵɵelementStart(0, "div",
|
|
690
|
-
i0.ɵɵlistener("click", function
|
|
700
|
+
i0.ɵɵelementStart(0, "div", 132);
|
|
701
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r24); const ɵ$index_567_r23 = i0.ɵɵnextContext().$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.ToggleDepsExpanded(ɵ$index_567_r23 + 1)); });
|
|
691
702
|
i0.ɵɵelementStart(1, "span");
|
|
692
703
|
i0.ɵɵtext(2);
|
|
693
704
|
i0.ɵɵelementEnd();
|
|
694
|
-
i0.ɵɵelement(3, "i",
|
|
705
|
+
i0.ɵɵelement(3, "i", 115);
|
|
695
706
|
i0.ɵɵelementEnd();
|
|
696
|
-
i0.ɵɵconditionalCreate(4,
|
|
707
|
+
i0.ɵɵconditionalCreate(4, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Conditional_4_Template, 3, 0, "div", 133);
|
|
697
708
|
} if (rf & 2) {
|
|
698
|
-
const ɵ$
|
|
709
|
+
const ɵ$index_567_r23 = i0.ɵɵnextContext().$index;
|
|
699
710
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
700
711
|
i0.ɵɵadvance(2);
|
|
701
|
-
i0.ɵɵtextInterpolate(ctx_r1.IsDepsExpanded(ɵ$
|
|
712
|
+
i0.ɵɵtextInterpolate(ctx_r1.IsDepsExpanded(ɵ$index_567_r23 + 1) ? "Hide details" : "Show details");
|
|
702
713
|
i0.ɵɵadvance();
|
|
703
|
-
i0.ɵɵclassProp("fa-chevron-down", !ctx_r1.IsDepsExpanded(ɵ$
|
|
714
|
+
i0.ɵɵclassProp("fa-chevron-down", !ctx_r1.IsDepsExpanded(ɵ$index_567_r23 + 1))("fa-chevron-up", ctx_r1.IsDepsExpanded(ɵ$index_567_r23 + 1));
|
|
704
715
|
i0.ɵɵadvance();
|
|
705
|
-
i0.ɵɵconditional(ctx_r1.IsDepsExpanded(ɵ$
|
|
716
|
+
i0.ɵɵconditional(ctx_r1.IsDepsExpanded(ɵ$index_567_r23 + 1) ? 4 : -1);
|
|
717
|
+
} }
|
|
718
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_24_Template(rf, ctx) { if (rf & 1) {
|
|
719
|
+
const _r29 = i0.ɵɵgetCurrentView();
|
|
720
|
+
i0.ɵɵelementStart(0, "button", 150);
|
|
721
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_24_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r29); const match_r30 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.RejectIndividualMatch(match_r30)); });
|
|
722
|
+
i0.ɵɵelement(1, "i", 67);
|
|
723
|
+
i0.ɵɵtext(2, " Skip ");
|
|
724
|
+
i0.ɵɵelementEnd();
|
|
725
|
+
} }
|
|
726
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_25_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
727
|
+
const _r31 = i0.ɵɵgetCurrentView();
|
|
728
|
+
i0.ɵɵelementStart(0, "button", 153);
|
|
729
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_25_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r31); const match_r30 = i0.ɵɵnextContext(2).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UndoRejectIndividualMatch(match_r30)); });
|
|
730
|
+
i0.ɵɵelement(1, "i", 154);
|
|
731
|
+
i0.ɵɵtext(2, " Undo ");
|
|
732
|
+
i0.ɵɵelementEnd();
|
|
706
733
|
} }
|
|
707
|
-
function
|
|
708
|
-
i0.ɵɵelementStart(0, "span",
|
|
709
|
-
i0.ɵɵelement(1, "i",
|
|
734
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_25_Template(rf, ctx) { if (rf & 1) {
|
|
735
|
+
i0.ɵɵelementStart(0, "span", 151);
|
|
736
|
+
i0.ɵɵelement(1, "i", 115);
|
|
710
737
|
i0.ɵɵtext(2);
|
|
711
738
|
i0.ɵɵelementEnd();
|
|
739
|
+
i0.ɵɵconditionalCreate(3, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_25_Conditional_3_Template, 3, 0, "button", 152);
|
|
712
740
|
} if (rf & 2) {
|
|
713
|
-
const
|
|
714
|
-
i0.ɵɵclassProp("status-approved",
|
|
741
|
+
const match_r30 = i0.ɵɵnextContext().$implicit;
|
|
742
|
+
i0.ɵɵclassProp("status-approved", match_r30.Match.ApprovalStatus === "Approved")("status-rejected", match_r30.Match.ApprovalStatus === "Rejected");
|
|
715
743
|
i0.ɵɵadvance();
|
|
716
|
-
i0.ɵɵclassProp("fa-check",
|
|
744
|
+
i0.ɵɵclassProp("fa-check", match_r30.Match.ApprovalStatus === "Approved")("fa-times", match_r30.Match.ApprovalStatus === "Rejected");
|
|
717
745
|
i0.ɵɵadvance();
|
|
718
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
746
|
+
i0.ɵɵtextInterpolate1(" ", match_r30.Match.ApprovalStatus === "Rejected" ? "Skipped" : match_r30.Match.ApprovalStatus, " ");
|
|
747
|
+
i0.ɵɵadvance();
|
|
748
|
+
i0.ɵɵconditional(match_r30.Match.ApprovalStatus === "Rejected" ? 3 : -1);
|
|
719
749
|
} }
|
|
720
|
-
function
|
|
750
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_47_Template(rf, ctx) { if (rf & 1) {
|
|
721
751
|
const _r22 = i0.ɵɵgetCurrentView();
|
|
722
|
-
i0.ɵɵelementStart(0, "div",
|
|
752
|
+
i0.ɵɵelementStart(0, "div", 145)(1, "div", 146)(2, "span", 110);
|
|
723
753
|
i0.ɵɵtext(3);
|
|
724
754
|
i0.ɵɵelementEnd();
|
|
725
|
-
i0.ɵɵelementStart(4, "span",
|
|
755
|
+
i0.ɵɵelementStart(4, "span", 75);
|
|
726
756
|
i0.ɵɵtext(5);
|
|
727
757
|
i0.ɵɵelementEnd()();
|
|
728
|
-
i0.ɵɵelementStart(6, "span",
|
|
758
|
+
i0.ɵɵelementStart(6, "span", 147);
|
|
729
759
|
i0.ɵɵtext(7);
|
|
730
760
|
i0.ɵɵelementEnd();
|
|
731
|
-
i0.ɵɵelementStart(8, "div",
|
|
732
|
-
i0.ɵɵlistener("change", function
|
|
761
|
+
i0.ɵɵelementStart(8, "div", 111)(9, "input", 112);
|
|
762
|
+
i0.ɵɵlistener("change", function DuplicateDetectionResourceComponent_Conditional_68_For_47_Template_input_change_9_listener() { const ɵ$index_567_r23 = i0.ɵɵrestoreView(_r22).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SetSurvivor(ɵ$index_567_r23 + 1)); });
|
|
733
763
|
i0.ɵɵelementEnd();
|
|
734
|
-
i0.ɵɵelementStart(10, "span",
|
|
764
|
+
i0.ɵɵelementStart(10, "span", 113);
|
|
735
765
|
i0.ɵɵtext(11);
|
|
736
766
|
i0.ɵɵelementEnd()();
|
|
737
|
-
i0.ɵɵelementStart(12, "button",
|
|
738
|
-
i0.ɵɵlistener("click", function
|
|
739
|
-
i0.ɵɵelement(13, "i",
|
|
767
|
+
i0.ɵɵelementStart(12, "button", 114);
|
|
768
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_47_Template_button_click_12_listener() { const ɵ$index_567_r23 = i0.ɵɵrestoreView(_r22).$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.UseAllFieldsFrom(ɵ$index_567_r23 + 1)); });
|
|
769
|
+
i0.ɵɵelement(13, "i", 115);
|
|
740
770
|
i0.ɵɵtext(14);
|
|
741
771
|
i0.ɵɵelementEnd();
|
|
742
|
-
i0.ɵɵelementStart(15, "div",
|
|
743
|
-
i0.ɵɵelement(17, "i",
|
|
744
|
-
i0.ɵɵelementStart(18, "span",
|
|
772
|
+
i0.ɵɵelementStart(15, "div", 116)(16, "div", 117);
|
|
773
|
+
i0.ɵɵelement(17, "i", 118);
|
|
774
|
+
i0.ɵɵelementStart(18, "span", 119);
|
|
745
775
|
i0.ɵɵtext(19);
|
|
746
776
|
i0.ɵɵelementEnd();
|
|
747
777
|
i0.ɵɵtext(20);
|
|
748
|
-
i0.ɵɵconditionalCreate(21,
|
|
749
|
-
i0.ɵɵelementEnd();
|
|
750
|
-
i0.ɵɵconditionalCreate(22, DuplicateDetectionResourceComponent_Conditional_66_For_47_Conditional_22_Template, 5, 6);
|
|
778
|
+
i0.ɵɵconditionalCreate(21, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_21_Template, 3, 0, "span", 120);
|
|
751
779
|
i0.ɵɵelementEnd();
|
|
752
|
-
i0.ɵɵconditionalCreate(
|
|
780
|
+
i0.ɵɵconditionalCreate(22, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_22_Template, 5, 6);
|
|
753
781
|
i0.ɵɵelementEnd();
|
|
782
|
+
i0.ɵɵelementStart(23, "div", 148);
|
|
783
|
+
i0.ɵɵconditionalCreate(24, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_24_Template, 3, 0, "button", 149)(25, DuplicateDetectionResourceComponent_Conditional_68_For_47_Conditional_25_Template, 4, 10);
|
|
784
|
+
i0.ɵɵelementEnd()();
|
|
754
785
|
} if (rf & 2) {
|
|
755
|
-
const
|
|
756
|
-
const ɵ$
|
|
786
|
+
const match_r30 = ctx.$implicit;
|
|
787
|
+
const ɵ$index_567_r23 = ctx.$index;
|
|
757
788
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
758
|
-
i0.ɵɵclassProp("match-approved",
|
|
789
|
+
i0.ɵɵclassProp("match-approved", match_r30.Match.ApprovalStatus === "Approved")("match-rejected", match_r30.Match.ApprovalStatus === "Rejected");
|
|
759
790
|
i0.ɵɵadvance(3);
|
|
760
|
-
i0.ɵɵtextInterpolate(
|
|
791
|
+
i0.ɵɵtextInterpolate(match_r30.Name);
|
|
761
792
|
i0.ɵɵadvance();
|
|
762
|
-
i0.ɵɵclassMap(ctx_r1.GetScoreClass(
|
|
793
|
+
i0.ɵɵclassMap(ctx_r1.GetScoreClass(match_r30.Score));
|
|
763
794
|
i0.ɵɵadvance();
|
|
764
|
-
i0.ɵɵtextInterpolate1(" ", (
|
|
795
|
+
i0.ɵɵtextInterpolate1(" ", (match_r30.Score * 100).toFixed(0), "% ");
|
|
765
796
|
i0.ɵɵadvance(2);
|
|
766
|
-
i0.ɵɵtextInterpolate2("",
|
|
797
|
+
i0.ɵɵtextInterpolate2("", match_r30.DiffCount, " difference", match_r30.DiffCount !== 1 ? "s" : "");
|
|
767
798
|
i0.ɵɵadvance(2);
|
|
768
|
-
i0.ɵɵproperty("checked", ctx_r1.SurvivorColumnIndex === ɵ$
|
|
799
|
+
i0.ɵɵproperty("checked", ctx_r1.SurvivorColumnIndex === ɵ$index_567_r23 + 1);
|
|
769
800
|
i0.ɵɵadvance();
|
|
770
|
-
i0.ɵɵclassProp("is-survivor", ctx_r1.SurvivorColumnIndex === ɵ$
|
|
801
|
+
i0.ɵɵclassProp("is-survivor", ctx_r1.SurvivorColumnIndex === ɵ$index_567_r23 + 1);
|
|
771
802
|
i0.ɵɵadvance();
|
|
772
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.SurvivorColumnIndex === ɵ$
|
|
803
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.SurvivorColumnIndex === ɵ$index_567_r23 + 1 ? "Surviving Record" : "Set as survivor", " ");
|
|
773
804
|
i0.ɵɵadvance();
|
|
774
|
-
i0.ɵɵclassProp("all-selected", ctx_r1.AllFieldsSelectedFrom(ɵ$
|
|
805
|
+
i0.ɵɵclassProp("all-selected", ctx_r1.AllFieldsSelectedFrom(ɵ$index_567_r23 + 1));
|
|
775
806
|
i0.ɵɵadvance();
|
|
776
|
-
i0.ɵɵclassProp("fa-check-double", ctx_r1.AllFieldsSelectedFrom(ɵ$
|
|
807
|
+
i0.ɵɵclassProp("fa-check-double", ctx_r1.AllFieldsSelectedFrom(ɵ$index_567_r23 + 1))("fa-clone", !ctx_r1.AllFieldsSelectedFrom(ɵ$index_567_r23 + 1));
|
|
777
808
|
i0.ɵɵadvance();
|
|
778
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.AllFieldsSelectedFrom(ɵ$
|
|
809
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.AllFieldsSelectedFrom(ɵ$index_567_r23 + 1) ? "Using all fields" : "Use all fields", " ");
|
|
779
810
|
i0.ɵɵadvance(5);
|
|
780
|
-
i0.ɵɵtextInterpolate(ctx_r1.GetTotalDeps(ɵ$
|
|
781
|
-
i0.ɵɵadvance();
|
|
782
|
-
i0.ɵɵtextInterpolate1(" ", ctx_r1.GetTotalDeps(ɵ$index_556_r23 + 1) === 1 ? "dependency" : "dependencies", " ");
|
|
811
|
+
i0.ɵɵtextInterpolate(ctx_r1.GetTotalDeps(ɵ$index_567_r23 + 1));
|
|
783
812
|
i0.ɵɵadvance();
|
|
784
|
-
i0.ɵɵ
|
|
813
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.GetTotalDeps(ɵ$index_567_r23 + 1) === 1 ? "dependency" : "dependencies", " ");
|
|
785
814
|
i0.ɵɵadvance();
|
|
786
|
-
i0.ɵɵconditional(ctx_r1.
|
|
815
|
+
i0.ɵɵconditional(ctx_r1.GetMaxDepsColumnIndex() === ɵ$index_567_r23 + 1 && ctx_r1.GetTotalDeps(ɵ$index_567_r23 + 1) > 0 ? 21 : -1);
|
|
787
816
|
i0.ɵɵadvance();
|
|
788
|
-
i0.ɵɵconditional(
|
|
817
|
+
i0.ɵɵconditional(ctx_r1.GetGroupedDeps(ɵ$index_567_r23 + 1).length > 0 ? 22 : -1);
|
|
818
|
+
i0.ɵɵadvance(2);
|
|
819
|
+
i0.ɵɵconditional(match_r30.Match.ApprovalStatus === "Pending" ? 24 : 25);
|
|
789
820
|
} }
|
|
790
|
-
function
|
|
821
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
791
822
|
i0.ɵɵtext(0);
|
|
792
823
|
} if (rf & 2) {
|
|
793
|
-
const
|
|
794
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
824
|
+
const field_r33 = i0.ɵɵnextContext().$implicit;
|
|
825
|
+
i0.ɵɵtextInterpolate1(" ", field_r33.SourceValue, " ");
|
|
795
826
|
} }
|
|
796
|
-
function
|
|
797
|
-
i0.ɵɵelementStart(0, "span",
|
|
827
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
828
|
+
i0.ɵɵelementStart(0, "span", 157);
|
|
798
829
|
i0.ɵɵtext(1, "(not available)");
|
|
799
830
|
i0.ɵɵelementEnd();
|
|
800
831
|
} }
|
|
801
|
-
function
|
|
802
|
-
const
|
|
803
|
-
i0.ɵɵelementStart(0, "input",
|
|
804
|
-
i0.ɵɵlistener("click", function
|
|
832
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
833
|
+
const _r34 = i0.ɵɵgetCurrentView();
|
|
834
|
+
i0.ɵɵelementStart(0, "input", 160);
|
|
835
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_5_Template_input_click_0_listener($event) { i0.ɵɵrestoreView(_r34); return i0.ɵɵresetView($event.stopPropagation()); })("change", function DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_5_Template_input_change_0_listener() { i0.ɵɵrestoreView(_r34); const field_r33 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SelectFieldValue(field_r33, 0)); });
|
|
805
836
|
i0.ɵɵelementEnd();
|
|
806
837
|
} if (rf & 2) {
|
|
807
|
-
const
|
|
808
|
-
i0.ɵɵproperty("name", "field-" +
|
|
838
|
+
const field_r33 = i0.ɵɵnextContext().$implicit;
|
|
839
|
+
i0.ɵɵproperty("name", "field-" + field_r33.FieldName)("checked", field_r33.SelectedColumnIndex === 0);
|
|
809
840
|
} }
|
|
810
|
-
function
|
|
811
|
-
const
|
|
812
|
-
i0.ɵɵelementStart(0, "input",
|
|
813
|
-
i0.ɵɵlistener("click", function
|
|
841
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
842
|
+
const _r39 = i0.ɵɵgetCurrentView();
|
|
843
|
+
i0.ɵɵelementStart(0, "input", 160);
|
|
844
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_1_Conditional_1_Template_input_click_0_listener($event) { i0.ɵɵrestoreView(_r39); return i0.ɵɵresetView($event.stopPropagation()); })("change", function DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_1_Conditional_1_Template_input_change_0_listener() { i0.ɵɵrestoreView(_r39); const ɵ$index_685_r38 = i0.ɵɵnextContext(2).$index; const field_r33 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SelectFieldValue(field_r33, ɵ$index_685_r38 + 1)); });
|
|
814
845
|
i0.ɵɵelementEnd();
|
|
815
846
|
} if (rf & 2) {
|
|
816
|
-
const ɵ$
|
|
817
|
-
const
|
|
818
|
-
i0.ɵɵproperty("name", "field-" +
|
|
847
|
+
const ɵ$index_685_r38 = i0.ɵɵnextContext(2).$index;
|
|
848
|
+
const field_r33 = i0.ɵɵnextContext().$implicit;
|
|
849
|
+
i0.ɵɵproperty("name", "field-" + field_r33.FieldName)("checked", field_r33.SelectedColumnIndex === ɵ$index_685_r38 + 1);
|
|
819
850
|
} }
|
|
820
|
-
function
|
|
851
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
821
852
|
i0.ɵɵtext(0);
|
|
822
|
-
i0.ɵɵconditionalCreate(1,
|
|
853
|
+
i0.ɵɵconditionalCreate(1, DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_1_Conditional_1_Template, 1, 2, "input", 158);
|
|
823
854
|
} if (rf & 2) {
|
|
824
|
-
const
|
|
825
|
-
const
|
|
826
|
-
const ɵ$
|
|
827
|
-
const
|
|
828
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
855
|
+
const ctx_r39 = i0.ɵɵnextContext();
|
|
856
|
+
const matchVal_r37 = ctx_r39.$implicit;
|
|
857
|
+
const ɵ$index_685_r38 = ctx_r39.$index;
|
|
858
|
+
const field_r33 = i0.ɵɵnextContext().$implicit;
|
|
859
|
+
i0.ɵɵtextInterpolate1(" ", matchVal_r37, " ");
|
|
829
860
|
i0.ɵɵadvance();
|
|
830
|
-
i0.ɵɵconditional(
|
|
861
|
+
i0.ɵɵconditional(field_r33.HasDifference || field_r33.SelectedColumnIndex === ɵ$index_685_r38 + 1 ? 1 : -1);
|
|
831
862
|
} }
|
|
832
|
-
function
|
|
833
|
-
i0.ɵɵelementStart(0, "span",
|
|
863
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
864
|
+
i0.ɵɵelementStart(0, "span", 157);
|
|
834
865
|
i0.ɵɵtext(1, "(not available)");
|
|
835
866
|
i0.ɵɵelementEnd();
|
|
836
867
|
} }
|
|
837
|
-
function
|
|
838
|
-
const
|
|
839
|
-
i0.ɵɵelementStart(0, "div",
|
|
840
|
-
i0.ɵɵlistener("click", function
|
|
841
|
-
i0.ɵɵconditionalCreate(1,
|
|
868
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Template(rf, ctx) { if (rf & 1) {
|
|
869
|
+
const _r35 = i0.ɵɵgetCurrentView();
|
|
870
|
+
i0.ɵɵelementStart(0, "div", 161);
|
|
871
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Template_div_click_0_listener() { const ctx_r35 = i0.ɵɵrestoreView(_r35); const matchVal_r37 = ctx_r35.$implicit; const ɵ$index_685_r38 = ctx_r35.$index; const field_r33 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(matchVal_r37 != null ? ctx_r1.SelectFieldValue(field_r33, ɵ$index_685_r38 + 1) : null); });
|
|
872
|
+
i0.ɵɵconditionalCreate(1, DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_1_Template, 2, 2)(2, DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Conditional_2_Template, 2, 0, "span", 157);
|
|
842
873
|
i0.ɵɵelementEnd();
|
|
843
874
|
} if (rf & 2) {
|
|
844
|
-
const
|
|
845
|
-
const ɵ$
|
|
846
|
-
const
|
|
847
|
-
const
|
|
848
|
-
const ɵ$
|
|
875
|
+
const matchVal_r37 = ctx.$implicit;
|
|
876
|
+
const ɵ$index_685_r38 = ctx.$index;
|
|
877
|
+
const ctx_r40 = i0.ɵɵnextContext();
|
|
878
|
+
const field_r33 = ctx_r40.$implicit;
|
|
879
|
+
const ɵ$index_670_r42 = ctx_r40.$index;
|
|
849
880
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
850
|
-
i0.ɵɵclassProp("grid-row-odd", ɵ$
|
|
881
|
+
i0.ɵɵclassProp("grid-row-odd", ɵ$index_670_r42 % 2 !== 0)("value-same", ctx_r1.AreValuesEqual(field_r33.SourceValue, matchVal_r37))("value-different", matchVal_r37 != null && field_r33.SourceValue != null && !ctx_r1.AreValuesEqual(field_r33.SourceValue, matchVal_r37))("field-selected", field_r33.SelectedColumnIndex === ɵ$index_685_r38 + 1);
|
|
851
882
|
i0.ɵɵadvance();
|
|
852
|
-
i0.ɵɵconditional(
|
|
883
|
+
i0.ɵɵconditional(matchVal_r37 != null ? 1 : 2);
|
|
853
884
|
} }
|
|
854
|
-
function
|
|
855
|
-
const
|
|
856
|
-
i0.ɵɵelementStart(0, "div",
|
|
885
|
+
function DuplicateDetectionResourceComponent_Conditional_68_For_49_Template(rf, ctx) { if (rf & 1) {
|
|
886
|
+
const _r32 = i0.ɵɵgetCurrentView();
|
|
887
|
+
i0.ɵɵelementStart(0, "div", 155);
|
|
857
888
|
i0.ɵɵtext(1);
|
|
858
889
|
i0.ɵɵelementEnd();
|
|
859
|
-
i0.ɵɵelementStart(2, "div",
|
|
860
|
-
i0.ɵɵlistener("click", function
|
|
861
|
-
i0.ɵɵconditionalCreate(3,
|
|
862
|
-
i0.ɵɵconditionalCreate(5,
|
|
890
|
+
i0.ɵɵelementStart(2, "div", 156);
|
|
891
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_For_49_Template_div_click_2_listener() { const field_r33 = i0.ɵɵrestoreView(_r32).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.SelectFieldValue(field_r33, 0)); });
|
|
892
|
+
i0.ɵɵconditionalCreate(3, DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_3_Template, 1, 1)(4, DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_4_Template, 2, 0, "span", 157);
|
|
893
|
+
i0.ɵɵconditionalCreate(5, DuplicateDetectionResourceComponent_Conditional_68_For_49_Conditional_5_Template, 1, 2, "input", 158);
|
|
863
894
|
i0.ɵɵelementEnd();
|
|
864
|
-
i0.ɵɵrepeaterCreate(6,
|
|
895
|
+
i0.ɵɵrepeaterCreate(6, DuplicateDetectionResourceComponent_Conditional_68_For_49_For_7_Template, 3, 9, "div", 159, i0.ɵɵrepeaterTrackByIndex);
|
|
865
896
|
} if (rf & 2) {
|
|
866
|
-
const
|
|
867
|
-
const ɵ$
|
|
868
|
-
i0.ɵɵclassProp("grid-row-odd", ɵ$
|
|
897
|
+
const field_r33 = ctx.$implicit;
|
|
898
|
+
const ɵ$index_670_r42 = ctx.$index;
|
|
899
|
+
i0.ɵɵclassProp("grid-row-odd", ɵ$index_670_r42 % 2 !== 0);
|
|
869
900
|
i0.ɵɵadvance();
|
|
870
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
901
|
+
i0.ɵɵtextInterpolate1(" ", field_r33.DisplayName, " ");
|
|
871
902
|
i0.ɵɵadvance();
|
|
872
|
-
i0.ɵɵclassProp("grid-row-odd", ɵ$
|
|
903
|
+
i0.ɵɵclassProp("grid-row-odd", ɵ$index_670_r42 % 2 !== 0)("has-diff-in-row", field_r33.HasDifference)("field-selected", field_r33.SelectedColumnIndex === 0);
|
|
873
904
|
i0.ɵɵadvance();
|
|
874
|
-
i0.ɵɵconditional(
|
|
905
|
+
i0.ɵɵconditional(field_r33.SourceValue != null ? 3 : 4);
|
|
875
906
|
i0.ɵɵadvance(2);
|
|
876
|
-
i0.ɵɵconditional(
|
|
907
|
+
i0.ɵɵconditional(field_r33.HasDifference || field_r33.SelectedColumnIndex === 0 ? 5 : -1);
|
|
877
908
|
i0.ɵɵadvance();
|
|
878
|
-
i0.ɵɵrepeater(
|
|
909
|
+
i0.ɵɵrepeater(field_r33.MatchValues);
|
|
879
910
|
} }
|
|
880
|
-
function
|
|
911
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_59_Template(rf, ctx) { if (rf & 1) {
|
|
881
912
|
i0.ɵɵtext(0);
|
|
882
913
|
} if (rf & 2) {
|
|
883
914
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
884
915
|
i0.ɵɵtextInterpolate2(" \u00B7 ", ctx_r1.CherryPickedCount(), " field", ctx_r1.CherryPickedCount() !== 1 ? "s" : "", " cherry-picked ");
|
|
885
916
|
} }
|
|
886
|
-
function
|
|
917
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Conditional_67_Template(rf, ctx) { if (rf & 1) {
|
|
918
|
+
i0.ɵɵelementStart(0, "span", 129);
|
|
919
|
+
i0.ɵɵelement(1, "i", 162);
|
|
920
|
+
i0.ɵɵtext(2, " Merging disabled for this entity");
|
|
921
|
+
i0.ɵɵelementEnd();
|
|
922
|
+
} }
|
|
923
|
+
function DuplicateDetectionResourceComponent_Conditional_68_Template(rf, ctx) { if (rf & 1) {
|
|
887
924
|
const _r16 = i0.ɵɵgetCurrentView();
|
|
888
|
-
i0.ɵɵelementStart(0, "div",
|
|
889
|
-
i0.ɵɵlistener("click", function
|
|
925
|
+
i0.ɵɵelementStart(0, "div", 92);
|
|
926
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseComparison()); });
|
|
890
927
|
i0.ɵɵelementEnd();
|
|
891
|
-
i0.ɵɵelementStart(1, "div",
|
|
892
|
-
i0.ɵɵlistener("click", function
|
|
893
|
-
i0.ɵɵelementStart(2, "div",
|
|
928
|
+
i0.ɵɵelementStart(1, "div", 93);
|
|
929
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r16); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
930
|
+
i0.ɵɵelementStart(2, "div", 94)(3, "div", 95)(4, "div", 96);
|
|
894
931
|
i0.ɵɵelement(5, "i");
|
|
895
932
|
i0.ɵɵelementEnd();
|
|
896
|
-
i0.ɵɵelementStart(6, "div")(7, "div",
|
|
933
|
+
i0.ɵɵelementStart(6, "div")(7, "div", 97);
|
|
897
934
|
i0.ɵɵtext(8);
|
|
898
935
|
i0.ɵɵelementEnd();
|
|
899
|
-
i0.ɵɵelementStart(9, "span",
|
|
936
|
+
i0.ɵɵelementStart(9, "span", 98);
|
|
900
937
|
i0.ɵɵtext(10);
|
|
901
938
|
i0.ɵɵelementEnd();
|
|
902
|
-
i0.ɵɵelementStart(11, "span",
|
|
939
|
+
i0.ɵɵelementStart(11, "span", 99);
|
|
903
940
|
i0.ɵɵtext(12);
|
|
904
941
|
i0.ɵɵelementEnd()()();
|
|
905
|
-
i0.ɵɵelementStart(13, "div",
|
|
906
|
-
i0.ɵɵlistener("click", function
|
|
942
|
+
i0.ɵɵelementStart(13, "div", 100)(14, "div", 101)(15, "button", 102);
|
|
943
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ComparisonShowAllFields = true); });
|
|
907
944
|
i0.ɵɵtext(16, "All Fields");
|
|
908
945
|
i0.ɵɵelementEnd();
|
|
909
|
-
i0.ɵɵelementStart(17, "button",
|
|
910
|
-
i0.ɵɵlistener("click", function
|
|
946
|
+
i0.ɵɵelementStart(17, "button", 102);
|
|
947
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_button_click_17_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ComparisonShowAllFields = false); });
|
|
911
948
|
i0.ɵɵtext(18, "Differences Only");
|
|
912
949
|
i0.ɵɵelementEnd()();
|
|
913
|
-
i0.ɵɵelementStart(19, "button",
|
|
914
|
-
i0.ɵɵlistener("click", function
|
|
915
|
-
i0.ɵɵelement(20, "i",
|
|
950
|
+
i0.ɵɵelementStart(19, "button", 103);
|
|
951
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_button_click_19_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseComparison()); });
|
|
952
|
+
i0.ɵɵelement(20, "i", 50);
|
|
916
953
|
i0.ɵɵelementEnd()()();
|
|
917
|
-
i0.ɵɵconditionalCreate(21,
|
|
918
|
-
i0.ɵɵelementStart(22, "div",
|
|
954
|
+
i0.ɵɵconditionalCreate(21, DuplicateDetectionResourceComponent_Conditional_68_Conditional_21_Template, 2, 0, "div", 104);
|
|
955
|
+
i0.ɵɵelementStart(22, "div", 105)(23, "div", 106)(24, "div", 107);
|
|
919
956
|
i0.ɵɵtext(25, "Field");
|
|
920
957
|
i0.ɵɵelementEnd();
|
|
921
|
-
i0.ɵɵelementStart(26, "div",
|
|
958
|
+
i0.ɵɵelementStart(26, "div", 108)(27, "span", 109);
|
|
922
959
|
i0.ɵɵtext(28, "Source");
|
|
923
960
|
i0.ɵɵelementEnd();
|
|
924
|
-
i0.ɵɵelementStart(29, "span",
|
|
961
|
+
i0.ɵɵelementStart(29, "span", 110);
|
|
925
962
|
i0.ɵɵtext(30);
|
|
926
963
|
i0.ɵɵelementEnd();
|
|
927
|
-
i0.ɵɵelementStart(31, "div",
|
|
928
|
-
i0.ɵɵlistener("change", function
|
|
964
|
+
i0.ɵɵelementStart(31, "div", 111)(32, "input", 112);
|
|
965
|
+
i0.ɵɵlistener("change", function DuplicateDetectionResourceComponent_Conditional_68_Template_input_change_32_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.SetSurvivor(0)); });
|
|
929
966
|
i0.ɵɵelementEnd();
|
|
930
|
-
i0.ɵɵelementStart(33, "span",
|
|
967
|
+
i0.ɵɵelementStart(33, "span", 113);
|
|
931
968
|
i0.ɵɵtext(34);
|
|
932
969
|
i0.ɵɵelementEnd()();
|
|
933
|
-
i0.ɵɵelementStart(35, "button",
|
|
934
|
-
i0.ɵɵlistener("click", function
|
|
935
|
-
i0.ɵɵelement(36, "i",
|
|
970
|
+
i0.ɵɵelementStart(35, "button", 114);
|
|
971
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_button_click_35_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.UseAllFieldsFrom(0)); });
|
|
972
|
+
i0.ɵɵelement(36, "i", 115);
|
|
936
973
|
i0.ɵɵtext(37);
|
|
937
974
|
i0.ɵɵelementEnd();
|
|
938
|
-
i0.ɵɵelementStart(38, "div",
|
|
939
|
-
i0.ɵɵelement(40, "i",
|
|
940
|
-
i0.ɵɵelementStart(41, "span",
|
|
975
|
+
i0.ɵɵelementStart(38, "div", 116)(39, "div", 117);
|
|
976
|
+
i0.ɵɵelement(40, "i", 118);
|
|
977
|
+
i0.ɵɵelementStart(41, "span", 119);
|
|
941
978
|
i0.ɵɵtext(42);
|
|
942
979
|
i0.ɵɵelementEnd();
|
|
943
980
|
i0.ɵɵtext(43);
|
|
944
|
-
i0.ɵɵconditionalCreate(44,
|
|
981
|
+
i0.ɵɵconditionalCreate(44, DuplicateDetectionResourceComponent_Conditional_68_Conditional_44_Template, 3, 0, "span", 120);
|
|
945
982
|
i0.ɵɵelementEnd();
|
|
946
|
-
i0.ɵɵconditionalCreate(45,
|
|
983
|
+
i0.ɵɵconditionalCreate(45, DuplicateDetectionResourceComponent_Conditional_68_Conditional_45_Template, 5, 6);
|
|
947
984
|
i0.ɵɵelementEnd()();
|
|
948
|
-
i0.ɵɵrepeaterCreate(46,
|
|
949
|
-
i0.ɵɵrepeaterCreate(48,
|
|
985
|
+
i0.ɵɵrepeaterCreate(46, DuplicateDetectionResourceComponent_Conditional_68_For_47_Template, 26, 26, "div", 121, _forTrack3);
|
|
986
|
+
i0.ɵɵrepeaterCreate(48, DuplicateDetectionResourceComponent_Conditional_68_For_49_Template, 8, 11, null, null, _forTrack4);
|
|
950
987
|
i0.ɵɵelementEnd()();
|
|
951
|
-
i0.ɵɵelementStart(50, "div",
|
|
988
|
+
i0.ɵɵelementStart(50, "div", 122)(51, "div", 123)(52, "span", 124);
|
|
952
989
|
i0.ɵɵtext(53);
|
|
953
990
|
i0.ɵɵelementEnd();
|
|
954
|
-
i0.ɵɵelementStart(54, "span",
|
|
955
|
-
i0.ɵɵelement(55, "i",
|
|
991
|
+
i0.ɵɵelementStart(54, "span", 125);
|
|
992
|
+
i0.ɵɵelement(55, "i", 126);
|
|
956
993
|
i0.ɵɵtext(56, " Surviving: ");
|
|
957
994
|
i0.ɵɵelementStart(57, "strong");
|
|
958
995
|
i0.ɵɵtext(58);
|
|
959
996
|
i0.ɵɵelementEnd();
|
|
960
|
-
i0.ɵɵconditionalCreate(59,
|
|
997
|
+
i0.ɵɵconditionalCreate(59, DuplicateDetectionResourceComponent_Conditional_68_Conditional_59_Template, 1, 2);
|
|
961
998
|
i0.ɵɵelementEnd()();
|
|
962
|
-
i0.ɵɵelementStart(60, "div",
|
|
963
|
-
i0.ɵɵlistener("click", function
|
|
964
|
-
i0.ɵɵelement(62, "i",
|
|
999
|
+
i0.ɵɵelementStart(60, "div", 127)(61, "button", 85);
|
|
1000
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_button_click_61_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.RejectMatch(ctx_r1.ComparisonGroup); return i0.ɵɵresetView(ctx_r1.CloseComparison()); });
|
|
1001
|
+
i0.ɵɵelement(62, "i", 50);
|
|
965
1002
|
i0.ɵɵtext(63, " Reject All ");
|
|
966
1003
|
i0.ɵɵelementEnd();
|
|
967
|
-
i0.ɵɵelementStart(64, "button",
|
|
968
|
-
i0.ɵɵlistener("click", function
|
|
969
|
-
i0.ɵɵelement(65, "i",
|
|
1004
|
+
i0.ɵɵelementStart(64, "button", 128);
|
|
1005
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_68_Template_button_click_64_listener() { i0.ɵɵrestoreView(_r16); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OpenMergeConfirm()); });
|
|
1006
|
+
i0.ɵɵelement(65, "i", 126);
|
|
970
1007
|
i0.ɵɵtext(66, " Merge Records ");
|
|
971
|
-
i0.ɵɵelementEnd()
|
|
1008
|
+
i0.ɵɵelementEnd();
|
|
1009
|
+
i0.ɵɵconditionalCreate(67, DuplicateDetectionResourceComponent_Conditional_68_Conditional_67_Template, 3, 0, "span", 129);
|
|
1010
|
+
i0.ɵɵelementEnd()()();
|
|
972
1011
|
} if (rf & 2) {
|
|
973
1012
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
974
1013
|
i0.ɵɵclassProp("comparison-closing", ctx_r1.ComparisonClosing);
|
|
@@ -1027,32 +1066,34 @@ function DuplicateDetectionResourceComponent_Conditional_66_Template(rf, ctx) {
|
|
|
1027
1066
|
i0.ɵɵadvance(2);
|
|
1028
1067
|
i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
|
|
1029
1068
|
i0.ɵɵadvance(3);
|
|
1030
|
-
i0.ɵɵproperty("disabled", ctx_r1.IsSaving);
|
|
1069
|
+
i0.ɵɵproperty("disabled", ctx_r1.IsSaving || !ctx_r1.HasMergeableMatches || !ctx_r1.MergeEnabled)("title", !ctx_r1.MergeEnabled ? "Merging is not enabled for this entity" : ctx_r1.HasMergeableMatches ? "Merge non-skipped records" : "All matches have been skipped");
|
|
1070
|
+
i0.ɵɵadvance(3);
|
|
1071
|
+
i0.ɵɵconditional(!ctx_r1.MergeEnabled ? 67 : -1);
|
|
1031
1072
|
} }
|
|
1032
|
-
function
|
|
1033
|
-
i0.ɵɵelementStart(0, "div",
|
|
1073
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_22_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
1074
|
+
i0.ɵɵelementStart(0, "div", 187)(1, "span", 188);
|
|
1034
1075
|
i0.ɵɵtext(2);
|
|
1035
1076
|
i0.ɵɵelementEnd();
|
|
1036
|
-
i0.ɵɵelementStart(3, "span",
|
|
1077
|
+
i0.ɵɵelementStart(3, "span", 189);
|
|
1037
1078
|
i0.ɵɵtext(4);
|
|
1038
1079
|
i0.ɵɵelementEnd();
|
|
1039
|
-
i0.ɵɵelementStart(5, "span",
|
|
1080
|
+
i0.ɵɵelementStart(5, "span", 190);
|
|
1040
1081
|
i0.ɵɵtext(6);
|
|
1041
1082
|
i0.ɵɵelementEnd()();
|
|
1042
1083
|
} if (rf & 2) {
|
|
1043
|
-
const
|
|
1084
|
+
const field_r44 = ctx.$implicit;
|
|
1044
1085
|
i0.ɵɵadvance(2);
|
|
1045
|
-
i0.ɵɵtextInterpolate(
|
|
1086
|
+
i0.ɵɵtextInterpolate(field_r44.DisplayName);
|
|
1046
1087
|
i0.ɵɵadvance(2);
|
|
1047
|
-
i0.ɵɵtextInterpolate1("\"",
|
|
1088
|
+
i0.ɵɵtextInterpolate1("\"", field_r44.Value, "\"");
|
|
1048
1089
|
i0.ɵɵadvance(2);
|
|
1049
|
-
i0.ɵɵtextInterpolate1("from ",
|
|
1090
|
+
i0.ɵɵtextInterpolate1("from ", field_r44.SourceName);
|
|
1050
1091
|
} }
|
|
1051
|
-
function
|
|
1052
|
-
i0.ɵɵelementStart(0, "div")(1, "div",
|
|
1092
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
1093
|
+
i0.ɵɵelementStart(0, "div")(1, "div", 186);
|
|
1053
1094
|
i0.ɵɵtext(2);
|
|
1054
1095
|
i0.ɵɵelementEnd();
|
|
1055
|
-
i0.ɵɵrepeaterCreate(3,
|
|
1096
|
+
i0.ɵɵrepeaterCreate(3, DuplicateDetectionResourceComponent_Conditional_69_Conditional_22_For_4_Template, 7, 3, "div", 187, _forTrack4);
|
|
1056
1097
|
i0.ɵɵelementEnd();
|
|
1057
1098
|
} if (rf & 2) {
|
|
1058
1099
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -1061,7 +1102,7 @@ function DuplicateDetectionResourceComponent_Conditional_67_Conditional_22_Templ
|
|
|
1061
1102
|
i0.ɵɵadvance();
|
|
1062
1103
|
i0.ɵɵrepeater(ctx_r1.GetCherryPickedFields());
|
|
1063
1104
|
} }
|
|
1064
|
-
function
|
|
1105
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_For_5_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
1065
1106
|
i0.ɵɵelementStart(0, "strong");
|
|
1066
1107
|
i0.ɵɵtext(1);
|
|
1067
1108
|
i0.ɵɵelementEnd();
|
|
@@ -1071,18 +1112,18 @@ function DuplicateDetectionResourceComponent_Conditional_67_Conditional_23_For_5
|
|
|
1071
1112
|
i0.ɵɵelementEnd();
|
|
1072
1113
|
i0.ɵɵtext(5);
|
|
1073
1114
|
} if (rf & 2) {
|
|
1074
|
-
const
|
|
1115
|
+
const col_r45 = i0.ɵɵnextContext().$implicit;
|
|
1075
1116
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
1076
1117
|
i0.ɵɵadvance();
|
|
1077
|
-
i0.ɵɵtextInterpolate(
|
|
1118
|
+
i0.ɵɵtextInterpolate(col_r45.DepCount);
|
|
1078
1119
|
i0.ɵɵadvance();
|
|
1079
|
-
i0.ɵɵtextInterpolate1(" ",
|
|
1120
|
+
i0.ɵɵtextInterpolate1(" ", col_r45.DepCount === 1 ? "dependency" : "dependencies", " from ");
|
|
1080
1121
|
i0.ɵɵadvance(2);
|
|
1081
|
-
i0.ɵɵtextInterpolate(
|
|
1122
|
+
i0.ɵɵtextInterpolate(col_r45.Name);
|
|
1082
1123
|
i0.ɵɵadvance();
|
|
1083
1124
|
i0.ɵɵtextInterpolate1(" \u2192 ", ctx_r1.SurvivorName(), " ");
|
|
1084
1125
|
} }
|
|
1085
|
-
function
|
|
1126
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_For_5_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
1086
1127
|
i0.ɵɵelementStart(0, "strong");
|
|
1087
1128
|
i0.ɵɵtext(1, "0");
|
|
1088
1129
|
i0.ɵɵelementEnd();
|
|
@@ -1091,113 +1132,113 @@ function DuplicateDetectionResourceComponent_Conditional_67_Conditional_23_For_5
|
|
|
1091
1132
|
i0.ɵɵtext(4);
|
|
1092
1133
|
i0.ɵɵelementEnd();
|
|
1093
1134
|
} if (rf & 2) {
|
|
1094
|
-
const
|
|
1135
|
+
const col_r45 = i0.ɵɵnextContext().$implicit;
|
|
1095
1136
|
i0.ɵɵadvance(4);
|
|
1096
|
-
i0.ɵɵtextInterpolate(
|
|
1137
|
+
i0.ɵɵtextInterpolate(col_r45.Name);
|
|
1097
1138
|
} }
|
|
1098
|
-
function
|
|
1099
|
-
i0.ɵɵelementStart(0, "div",
|
|
1100
|
-
i0.ɵɵelement(1, "i",
|
|
1139
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_For_5_Template(rf, ctx) { if (rf & 1) {
|
|
1140
|
+
i0.ɵɵelementStart(0, "div", 193);
|
|
1141
|
+
i0.ɵɵelement(1, "i", 194);
|
|
1101
1142
|
i0.ɵɵelementStart(2, "span");
|
|
1102
|
-
i0.ɵɵconditionalCreate(3,
|
|
1143
|
+
i0.ɵɵconditionalCreate(3, DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_For_5_Conditional_3_Template, 6, 4)(4, DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_For_5_Conditional_4_Template, 5, 1);
|
|
1103
1144
|
i0.ɵɵelementEnd()();
|
|
1104
1145
|
} if (rf & 2) {
|
|
1105
|
-
const
|
|
1146
|
+
const col_r45 = ctx.$implicit;
|
|
1106
1147
|
i0.ɵɵadvance(3);
|
|
1107
|
-
i0.ɵɵconditional(
|
|
1148
|
+
i0.ɵɵconditional(col_r45.DepCount > 0 ? 3 : 4);
|
|
1108
1149
|
} }
|
|
1109
|
-
function
|
|
1110
|
-
i0.ɵɵelementStart(0, "div",
|
|
1111
|
-
i0.ɵɵelement(2, "i",
|
|
1150
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_Template(rf, ctx) { if (rf & 1) {
|
|
1151
|
+
i0.ɵɵelementStart(0, "div", 177)(1, "div", 191);
|
|
1152
|
+
i0.ɵɵelement(2, "i", 192);
|
|
1112
1153
|
i0.ɵɵtext(3, " Dependencies to Transfer");
|
|
1113
1154
|
i0.ɵɵelementEnd();
|
|
1114
|
-
i0.ɵɵrepeaterCreate(4,
|
|
1155
|
+
i0.ɵɵrepeaterCreate(4, DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_For_5_Template, 5, 1, "div", 193, _forTrack6);
|
|
1115
1156
|
i0.ɵɵelementEnd();
|
|
1116
1157
|
} if (rf & 2) {
|
|
1117
1158
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
1118
1159
|
i0.ɵɵadvance(4);
|
|
1119
1160
|
i0.ɵɵrepeater(ctx_r1.GetNonSurvivorColumns());
|
|
1120
1161
|
} }
|
|
1121
|
-
function
|
|
1162
|
+
function DuplicateDetectionResourceComponent_Conditional_69_For_29_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
1122
1163
|
i0.ɵɵtext(0);
|
|
1123
1164
|
} if (rf & 2) {
|
|
1124
|
-
const
|
|
1125
|
-
i0.ɵɵtextInterpolate2(" ",
|
|
1165
|
+
const col_r46 = i0.ɵɵnextContext().$implicit;
|
|
1166
|
+
i0.ɵɵtextInterpolate2(" ", col_r46.DepCount, " dep", col_r46.DepCount !== 1 ? "s" : "", " transferring ");
|
|
1126
1167
|
} }
|
|
1127
|
-
function
|
|
1168
|
+
function DuplicateDetectionResourceComponent_Conditional_69_For_29_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
1128
1169
|
i0.ɵɵtext(0, " no deps ");
|
|
1129
1170
|
} }
|
|
1130
|
-
function
|
|
1131
|
-
i0.ɵɵelementStart(0, "div",
|
|
1171
|
+
function DuplicateDetectionResourceComponent_Conditional_69_For_29_Template(rf, ctx) { if (rf & 1) {
|
|
1172
|
+
i0.ɵɵelementStart(0, "div", 181)(1, "span", 195);
|
|
1132
1173
|
i0.ɵɵtext(2);
|
|
1133
1174
|
i0.ɵɵelementEnd();
|
|
1134
|
-
i0.ɵɵelementStart(3, "span",
|
|
1135
|
-
i0.ɵɵconditionalCreate(4,
|
|
1175
|
+
i0.ɵɵelementStart(3, "span", 196);
|
|
1176
|
+
i0.ɵɵconditionalCreate(4, DuplicateDetectionResourceComponent_Conditional_69_For_29_Conditional_4_Template, 1, 2)(5, DuplicateDetectionResourceComponent_Conditional_69_For_29_Conditional_5_Template, 1, 0);
|
|
1136
1177
|
i0.ɵɵelementEnd()();
|
|
1137
1178
|
} if (rf & 2) {
|
|
1138
|
-
const
|
|
1179
|
+
const col_r46 = ctx.$implicit;
|
|
1139
1180
|
i0.ɵɵadvance(2);
|
|
1140
|
-
i0.ɵɵtextInterpolate(
|
|
1181
|
+
i0.ɵɵtextInterpolate(col_r46.Name);
|
|
1141
1182
|
i0.ɵɵadvance(2);
|
|
1142
|
-
i0.ɵɵconditional(
|
|
1183
|
+
i0.ɵɵconditional(col_r46.DepCount > 0 ? 4 : 5);
|
|
1143
1184
|
} }
|
|
1144
|
-
function
|
|
1145
|
-
i0.ɵɵelement(0, "i",
|
|
1185
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_35_Template(rf, ctx) { if (rf & 1) {
|
|
1186
|
+
i0.ɵɵelement(0, "i", 34);
|
|
1146
1187
|
i0.ɵɵtext(1, " Merging... ");
|
|
1147
1188
|
} }
|
|
1148
|
-
function
|
|
1149
|
-
i0.ɵɵelement(0, "i",
|
|
1189
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Conditional_36_Template(rf, ctx) { if (rf & 1) {
|
|
1190
|
+
i0.ɵɵelement(0, "i", 126);
|
|
1150
1191
|
i0.ɵɵtext(1);
|
|
1151
1192
|
} if (rf & 2) {
|
|
1152
1193
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
1153
1194
|
i0.ɵɵadvance();
|
|
1154
1195
|
i0.ɵɵtextInterpolate1(" Confirm Merge (", ctx_r1.GetNonSurvivorColumns().length + 1, " records \u2192 1) ");
|
|
1155
1196
|
} }
|
|
1156
|
-
function
|
|
1157
|
-
const
|
|
1158
|
-
i0.ɵɵelementStart(0, "div",
|
|
1159
|
-
i0.ɵɵlistener("click", function
|
|
1160
|
-
i0.ɵɵelementStart(1, "div",
|
|
1161
|
-
i0.ɵɵlistener("click", function
|
|
1162
|
-
i0.ɵɵelementStart(2, "div",
|
|
1163
|
-
i0.ɵɵelement(4, "i",
|
|
1164
|
-
i0.ɵɵelementEnd();
|
|
1165
|
-
i0.ɵɵelementStart(5, "div")(6, "div",
|
|
1197
|
+
function DuplicateDetectionResourceComponent_Conditional_69_Template(rf, ctx) { if (rf & 1) {
|
|
1198
|
+
const _r43 = i0.ɵɵgetCurrentView();
|
|
1199
|
+
i0.ɵɵelementStart(0, "div", 163);
|
|
1200
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_69_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r43); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseMergeConfirm()); });
|
|
1201
|
+
i0.ɵɵelementStart(1, "div", 164);
|
|
1202
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_69_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r43); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
1203
|
+
i0.ɵɵelementStart(2, "div", 165)(3, "div", 166);
|
|
1204
|
+
i0.ɵɵelement(4, "i", 126);
|
|
1205
|
+
i0.ɵɵelementEnd();
|
|
1206
|
+
i0.ɵɵelementStart(5, "div")(6, "div", 167);
|
|
1166
1207
|
i0.ɵɵtext(7, "Confirm Record Merge");
|
|
1167
1208
|
i0.ɵɵelementEnd();
|
|
1168
|
-
i0.ɵɵelementStart(8, "div",
|
|
1209
|
+
i0.ɵɵelementStart(8, "div", 168);
|
|
1169
1210
|
i0.ɵɵtext(9, "This action cannot be undone. Please review carefully.");
|
|
1170
1211
|
i0.ɵɵelementEnd()()();
|
|
1171
|
-
i0.ɵɵelementStart(10, "div",
|
|
1172
|
-
i0.ɵɵelement(13, "i",
|
|
1212
|
+
i0.ɵɵelementStart(10, "div", 169)(11, "div", 170)(12, "div", 171);
|
|
1213
|
+
i0.ɵɵelement(13, "i", 172);
|
|
1173
1214
|
i0.ɵɵtext(14, " Surviving Record");
|
|
1174
1215
|
i0.ɵɵelementEnd();
|
|
1175
|
-
i0.ɵɵelementStart(15, "div",
|
|
1216
|
+
i0.ɵɵelementStart(15, "div", 173);
|
|
1176
1217
|
i0.ɵɵtext(16);
|
|
1177
1218
|
i0.ɵɵelementEnd();
|
|
1178
|
-
i0.ɵɵelementStart(17, "div",
|
|
1179
|
-
i0.ɵɵelement(18, "i",
|
|
1219
|
+
i0.ɵɵelementStart(17, "div", 174);
|
|
1220
|
+
i0.ɵɵelement(18, "i", 175);
|
|
1180
1221
|
i0.ɵɵtext(19);
|
|
1181
1222
|
i0.ɵɵelementEnd();
|
|
1182
|
-
i0.ɵɵelementStart(20, "div",
|
|
1223
|
+
i0.ɵɵelementStart(20, "div", 176);
|
|
1183
1224
|
i0.ɵɵtext(21, "This record's ID will be retained. All dependencies from merged records will be transferred here.");
|
|
1184
1225
|
i0.ɵɵelementEnd()();
|
|
1185
|
-
i0.ɵɵconditionalCreate(22,
|
|
1186
|
-
i0.ɵɵconditionalCreate(23,
|
|
1187
|
-
i0.ɵɵelementStart(24, "div",
|
|
1188
|
-
i0.ɵɵelement(26, "i",
|
|
1226
|
+
i0.ɵɵconditionalCreate(22, DuplicateDetectionResourceComponent_Conditional_69_Conditional_22_Template, 5, 2, "div");
|
|
1227
|
+
i0.ɵɵconditionalCreate(23, DuplicateDetectionResourceComponent_Conditional_69_Conditional_23_Template, 6, 0, "div", 177);
|
|
1228
|
+
i0.ɵɵelementStart(24, "div", 178)(25, "div", 179);
|
|
1229
|
+
i0.ɵɵelement(26, "i", 180);
|
|
1189
1230
|
i0.ɵɵtext(27, " Records to Delete After Merge");
|
|
1190
1231
|
i0.ɵɵelementEnd();
|
|
1191
|
-
i0.ɵɵrepeaterCreate(28,
|
|
1232
|
+
i0.ɵɵrepeaterCreate(28, DuplicateDetectionResourceComponent_Conditional_69_For_29_Template, 6, 2, "div", 181, _forTrack6);
|
|
1192
1233
|
i0.ɵɵelementEnd()();
|
|
1193
|
-
i0.ɵɵelementStart(30, "div",
|
|
1194
|
-
i0.ɵɵlistener("click", function
|
|
1195
|
-
i0.ɵɵelement(32, "i",
|
|
1234
|
+
i0.ɵɵelementStart(30, "div", 182)(31, "button", 183);
|
|
1235
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_69_Template_button_click_31_listener() { i0.ɵɵrestoreView(_r43); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.CloseMergeConfirm()); });
|
|
1236
|
+
i0.ɵɵelement(32, "i", 184);
|
|
1196
1237
|
i0.ɵɵtext(33, " Back ");
|
|
1197
1238
|
i0.ɵɵelementEnd();
|
|
1198
|
-
i0.ɵɵelementStart(34, "button",
|
|
1199
|
-
i0.ɵɵlistener("click", function
|
|
1200
|
-
i0.ɵɵconditionalCreate(35,
|
|
1239
|
+
i0.ɵɵelementStart(34, "button", 185);
|
|
1240
|
+
i0.ɵɵlistener("click", function DuplicateDetectionResourceComponent_Conditional_69_Template_button_click_34_listener() { i0.ɵɵrestoreView(_r43); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ExecuteMerge()); });
|
|
1241
|
+
i0.ɵɵconditionalCreate(35, DuplicateDetectionResourceComponent_Conditional_69_Conditional_35_Template, 2, 0)(36, DuplicateDetectionResourceComponent_Conditional_69_Conditional_36_Template, 2, 1);
|
|
1201
1242
|
i0.ɵɵelementEnd()()()();
|
|
1202
1243
|
} if (rf & 2) {
|
|
1203
1244
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -1219,12 +1260,20 @@ function DuplicateDetectionResourceComponent_Conditional_67_Template(rf, ctx) {
|
|
|
1219
1260
|
i0.ɵɵconditional(ctx_r1.IsMerging ? 35 : 36);
|
|
1220
1261
|
} }
|
|
1221
1262
|
let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceComponent extends BaseResourceComponent {
|
|
1263
|
+
/** Close comparison panel on Escape key */
|
|
1264
|
+
OnEscapeKey() {
|
|
1265
|
+
if (this.ComparisonGroup) {
|
|
1266
|
+
this.CloseComparison();
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1222
1269
|
cdr = inject(ChangeDetectorRef);
|
|
1223
1270
|
navigationService = inject(NavigationService);
|
|
1224
1271
|
destroy$ = new Subject();
|
|
1225
1272
|
filterSubject = new Subject();
|
|
1226
1273
|
// Loading state
|
|
1227
1274
|
IsLoading = false;
|
|
1275
|
+
/** Whether the results area (runs/details/matches) is still loading */
|
|
1276
|
+
IsLoadingResults = false;
|
|
1228
1277
|
IsSaving = false;
|
|
1229
1278
|
// ── Comparison Panel State ──
|
|
1230
1279
|
/** The group being compared (null = panel closed) */
|
|
@@ -1255,6 +1304,10 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1255
1304
|
ShowMergeConfirm = false;
|
|
1256
1305
|
/** Whether the merge is currently executing */
|
|
1257
1306
|
IsMerging = false;
|
|
1307
|
+
/** Whether the current entity allows record merging (controls merge button availability) */
|
|
1308
|
+
MergeEnabled = true;
|
|
1309
|
+
/** Whether merge-not-available inline banner should be shown in the results area */
|
|
1310
|
+
ShowMergeWarningBanner = false;
|
|
1258
1311
|
// Raw data
|
|
1259
1312
|
Runs = [];
|
|
1260
1313
|
Details = [];
|
|
@@ -1278,6 +1331,8 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1278
1331
|
IsDetecting = false;
|
|
1279
1332
|
DetectionProgress = 0;
|
|
1280
1333
|
DetectionStage = '';
|
|
1334
|
+
/** Raw stage key from the last progress event — used to detect phase transitions */
|
|
1335
|
+
detectionRawStage = '';
|
|
1281
1336
|
/** Runtime threshold overrides — initialized from entity doc, adjustable via sliders */
|
|
1282
1337
|
RunPotentialThreshold = 0.70;
|
|
1283
1338
|
RunAbsoluteThreshold = 0.95;
|
|
@@ -1385,6 +1440,13 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1385
1440
|
async ngAfterViewInit() {
|
|
1386
1441
|
this.setupFilterDebounce();
|
|
1387
1442
|
await this.LoadData();
|
|
1443
|
+
this.navigationService.SetAgentContext(this, {
|
|
1444
|
+
DetectionStatus: this.IsDetecting ? 'running' : 'idle',
|
|
1445
|
+
PendingCount: this.PendingGroups.length,
|
|
1446
|
+
ApprovedCount: this.ApprovedGroups.length,
|
|
1447
|
+
RejectedCount: this.RejectedGroups.length,
|
|
1448
|
+
SelectedEntityDoc: this.SelectedEntityDocumentID || null,
|
|
1449
|
+
});
|
|
1388
1450
|
this.NotifyLoadComplete();
|
|
1389
1451
|
}
|
|
1390
1452
|
ngOnDestroy() {
|
|
@@ -1399,58 +1461,94 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1399
1461
|
}
|
|
1400
1462
|
/**
|
|
1401
1463
|
* Loads all duplicate run data and builds the Kanban groups.
|
|
1464
|
+
* Split into two phases so that controls become interactive immediately:
|
|
1465
|
+
* Phase 1 - entity docs from KH engine cache (instant)
|
|
1466
|
+
* Phase 2 - runs/details/matches via RunViews (heavy)
|
|
1402
1467
|
*/
|
|
1403
1468
|
async LoadData() {
|
|
1404
1469
|
this.IsLoading = true;
|
|
1405
1470
|
this.cdr.detectChanges();
|
|
1406
1471
|
try {
|
|
1407
|
-
//
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
OrderBy: 'StartedAt DESC',
|
|
1416
|
-
ResultType: 'entity_object'
|
|
1417
|
-
},
|
|
1418
|
-
{
|
|
1419
|
-
EntityName: 'MJ: Duplicate Run Details',
|
|
1420
|
-
ExtraFilter: "MatchStatus = 'Complete'",
|
|
1421
|
-
OrderBy: '__mj_CreatedAt DESC',
|
|
1422
|
-
ResultType: 'entity_object'
|
|
1423
|
-
},
|
|
1424
|
-
{
|
|
1425
|
-
EntityName: 'MJ: Duplicate Run Detail Matches',
|
|
1426
|
-
OrderBy: 'MatchProbability DESC',
|
|
1427
|
-
ResultType: 'entity_object'
|
|
1428
|
-
}
|
|
1429
|
-
]);
|
|
1430
|
-
if (runsResult.Success) {
|
|
1431
|
-
this.Runs = runsResult.Results;
|
|
1432
|
-
}
|
|
1433
|
-
if (detailsResult.Success) {
|
|
1434
|
-
this.Details = detailsResult.Results;
|
|
1435
|
-
}
|
|
1436
|
-
if (matchesResult.Success) {
|
|
1437
|
-
this.Matches = matchesResult.Results;
|
|
1438
|
-
}
|
|
1439
|
-
// Build entity document options from cached active documents
|
|
1440
|
-
this.buildEntityDocumentOptionsFromEngine(engine.GetActiveEntityDocuments());
|
|
1441
|
-
this.buildGroups();
|
|
1442
|
-
this.extractEntityNames();
|
|
1443
|
-
this.computeDataRanges();
|
|
1444
|
-
this.applyFilters();
|
|
1472
|
+
// Phase 1: Populate entity document picker from cache (instant)
|
|
1473
|
+
await this.loadEntityDocuments();
|
|
1474
|
+
// Controls are now interactive - only the results area is loading
|
|
1475
|
+
this.IsLoading = false;
|
|
1476
|
+
this.IsLoadingResults = true;
|
|
1477
|
+
this.cdr.detectChanges();
|
|
1478
|
+
// Phase 2: Load heavy run/detail/match data
|
|
1479
|
+
await this.loadRunData();
|
|
1445
1480
|
}
|
|
1446
1481
|
catch (error) {
|
|
1447
1482
|
console.error('Error loading duplicate detection data:', error);
|
|
1448
1483
|
}
|
|
1449
1484
|
finally {
|
|
1450
1485
|
this.IsLoading = false;
|
|
1486
|
+
this.IsLoadingResults = false;
|
|
1451
1487
|
this.cdr.detectChanges();
|
|
1452
1488
|
}
|
|
1453
1489
|
}
|
|
1490
|
+
/** Phase 1: Load entity documents from KH engine cache (instant). */
|
|
1491
|
+
async loadEntityDocuments() {
|
|
1492
|
+
const engine = KnowledgeHubMetadataEngine.Instance;
|
|
1493
|
+
await engine.Config(false);
|
|
1494
|
+
this.buildEntityDocumentOptionsFromEngine(engine.GetActiveEntityDocuments());
|
|
1495
|
+
}
|
|
1496
|
+
/** Phase 2: Load runs, details, and matches via RunViews batch. */
|
|
1497
|
+
async loadRunData() {
|
|
1498
|
+
const rv = new RunView();
|
|
1499
|
+
const [runsResult, detailsResult, matchesResult] = await rv.RunViews([
|
|
1500
|
+
{
|
|
1501
|
+
EntityName: 'MJ: Duplicate Runs',
|
|
1502
|
+
ExtraFilter: "ProcessingStatus IN ('Complete', 'Failed', 'In Progress')",
|
|
1503
|
+
OrderBy: 'StartedAt DESC',
|
|
1504
|
+
ResultType: 'entity_object'
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
EntityName: 'MJ: Duplicate Run Details',
|
|
1508
|
+
ExtraFilter: "MatchStatus = 'Complete'",
|
|
1509
|
+
OrderBy: '__mj_CreatedAt DESC',
|
|
1510
|
+
ResultType: 'entity_object'
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
EntityName: 'MJ: Duplicate Run Detail Matches',
|
|
1514
|
+
OrderBy: 'MatchProbability DESC',
|
|
1515
|
+
ResultType: 'entity_object'
|
|
1516
|
+
}
|
|
1517
|
+
]);
|
|
1518
|
+
if (runsResult.Success) {
|
|
1519
|
+
this.Runs = runsResult.Results;
|
|
1520
|
+
}
|
|
1521
|
+
if (detailsResult.Success) {
|
|
1522
|
+
this.Details = detailsResult.Results;
|
|
1523
|
+
}
|
|
1524
|
+
if (matchesResult.Success) {
|
|
1525
|
+
this.Matches = matchesResult.Results;
|
|
1526
|
+
}
|
|
1527
|
+
this.buildGroups();
|
|
1528
|
+
this.extractEntityNames();
|
|
1529
|
+
this.computeDataRanges();
|
|
1530
|
+
this.applyFilters();
|
|
1531
|
+
// Reconnect to any in-progress detection run
|
|
1532
|
+
this.reconnectToActiveRun();
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* Check if there's an in-progress detection run and reconnect to its
|
|
1536
|
+
* progress subscription. This handles the case where the user navigated
|
|
1537
|
+
* away and came back while a run was active.
|
|
1538
|
+
*/
|
|
1539
|
+
reconnectToActiveRun() {
|
|
1540
|
+
if (this.IsDetecting)
|
|
1541
|
+
return; // Already tracking a run
|
|
1542
|
+
const activeRun = this.Runs.find(r => r.ProcessingStatus === 'In Progress');
|
|
1543
|
+
if (!activeRun)
|
|
1544
|
+
return;
|
|
1545
|
+
LogStatus(`[DuplicateDetection] Reconnecting to in-progress run ${activeRun.ID}`);
|
|
1546
|
+
this.IsDetecting = true;
|
|
1547
|
+
this.DetectionProgress = 0;
|
|
1548
|
+
this.DetectionStage = 'Reconnecting...';
|
|
1549
|
+
this.cdr.detectChanges();
|
|
1550
|
+
this.subscribeToPipelineProgress(activeRun.ID);
|
|
1551
|
+
}
|
|
1454
1552
|
/**
|
|
1455
1553
|
* Trigger a new duplicate detection run by creating a DuplicateRun entity.
|
|
1456
1554
|
* The server hook auto-triggers detection when a run is saved with EndedAt === null.
|
|
@@ -1472,9 +1570,17 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1472
1570
|
dupeRun.NewRecord();
|
|
1473
1571
|
// Look up the EntityID from the entity document's entity name
|
|
1474
1572
|
const entityInfo = md.Entities.find(e => e.Name === selectedDoc.EntityName);
|
|
1475
|
-
if (entityInfo) {
|
|
1476
|
-
|
|
1573
|
+
if (!entityInfo) {
|
|
1574
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Entity "${selectedDoc.EntityName}" not found in metadata`, 'error', 5000);
|
|
1575
|
+
this.IsDetecting = false;
|
|
1576
|
+
this.DetectionStage = '';
|
|
1577
|
+
this.cdr.detectChanges();
|
|
1578
|
+
return;
|
|
1477
1579
|
}
|
|
1580
|
+
// DD-1: Track whether merging is available for the selected entity
|
|
1581
|
+
this.MergeEnabled = entityInfo.AllowRecordMerge;
|
|
1582
|
+
this.ShowMergeWarningBanner = !entityInfo.AllowRecordMerge;
|
|
1583
|
+
dupeRun.EntityID = entityInfo.ID;
|
|
1478
1584
|
dupeRun.StartedByUserID = new Metadata().CurrentUser.ID;
|
|
1479
1585
|
dupeRun.StartedAt = new Date();
|
|
1480
1586
|
dupeRun.ProcessingStatus = 'In Progress';
|
|
@@ -1649,6 +1755,39 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1649
1755
|
return 'Low';
|
|
1650
1756
|
}
|
|
1651
1757
|
/** Format a date for display */
|
|
1758
|
+
/**
|
|
1759
|
+
* Format a composite key string (e.g., "ID|5A07433E-F36B-1410-8AA5-00F1597429B5")
|
|
1760
|
+
* into a readable format. For single-key entities, shows just the value truncated.
|
|
1761
|
+
* For composite keys, shows key: value pairs.
|
|
1762
|
+
*/
|
|
1763
|
+
/** Whether there are any non-skipped matches available for merging */
|
|
1764
|
+
get HasMergeableMatches() {
|
|
1765
|
+
return this.ComparisonMatches.some(m => m.Match.ApprovalStatus !== 'Rejected');
|
|
1766
|
+
}
|
|
1767
|
+
FormatRecordID(recordID) {
|
|
1768
|
+
if (!recordID)
|
|
1769
|
+
return '';
|
|
1770
|
+
const pairs = recordID.split('||');
|
|
1771
|
+
if (pairs.length === 1) {
|
|
1772
|
+
// Single key — extract just the value
|
|
1773
|
+
const parts = pairs[0].split('|');
|
|
1774
|
+
if (parts.length === 2) {
|
|
1775
|
+
const val = parts[1];
|
|
1776
|
+
// Truncate long UUIDs
|
|
1777
|
+
return val.length > 12 ? val.substring(0, 8) + '...' : val;
|
|
1778
|
+
}
|
|
1779
|
+
return recordID.length > 12 ? recordID.substring(0, 8) + '...' : recordID;
|
|
1780
|
+
}
|
|
1781
|
+
// Composite key — show key: truncated value pairs
|
|
1782
|
+
return pairs.map(p => {
|
|
1783
|
+
const parts = p.split('|');
|
|
1784
|
+
if (parts.length === 2) {
|
|
1785
|
+
const val = parts[1].length > 8 ? parts[1].substring(0, 8) + '...' : parts[1];
|
|
1786
|
+
return `${parts[0]}: ${val}`;
|
|
1787
|
+
}
|
|
1788
|
+
return p;
|
|
1789
|
+
}).join(', ');
|
|
1790
|
+
}
|
|
1652
1791
|
FormatDate(date) {
|
|
1653
1792
|
if (!date)
|
|
1654
1793
|
return '';
|
|
@@ -1744,6 +1883,8 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1744
1883
|
}, 60000); // 60s timeout for duplicate detection (can be very long)
|
|
1745
1884
|
};
|
|
1746
1885
|
resetIdleTimer();
|
|
1886
|
+
// Reset phase tracking for this new subscription
|
|
1887
|
+
this.detectionRawStage = '';
|
|
1747
1888
|
const sub = provider.subscribe(subscriptionQuery, { pipelineRunID });
|
|
1748
1889
|
const rxSub = sub.pipe(takeUntil(this.destroy$)).subscribe({
|
|
1749
1890
|
next: (data) => {
|
|
@@ -1751,10 +1892,22 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1751
1892
|
if (!progress)
|
|
1752
1893
|
return;
|
|
1753
1894
|
const stage = progress['Stage'];
|
|
1754
|
-
const pct = progress['PercentComplete'];
|
|
1895
|
+
const pct = Math.max(0, Math.min(100, progress['PercentComplete']));
|
|
1755
1896
|
const currentItem = progress['CurrentItem'];
|
|
1756
|
-
|
|
1757
|
-
|
|
1897
|
+
// Detect phase transitions vs. within-phase updates
|
|
1898
|
+
const isNewPhase = stage !== this.detectionRawStage;
|
|
1899
|
+
if (isNewPhase) {
|
|
1900
|
+
// New phase: reset progress and update display
|
|
1901
|
+
this.detectionRawStage = stage;
|
|
1902
|
+
this.DetectionProgress = pct;
|
|
1903
|
+
this.DetectionStage = this.formatDetectionStage(stage);
|
|
1904
|
+
}
|
|
1905
|
+
else {
|
|
1906
|
+
// Same phase: only move forward (never backward)
|
|
1907
|
+
if (pct >= this.DetectionProgress) {
|
|
1908
|
+
this.DetectionProgress = pct;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1758
1911
|
this.DetectionCurrentItem = currentItem ?? '';
|
|
1759
1912
|
this.cdr.detectChanges();
|
|
1760
1913
|
if (stage === 'complete') {
|
|
@@ -1839,7 +1992,7 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
1839
1992
|
const metadata = this.parseRecordMetadata(detail.RecordMetadata);
|
|
1840
1993
|
const entityName = metadata.Entity || run?.Entity || 'Unknown';
|
|
1841
1994
|
const entityIcon = metadata.EntityIcon || 'fa-solid fa-database';
|
|
1842
|
-
const recordName = metadata
|
|
1995
|
+
const recordName = this.resolveRecordName(metadata, entityName, detail.RecordID);
|
|
1843
1996
|
// Build top match summaries from match metadata
|
|
1844
1997
|
const topMatchSummaries = this.buildTopMatchSummaries(detailMatches, 3);
|
|
1845
1998
|
this.AllGroups.push({
|
|
@@ -2141,6 +2294,7 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2141
2294
|
return match?.Name ?? 'Unknown';
|
|
2142
2295
|
}
|
|
2143
2296
|
// ════════════════════════════════════════════
|
|
2297
|
+
// ════════════════════════════════════════════
|
|
2144
2298
|
// Merge Confirmation
|
|
2145
2299
|
// ════════════════════════════════════════════
|
|
2146
2300
|
/** Open the merge confirmation panel */
|
|
@@ -2170,12 +2324,19 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2170
2324
|
});
|
|
2171
2325
|
}
|
|
2172
2326
|
/** Get non-surviving columns with their dependency counts */
|
|
2327
|
+
/** Get non-surviving columns excluding skipped (Rejected) matches for merge confirmation display */
|
|
2173
2328
|
GetNonSurvivorColumns() {
|
|
2174
2329
|
const result = [];
|
|
2175
2330
|
const totalColumns = 1 + this.ComparisonMatches.length;
|
|
2176
2331
|
for (let i = 0; i < totalColumns; i++) {
|
|
2177
2332
|
if (i === this.SurvivorColumnIndex)
|
|
2178
2333
|
continue;
|
|
2334
|
+
// Skip records marked as Rejected/Skipped
|
|
2335
|
+
if (i > 0) {
|
|
2336
|
+
const matchInfo = this.ComparisonMatches[i - 1];
|
|
2337
|
+
if (matchInfo?.Match?.ApprovalStatus === 'Rejected')
|
|
2338
|
+
continue;
|
|
2339
|
+
}
|
|
2179
2340
|
result.push({
|
|
2180
2341
|
ColumnIndex: i,
|
|
2181
2342
|
Name: this.GetColumnName(i),
|
|
@@ -2244,6 +2405,12 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2244
2405
|
for (let i = 0; i < totalColumns; i++) {
|
|
2245
2406
|
if (i === this.SurvivorColumnIndex)
|
|
2246
2407
|
continue;
|
|
2408
|
+
// Skip records that the user has marked as "Skipped" (Rejected)
|
|
2409
|
+
if (i > 0) {
|
|
2410
|
+
const matchInfo = this.ComparisonMatches[i - 1];
|
|
2411
|
+
if (matchInfo?.Match?.ApprovalStatus === 'Rejected')
|
|
2412
|
+
continue;
|
|
2413
|
+
}
|
|
2247
2414
|
const keyStr = this.getCompositeKeyStringForColumn(i);
|
|
2248
2415
|
if (keyStr) {
|
|
2249
2416
|
const ck = new CompositeKey();
|
|
@@ -2261,7 +2428,7 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2261
2428
|
this.IsSaving = false;
|
|
2262
2429
|
this.cdr.detectChanges();
|
|
2263
2430
|
}
|
|
2264
|
-
/** Reject an individual match */
|
|
2431
|
+
/** Reject an individual match (skip it from merge) */
|
|
2265
2432
|
async RejectIndividualMatch(matchInfo) {
|
|
2266
2433
|
this.IsSaving = true;
|
|
2267
2434
|
matchInfo.Match.ApprovalStatus = 'Rejected';
|
|
@@ -2269,6 +2436,14 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2269
2436
|
this.IsSaving = false;
|
|
2270
2437
|
this.cdr.detectChanges();
|
|
2271
2438
|
}
|
|
2439
|
+
/** Undo a rejected individual match (restore to Pending) */
|
|
2440
|
+
async UndoRejectIndividualMatch(matchInfo) {
|
|
2441
|
+
this.IsSaving = true;
|
|
2442
|
+
matchInfo.Match.ApprovalStatus = 'Pending';
|
|
2443
|
+
await matchInfo.Match.Save();
|
|
2444
|
+
this.IsSaving = false;
|
|
2445
|
+
this.cdr.detectChanges();
|
|
2446
|
+
}
|
|
2272
2447
|
/**
|
|
2273
2448
|
* Load the actual entity records for the source + all matches in one RunView call.
|
|
2274
2449
|
* Record IDs are stored as composite key strings (e.g., "ID|uuid") — we parse each
|
|
@@ -2377,11 +2552,12 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2377
2552
|
.sort((a, b) => b.MatchProbability - a.MatchProbability)
|
|
2378
2553
|
.map(m => {
|
|
2379
2554
|
const meta = this.parseRecordMetadata(m.RecordMetadata);
|
|
2380
|
-
//
|
|
2381
|
-
const
|
|
2555
|
+
// Resolve display name using IsNameField fields from entity metadata
|
|
2556
|
+
const entityName = this.ComparisonGroup.EntityName;
|
|
2557
|
+
const resolvedName = this.resolveMatchName(entityName, m.MatchRecordID, meta);
|
|
2382
2558
|
return {
|
|
2383
2559
|
Match: m,
|
|
2384
|
-
Name:
|
|
2560
|
+
Name: resolvedName,
|
|
2385
2561
|
Score: m.MatchProbability,
|
|
2386
2562
|
Metadata: meta,
|
|
2387
2563
|
DiffCount: 0,
|
|
@@ -2398,7 +2574,15 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2398
2574
|
const matchRecordIds = this.ComparisonGroup.Matches
|
|
2399
2575
|
.sort((a, b) => b.MatchProbability - a.MatchProbability)
|
|
2400
2576
|
.map(m => m.MatchRecordID);
|
|
2401
|
-
|
|
2577
|
+
// Sort fields: IsNameField first, then DefaultInView, then by Sequence
|
|
2578
|
+
const sortedFields = [...entityFields].sort((a, b) => {
|
|
2579
|
+
if (a.IsNameField !== b.IsNameField)
|
|
2580
|
+
return a.IsNameField ? -1 : 1;
|
|
2581
|
+
if (a.DefaultInView !== b.DefaultInView)
|
|
2582
|
+
return a.DefaultInView ? -1 : 1;
|
|
2583
|
+
return (a.Sequence ?? 9999) - (b.Sequence ?? 9999);
|
|
2584
|
+
});
|
|
2585
|
+
for (const field of sortedFields) {
|
|
2402
2586
|
if (skip.has(field.Name) || field.IsPrimaryKey)
|
|
2403
2587
|
continue;
|
|
2404
2588
|
const sourceVal = this.getRecordFieldValue(sourceId, field.Name);
|
|
@@ -2441,11 +2625,86 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2441
2625
|
.map(m => {
|
|
2442
2626
|
const meta = this.parseRecordMetadata(m.RecordMetadata);
|
|
2443
2627
|
return {
|
|
2444
|
-
Name: meta.
|
|
2628
|
+
Name: this.resolveRecordName(meta, this.SelectedEntityFilter || 'Unknown', m.MatchRecordID ?? ''),
|
|
2445
2629
|
Score: m.MatchProbability,
|
|
2446
2630
|
};
|
|
2447
2631
|
});
|
|
2448
2632
|
}
|
|
2633
|
+
/**
|
|
2634
|
+
* Resolve match record name from loaded entity records using IsNameField fields.
|
|
2635
|
+
* Falls back to metadata, then truncated record ID.
|
|
2636
|
+
*/
|
|
2637
|
+
resolveMatchName(entityName, matchRecordID, meta) {
|
|
2638
|
+
try {
|
|
2639
|
+
const md = new Metadata();
|
|
2640
|
+
const entityInfo = md.Entities.find(e => e.Name === entityName);
|
|
2641
|
+
if (entityInfo) {
|
|
2642
|
+
const nameFields = entityInfo.Fields
|
|
2643
|
+
.filter(f => f.IsNameField)
|
|
2644
|
+
.sort((a, b) => (a.Sequence ?? 9999) - (b.Sequence ?? 9999));
|
|
2645
|
+
if (nameFields.length > 0) {
|
|
2646
|
+
// Try loaded entity record data first
|
|
2647
|
+
const parts = nameFields
|
|
2648
|
+
.map(f => this.getRecordFieldValue(matchRecordID, f.Name))
|
|
2649
|
+
.filter(v => v != null && String(v).trim() !== '')
|
|
2650
|
+
.map(v => String(v));
|
|
2651
|
+
if (parts.length > 0)
|
|
2652
|
+
return parts.join(' ');
|
|
2653
|
+
// Fall back to vector metadata
|
|
2654
|
+
const metaParts = nameFields
|
|
2655
|
+
.map(f => meta[f.Name])
|
|
2656
|
+
.filter(v => v != null && String(v).trim() !== '')
|
|
2657
|
+
.map(v => String(v));
|
|
2658
|
+
if (metaParts.length > 0)
|
|
2659
|
+
return metaParts.join(' ');
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
catch { /* fall through */ }
|
|
2664
|
+
return meta.Name || this.FormatRecordID(matchRecordID ?? '');
|
|
2665
|
+
}
|
|
2666
|
+
/**
|
|
2667
|
+
* Resolve record display name from metadata using entity IsNameField fields.
|
|
2668
|
+
* Combines multiple name fields (e.g., FirstName + LastName → "Sarah Chen").
|
|
2669
|
+
* Falls back to metadata.Name, then recordID.
|
|
2670
|
+
*/
|
|
2671
|
+
resolveRecordName(metadata, entityName, recordID) {
|
|
2672
|
+
try {
|
|
2673
|
+
const md = new Metadata();
|
|
2674
|
+
const entityInfo = md.Entities.find(e => e.Name === entityName);
|
|
2675
|
+
if (entityInfo) {
|
|
2676
|
+
const nameFields = entityInfo.Fields
|
|
2677
|
+
.filter(f => f.IsNameField)
|
|
2678
|
+
.sort((a, b) => (a.Sequence ?? 9999) - (b.Sequence ?? 9999));
|
|
2679
|
+
if (nameFields.length > 0) {
|
|
2680
|
+
// 1. Try individual name fields from metadata (new rich metadata)
|
|
2681
|
+
const metaParts = nameFields
|
|
2682
|
+
.map(f => metadata[f.Name])
|
|
2683
|
+
.filter(v => v != null && String(v).trim() !== '')
|
|
2684
|
+
.map(v => String(v));
|
|
2685
|
+
if (metaParts.length > 0)
|
|
2686
|
+
return metaParts.join(' ');
|
|
2687
|
+
// 2. Try loaded entity records (available in comparison panel)
|
|
2688
|
+
const recordParts = nameFields
|
|
2689
|
+
.map(f => this.getRecordFieldValue(recordID, f.Name))
|
|
2690
|
+
.filter(v => v != null && String(v).trim() !== '')
|
|
2691
|
+
.map(v => String(v));
|
|
2692
|
+
if (recordParts.length > 0)
|
|
2693
|
+
return recordParts.join(' ');
|
|
2694
|
+
}
|
|
2695
|
+
// 3. Single NameField fallback
|
|
2696
|
+
if (entityInfo.NameField && metadata[entityInfo.NameField.Name]) {
|
|
2697
|
+
return String(metadata[entityInfo.NameField.Name]);
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
catch { /* fall through */ }
|
|
2702
|
+
// 4. Heuristic — skip single-char or initial-only names from old sparse metadata
|
|
2703
|
+
const metaName = metadata.Name;
|
|
2704
|
+
if (metaName && metaName.length > 2)
|
|
2705
|
+
return metaName;
|
|
2706
|
+
return metadata.Title || this.FormatRecordID(recordID);
|
|
2707
|
+
}
|
|
2449
2708
|
/**
|
|
2450
2709
|
* Determine the dominant approval status for a group of matches.
|
|
2451
2710
|
* If any match is Pending, the group is Pending.
|
|
@@ -2530,7 +2789,9 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2530
2789
|
}
|
|
2531
2790
|
}
|
|
2532
2791
|
static ɵfac = /*@__PURE__*/ (() => { let ɵDuplicateDetectionResourceComponent_BaseFactory; return function DuplicateDetectionResourceComponent_Factory(__ngFactoryType__) { return (ɵDuplicateDetectionResourceComponent_BaseFactory || (ɵDuplicateDetectionResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(DuplicateDetectionResourceComponent)))(__ngFactoryType__ || DuplicateDetectionResourceComponent); }; })();
|
|
2533
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DuplicateDetectionResourceComponent, selectors: [["app-duplicate-detection-resource"]],
|
|
2792
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DuplicateDetectionResourceComponent, selectors: [["app-duplicate-detection-resource"]], hostBindings: function DuplicateDetectionResourceComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
2793
|
+
i0.ɵɵlistener("keydown.escape", function DuplicateDetectionResourceComponent_keydown_escape_HostBindingHandler() { return ctx.OnEscapeKey(); }, i0.ɵɵresolveDocument);
|
|
2794
|
+
} }, inputs: { EmbeddedMode: "EmbeddedMode" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 70, vars: 29, consts: [[1, "duplicate-detection-container"], [1, "page-header"], [1, "header-left"], [1, "page-title"], [1, "fa-solid", "fa-clone"], [1, "header-actions"], [1, "run-detection-controls"], [1, "entity-doc-select", 3, "ngModelChange", "ngModel", "disabled"], ["value", ""], [3, "value"], [1, "run-detection-btn", 3, "click", "disabled"], [1, "detection-progress-section"], [1, "threshold-controls"], [1, "kpi-strip"], [1, "kpi-card"], [1, "kpi-value"], [1, "kpi-label"], [1, "kpi-card", "kpi-pending"], [1, "kpi-card", "kpi-approved"], [1, "kpi-card", "kpi-rejected"], [1, "filter-bar"], [1, "filter-group"], [1, "filter-select", 3, "ngModelChange", "ngModel", "disabled"], [1, "filter-range"], [1, "filter-label"], ["type", "number", "min", "0", "max", "1", "step", "0.05", 1, "filter-input", "filter-input-score", 3, "ngModelChange", "placeholder", "ngModel"], ["type", "date", 1, "filter-input", "filter-input-date", 3, "ngModelChange", "min", "max", "ngModel"], [1, "clear-filters-btn"], [1, "merge-warning-banner"], [1, "loading-container"], [1, "empty-state"], [1, "kanban-board"], [1, "saving-overlay"], [1, "merge-confirm-backdrop"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "fa-solid", "fa-magnifying-glass"], [1, "progress-header"], [1, "progress-stage"], [1, "progress-percent"], [1, "progress-bar-track"], [1, "progress-bar-fill"], [1, "progress-current-item"], [1, "threshold-slider-group"], [1, "threshold-label"], [1, "fa-solid", "fa-adjust"], [1, "threshold-value"], ["type", "range", 1, "threshold-slider", 3, "input", "min", "max", "step", "value", "disabled"], [1, "threshold-hint"], [1, "fa-solid", "fa-bullseye"], [1, "clear-filters-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "fa-solid", "fa-triangle-exclamation"], ["text", "Loading duplicate detection results..."], [1, "fa-solid", "fa-clone", "empty-icon"], [1, "empty-text"], [1, "empty-subtext"], [1, "kanban-column"], [1, "column-header", "column-header-pending"], [1, "fa-solid", "fa-clock"], [1, "column-title"], [1, "column-count"], [1, "column-body", 3, "dragover", "dragleave", "drop"], ["draggable", "true", 1, "kanban-card"], [1, "column-empty"], [1, "column-header", "column-header-approved"], [1, "fa-solid", "fa-check-circle"], [1, "column-header", "column-header-rejected"], [1, "fa-solid", "fa-ban"], ["draggable", "true", 1, "kanban-card", 3, "dragstart", "dragend", "click"], [1, "card-header"], [1, "card-header-left"], [1, "card-icon"], [1, "card-title-block"], [1, "card-record-name", 3, "title"], [1, "entity-badge"], [1, "score-indicator"], [1, "card-body"], [1, "match-summaries"], [1, "card-meta-row"], [1, "card-meta-item"], [1, "fa-solid", "fa-layer-group"], [1, "fa-solid", "fa-calendar"], [1, "card-actions"], [1, "action-btn", "approve-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-check"], [1, "action-btn", "reject-btn", 3, "click", "disabled"], [1, "match-summary-row"], [1, "match-summary-more"], [1, "match-score"], [1, "match-name"], [1, "fa-solid", "fa-inbox"], ["text", "Saving...", "size", "small"], [1, "slide-backdrop", 3, "click"], [1, "comparison-panel", 3, "click"], [1, "comparison-header"], [1, "comparison-header-left"], [1, "comparison-entity-icon"], [1, "comparison-title"], [1, "comparison-entity-badge"], [1, "comparison-match-count"], [1, "comparison-header-right"], [1, "comparison-toggle"], [1, "toggle-btn", 3, "click"], ["title", "Close (Esc)", 1, "comparison-close-btn", 3, "click"], [1, "comparison-loading"], [1, "comparison-grid-wrapper", 3, "hidden"], [1, "comparison-grid"], [1, "grid-corner-cell"], [1, "grid-col-header", "grid-col-source"], [1, "col-header-label"], [1, "col-header-name"], [1, "surviving-selector"], ["type", "radio", "name", "survivor", 1, "surviving-radio", 3, "change", "checked"], [1, "surviving-label"], [1, "use-all-btn", 3, "click"], [1, "fa-solid"], [1, "deps-summary"], [1, "deps-total"], [1, "fa-solid", "fa-link"], [1, "deps-total-number"], [1, "deps-total-recommended"], [1, "grid-col-header", 3, "match-approved", "match-rejected"], [1, "comparison-footer"], [1, "comparison-footer-left"], [1, "comparison-summary"], [1, "merge-summary"], [1, "fa-solid", "fa-code-merge"], [1, "comparison-footer-right"], [1, "action-btn", "merge-btn", 3, "click", "disabled", "title"], [1, "merge-disabled-hint"], ["text", "Loading records for comparison...", "size", "medium"], [1, "fa-solid", "fa-star"], [1, "deps-header", 3, "click"], [1, "deps-detail-list"], [1, "deps-detail-group"], [1, "deps-detail-row", 3, "click"], [1, "deps-detail-entity"], [1, "fa-solid", "deps-expand-icon"], [1, "deps-detail-count"], [1, "deps-records-list"], [1, "deps-record-loading"], [1, "deps-record-row"], [1, "deps-record-row", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square", "deps-record-icon"], [1, "deps-record-name"], [1, "grid-col-header"], [1, "col-header-top"], [1, "col-header-diff-count"], [1, "match-approval-actions"], ["title", "Skip this match (exclude from merge)", 1, "match-action-btn", "match-skip-btn"], ["title", "Skip this match (exclude from merge)", 1, "match-action-btn", "match-skip-btn", 3, "click"], [1, "match-status-badge"], ["title", "Undo skip", 1, "match-action-btn", "match-undo-btn"], ["title", "Undo skip", 1, "match-action-btn", "match-undo-btn", 3, "click"], [1, "fa-solid", "fa-undo"], [1, "grid-label-cell"], [1, "grid-value-cell", "grid-source-cell", 3, "click"], [1, "field-not-available"], ["type", "radio", 1, "field-select-radio", 3, "name", "checked"], [1, "grid-value-cell", 3, "grid-row-odd", "value-same", "value-different", "field-selected"], ["type", "radio", 1, "field-select-radio", 3, "click", "change", "name", "checked"], [1, "grid-value-cell", 3, "click"], [1, "fa-solid", "fa-info-circle"], [1, "merge-confirm-backdrop", 3, "click"], [1, "merge-confirm-panel", 3, "click"], [1, "merge-confirm-header"], [1, "merge-confirm-icon"], [1, "merge-confirm-title"], [1, "merge-confirm-subtitle"], [1, "merge-confirm-body"], [1, "merge-survivor-card"], [1, "merge-survivor-label"], [1, "fa-solid", "fa-shield-halved"], [1, "merge-survivor-name"], [1, "merge-survivor-pk"], [1, "fa-solid", "fa-key"], [1, "merge-survivor-detail"], [1, "merge-deps-transfer"], [1, "merge-delete-card"], [1, "merge-delete-label"], [1, "fa-solid", "fa-trash"], [1, "merge-delete-item"], [1, "merge-confirm-footer"], [1, "action-btn", "cancel-btn", 3, "click", "disabled"], [1, "fa-solid", "fa-arrow-left"], [1, "action-btn", "confirm-merge-btn", 3, "click", "disabled"], [1, "merge-section-label"], [1, "merge-field-override"], [1, "merge-field-name"], [1, "merge-field-value"], [1, "merge-field-source"], [1, "merge-deps-transfer-label"], [1, "fa-solid", "fa-arrow-right-arrow-left"], [1, "merge-deps-transfer-row"], [1, "fa-solid", "fa-arrow-right"], [1, "merge-delete-name"], [1, "merge-delete-deps"]], template: function DuplicateDetectionResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2534
2795
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "h2", 3);
|
|
2535
2796
|
i0.ɵɵelement(4, "i", 4);
|
|
2536
2797
|
i0.ɵɵtext(5, " Duplicate Detection ");
|
|
@@ -2608,10 +2869,11 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2608
2869
|
i0.ɵɵelementEnd()()();
|
|
2609
2870
|
i0.ɵɵconditionalCreate(61, DuplicateDetectionResourceComponent_Conditional_61_Template, 3, 0, "button", 27);
|
|
2610
2871
|
i0.ɵɵelementEnd();
|
|
2611
|
-
i0.ɵɵconditionalCreate(62, DuplicateDetectionResourceComponent_Conditional_62_Template,
|
|
2612
|
-
i0.ɵɵconditionalCreate(65, DuplicateDetectionResourceComponent_Conditional_65_Template,
|
|
2613
|
-
i0.ɵɵconditionalCreate(
|
|
2614
|
-
i0.ɵɵconditionalCreate(
|
|
2872
|
+
i0.ɵɵconditionalCreate(62, DuplicateDetectionResourceComponent_Conditional_62_Template, 3, 0, "div", 28);
|
|
2873
|
+
i0.ɵɵconditionalCreate(63, DuplicateDetectionResourceComponent_Conditional_63_Template, 2, 0, "div", 29)(64, DuplicateDetectionResourceComponent_Conditional_64_Template, 2, 0, "div", 29)(65, DuplicateDetectionResourceComponent_Conditional_65_Template, 6, 0, "div", 30)(66, DuplicateDetectionResourceComponent_Conditional_66_Template, 34, 12, "div", 31);
|
|
2874
|
+
i0.ɵɵconditionalCreate(67, DuplicateDetectionResourceComponent_Conditional_67_Template, 2, 0, "div", 32);
|
|
2875
|
+
i0.ɵɵconditionalCreate(68, DuplicateDetectionResourceComponent_Conditional_68_Template, 68, 42);
|
|
2876
|
+
i0.ɵɵconditionalCreate(69, DuplicateDetectionResourceComponent_Conditional_69_Template, 37, 7, "div", 33);
|
|
2615
2877
|
i0.ɵɵelementEnd();
|
|
2616
2878
|
} if (rf & 2) {
|
|
2617
2879
|
i0.ɵɵadvance(8);
|
|
@@ -2657,14 +2919,16 @@ let DuplicateDetectionResourceComponent = class DuplicateDetectionResourceCompon
|
|
|
2657
2919
|
i0.ɵɵadvance();
|
|
2658
2920
|
i0.ɵɵconditional(ctx.HasActiveFilters ? 61 : -1);
|
|
2659
2921
|
i0.ɵɵadvance();
|
|
2660
|
-
i0.ɵɵconditional(ctx.
|
|
2661
|
-
i0.ɵɵadvance(
|
|
2662
|
-
i0.ɵɵconditional(ctx.
|
|
2922
|
+
i0.ɵɵconditional(ctx.ShowMergeWarningBanner ? 62 : -1);
|
|
2923
|
+
i0.ɵɵadvance();
|
|
2924
|
+
i0.ɵɵconditional(ctx.IsLoading ? 63 : ctx.IsLoadingResults ? 64 : ctx.TotalGroupCount === 0 ? 65 : 66);
|
|
2925
|
+
i0.ɵɵadvance(4);
|
|
2926
|
+
i0.ɵɵconditional(ctx.IsSaving ? 67 : -1);
|
|
2663
2927
|
i0.ɵɵadvance();
|
|
2664
|
-
i0.ɵɵconditional(ctx.ComparisonGroup ?
|
|
2928
|
+
i0.ɵɵconditional(ctx.ComparisonGroup ? 68 : -1);
|
|
2665
2929
|
i0.ɵɵadvance();
|
|
2666
|
-
i0.ɵɵconditional(ctx.ShowMergeConfirm && ctx.ComparisonGroup ?
|
|
2667
|
-
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.NumberValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.MinValidator, i1.MaxValidator, i1.NgModel, i2.LoadingComponent], styles: ["/* ============================================================\n Duplicate Detection Kanban Board - Resource Component Styles\n All colors use MJ design tokens (--mj-*) exclusively.\n ============================================================ */\n\napp-duplicate-detection-resource {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n}\n\n.duplicate-detection-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 16px 20px;\n background: var(--mj-bg-page);\n position: relative;\n overflow: hidden;\n}\n\n/* ---- Page Header ---- */\n\n.page-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.page-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.page-title i {\n color: var(--mj-brand-primary);\n}\n\n/* ---- Header Actions ---- */\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.run-detection-controls {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.entity-doc-select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n min-width: 200px;\n}\n\n.entity-doc-select:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.run-detection-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n white-space: nowrap;\n}\n\n.run-detection-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.run-detection-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Detection Progress ---- */\n\n.detection-progress-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n padding: 14px 18px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.progress-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 8px;\n}\n\n.progress-stage {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.progress-percent {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.progress-bar-track {\n height: 6px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.progress-bar-fill {\n height: 100%;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n}\n\n.progress-current-item {\n display: block;\n margin-top: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---- Threshold Controls ---- */\n\n.threshold-controls {\n display: flex;\n gap: 24px;\n padding: 12px 16px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-status-info) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-subtle);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-slider-group {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.threshold-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.threshold-value {\n margin-left: auto;\n font-weight: 700;\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n}\n\n.threshold-slider {\n width: 100%;\n height: 4px;\n appearance: none;\n -webkit-appearance: none;\n background: var(--mj-border-default);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.threshold-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.threshold-hint {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n/* ---- Threshold Info (legacy) ---- */\n\n.threshold-info {\n display: flex;\n gap: 16px;\n padding: 8px 14px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-status-info) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-info-border);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-status-info-text);\n font-weight: 500;\n}\n\n.threshold-item i {\n font-size: 11px;\n}\n\n/* ---- KPI Strip ---- */\n\n.kpi-strip {\n display: flex;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.kpi-card {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.kpi-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.kpi-pending .kpi-value {\n color: var(--mj-status-warning);\n}\n\n.kpi-approved .kpi-value {\n color: var(--mj-status-success);\n}\n\n.kpi-rejected .kpi-value {\n color: var(--mj-status-error);\n}\n\n/* ---- Filter Bar ---- */\n\n.filter-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.filter-group {\n display: flex;\n align-items: flex-end;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.filter-select {\n height: 34px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n min-width: 160px;\n}\n\n.filter-select:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.filter-range {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.filter-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.filter-input {\n height: 34px;\n padding: 4px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n width: 100px;\n}\n\n.filter-input-score {\n width: 80px;\n}\n\n.filter-input-date {\n width: 140px;\n}\n\n.filter-input:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.clear-filters-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.clear-filters-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* ---- Loading & Empty States ---- */\n\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n gap: 8px;\n}\n\n.empty-icon {\n font-size: 48px;\n color: var(--mj-text-disabled);\n}\n\n.empty-text {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.empty-subtext {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin: 0;\n}\n\n/* ---- Kanban Board ---- */\n\n.kanban-board {\n display: flex;\n gap: 16px;\n flex: 1;\n min-height: 0;\n overflow-x: auto;\n}\n\n.kanban-column {\n flex: 1;\n min-width: 280px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.column-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-shrink: 0;\n}\n\n.column-header-pending {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n}\n\n.column-header-pending i {\n color: var(--mj-status-warning);\n}\n\n.column-header-approved {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n}\n\n.column-header-approved i {\n color: var(--mj-status-success);\n}\n\n.column-header-rejected {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n}\n\n.column-header-rejected i {\n color: var(--mj-status-error);\n}\n\n.column-title {\n flex: 1;\n}\n\n.column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.column-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.column-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n.column-empty i {\n font-size: 24px;\n}\n\n/* ---- Kanban Cards ---- */\n\n.kanban-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n transition: box-shadow 0.15s ease, border-color 0.15s ease;\n flex-shrink: 0; /* Prevent cards from shrinking \u2014 column scrolls instead */\n}\n\n.kanban-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n/* Drag and Drop */\n.kanban-card[draggable=\"true\"] {\n cursor: grab;\n}\n\n.kanban-card[draggable=\"true\"]:active {\n cursor: grabbing;\n}\n\n.drop-target-active {\n outline: 2px dashed var(--mj-brand-primary);\n outline-offset: -2px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface-card)) !important;\n}\n\n.drop-target-active .column-body {\n min-height: 100px;\n}\n\n.card-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n gap: 8px;\n}\n\n.card-header-left {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.card-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.card-title-block {\n min-width: 0;\n flex: 1;\n}\n\n.card-record-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-bottom: 2px;\n}\n\n.entity-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 3px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-text-muted);\n letter-spacing: 0.2px;\n}\n\n/* Score indicator colors */\n\n.score-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 40px;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 700;\n}\n\n.score-high {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.score-medium {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n.score-low {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.card-body {\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.match-summaries {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.match-summary-row {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.match-score {\n flex-shrink: 0;\n font-weight: 600;\n font-size: 11px;\n color: var(--mj-text-muted);\n min-width: 30px;\n}\n\n.match-name {\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.match-summary-more {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n padding-left: 38px;\n}\n\n.card-meta-row {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n border-top: 1px solid var(--mj-border-subtle);\n padding-top: 6px;\n}\n\n.card-meta-item {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.card-meta-item i {\n font-size: 10px;\n}\n font-size: 12px;\n max-width: 180px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Comparison Slide-In Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.slide-backdrop {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: fadeIn 0.2s ease;\n}\n\n.slide-backdrop.comparison-closing {\n animation: fadeOut 0.25s ease forwards;\n}\n\n@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }\n\n.comparison-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 82vw;\n max-width: 1300px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0,0,0,0.4);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.comparison-panel.comparison-closing {\n animation: slideOut 0.25s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }\n@keyframes slideOut { from { transform: translateX(0); } to { transform: translateX(100%); } }\n\n/* Header */\n.comparison-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 12px;\n}\n\n.comparison-header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.comparison-entity-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 1rem;\n flex-shrink: 0;\n}\n\n.comparison-title {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.comparison-entity-badge {\n display: inline-block;\n padding: 1px 7px;\n border-radius: 10px;\n font-size: 0.65rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n margin-right: 6px;\n}\n\n.comparison-match-count {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.comparison-header-right {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n}\n\n/* Toggle */\n.comparison-toggle {\n display: flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n}\n\n.toggle-btn {\n padding: 5px 12px;\n font-size: 0.7rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn:first-child {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.toggle-btn.toggle-active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.comparison-close-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n transition: all 0.15s ease;\n}\n\n.comparison-close-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Loading state */\n.comparison-loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Grid wrapper */\n.comparison-grid-wrapper {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* Grid */\n.comparison-grid {\n display: grid;\n min-width: 100%;\n}\n\n.comparison-grid > div {\n padding: 8px 12px;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n/* Corner cell */\n.grid-corner-cell {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 4;\n background: var(--mj-bg-surface-elevated);\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: flex-end;\n padding-bottom: 6px;\n}\n\n/* Column headers */\n.grid-col-header {\n position: sticky;\n top: 0;\n z-index: 3;\n background: var(--mj-bg-surface-elevated);\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.grid-col-source {\n border-left: 3px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface-elevated));\n}\n\n.col-header-label {\n font-size: 0.6rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n}\n\n.col-header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n}\n\n.col-header-name {\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-header-diff-count {\n font-size: 0.65rem;\n color: var(--mj-status-warning-text);\n}\n\n/* Surviving record selector */\n.surviving-selector {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n}\n\n.surviving-radio {\n appearance: none;\n width: 14px;\n height: 14px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.surviving-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2px var(--mj-bg-surface-elevated);\n}\n\n.surviving-label {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n\n.surviving-label.is-survivor {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* Use all fields button */\n.use-all-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 0.62rem;\n cursor: pointer;\n transition: all 0.12s ease;\n margin-top: 2px;\n}\n\n.use-all-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.use-all-btn.all-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* Per-match actions */\n.comparison-match-actions {\n display: flex;\n gap: 4px;\n margin-top: 3px;\n}\n\n.action-btn-sm {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid;\n border-radius: 5px;\n cursor: pointer;\n font-size: 0.65rem;\n transition: all 0.15s ease;\n}\n\n.approve-btn-sm {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n.approve-btn-sm:hover { background: rgba(34,197,94,0.25); }\n\n.reject-btn-sm {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n.reject-btn-sm:hover { background: rgba(239,68,68,0.25); }\n\n.match-status-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.68rem;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.status-approved {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.status-rejected {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.match-approved {\n border-top: 3px solid var(--mj-status-success);\n}\n\n.match-rejected {\n border-top: 3px solid var(--mj-status-error);\n opacity: 0.6;\n}\n\n/* Label cells */\n.grid-label-cell {\n position: sticky;\n left: 0;\n z-index: 2;\n background: var(--mj-bg-surface);\n font-size: 0.72rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n}\n\n.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n.grid-label-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n/* Value cells */\n.grid-value-cell {\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n line-height: 1.45;\n word-break: break-word;\n position: relative;\n cursor: pointer;\n}\n\n.grid-source-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, var(--mj-bg-surface));\n border-left: 3px solid transparent;\n}\n\n.grid-source-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface)));\n}\n\n.grid-source-cell.has-diff-in-row {\n font-weight: 600;\n}\n\n/* Diff highlighting */\n.value-same {\n color: var(--mj-text-muted);\n}\n\n.value-different {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, transparent) !important;\n border-left: 3px solid var(--mj-status-warning);\n color: var(--mj-text-primary);\n}\n\n.field-not-available {\n font-style: italic;\n font-size: 0.72rem;\n color: var(--mj-text-disabled);\n}\n\n/* Field selection radio */\n.field-select-radio {\n position: absolute;\n top: 50%;\n right: 8px;\n transform: translateY(-50%);\n appearance: none;\n width: 16px;\n height: 16px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.12s ease;\n opacity: 0.4;\n}\n\n.field-select-radio:hover {\n opacity: 0.8;\n}\n\n.field-select-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2.5px var(--mj-bg-surface);\n opacity: 1;\n}\n\n.grid-value-cell.field-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)) !important;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.grid-value-cell.field-selected .field-select-radio {\n opacity: 1;\n}\n\n/* Footer */\n.comparison-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 20px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.comparison-footer-left {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.comparison-summary {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.merge-summary {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.merge-summary i {\n font-size: 0.65rem;\n}\n\n.comparison-footer-right {\n display: flex;\n gap: 8px;\n}\n\n.comparison-footer-right .action-btn {\n flex: none;\n padding: 7px 14px;\n}\n\n.merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.merge-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.card-actions {\n display: flex;\n gap: 8px;\n padding: 10px 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.action-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 32px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n\n.action-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.approve-btn {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n\n.approve-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 20%, var(--mj-bg-surface));\n}\n\n.reject-btn {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n\n.reject-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n}\n\n/* ---- Responsive ---- */\n\n@media (max-width: 768px) {\n .kanban-board {\n flex-direction: column;\n }\n\n .kanban-column {\n min-width: auto;\n max-height: 400px;\n }\n}\n\n@media (max-width: 480px) {\n .kpi-strip {\n flex-direction: column;\n }\n\n .filter-bar {\n flex-wrap: wrap;\n }\n\n .filter-group {\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n }\n\n .filter-select {\n min-width: auto;\n width: 100%;\n }\n\n .filter-input {\n width: 100%;\n }\n\n .card-actions {\n flex-direction: column;\n }\n\n .action-btn {\n width: 100%;\n }\n}\n\n/* ---- Saving Overlay ---- */\n\n.saving-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-overlay);\n z-index: 10;\n border-radius: 8px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Dependencies Summary (in column headers)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.deps-summary {\n margin-top: 6px;\n padding: 6px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n font-size: 0.68rem;\n}\n\n.deps-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.deps-header i {\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-header:hover {\n color: var(--mj-text-primary);\n}\n\n.deps-total {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.72rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.deps-total i {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.deps-total-number {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 0.7rem;\n font-weight: 700;\n}\n\n.deps-total-recommended {\n font-size: 0.58rem;\n color: var(--mj-status-success-text);\n font-weight: 600;\n margin-left: 4px;\n}\n\n.deps-total-recommended i {\n color: var(--mj-status-success-text);\n}\n\n.deps-detail-list {\n margin-top: 4px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.deps-detail-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 3px 0;\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: background 0.1s ease;\n}\n\n.deps-detail-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.deps-detail-entity {\n display: flex;\n align-items: center;\n gap: 4px;\n color: var(--mj-text-secondary);\n}\n\n.deps-expand-icon {\n font-size: 0.5rem;\n width: 10px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n/* Individual dependency records list */\n.deps-records-list {\n padding-left: 14px;\n margin-bottom: 2px;\n}\n\n.deps-record-row {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 2px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: color 0.1s ease, background 0.1s ease;\n}\n\n.deps-record-row:hover {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.deps-record-icon {\n font-size: 0.5rem;\n flex-shrink: 0;\n}\n\n.deps-record-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 0.6rem;\n}\n\n.deps-record-loading {\n padding: 3px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-record-loading i {\n margin-right: 4px;\n}\n\n.deps-detail-count {\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Merge Confirmation Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-confirm-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 20000;\n animation: fadeIn 0.2s ease;\n}\n\n.merge-confirm-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 520px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0, 0, 0, 0.4);\n z-index: 20001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.merge-confirm-header {\n padding: 18px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.merge-confirm-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text);\n font-size: 1.1rem;\n flex-shrink: 0;\n}\n\n.merge-confirm-title {\n font-size: 1.05rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.merge-confirm-subtitle {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.merge-confirm-body {\n padding: 20px 24px;\n overflow-y: auto;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* Surviving record card */\n\n.merge-survivor-card {\n padding: 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n}\n\n.merge-survivor-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n margin-bottom: 4px;\n}\n\n.merge-survivor-label i {\n margin-right: 4px;\n}\n\n.merge-survivor-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.merge-survivor-pk {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 4px;\n font-size: 0.68rem;\n font-family: monospace;\n color: var(--mj-text-secondary);\n}\n\n.merge-survivor-pk i {\n font-size: 0.6rem;\n color: var(--mj-brand-primary);\n}\n\n.merge-survivor-detail {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n/* Cherry-picked fields section */\n\n.merge-section-label {\n font-size: 0.7rem;\n font-weight: 700;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 6px;\n}\n\n.merge-field-override {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.merge-field-name {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 110px;\n flex-shrink: 0;\n}\n\n.merge-field-value {\n color: var(--mj-text-primary);\n}\n\n.merge-field-source {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n margin-left: auto;\n white-space: nowrap;\n}\n\n/* Dependency transfer summary */\n\n.merge-deps-transfer {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.merge-deps-transfer-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.merge-deps-transfer-label i {\n margin-right: 4px;\n}\n\n.merge-deps-transfer-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 3px 0;\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n}\n\n.merge-deps-transfer-row i {\n color: var(--mj-brand-primary);\n font-size: 0.65rem;\n width: 14px;\n text-align: center;\n}\n\n/* Records to delete */\n\n.merge-delete-card {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n}\n\n.merge-delete-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-status-error-text);\n margin-bottom: 6px;\n}\n\n.merge-delete-label i {\n margin-right: 4px;\n}\n\n.merge-delete-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 5px 0;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.merge-delete-item:last-child {\n border-bottom: none;\n}\n\n.merge-delete-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.merge-delete-deps {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n/* Confirm footer */\n\n.merge-confirm-footer {\n padding: 14px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 10px;\n}\n\n.cancel-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n\n.cancel-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.confirm-merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.confirm-merge-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.confirm-merge-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Responsive: Merge Confirm ---- */\n\n@media (max-width: 600px) {\n .merge-confirm-panel {\n width: 100%;\n }\n}\n"], encapsulation: 2 });
|
|
2930
|
+
i0.ɵɵconditional(ctx.ShowMergeConfirm && ctx.ComparisonGroup ? 69 : -1);
|
|
2931
|
+
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i1.DefaultValueAccessor, i1.NumberValueAccessor, i1.SelectControlValueAccessor, i1.NgControlStatus, i1.MinValidator, i1.MaxValidator, i1.NgModel, i2.LoadingComponent], styles: ["/* ============================================================\n Duplicate Detection Kanban Board - Resource Component Styles\n All colors use MJ design tokens (--mj-*) exclusively.\n ============================================================ */\n\napp-duplicate-detection-resource {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n}\n\n.duplicate-detection-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 16px 20px;\n background: var(--mj-bg-page);\n position: relative;\n overflow: hidden;\n}\n\n/* ---- Page Header ---- */\n\n.page-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.page-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.page-title i {\n color: var(--mj-brand-primary);\n}\n\n/* ---- Header Actions ---- */\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.run-detection-controls {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.entity-doc-select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n min-width: 200px;\n}\n\n.entity-doc-select:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.run-detection-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n white-space: nowrap;\n}\n\n.run-detection-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.run-detection-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Detection Progress ---- */\n\n.detection-progress-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n padding: 14px 18px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.progress-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 8px;\n}\n\n.progress-stage {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.progress-percent {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.progress-bar-track {\n height: 6px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.progress-bar-fill {\n height: 100%;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n}\n\n.progress-current-item {\n display: block;\n margin-top: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---- Threshold Controls ---- */\n\n.threshold-controls {\n display: flex;\n gap: 24px;\n padding: 12px 16px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-status-info) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-subtle);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-slider-group {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.threshold-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.threshold-value {\n margin-left: auto;\n font-weight: 700;\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n}\n\n.threshold-slider {\n width: 100%;\n height: 4px;\n appearance: none;\n -webkit-appearance: none;\n background: var(--mj-border-default);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.threshold-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.threshold-hint {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n/* ---- Threshold Info (legacy) ---- */\n\n.threshold-info {\n display: flex;\n gap: 16px;\n padding: 8px 14px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-status-info) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-info-border);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-status-info-text);\n font-weight: 500;\n}\n\n.threshold-item i {\n font-size: 11px;\n}\n\n/* ---- KPI Strip ---- */\n\n.kpi-strip {\n display: flex;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.kpi-card {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.kpi-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.kpi-pending .kpi-value {\n color: var(--mj-status-warning);\n}\n\n.kpi-approved .kpi-value {\n color: var(--mj-status-success);\n}\n\n.kpi-rejected .kpi-value {\n color: var(--mj-status-error);\n}\n\n/* ---- Filter Bar ---- */\n\n.filter-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.filter-group {\n display: flex;\n align-items: flex-end;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.filter-select {\n height: 34px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n min-width: 160px;\n}\n\n.filter-select:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.filter-range {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.filter-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.filter-input {\n height: 34px;\n padding: 4px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n width: 100px;\n}\n\n.filter-input-score {\n width: 80px;\n}\n\n.filter-input-date {\n width: 140px;\n}\n\n.filter-input:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.clear-filters-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.clear-filters-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* ---- Loading & Empty States ---- */\n\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n gap: 8px;\n}\n\n.empty-icon {\n font-size: 48px;\n color: var(--mj-text-disabled);\n}\n\n.empty-text {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.empty-subtext {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin: 0;\n}\n\n/* ---- Kanban Board ---- */\n\n.kanban-board {\n display: flex;\n gap: 16px;\n flex: 1;\n min-height: 0;\n overflow-x: auto;\n}\n\n.kanban-column {\n flex: 1;\n min-width: 280px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.column-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-shrink: 0;\n}\n\n.column-header-pending {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n}\n\n.column-header-pending i {\n color: var(--mj-status-warning);\n}\n\n.column-header-approved {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n}\n\n.column-header-approved i {\n color: var(--mj-status-success);\n}\n\n.column-header-rejected {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n}\n\n.column-header-rejected i {\n color: var(--mj-status-error);\n}\n\n.column-title {\n flex: 1;\n}\n\n.column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.column-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.column-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n.column-empty i {\n font-size: 24px;\n}\n\n/* ---- Kanban Cards ---- */\n\n.kanban-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n transition: box-shadow 0.15s ease, border-color 0.15s ease;\n flex-shrink: 0; /* Prevent cards from shrinking \u2014 column scrolls instead */\n}\n\n.kanban-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n/* Drag and Drop */\n.kanban-card[draggable=\"true\"] {\n cursor: grab;\n}\n\n.kanban-card[draggable=\"true\"]:active {\n cursor: grabbing;\n}\n\n.drop-target-active {\n outline: 2px dashed var(--mj-brand-primary);\n outline-offset: -2px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface-card)) !important;\n}\n\n.drop-target-active .column-body {\n min-height: 100px;\n}\n\n.card-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n gap: 8px;\n}\n\n.card-header-left {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.card-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.card-title-block {\n min-width: 0;\n flex: 1;\n}\n\n.card-record-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-bottom: 2px;\n}\n\n.entity-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 3px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-text-muted);\n letter-spacing: 0.2px;\n}\n\n/* Score indicator colors */\n\n.score-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 40px;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 700;\n}\n\n.score-high {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.score-medium {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n.score-low {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.card-body {\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.match-summaries {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.match-summary-row {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.match-score {\n flex-shrink: 0;\n font-weight: 600;\n font-size: 11px;\n color: var(--mj-text-muted);\n min-width: 30px;\n}\n\n.match-name {\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.match-summary-more {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n padding-left: 38px;\n}\n\n.card-meta-row {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n border-top: 1px solid var(--mj-border-subtle);\n padding-top: 6px;\n}\n\n.card-meta-item {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.card-meta-item i {\n font-size: 10px;\n}\n font-size: 12px;\n max-width: 180px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Comparison Slide-In Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.slide-backdrop {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: fadeIn 0.2s ease;\n}\n\n.slide-backdrop.comparison-closing {\n animation: fadeOut 0.25s ease forwards;\n}\n\n@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }\n\n.comparison-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 82vw;\n max-width: 1300px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0,0,0,0.4);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.comparison-panel.comparison-closing {\n animation: slideOut 0.25s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }\n@keyframes slideOut { from { transform: translateX(0); } to { transform: translateX(100%); } }\n\n/* Header */\n.comparison-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 12px;\n}\n\n.comparison-header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.comparison-entity-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 1rem;\n flex-shrink: 0;\n}\n\n.comparison-title {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.comparison-entity-badge {\n display: inline-block;\n padding: 1px 7px;\n border-radius: 10px;\n font-size: 0.65rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n margin-right: 6px;\n}\n\n.comparison-match-count {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.comparison-header-right {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n}\n\n/* Toggle */\n.comparison-toggle {\n display: flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n}\n\n.toggle-btn {\n padding: 5px 12px;\n font-size: 0.7rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn:first-child {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.toggle-btn.toggle-active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.comparison-close-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n transition: all 0.15s ease;\n}\n\n.comparison-close-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Loading state */\n.comparison-loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Grid wrapper */\n.comparison-grid-wrapper {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* Grid */\n.comparison-grid {\n display: grid;\n min-width: 100%;\n}\n\n.comparison-grid > div {\n padding: 8px 12px;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n/* Corner cell */\n.grid-corner-cell {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 4;\n background: var(--mj-bg-surface-elevated);\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: flex-end;\n padding-bottom: 6px;\n}\n\n/* Column headers */\n.grid-col-header {\n position: sticky;\n top: 0;\n z-index: 3;\n background: var(--mj-bg-surface-elevated);\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.grid-col-source {\n border-left: 3px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface-elevated));\n}\n\n.col-header-label {\n font-size: 0.6rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n}\n\n.col-header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n}\n\n.col-header-name {\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-header-diff-count {\n font-size: 0.65rem;\n color: var(--mj-status-warning-text);\n}\n\n/* Surviving record selector */\n.surviving-selector {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n}\n\n.surviving-radio {\n appearance: none;\n width: 14px;\n height: 14px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.surviving-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2px var(--mj-bg-surface-elevated);\n}\n\n.surviving-label {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n\n.surviving-label.is-survivor {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* Use all fields button */\n.use-all-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 0.62rem;\n cursor: pointer;\n transition: all 0.12s ease;\n margin-top: 2px;\n}\n\n.use-all-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.use-all-btn.all-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* Per-match actions */\n.comparison-match-actions {\n display: flex;\n gap: 4px;\n margin-top: 3px;\n}\n\n.action-btn-sm {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid;\n border-radius: 5px;\n cursor: pointer;\n font-size: 0.65rem;\n transition: all 0.15s ease;\n}\n\n.approve-btn-sm {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n.approve-btn-sm:hover { background: rgba(34,197,94,0.25); }\n\n.reject-btn-sm {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n.reject-btn-sm:hover { background: rgba(239,68,68,0.25); }\n\n.match-status-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.68rem;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.status-approved {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.status-rejected {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.match-approval-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.match-action-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n border-radius: 6px;\n font-size: 0.7rem;\n font-weight: 500;\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n\n.match-skip-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-status-error);\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-border-default));\n}\n\n.match-skip-btn:hover {\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error);\n}\n\n.match-undo-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.match-undo-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.match-approved {\n border-top: 3px solid var(--mj-status-success);\n}\n\n.match-rejected {\n border-top: 3px solid var(--mj-status-error);\n opacity: 0.6;\n}\n\n/* Label cells */\n.grid-label-cell {\n position: sticky;\n left: 0;\n z-index: 2;\n background: var(--mj-bg-surface);\n font-size: 0.72rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n}\n\n.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n.grid-label-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n/* Value cells */\n.grid-value-cell {\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n line-height: 1.45;\n word-break: break-word;\n position: relative;\n cursor: pointer;\n}\n\n.grid-source-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, var(--mj-bg-surface));\n border-left: 3px solid transparent;\n}\n\n.grid-source-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface)));\n}\n\n.grid-source-cell.has-diff-in-row {\n font-weight: 600;\n}\n\n/* Diff highlighting */\n.value-same {\n color: var(--mj-text-muted);\n}\n\n.value-different {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, transparent) !important;\n border-left: 3px solid var(--mj-status-warning);\n color: var(--mj-text-primary);\n}\n\n.field-not-available {\n font-style: italic;\n font-size: 0.72rem;\n color: var(--mj-text-disabled);\n}\n\n/* Field selection radio */\n.field-select-radio {\n position: absolute;\n top: 50%;\n right: 8px;\n transform: translateY(-50%);\n appearance: none;\n width: 16px;\n height: 16px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.12s ease;\n opacity: 0.4;\n}\n\n.field-select-radio:hover {\n opacity: 0.8;\n}\n\n.field-select-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2.5px var(--mj-bg-surface);\n opacity: 1;\n}\n\n.grid-value-cell.field-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)) !important;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.grid-value-cell.field-selected .field-select-radio {\n opacity: 1;\n}\n\n/* Footer */\n.comparison-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 20px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.comparison-footer-left {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.comparison-summary {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.merge-summary {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.merge-summary i {\n font-size: 0.65rem;\n}\n\n.comparison-footer-right {\n display: flex;\n gap: 8px;\n}\n\n.comparison-footer-right .action-btn {\n flex: none;\n padding: 7px 14px;\n}\n\n.merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.merge-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.card-actions {\n display: flex;\n gap: 8px;\n padding: 10px 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.action-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 32px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n\n.action-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.approve-btn {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n\n.approve-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 20%, var(--mj-bg-surface));\n}\n\n.reject-btn {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n\n.reject-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n}\n\n/* ---- Responsive ---- */\n\n@media (max-width: 768px) {\n .kanban-board {\n flex-direction: column;\n }\n\n .kanban-column {\n min-width: auto;\n max-height: 400px;\n }\n}\n\n@media (max-width: 480px) {\n .kpi-strip {\n flex-direction: column;\n }\n\n .filter-bar {\n flex-wrap: wrap;\n }\n\n .filter-group {\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n }\n\n .filter-select {\n min-width: auto;\n width: 100%;\n }\n\n .filter-input {\n width: 100%;\n }\n\n .card-actions {\n flex-direction: column;\n }\n\n .action-btn {\n width: 100%;\n }\n}\n\n/* ---- Saving Overlay ---- */\n\n.saving-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-overlay);\n z-index: 10;\n border-radius: 8px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Dependencies Summary (in column headers)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.deps-summary {\n margin-top: 6px;\n padding: 6px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n font-size: 0.68rem;\n}\n\n.deps-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.deps-header i {\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-header:hover {\n color: var(--mj-text-primary);\n}\n\n.deps-total {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.72rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.deps-total i {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.deps-total-number {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 0.7rem;\n font-weight: 700;\n}\n\n.deps-total-recommended {\n font-size: 0.58rem;\n color: var(--mj-status-success-text);\n font-weight: 600;\n margin-left: 4px;\n}\n\n.deps-total-recommended i {\n color: var(--mj-status-success-text);\n}\n\n.deps-detail-list {\n margin-top: 4px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.deps-detail-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 3px 0;\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: background 0.1s ease;\n}\n\n.deps-detail-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.deps-detail-entity {\n display: flex;\n align-items: center;\n gap: 4px;\n color: var(--mj-text-secondary);\n}\n\n.deps-expand-icon {\n font-size: 0.5rem;\n width: 10px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n/* Individual dependency records list */\n.deps-records-list {\n padding-left: 14px;\n margin-bottom: 2px;\n}\n\n.deps-record-row {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 2px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: color 0.1s ease, background 0.1s ease;\n}\n\n.deps-record-row:hover {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.deps-record-icon {\n font-size: 0.5rem;\n flex-shrink: 0;\n}\n\n.deps-record-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 0.6rem;\n}\n\n.deps-record-loading {\n padding: 3px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-record-loading i {\n margin-right: 4px;\n}\n\n.deps-detail-count {\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Merge Confirmation Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-confirm-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 20000;\n animation: fadeIn 0.2s ease;\n}\n\n.merge-confirm-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 520px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0, 0, 0, 0.4);\n z-index: 20001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.merge-confirm-header {\n padding: 18px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.merge-confirm-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text);\n font-size: 1.1rem;\n flex-shrink: 0;\n}\n\n.merge-confirm-title {\n font-size: 1.05rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.merge-confirm-subtitle {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.merge-confirm-body {\n padding: 20px 24px;\n overflow-y: auto;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* Surviving record card */\n\n.merge-survivor-card {\n padding: 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n}\n\n.merge-survivor-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n margin-bottom: 4px;\n}\n\n.merge-survivor-label i {\n margin-right: 4px;\n}\n\n.merge-survivor-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.merge-survivor-pk {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 4px;\n font-size: 0.68rem;\n font-family: monospace;\n color: var(--mj-text-secondary);\n}\n\n.merge-survivor-pk i {\n font-size: 0.6rem;\n color: var(--mj-brand-primary);\n}\n\n.merge-survivor-detail {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n/* Cherry-picked fields section */\n\n.merge-section-label {\n font-size: 0.7rem;\n font-weight: 700;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 6px;\n}\n\n.merge-field-override {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.merge-field-name {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 110px;\n flex-shrink: 0;\n}\n\n.merge-field-value {\n color: var(--mj-text-primary);\n}\n\n.merge-field-source {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n margin-left: auto;\n white-space: nowrap;\n}\n\n/* Dependency transfer summary */\n\n.merge-deps-transfer {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.merge-deps-transfer-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.merge-deps-transfer-label i {\n margin-right: 4px;\n}\n\n.merge-deps-transfer-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 3px 0;\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n}\n\n.merge-deps-transfer-row i {\n color: var(--mj-brand-primary);\n font-size: 0.65rem;\n width: 14px;\n text-align: center;\n}\n\n/* Records to delete */\n\n.merge-delete-card {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n}\n\n.merge-delete-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-status-error-text);\n margin-bottom: 6px;\n}\n\n.merge-delete-label i {\n margin-right: 4px;\n}\n\n.merge-delete-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 5px 0;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.merge-delete-item:last-child {\n border-bottom: none;\n}\n\n.merge-delete-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.merge-delete-deps {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n/* Confirm footer */\n\n.merge-confirm-footer {\n padding: 14px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 10px;\n}\n\n.cancel-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n\n.cancel-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.confirm-merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.confirm-merge-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.confirm-merge-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Responsive: Merge Confirm ---- */\n\n@media (max-width: 600px) {\n .merge-confirm-panel {\n width: 100%;\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 Merge Disabled Hint \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-disabled-hint {\n font-size: 11.5px;\n color: var(--mj-status-warning-text, #e65100);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-left: 4px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 Merge Warning Banner (inline, non-blocking) \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-warning-banner {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n margin-bottom: 12px;\n border-radius: 6px;\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n font-size: 13px;\n font-weight: 500;\n flex-shrink: 0;\n}\n\n.merge-warning-banner i {\n font-size: 14px;\n flex-shrink: 0;\n}\n"], encapsulation: 2 });
|
|
2668
2932
|
};
|
|
2669
2933
|
DuplicateDetectionResourceComponent = __decorate([
|
|
2670
2934
|
RegisterClass(BaseResourceComponent, 'DuplicateDetectionResource')
|
|
@@ -2672,8 +2936,11 @@ DuplicateDetectionResourceComponent = __decorate([
|
|
|
2672
2936
|
export { DuplicateDetectionResourceComponent };
|
|
2673
2937
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DuplicateDetectionResourceComponent, [{
|
|
2674
2938
|
type: Component,
|
|
2675
|
-
args: [{ standalone: false, selector: 'app-duplicate-detection-resource', encapsulation: ViewEncapsulation.None, template: "<div class=\"duplicate-detection-container\">\n <!-- Header -->\n <div class=\"page-header\">\n <div class=\"header-left\">\n <h2 class=\"page-title\">\n <i class=\"fa-solid fa-clone\"></i> Duplicate Detection\n </h2>\n </div>\n <div class=\"header-actions\">\n <div class=\"run-detection-controls\">\n <select class=\"entity-doc-select\"\n [(ngModel)]=\"SelectedEntityDocumentID\"\n [disabled]=\"IsDetecting\">\n <option value=\"\">Select entity document...</option>\n @for (doc of EntityDocuments; track doc.ID) {\n <option [value]=\"doc.ID\">{{ doc.Name }} ({{ doc.EntityName }})</option>\n }\n </select>\n <button class=\"run-detection-btn\"\n (click)=\"RunDetection()\"\n [disabled]=\"IsDetecting || !SelectedEntityDocumentID\">\n @if (IsDetecting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Detecting...\n } @else {\n <i class=\"fa-solid fa-magnifying-glass\"></i> Run Detection\n }\n </button>\n </div>\n </div>\n </div>\n\n <!-- Detection Progress (visible during run) -->\n @if (IsDetecting) {\n <div class=\"detection-progress-section\">\n <div class=\"progress-header\">\n <span class=\"progress-stage\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n {{ DetectionStage }}\n </span>\n <span class=\"progress-percent\">{{ DetectionProgress }}%</span>\n </div>\n <div class=\"progress-bar-track\">\n <div class=\"progress-bar-fill\" [style.width.%]=\"DetectionProgress\"></div>\n </div>\n @if (DetectionCurrentItem) {\n <span class=\"progress-current-item\">{{ DetectionCurrentItem }}</span>\n }\n </div>\n }\n\n <!-- Threshold Controls (when entity doc selected) -->\n @if (SelectedDocumentThresholds) {\n <div class=\"threshold-controls\">\n <div class=\"threshold-slider-group\">\n <label class=\"threshold-label\">\n <i class=\"fa-solid fa-adjust\"></i>\n Potential Match\n <span class=\"threshold-value\">{{ (RunPotentialThreshold * 100).toFixed(0) }}%</span>\n </label>\n <input type=\"range\" class=\"threshold-slider\"\n [min]=\"30\" [max]=\"99\" [step]=\"1\"\n [value]=\"RunPotentialThreshold * 100\"\n (input)=\"OnPotentialThresholdChanged($any($event.target).value / 100)\"\n [disabled]=\"IsDetecting\" />\n <span class=\"threshold-hint\">Score above which duplicates are flagged for review</span>\n </div>\n <div class=\"threshold-slider-group\">\n <label class=\"threshold-label\">\n <i class=\"fa-solid fa-bullseye\"></i>\n Absolute Match\n <span class=\"threshold-value\">{{ (RunAbsoluteThreshold * 100).toFixed(0) }}%</span>\n </label>\n <input type=\"range\" class=\"threshold-slider\"\n [min]=\"50\" [max]=\"100\" [step]=\"1\"\n [value]=\"RunAbsoluteThreshold * 100\"\n (input)=\"OnAbsoluteThresholdChanged($any($event.target).value / 100)\"\n [disabled]=\"IsDetecting\" />\n <span class=\"threshold-hint\">Score above which duplicates are auto-confirmed</span>\n </div>\n </div>\n }\n\n <!-- KPI Strip -->\n <div class=\"kpi-strip\">\n <div class=\"kpi-card\">\n <div class=\"kpi-value\">{{ TotalGroupCount }}</div>\n <div class=\"kpi-label\">Total Groups</div>\n </div>\n <div class=\"kpi-card kpi-pending\">\n <div class=\"kpi-value\">{{ PendingCount }}</div>\n <div class=\"kpi-label\">Pending</div>\n </div>\n <div class=\"kpi-card kpi-approved\">\n <div class=\"kpi-value\">{{ ApprovedCount }}</div>\n <div class=\"kpi-label\">Approved</div>\n </div>\n <div class=\"kpi-card kpi-rejected\">\n <div class=\"kpi-value\">{{ RejectedCount }}</div>\n <div class=\"kpi-label\">Rejected</div>\n </div>\n </div>\n\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"filter-group\">\n <select class=\"filter-select\"\n [(ngModel)]=\"Filters.EntityName\"\n (ngModelChange)=\"OnFilterChange()\"\n [disabled]=\"EntityNames.length <= 1\">\n @if (EntityNames.length > 1) {\n <option value=\"\">All Entities</option>\n }\n @for (name of EntityNames; track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">Min Score</label>\n <input type=\"number\"\n class=\"filter-input filter-input-score\"\n min=\"0\" max=\"1\" step=\"0.05\"\n [placeholder]=\"DataMinScore\"\n [(ngModel)]=\"Filters.MinScore\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">Max Score</label>\n <input type=\"number\"\n class=\"filter-input filter-input-score\"\n min=\"0\" max=\"1\" step=\"0.05\"\n [placeholder]=\"DataMaxScore\"\n [(ngModel)]=\"Filters.MaxScore\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">From</label>\n <input type=\"date\"\n class=\"filter-input filter-input-date\"\n [min]=\"DataMinDate\" [max]=\"DataMaxDate\"\n [(ngModel)]=\"Filters.DateFrom\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">To</label>\n <input type=\"date\"\n class=\"filter-input filter-input-date\"\n [min]=\"DataMinDate\" [max]=\"DataMaxDate\"\n [(ngModel)]=\"Filters.DateTo\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n </div>\n\n @if (HasActiveFilters) {\n <button class=\"clear-filters-btn\" (click)=\"ClearFilters()\">\n <i class=\"fa-solid fa-times\"></i> Clear Filters\n </button>\n }\n </div>\n\n <!-- Content -->\n @if (IsLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading duplicate detection results...\"></mj-loading>\n </div>\n } @else if (TotalGroupCount === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-clone empty-icon\"></i>\n <p class=\"empty-text\">No duplicate detection results found.</p>\n <p class=\"empty-subtext\">Select an entity document and click \"Run Detection\" to start.</p>\n </div>\n } @else {\n <!-- Kanban Board -->\n <div class=\"kanban-board\">\n <!-- Pending Column -->\n <div class=\"kanban-column\" [class.drop-target-active]=\"DragOverColumn === 'Pending' && DraggedGroup?.ApprovalStatus !== 'Pending'\">\n <div class=\"column-header column-header-pending\">\n <i class=\"fa-solid fa-clock\"></i>\n <span class=\"column-title\">Pending Review</span>\n <span class=\"column-count\">{{ PendingCount }}</span>\n </div>\n <div class=\"column-body\"\n (dragover)=\"OnDragOver($event, 'Pending')\"\n (dragleave)=\"OnDragLeave($event, 'Pending')\"\n (drop)=\"OnDrop($event, 'Pending')\">\n @for (group of PendingGroups; track group.DetailId) {\n <div class=\"kanban-card\"\n draggable=\"true\"\n (dragstart)=\"OnDragStart($event, group)\"\n (dragend)=\"OnDragEnd()\"\n (click)=\"OpenComparison(group)\">\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon\">\n <i [class]=\"group.EntityIcon\"></i>\n </div>\n <div class=\"card-title-block\">\n <div class=\"card-record-name\" [title]=\"group.RecordName\">{{ group.RecordName }}</div>\n <span class=\"entity-badge\">{{ group.EntityName }}</span>\n </div>\n </div>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(group.HighestScore)\">\n {{ (group.HighestScore * 100).toFixed(0) }}%\n </span>\n </div>\n <div class=\"card-body\">\n @if (group.TopMatchSummaries.length > 0) {\n <div class=\"match-summaries\">\n @for (ms of group.TopMatchSummaries; track ms.Name) {\n <div class=\"match-summary-row\">\n <span class=\"match-score\">{{ (ms.Score * 100).toFixed(0) }}%</span>\n <span class=\"match-name\">{{ ms.Name }}</span>\n </div>\n }\n @if (group.MatchCount > group.TopMatchSummaries.length) {\n <div class=\"match-summary-more\">+{{ group.MatchCount - group.TopMatchSummaries.length }} more</div>\n }\n </div>\n }\n <div class=\"card-meta-row\">\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n {{ group.MatchCount }} match{{ group.MatchCount !== 1 ? 'es' : '' }}\n </span>\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(group.MatchedAt) }}\n </span>\n </div>\n </div>\n <div class=\"card-actions\">\n <button class=\"action-btn approve-btn\"\n [disabled]=\"IsSaving\"\n (click)=\"ApproveMatch(group); $event.stopPropagation()\">\n <i class=\"fa-solid fa-check\"></i> Approve\n </button>\n <button class=\"action-btn reject-btn\"\n [disabled]=\"IsSaving\"\n (click)=\"RejectMatch(group); $event.stopPropagation()\">\n <i class=\"fa-solid fa-times\"></i> Reject\n </button>\n </div>\n </div>\n }\n @if (PendingGroups.length === 0) {\n <div class=\"column-empty\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span>No pending items</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Approved Column -->\n <div class=\"kanban-column\" [class.drop-target-active]=\"DragOverColumn === 'Approved' && DraggedGroup?.ApprovalStatus !== 'Approved'\">\n <div class=\"column-header column-header-approved\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span class=\"column-title\">Approved</span>\n <span class=\"column-count\">{{ ApprovedCount }}</span>\n </div>\n <div class=\"column-body\"\n (dragover)=\"OnDragOver($event, 'Approved')\"\n (dragleave)=\"OnDragLeave($event, 'Approved')\"\n (drop)=\"OnDrop($event, 'Approved')\">\n @for (group of ApprovedGroups; track group.DetailId) {\n <div class=\"kanban-card\"\n draggable=\"true\"\n (dragstart)=\"OnDragStart($event, group)\"\n (dragend)=\"OnDragEnd()\"\n (click)=\"OpenComparison(group)\">\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon\">\n <i [class]=\"group.EntityIcon\"></i>\n </div>\n <div class=\"card-title-block\">\n <div class=\"card-record-name\" [title]=\"group.RecordName\">{{ group.RecordName }}</div>\n <span class=\"entity-badge\">{{ group.EntityName }}</span>\n </div>\n </div>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(group.HighestScore)\">\n {{ (group.HighestScore * 100).toFixed(0) }}%\n </span>\n </div>\n <div class=\"card-body\">\n @if (group.TopMatchSummaries.length > 0) {\n <div class=\"match-summaries\">\n @for (ms of group.TopMatchSummaries; track ms.Name) {\n <div class=\"match-summary-row\">\n <span class=\"match-score\">{{ (ms.Score * 100).toFixed(0) }}%</span>\n <span class=\"match-name\">{{ ms.Name }}</span>\n </div>\n }\n @if (group.MatchCount > group.TopMatchSummaries.length) {\n <div class=\"match-summary-more\">+{{ group.MatchCount - group.TopMatchSummaries.length }} more</div>\n }\n </div>\n }\n <div class=\"card-meta-row\">\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n {{ group.MatchCount }} match{{ group.MatchCount !== 1 ? 'es' : '' }}\n </span>\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(group.MatchedAt) }}\n </span>\n </div>\n </div>\n </div>\n }\n @if (ApprovedGroups.length === 0) {\n <div class=\"column-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No approved items</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Rejected Column -->\n <div class=\"kanban-column\" [class.drop-target-active]=\"DragOverColumn === 'Rejected' && DraggedGroup?.ApprovalStatus !== 'Rejected'\">\n <div class=\"column-header column-header-rejected\">\n <i class=\"fa-solid fa-ban\"></i>\n <span class=\"column-title\">Rejected</span>\n <span class=\"column-count\">{{ RejectedCount }}</span>\n </div>\n <div class=\"column-body\"\n (dragover)=\"OnDragOver($event, 'Rejected')\"\n (dragleave)=\"OnDragLeave($event, 'Rejected')\"\n (drop)=\"OnDrop($event, 'Rejected')\">\n @for (group of RejectedGroups; track group.DetailId) {\n <div class=\"kanban-card\"\n draggable=\"true\"\n (dragstart)=\"OnDragStart($event, group)\"\n (dragend)=\"OnDragEnd()\"\n (click)=\"OpenComparison(group)\">\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon\">\n <i [class]=\"group.EntityIcon\"></i>\n </div>\n <div class=\"card-title-block\">\n <div class=\"card-record-name\" [title]=\"group.RecordName\">{{ group.RecordName }}</div>\n <span class=\"entity-badge\">{{ group.EntityName }}</span>\n </div>\n </div>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(group.HighestScore)\">\n {{ (group.HighestScore * 100).toFixed(0) }}%\n </span>\n </div>\n <div class=\"card-body\">\n @if (group.TopMatchSummaries.length > 0) {\n <div class=\"match-summaries\">\n @for (ms of group.TopMatchSummaries; track ms.Name) {\n <div class=\"match-summary-row\">\n <span class=\"match-score\">{{ (ms.Score * 100).toFixed(0) }}%</span>\n <span class=\"match-name\">{{ ms.Name }}</span>\n </div>\n }\n @if (group.MatchCount > group.TopMatchSummaries.length) {\n <div class=\"match-summary-more\">+{{ group.MatchCount - group.TopMatchSummaries.length }} more</div>\n }\n </div>\n }\n <div class=\"card-meta-row\">\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n {{ group.MatchCount }} match{{ group.MatchCount !== 1 ? 'es' : '' }}\n </span>\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(group.MatchedAt) }}\n </span>\n </div>\n </div>\n </div>\n }\n @if (RejectedGroups.length === 0) {\n <div class=\"column-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No rejected items</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Saving overlay -->\n @if (IsSaving) {\n <div class=\"saving-overlay\">\n <mj-loading text=\"Saving...\" size=\"small\"></mj-loading>\n </div>\n }\n\n <!-- \u2550\u2550\u2550 Comparison Slide-In Panel \u2550\u2550\u2550 -->\n @if (ComparisonGroup) {\n <div class=\"slide-backdrop\" [class.comparison-closing]=\"ComparisonClosing\" (click)=\"CloseComparison()\"></div>\n <div class=\"comparison-panel\" [class.comparison-closing]=\"ComparisonClosing\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"comparison-header\">\n <div class=\"comparison-header-left\">\n <div class=\"comparison-entity-icon\">\n <i [class]=\"ComparisonGroup.EntityIcon\"></i>\n </div>\n <div>\n <div class=\"comparison-title\">{{ ComparisonGroup.RecordName }}</div>\n <span class=\"comparison-entity-badge\">{{ ComparisonGroup.EntityName }}</span>\n <span class=\"comparison-match-count\">\n {{ ComparisonGroup.MatchCount }} potential duplicate{{ ComparisonGroup.MatchCount !== 1 ? 's' : '' }}\n </span>\n </div>\n </div>\n <div class=\"comparison-header-right\">\n <div class=\"comparison-toggle\">\n <button class=\"toggle-btn\" [class.toggle-active]=\"ComparisonShowAllFields\"\n (click)=\"ComparisonShowAllFields = true\">All Fields</button>\n <button class=\"toggle-btn\" [class.toggle-active]=\"!ComparisonShowAllFields\"\n (click)=\"ComparisonShowAllFields = false\">Differences Only</button>\n </div>\n <button class=\"comparison-close-btn\" (click)=\"CloseComparison()\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n\n <!-- Grid -->\n @if (ComparisonLoading) {\n <div class=\"comparison-loading\">\n <mj-loading text=\"Loading records for comparison...\" size=\"medium\"></mj-loading>\n </div>\n }\n <div class=\"comparison-grid-wrapper\" [hidden]=\"ComparisonLoading\">\n <div class=\"comparison-grid\"\n [style.grid-template-columns]=\"'160px repeat(' + (1 + ComparisonMatches.length) + ', minmax(180px, 1fr))'\">\n\n <!-- Corner cell -->\n <div class=\"grid-corner-cell\">Field</div>\n\n <!-- Source column header -->\n <div class=\"grid-col-header grid-col-source\">\n <span class=\"col-header-label\">Source</span>\n <span class=\"col-header-name\">{{ ComparisonGroup.RecordName }}</span>\n <div class=\"surviving-selector\">\n <input type=\"radio\" name=\"survivor\" class=\"surviving-radio\"\n [checked]=\"SurvivorColumnIndex === 0\"\n (change)=\"SetSurvivor(0)\">\n <span class=\"surviving-label\" [class.is-survivor]=\"SurvivorColumnIndex === 0\">\n {{ SurvivorColumnIndex === 0 ? 'Surviving Record' : 'Set as survivor' }}\n </span>\n </div>\n <button class=\"use-all-btn\" [class.all-selected]=\"AllFieldsSelectedFrom(0)\"\n (click)=\"UseAllFieldsFrom(0)\">\n <i class=\"fa-solid\" [class.fa-check-double]=\"AllFieldsSelectedFrom(0)\" [class.fa-clone]=\"!AllFieldsSelectedFrom(0)\"></i>\n {{ AllFieldsSelectedFrom(0) ? 'Using all fields' : 'Use all fields' }}\n </button>\n <!-- Dependencies Summary -->\n <div class=\"deps-summary\">\n <div class=\"deps-total\">\n <i class=\"fa-solid fa-link\"></i>\n <span class=\"deps-total-number\">{{ GetTotalDeps(0) }}</span>\n {{ GetTotalDeps(0) === 1 ? 'dependency' : 'dependencies' }}\n @if (GetMaxDepsColumnIndex() === 0 && GetTotalDeps(0) > 0) {\n <span class=\"deps-total-recommended\"><i class=\"fa-solid fa-star\"></i> Most deps</span>\n }\n </div>\n @if (GetGroupedDeps(0).length > 0) {\n <div class=\"deps-header\" (click)=\"ToggleDepsExpanded(0)\">\n <span>{{ IsDepsExpanded(0) ? 'Hide details' : 'Show details' }}</span>\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!IsDepsExpanded(0)\" [class.fa-chevron-up]=\"IsDepsExpanded(0)\"></i>\n </div>\n @if (IsDepsExpanded(0)) {\n <div class=\"deps-detail-list\">\n @for (dep of GetGroupedDeps(0); track dep.Entity) {\n <div class=\"deps-detail-group\">\n <div class=\"deps-detail-row\" (click)=\"ToggleDepEntityGroup(0, dep.Entity); $event.stopPropagation()\">\n <span class=\"deps-detail-entity\">\n <i class=\"fa-solid deps-expand-icon\"\n [class.fa-chevron-right]=\"!IsDepEntityGroupExpanded(0, dep.Entity)\"\n [class.fa-chevron-down]=\"IsDepEntityGroupExpanded(0, dep.Entity)\"></i>\n {{ dep.Entity }}\n </span>\n <span class=\"deps-detail-count\">{{ dep.Count }}</span>\n </div>\n @if (IsDepEntityGroupExpanded(0, dep.Entity)) {\n <div class=\"deps-records-list\">\n @if (IsDepRecordsLoading(0, dep.Entity)) {\n <div class=\"deps-record-loading\"><i class=\"fa-solid fa-spinner fa-spin\"></i> Loading...</div>\n }\n @for (record of GetDepRecords(0, dep.Entity); track $index) {\n <div class=\"deps-record-row\" (click)=\"OpenDepRecord(record); $event.stopPropagation()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square deps-record-icon\"></i>\n <span class=\"deps-record-name\">{{ record.Name }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Match column headers -->\n @for (match of ComparisonMatches; track match.Match.ID; let mi = $index) {\n <div class=\"grid-col-header\"\n [class.match-approved]=\"match.Match.ApprovalStatus === 'Approved'\"\n [class.match-rejected]=\"match.Match.ApprovalStatus === 'Rejected'\">\n <div class=\"col-header-top\">\n <span class=\"col-header-name\">{{ match.Name }}</span>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(match.Score)\">\n {{ (match.Score * 100).toFixed(0) }}%\n </span>\n </div>\n <span class=\"col-header-diff-count\">{{ match.DiffCount }} difference{{ match.DiffCount !== 1 ? 's' : '' }}</span>\n <div class=\"surviving-selector\">\n <input type=\"radio\" name=\"survivor\" class=\"surviving-radio\"\n [checked]=\"SurvivorColumnIndex === mi + 1\"\n (change)=\"SetSurvivor(mi + 1)\">\n <span class=\"surviving-label\" [class.is-survivor]=\"SurvivorColumnIndex === mi + 1\">\n {{ SurvivorColumnIndex === mi + 1 ? 'Surviving Record' : 'Set as survivor' }}\n </span>\n </div>\n <button class=\"use-all-btn\" [class.all-selected]=\"AllFieldsSelectedFrom(mi + 1)\"\n (click)=\"UseAllFieldsFrom(mi + 1)\">\n <i class=\"fa-solid\" [class.fa-check-double]=\"AllFieldsSelectedFrom(mi + 1)\" [class.fa-clone]=\"!AllFieldsSelectedFrom(mi + 1)\"></i>\n {{ AllFieldsSelectedFrom(mi + 1) ? 'Using all fields' : 'Use all fields' }}\n </button>\n <!-- Dependencies Summary -->\n <div class=\"deps-summary\">\n <div class=\"deps-total\">\n <i class=\"fa-solid fa-link\"></i>\n <span class=\"deps-total-number\">{{ GetTotalDeps(mi + 1) }}</span>\n {{ GetTotalDeps(mi + 1) === 1 ? 'dependency' : 'dependencies' }}\n @if (GetMaxDepsColumnIndex() === mi + 1 && GetTotalDeps(mi + 1) > 0) {\n <span class=\"deps-total-recommended\"><i class=\"fa-solid fa-star\"></i> Most deps</span>\n }\n </div>\n @if (GetGroupedDeps(mi + 1).length > 0) {\n <div class=\"deps-header\" (click)=\"ToggleDepsExpanded(mi + 1)\">\n <span>{{ IsDepsExpanded(mi + 1) ? 'Hide details' : 'Show details' }}</span>\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!IsDepsExpanded(mi + 1)\" [class.fa-chevron-up]=\"IsDepsExpanded(mi + 1)\"></i>\n </div>\n @if (IsDepsExpanded(mi + 1)) {\n <div class=\"deps-detail-list\">\n @for (dep of GetGroupedDeps(mi + 1); track dep.Entity) {\n <div class=\"deps-detail-group\">\n <div class=\"deps-detail-row\" (click)=\"ToggleDepEntityGroup(mi + 1, dep.Entity); $event.stopPropagation()\">\n <span class=\"deps-detail-entity\">\n <i class=\"fa-solid deps-expand-icon\"\n [class.fa-chevron-right]=\"!IsDepEntityGroupExpanded(mi + 1, dep.Entity)\"\n [class.fa-chevron-down]=\"IsDepEntityGroupExpanded(mi + 1, dep.Entity)\"></i>\n {{ dep.Entity }}\n </span>\n <span class=\"deps-detail-count\">{{ dep.Count }}</span>\n </div>\n @if (IsDepEntityGroupExpanded(mi + 1, dep.Entity)) {\n <div class=\"deps-records-list\">\n @if (IsDepRecordsLoading(mi + 1, dep.Entity)) {\n <div class=\"deps-record-loading\"><i class=\"fa-solid fa-spinner fa-spin\"></i> Loading...</div>\n }\n @for (record of GetDepRecords(mi + 1, dep.Entity); track $index) {\n <div class=\"deps-record-row\" (click)=\"OpenDepRecord(record); $event.stopPropagation()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square deps-record-icon\"></i>\n <span class=\"deps-record-name\">{{ record.Name }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n @if (match.Match.ApprovalStatus !== 'Pending') {\n <span class=\"match-status-badge\"\n [class.status-approved]=\"match.Match.ApprovalStatus === 'Approved'\"\n [class.status-rejected]=\"match.Match.ApprovalStatus === 'Rejected'\">\n <i class=\"fa-solid\" [class.fa-check]=\"match.Match.ApprovalStatus === 'Approved'\"\n [class.fa-times]=\"match.Match.ApprovalStatus === 'Rejected'\"></i>\n {{ match.Match.ApprovalStatus }}\n </span>\n }\n </div>\n }\n\n <!-- Field rows -->\n @for (field of GetVisibleFields(); track field.FieldName; let odd = $odd) {\n <!-- Label cell -->\n <div class=\"grid-label-cell\" [class.grid-row-odd]=\"odd\">\n {{ field.DisplayName }}\n </div>\n <!-- Source value cell -->\n <div class=\"grid-value-cell grid-source-cell\"\n [class.grid-row-odd]=\"odd\"\n [class.has-diff-in-row]=\"field.HasDifference\"\n [class.field-selected]=\"field.SelectedColumnIndex === 0\"\n (click)=\"SelectFieldValue(field, 0)\">\n @if (field.SourceValue != null) {\n {{ field.SourceValue }}\n } @else {\n <span class=\"field-not-available\">(not available)</span>\n }\n @if (field.HasDifference || field.SelectedColumnIndex === 0) {\n <input type=\"radio\" [name]=\"'field-' + field.FieldName\" class=\"field-select-radio\"\n [checked]=\"field.SelectedColumnIndex === 0\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"SelectFieldValue(field, 0)\">\n }\n </div>\n <!-- Match value cells -->\n @for (matchVal of field.MatchValues; track $index; let mi = $index) {\n <div class=\"grid-value-cell\"\n [class.grid-row-odd]=\"odd\"\n [class.value-same]=\"AreValuesEqual(field.SourceValue, matchVal)\"\n [class.value-different]=\"matchVal != null && field.SourceValue != null && !AreValuesEqual(field.SourceValue, matchVal)\"\n [class.field-selected]=\"field.SelectedColumnIndex === mi + 1\"\n (click)=\"matchVal != null ? SelectFieldValue(field, mi + 1) : null\">\n @if (matchVal != null) {\n {{ matchVal }}\n @if (field.HasDifference || field.SelectedColumnIndex === mi + 1) {\n <input type=\"radio\" [name]=\"'field-' + field.FieldName\" class=\"field-select-radio\"\n [checked]=\"field.SelectedColumnIndex === mi + 1\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"SelectFieldValue(field, mi + 1)\">\n }\n } @else {\n <span class=\"field-not-available\">(not available)</span>\n }\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Footer -->\n <div class=\"comparison-footer\">\n <div class=\"comparison-footer-left\">\n <span class=\"comparison-summary\">\n Showing {{ GetVisibleFields().length }} of {{ ComparisonFields.length }} fields\n </span>\n <span class=\"merge-summary\">\n <i class=\"fa-solid fa-code-merge\"></i>\n Surviving: <strong>{{ SurvivorName() }}</strong>\n @if (CherryPickedCount() > 0) {\n · {{ CherryPickedCount() }} field{{ CherryPickedCount() !== 1 ? 's' : '' }} cherry-picked\n }\n </span>\n </div>\n <div class=\"comparison-footer-right\">\n <button class=\"action-btn reject-btn\" [disabled]=\"IsSaving\"\n (click)=\"RejectMatch(ComparisonGroup!); CloseComparison()\">\n <i class=\"fa-solid fa-times\"></i> Reject All\n </button>\n <button class=\"action-btn merge-btn\" [disabled]=\"IsSaving\"\n (click)=\"OpenMergeConfirm()\">\n <i class=\"fa-solid fa-code-merge\"></i> Merge Records\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550 Merge Confirmation Panel \u2550\u2550\u2550 -->\n @if (ShowMergeConfirm && ComparisonGroup) {\n <div class=\"merge-confirm-backdrop\" (click)=\"CloseMergeConfirm()\">\n <div class=\"merge-confirm-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"merge-confirm-header\">\n <div class=\"merge-confirm-icon\"><i class=\"fa-solid fa-code-merge\"></i></div>\n <div>\n <div class=\"merge-confirm-title\">Confirm Record Merge</div>\n <div class=\"merge-confirm-subtitle\">This action cannot be undone. Please review carefully.</div>\n </div>\n </div>\n\n <div class=\"merge-confirm-body\">\n <!-- Surviving Record -->\n <div class=\"merge-survivor-card\">\n <div class=\"merge-survivor-label\"><i class=\"fa-solid fa-shield-halved\"></i> Surviving Record</div>\n <div class=\"merge-survivor-name\">{{ SurvivorName() }}</div>\n <div class=\"merge-survivor-pk\">\n <i class=\"fa-solid fa-key\"></i>\n {{ SurvivorKeyDisplay() }}\n </div>\n <div class=\"merge-survivor-detail\">This record's ID will be retained. All dependencies from merged records will be transferred here.</div>\n </div>\n\n <!-- Cherry-picked field overrides -->\n @if (GetCherryPickedFields().length > 0) {\n <div>\n <div class=\"merge-section-label\">Field Value Overrides ({{ GetCherryPickedFields().length }} field{{ GetCherryPickedFields().length !== 1 ? 's' : '' }})</div>\n @for (field of GetCherryPickedFields(); track field.FieldName) {\n <div class=\"merge-field-override\">\n <span class=\"merge-field-name\">{{ field.DisplayName }}</span>\n <span class=\"merge-field-value\">\"{{ field.Value }}\"</span>\n <span class=\"merge-field-source\">from {{ field.SourceName }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Dependency transfer -->\n @if (GetNonSurvivorColumns().length > 0) {\n <div class=\"merge-deps-transfer\">\n <div class=\"merge-deps-transfer-label\"><i class=\"fa-solid fa-arrow-right-arrow-left\"></i> Dependencies to Transfer</div>\n @for (col of GetNonSurvivorColumns(); track col.ColumnIndex) {\n <div class=\"merge-deps-transfer-row\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n <span>\n @if (col.DepCount > 0) {\n <strong>{{ col.DepCount }}</strong> {{ col.DepCount === 1 ? 'dependency' : 'dependencies' }} from <strong>{{ col.Name }}</strong> → {{ SurvivorName() }}\n } @else {\n <strong>0</strong> dependencies from <strong>{{ col.Name }}</strong>\n }\n </span>\n </div>\n }\n </div>\n }\n\n <!-- Records to be deleted -->\n <div class=\"merge-delete-card\">\n <div class=\"merge-delete-label\"><i class=\"fa-solid fa-trash\"></i> Records to Delete After Merge</div>\n @for (col of GetNonSurvivorColumns(); track col.ColumnIndex) {\n <div class=\"merge-delete-item\">\n <span class=\"merge-delete-name\">{{ col.Name }}</span>\n <span class=\"merge-delete-deps\">\n @if (col.DepCount > 0) {\n {{ col.DepCount }} dep{{ col.DepCount !== 1 ? 's' : '' }} transferring\n } @else {\n no deps\n }\n </span>\n </div>\n }\n </div>\n </div>\n\n <div class=\"merge-confirm-footer\">\n <button class=\"action-btn cancel-btn\" (click)=\"CloseMergeConfirm()\" [disabled]=\"IsMerging\">\n <i class=\"fa-solid fa-arrow-left\"></i> Back\n </button>\n <button class=\"action-btn confirm-merge-btn\" (click)=\"ExecuteMerge()\" [disabled]=\"IsMerging\">\n @if (IsMerging) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Merging...\n } @else {\n <i class=\"fa-solid fa-code-merge\"></i> Confirm Merge ({{ GetNonSurvivorColumns().length + 1 }} records → 1)\n }\n </button>\n </div>\n </div>\n </div>\n }\n</div>\n", styles: ["/* ============================================================\n Duplicate Detection Kanban Board - Resource Component Styles\n All colors use MJ design tokens (--mj-*) exclusively.\n ============================================================ */\n\napp-duplicate-detection-resource {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n}\n\n.duplicate-detection-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 16px 20px;\n background: var(--mj-bg-page);\n position: relative;\n overflow: hidden;\n}\n\n/* ---- Page Header ---- */\n\n.page-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.page-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.page-title i {\n color: var(--mj-brand-primary);\n}\n\n/* ---- Header Actions ---- */\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.run-detection-controls {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.entity-doc-select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n min-width: 200px;\n}\n\n.entity-doc-select:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.run-detection-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n white-space: nowrap;\n}\n\n.run-detection-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.run-detection-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Detection Progress ---- */\n\n.detection-progress-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n padding: 14px 18px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.progress-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 8px;\n}\n\n.progress-stage {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.progress-percent {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.progress-bar-track {\n height: 6px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.progress-bar-fill {\n height: 100%;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n}\n\n.progress-current-item {\n display: block;\n margin-top: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---- Threshold Controls ---- */\n\n.threshold-controls {\n display: flex;\n gap: 24px;\n padding: 12px 16px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-status-info) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-subtle);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-slider-group {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.threshold-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.threshold-value {\n margin-left: auto;\n font-weight: 700;\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n}\n\n.threshold-slider {\n width: 100%;\n height: 4px;\n appearance: none;\n -webkit-appearance: none;\n background: var(--mj-border-default);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.threshold-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.threshold-hint {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n/* ---- Threshold Info (legacy) ---- */\n\n.threshold-info {\n display: flex;\n gap: 16px;\n padding: 8px 14px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-status-info) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-info-border);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-status-info-text);\n font-weight: 500;\n}\n\n.threshold-item i {\n font-size: 11px;\n}\n\n/* ---- KPI Strip ---- */\n\n.kpi-strip {\n display: flex;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.kpi-card {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.kpi-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.kpi-pending .kpi-value {\n color: var(--mj-status-warning);\n}\n\n.kpi-approved .kpi-value {\n color: var(--mj-status-success);\n}\n\n.kpi-rejected .kpi-value {\n color: var(--mj-status-error);\n}\n\n/* ---- Filter Bar ---- */\n\n.filter-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.filter-group {\n display: flex;\n align-items: flex-end;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.filter-select {\n height: 34px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n min-width: 160px;\n}\n\n.filter-select:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.filter-range {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.filter-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.filter-input {\n height: 34px;\n padding: 4px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n width: 100px;\n}\n\n.filter-input-score {\n width: 80px;\n}\n\n.filter-input-date {\n width: 140px;\n}\n\n.filter-input:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.clear-filters-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.clear-filters-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* ---- Loading & Empty States ---- */\n\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n gap: 8px;\n}\n\n.empty-icon {\n font-size: 48px;\n color: var(--mj-text-disabled);\n}\n\n.empty-text {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.empty-subtext {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin: 0;\n}\n\n/* ---- Kanban Board ---- */\n\n.kanban-board {\n display: flex;\n gap: 16px;\n flex: 1;\n min-height: 0;\n overflow-x: auto;\n}\n\n.kanban-column {\n flex: 1;\n min-width: 280px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.column-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-shrink: 0;\n}\n\n.column-header-pending {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n}\n\n.column-header-pending i {\n color: var(--mj-status-warning);\n}\n\n.column-header-approved {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n}\n\n.column-header-approved i {\n color: var(--mj-status-success);\n}\n\n.column-header-rejected {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n}\n\n.column-header-rejected i {\n color: var(--mj-status-error);\n}\n\n.column-title {\n flex: 1;\n}\n\n.column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.column-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.column-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n.column-empty i {\n font-size: 24px;\n}\n\n/* ---- Kanban Cards ---- */\n\n.kanban-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n transition: box-shadow 0.15s ease, border-color 0.15s ease;\n flex-shrink: 0; /* Prevent cards from shrinking \u2014 column scrolls instead */\n}\n\n.kanban-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n/* Drag and Drop */\n.kanban-card[draggable=\"true\"] {\n cursor: grab;\n}\n\n.kanban-card[draggable=\"true\"]:active {\n cursor: grabbing;\n}\n\n.drop-target-active {\n outline: 2px dashed var(--mj-brand-primary);\n outline-offset: -2px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface-card)) !important;\n}\n\n.drop-target-active .column-body {\n min-height: 100px;\n}\n\n.card-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n gap: 8px;\n}\n\n.card-header-left {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.card-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.card-title-block {\n min-width: 0;\n flex: 1;\n}\n\n.card-record-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-bottom: 2px;\n}\n\n.entity-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 3px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-text-muted);\n letter-spacing: 0.2px;\n}\n\n/* Score indicator colors */\n\n.score-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 40px;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 700;\n}\n\n.score-high {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.score-medium {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n.score-low {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.card-body {\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.match-summaries {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.match-summary-row {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.match-score {\n flex-shrink: 0;\n font-weight: 600;\n font-size: 11px;\n color: var(--mj-text-muted);\n min-width: 30px;\n}\n\n.match-name {\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.match-summary-more {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n padding-left: 38px;\n}\n\n.card-meta-row {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n border-top: 1px solid var(--mj-border-subtle);\n padding-top: 6px;\n}\n\n.card-meta-item {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.card-meta-item i {\n font-size: 10px;\n}\n font-size: 12px;\n max-width: 180px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Comparison Slide-In Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.slide-backdrop {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: fadeIn 0.2s ease;\n}\n\n.slide-backdrop.comparison-closing {\n animation: fadeOut 0.25s ease forwards;\n}\n\n@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }\n\n.comparison-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 82vw;\n max-width: 1300px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0,0,0,0.4);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.comparison-panel.comparison-closing {\n animation: slideOut 0.25s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }\n@keyframes slideOut { from { transform: translateX(0); } to { transform: translateX(100%); } }\n\n/* Header */\n.comparison-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 12px;\n}\n\n.comparison-header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.comparison-entity-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 1rem;\n flex-shrink: 0;\n}\n\n.comparison-title {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.comparison-entity-badge {\n display: inline-block;\n padding: 1px 7px;\n border-radius: 10px;\n font-size: 0.65rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n margin-right: 6px;\n}\n\n.comparison-match-count {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.comparison-header-right {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n}\n\n/* Toggle */\n.comparison-toggle {\n display: flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n}\n\n.toggle-btn {\n padding: 5px 12px;\n font-size: 0.7rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn:first-child {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.toggle-btn.toggle-active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.comparison-close-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n transition: all 0.15s ease;\n}\n\n.comparison-close-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Loading state */\n.comparison-loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Grid wrapper */\n.comparison-grid-wrapper {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* Grid */\n.comparison-grid {\n display: grid;\n min-width: 100%;\n}\n\n.comparison-grid > div {\n padding: 8px 12px;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n/* Corner cell */\n.grid-corner-cell {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 4;\n background: var(--mj-bg-surface-elevated);\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: flex-end;\n padding-bottom: 6px;\n}\n\n/* Column headers */\n.grid-col-header {\n position: sticky;\n top: 0;\n z-index: 3;\n background: var(--mj-bg-surface-elevated);\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.grid-col-source {\n border-left: 3px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface-elevated));\n}\n\n.col-header-label {\n font-size: 0.6rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n}\n\n.col-header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n}\n\n.col-header-name {\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-header-diff-count {\n font-size: 0.65rem;\n color: var(--mj-status-warning-text);\n}\n\n/* Surviving record selector */\n.surviving-selector {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n}\n\n.surviving-radio {\n appearance: none;\n width: 14px;\n height: 14px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.surviving-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2px var(--mj-bg-surface-elevated);\n}\n\n.surviving-label {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n\n.surviving-label.is-survivor {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* Use all fields button */\n.use-all-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 0.62rem;\n cursor: pointer;\n transition: all 0.12s ease;\n margin-top: 2px;\n}\n\n.use-all-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.use-all-btn.all-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* Per-match actions */\n.comparison-match-actions {\n display: flex;\n gap: 4px;\n margin-top: 3px;\n}\n\n.action-btn-sm {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid;\n border-radius: 5px;\n cursor: pointer;\n font-size: 0.65rem;\n transition: all 0.15s ease;\n}\n\n.approve-btn-sm {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n.approve-btn-sm:hover { background: rgba(34,197,94,0.25); }\n\n.reject-btn-sm {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n.reject-btn-sm:hover { background: rgba(239,68,68,0.25); }\n\n.match-status-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.68rem;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.status-approved {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.status-rejected {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.match-approved {\n border-top: 3px solid var(--mj-status-success);\n}\n\n.match-rejected {\n border-top: 3px solid var(--mj-status-error);\n opacity: 0.6;\n}\n\n/* Label cells */\n.grid-label-cell {\n position: sticky;\n left: 0;\n z-index: 2;\n background: var(--mj-bg-surface);\n font-size: 0.72rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n}\n\n.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n.grid-label-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n/* Value cells */\n.grid-value-cell {\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n line-height: 1.45;\n word-break: break-word;\n position: relative;\n cursor: pointer;\n}\n\n.grid-source-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, var(--mj-bg-surface));\n border-left: 3px solid transparent;\n}\n\n.grid-source-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface)));\n}\n\n.grid-source-cell.has-diff-in-row {\n font-weight: 600;\n}\n\n/* Diff highlighting */\n.value-same {\n color: var(--mj-text-muted);\n}\n\n.value-different {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, transparent) !important;\n border-left: 3px solid var(--mj-status-warning);\n color: var(--mj-text-primary);\n}\n\n.field-not-available {\n font-style: italic;\n font-size: 0.72rem;\n color: var(--mj-text-disabled);\n}\n\n/* Field selection radio */\n.field-select-radio {\n position: absolute;\n top: 50%;\n right: 8px;\n transform: translateY(-50%);\n appearance: none;\n width: 16px;\n height: 16px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.12s ease;\n opacity: 0.4;\n}\n\n.field-select-radio:hover {\n opacity: 0.8;\n}\n\n.field-select-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2.5px var(--mj-bg-surface);\n opacity: 1;\n}\n\n.grid-value-cell.field-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)) !important;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.grid-value-cell.field-selected .field-select-radio {\n opacity: 1;\n}\n\n/* Footer */\n.comparison-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 20px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.comparison-footer-left {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.comparison-summary {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.merge-summary {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.merge-summary i {\n font-size: 0.65rem;\n}\n\n.comparison-footer-right {\n display: flex;\n gap: 8px;\n}\n\n.comparison-footer-right .action-btn {\n flex: none;\n padding: 7px 14px;\n}\n\n.merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.merge-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.card-actions {\n display: flex;\n gap: 8px;\n padding: 10px 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.action-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 32px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n\n.action-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.approve-btn {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n\n.approve-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 20%, var(--mj-bg-surface));\n}\n\n.reject-btn {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n\n.reject-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n}\n\n/* ---- Responsive ---- */\n\n@media (max-width: 768px) {\n .kanban-board {\n flex-direction: column;\n }\n\n .kanban-column {\n min-width: auto;\n max-height: 400px;\n }\n}\n\n@media (max-width: 480px) {\n .kpi-strip {\n flex-direction: column;\n }\n\n .filter-bar {\n flex-wrap: wrap;\n }\n\n .filter-group {\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n }\n\n .filter-select {\n min-width: auto;\n width: 100%;\n }\n\n .filter-input {\n width: 100%;\n }\n\n .card-actions {\n flex-direction: column;\n }\n\n .action-btn {\n width: 100%;\n }\n}\n\n/* ---- Saving Overlay ---- */\n\n.saving-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-overlay);\n z-index: 10;\n border-radius: 8px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Dependencies Summary (in column headers)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.deps-summary {\n margin-top: 6px;\n padding: 6px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n font-size: 0.68rem;\n}\n\n.deps-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.deps-header i {\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-header:hover {\n color: var(--mj-text-primary);\n}\n\n.deps-total {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.72rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.deps-total i {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.deps-total-number {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 0.7rem;\n font-weight: 700;\n}\n\n.deps-total-recommended {\n font-size: 0.58rem;\n color: var(--mj-status-success-text);\n font-weight: 600;\n margin-left: 4px;\n}\n\n.deps-total-recommended i {\n color: var(--mj-status-success-text);\n}\n\n.deps-detail-list {\n margin-top: 4px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.deps-detail-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 3px 0;\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: background 0.1s ease;\n}\n\n.deps-detail-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.deps-detail-entity {\n display: flex;\n align-items: center;\n gap: 4px;\n color: var(--mj-text-secondary);\n}\n\n.deps-expand-icon {\n font-size: 0.5rem;\n width: 10px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n/* Individual dependency records list */\n.deps-records-list {\n padding-left: 14px;\n margin-bottom: 2px;\n}\n\n.deps-record-row {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 2px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: color 0.1s ease, background 0.1s ease;\n}\n\n.deps-record-row:hover {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.deps-record-icon {\n font-size: 0.5rem;\n flex-shrink: 0;\n}\n\n.deps-record-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 0.6rem;\n}\n\n.deps-record-loading {\n padding: 3px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-record-loading i {\n margin-right: 4px;\n}\n\n.deps-detail-count {\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Merge Confirmation Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-confirm-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 20000;\n animation: fadeIn 0.2s ease;\n}\n\n.merge-confirm-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 520px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0, 0, 0, 0.4);\n z-index: 20001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.merge-confirm-header {\n padding: 18px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.merge-confirm-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text);\n font-size: 1.1rem;\n flex-shrink: 0;\n}\n\n.merge-confirm-title {\n font-size: 1.05rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.merge-confirm-subtitle {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.merge-confirm-body {\n padding: 20px 24px;\n overflow-y: auto;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* Surviving record card */\n\n.merge-survivor-card {\n padding: 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n}\n\n.merge-survivor-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n margin-bottom: 4px;\n}\n\n.merge-survivor-label i {\n margin-right: 4px;\n}\n\n.merge-survivor-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.merge-survivor-pk {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 4px;\n font-size: 0.68rem;\n font-family: monospace;\n color: var(--mj-text-secondary);\n}\n\n.merge-survivor-pk i {\n font-size: 0.6rem;\n color: var(--mj-brand-primary);\n}\n\n.merge-survivor-detail {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n/* Cherry-picked fields section */\n\n.merge-section-label {\n font-size: 0.7rem;\n font-weight: 700;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 6px;\n}\n\n.merge-field-override {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.merge-field-name {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 110px;\n flex-shrink: 0;\n}\n\n.merge-field-value {\n color: var(--mj-text-primary);\n}\n\n.merge-field-source {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n margin-left: auto;\n white-space: nowrap;\n}\n\n/* Dependency transfer summary */\n\n.merge-deps-transfer {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.merge-deps-transfer-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.merge-deps-transfer-label i {\n margin-right: 4px;\n}\n\n.merge-deps-transfer-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 3px 0;\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n}\n\n.merge-deps-transfer-row i {\n color: var(--mj-brand-primary);\n font-size: 0.65rem;\n width: 14px;\n text-align: center;\n}\n\n/* Records to delete */\n\n.merge-delete-card {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n}\n\n.merge-delete-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-status-error-text);\n margin-bottom: 6px;\n}\n\n.merge-delete-label i {\n margin-right: 4px;\n}\n\n.merge-delete-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 5px 0;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.merge-delete-item:last-child {\n border-bottom: none;\n}\n\n.merge-delete-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.merge-delete-deps {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n/* Confirm footer */\n\n.merge-confirm-footer {\n padding: 14px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 10px;\n}\n\n.cancel-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n\n.cancel-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.confirm-merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.confirm-merge-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.confirm-merge-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Responsive: Merge Confirm ---- */\n\n@media (max-width: 600px) {\n .merge-confirm-panel {\n width: 100%;\n }\n}\n"] }]
|
|
2676
|
-
}], null, {
|
|
2939
|
+
args: [{ standalone: false, selector: 'app-duplicate-detection-resource', encapsulation: ViewEncapsulation.None, template: "<div class=\"duplicate-detection-container\">\n <!-- Header -->\n <div class=\"page-header\">\n <div class=\"header-left\">\n <h2 class=\"page-title\">\n <i class=\"fa-solid fa-clone\"></i> Duplicate Detection\n </h2>\n </div>\n <div class=\"header-actions\">\n <div class=\"run-detection-controls\">\n <select class=\"entity-doc-select\"\n [(ngModel)]=\"SelectedEntityDocumentID\"\n [disabled]=\"IsDetecting\">\n <option value=\"\">Select entity document...</option>\n @for (doc of EntityDocuments; track doc.ID) {\n <option [value]=\"doc.ID\">{{ doc.Name }} ({{ doc.EntityName }})</option>\n }\n </select>\n <button class=\"run-detection-btn\"\n (click)=\"RunDetection()\"\n [disabled]=\"IsDetecting || !SelectedEntityDocumentID\">\n @if (IsDetecting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Detecting...\n } @else {\n <i class=\"fa-solid fa-magnifying-glass\"></i> Run Detection\n }\n </button>\n </div>\n </div>\n </div>\n\n <!-- Detection Progress (visible during run) -->\n @if (IsDetecting) {\n <div class=\"detection-progress-section\">\n <div class=\"progress-header\">\n <span class=\"progress-stage\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n {{ DetectionStage }}\n </span>\n <span class=\"progress-percent\">{{ DetectionProgress }}%</span>\n </div>\n <div class=\"progress-bar-track\">\n <div class=\"progress-bar-fill\" [style.width.%]=\"DetectionProgress\"></div>\n </div>\n @if (DetectionCurrentItem) {\n <span class=\"progress-current-item\">{{ DetectionCurrentItem }}</span>\n }\n </div>\n }\n\n <!-- Threshold Controls (when entity doc selected) -->\n @if (SelectedDocumentThresholds) {\n <div class=\"threshold-controls\">\n <div class=\"threshold-slider-group\">\n <label class=\"threshold-label\">\n <i class=\"fa-solid fa-adjust\"></i>\n Potential Match\n <span class=\"threshold-value\">{{ (RunPotentialThreshold * 100).toFixed(0) }}%</span>\n </label>\n <input type=\"range\" class=\"threshold-slider\"\n [min]=\"30\" [max]=\"99\" [step]=\"1\"\n [value]=\"RunPotentialThreshold * 100\"\n (input)=\"OnPotentialThresholdChanged($any($event.target).value / 100)\"\n [disabled]=\"IsDetecting\" />\n <span class=\"threshold-hint\">Score above which duplicates are flagged for review</span>\n </div>\n <div class=\"threshold-slider-group\">\n <label class=\"threshold-label\">\n <i class=\"fa-solid fa-bullseye\"></i>\n Absolute Match\n <span class=\"threshold-value\">{{ (RunAbsoluteThreshold * 100).toFixed(0) }}%</span>\n </label>\n <input type=\"range\" class=\"threshold-slider\"\n [min]=\"50\" [max]=\"100\" [step]=\"1\"\n [value]=\"RunAbsoluteThreshold * 100\"\n (input)=\"OnAbsoluteThresholdChanged($any($event.target).value / 100)\"\n [disabled]=\"IsDetecting\" />\n <span class=\"threshold-hint\">Score above which duplicates are auto-confirmed</span>\n </div>\n </div>\n }\n\n <!-- KPI Strip -->\n <div class=\"kpi-strip\">\n <div class=\"kpi-card\">\n <div class=\"kpi-value\">{{ TotalGroupCount }}</div>\n <div class=\"kpi-label\">Total Groups</div>\n </div>\n <div class=\"kpi-card kpi-pending\">\n <div class=\"kpi-value\">{{ PendingCount }}</div>\n <div class=\"kpi-label\">Pending</div>\n </div>\n <div class=\"kpi-card kpi-approved\">\n <div class=\"kpi-value\">{{ ApprovedCount }}</div>\n <div class=\"kpi-label\">Approved</div>\n </div>\n <div class=\"kpi-card kpi-rejected\">\n <div class=\"kpi-value\">{{ RejectedCount }}</div>\n <div class=\"kpi-label\">Rejected</div>\n </div>\n </div>\n\n <!-- Filter Bar -->\n <div class=\"filter-bar\">\n <div class=\"filter-group\">\n <select class=\"filter-select\"\n [(ngModel)]=\"Filters.EntityName\"\n (ngModelChange)=\"OnFilterChange()\"\n [disabled]=\"EntityNames.length <= 1\">\n @if (EntityNames.length > 1) {\n <option value=\"\">All Entities</option>\n }\n @for (name of EntityNames; track name) {\n <option [value]=\"name\">{{ name }}</option>\n }\n </select>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">Min Score</label>\n <input type=\"number\"\n class=\"filter-input filter-input-score\"\n min=\"0\" max=\"1\" step=\"0.05\"\n [placeholder]=\"DataMinScore\"\n [(ngModel)]=\"Filters.MinScore\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">Max Score</label>\n <input type=\"number\"\n class=\"filter-input filter-input-score\"\n min=\"0\" max=\"1\" step=\"0.05\"\n [placeholder]=\"DataMaxScore\"\n [(ngModel)]=\"Filters.MaxScore\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">From</label>\n <input type=\"date\"\n class=\"filter-input filter-input-date\"\n [min]=\"DataMinDate\" [max]=\"DataMaxDate\"\n [(ngModel)]=\"Filters.DateFrom\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n\n <div class=\"filter-range\">\n <label class=\"filter-label\">To</label>\n <input type=\"date\"\n class=\"filter-input filter-input-date\"\n [min]=\"DataMinDate\" [max]=\"DataMaxDate\"\n [(ngModel)]=\"Filters.DateTo\"\n (ngModelChange)=\"OnFilterChange()\">\n </div>\n </div>\n\n @if (HasActiveFilters) {\n <button class=\"clear-filters-btn\" (click)=\"ClearFilters()\">\n <i class=\"fa-solid fa-times\"></i> Clear Filters\n </button>\n }\n </div>\n\n <!-- Merge Warning Banner (non-blocking, shown when entity lacks AllowRecordMerge) -->\n @if (ShowMergeWarningBanner) {\n <div class=\"merge-warning-banner\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n Merging is not available for this entity. Detection results are read-only.\n </div>\n }\n\n <!-- Content -->\n @if (IsLoading) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading duplicate detection results...\"></mj-loading>\n </div>\n } @else if (IsLoadingResults) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading duplicate detection results...\"></mj-loading>\n </div>\n } @else if (TotalGroupCount === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-clone empty-icon\"></i>\n <p class=\"empty-text\">No duplicate detection results found.</p>\n <p class=\"empty-subtext\">Select an entity document and click \"Run Detection\" to start.</p>\n </div>\n } @else {\n <!-- Kanban Board -->\n <div class=\"kanban-board\">\n <!-- Pending Column -->\n <div class=\"kanban-column\" [class.drop-target-active]=\"DragOverColumn === 'Pending' && DraggedGroup?.ApprovalStatus !== 'Pending'\">\n <div class=\"column-header column-header-pending\">\n <i class=\"fa-solid fa-clock\"></i>\n <span class=\"column-title\">Pending Review</span>\n <span class=\"column-count\">{{ PendingCount }}</span>\n </div>\n <div class=\"column-body\"\n (dragover)=\"OnDragOver($event, 'Pending')\"\n (dragleave)=\"OnDragLeave($event, 'Pending')\"\n (drop)=\"OnDrop($event, 'Pending')\">\n @for (group of PendingGroups; track group.DetailId) {\n <div class=\"kanban-card\"\n draggable=\"true\"\n (dragstart)=\"OnDragStart($event, group)\"\n (dragend)=\"OnDragEnd()\"\n (click)=\"OpenComparison(group)\">\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon\">\n <i [class]=\"group.EntityIcon\"></i>\n </div>\n <div class=\"card-title-block\">\n <div class=\"card-record-name\" [title]=\"group.RecordName\">{{ group.RecordName }}</div>\n <span class=\"entity-badge\">{{ group.EntityName }}</span>\n </div>\n </div>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(group.HighestScore)\">\n {{ (group.HighestScore * 100).toFixed(0) }}%\n </span>\n </div>\n <div class=\"card-body\">\n @if (group.TopMatchSummaries.length > 0) {\n <div class=\"match-summaries\">\n @for (ms of group.TopMatchSummaries; track ms.Name) {\n <div class=\"match-summary-row\">\n <span class=\"match-score\">{{ (ms.Score * 100).toFixed(0) }}%</span>\n <span class=\"match-name\">{{ ms.Name }}</span>\n </div>\n }\n @if (group.MatchCount > group.TopMatchSummaries.length) {\n <div class=\"match-summary-more\">+{{ group.MatchCount - group.TopMatchSummaries.length }} more</div>\n }\n </div>\n }\n <div class=\"card-meta-row\">\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n {{ group.MatchCount }} match{{ group.MatchCount !== 1 ? 'es' : '' }}\n </span>\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(group.MatchedAt) }}\n </span>\n </div>\n </div>\n <div class=\"card-actions\">\n <button class=\"action-btn approve-btn\"\n [disabled]=\"IsSaving\"\n (click)=\"ApproveMatch(group); $event.stopPropagation()\">\n <i class=\"fa-solid fa-check\"></i> Approve\n </button>\n <button class=\"action-btn reject-btn\"\n [disabled]=\"IsSaving\"\n (click)=\"RejectMatch(group); $event.stopPropagation()\">\n <i class=\"fa-solid fa-times\"></i> Reject\n </button>\n </div>\n </div>\n }\n @if (PendingGroups.length === 0) {\n <div class=\"column-empty\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span>No pending items</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Approved Column -->\n <div class=\"kanban-column\" [class.drop-target-active]=\"DragOverColumn === 'Approved' && DraggedGroup?.ApprovalStatus !== 'Approved'\">\n <div class=\"column-header column-header-approved\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span class=\"column-title\">Approved</span>\n <span class=\"column-count\">{{ ApprovedCount }}</span>\n </div>\n <div class=\"column-body\"\n (dragover)=\"OnDragOver($event, 'Approved')\"\n (dragleave)=\"OnDragLeave($event, 'Approved')\"\n (drop)=\"OnDrop($event, 'Approved')\">\n @for (group of ApprovedGroups; track group.DetailId) {\n <div class=\"kanban-card\"\n draggable=\"true\"\n (dragstart)=\"OnDragStart($event, group)\"\n (dragend)=\"OnDragEnd()\"\n (click)=\"OpenComparison(group)\">\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon\">\n <i [class]=\"group.EntityIcon\"></i>\n </div>\n <div class=\"card-title-block\">\n <div class=\"card-record-name\" [title]=\"group.RecordName\">{{ group.RecordName }}</div>\n <span class=\"entity-badge\">{{ group.EntityName }}</span>\n </div>\n </div>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(group.HighestScore)\">\n {{ (group.HighestScore * 100).toFixed(0) }}%\n </span>\n </div>\n <div class=\"card-body\">\n @if (group.TopMatchSummaries.length > 0) {\n <div class=\"match-summaries\">\n @for (ms of group.TopMatchSummaries; track ms.Name) {\n <div class=\"match-summary-row\">\n <span class=\"match-score\">{{ (ms.Score * 100).toFixed(0) }}%</span>\n <span class=\"match-name\">{{ ms.Name }}</span>\n </div>\n }\n @if (group.MatchCount > group.TopMatchSummaries.length) {\n <div class=\"match-summary-more\">+{{ group.MatchCount - group.TopMatchSummaries.length }} more</div>\n }\n </div>\n }\n <div class=\"card-meta-row\">\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n {{ group.MatchCount }} match{{ group.MatchCount !== 1 ? 'es' : '' }}\n </span>\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(group.MatchedAt) }}\n </span>\n </div>\n </div>\n </div>\n }\n @if (ApprovedGroups.length === 0) {\n <div class=\"column-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No approved items</span>\n </div>\n }\n </div>\n </div>\n\n <!-- Rejected Column -->\n <div class=\"kanban-column\" [class.drop-target-active]=\"DragOverColumn === 'Rejected' && DraggedGroup?.ApprovalStatus !== 'Rejected'\">\n <div class=\"column-header column-header-rejected\">\n <i class=\"fa-solid fa-ban\"></i>\n <span class=\"column-title\">Rejected</span>\n <span class=\"column-count\">{{ RejectedCount }}</span>\n </div>\n <div class=\"column-body\"\n (dragover)=\"OnDragOver($event, 'Rejected')\"\n (dragleave)=\"OnDragLeave($event, 'Rejected')\"\n (drop)=\"OnDrop($event, 'Rejected')\">\n @for (group of RejectedGroups; track group.DetailId) {\n <div class=\"kanban-card\"\n draggable=\"true\"\n (dragstart)=\"OnDragStart($event, group)\"\n (dragend)=\"OnDragEnd()\"\n (click)=\"OpenComparison(group)\">\n <div class=\"card-header\">\n <div class=\"card-header-left\">\n <div class=\"card-icon\">\n <i [class]=\"group.EntityIcon\"></i>\n </div>\n <div class=\"card-title-block\">\n <div class=\"card-record-name\" [title]=\"group.RecordName\">{{ group.RecordName }}</div>\n <span class=\"entity-badge\">{{ group.EntityName }}</span>\n </div>\n </div>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(group.HighestScore)\">\n {{ (group.HighestScore * 100).toFixed(0) }}%\n </span>\n </div>\n <div class=\"card-body\">\n @if (group.TopMatchSummaries.length > 0) {\n <div class=\"match-summaries\">\n @for (ms of group.TopMatchSummaries; track ms.Name) {\n <div class=\"match-summary-row\">\n <span class=\"match-score\">{{ (ms.Score * 100).toFixed(0) }}%</span>\n <span class=\"match-name\">{{ ms.Name }}</span>\n </div>\n }\n @if (group.MatchCount > group.TopMatchSummaries.length) {\n <div class=\"match-summary-more\">+{{ group.MatchCount - group.TopMatchSummaries.length }} more</div>\n }\n </div>\n }\n <div class=\"card-meta-row\">\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n {{ group.MatchCount }} match{{ group.MatchCount !== 1 ? 'es' : '' }}\n </span>\n <span class=\"card-meta-item\">\n <i class=\"fa-solid fa-calendar\"></i>\n {{ FormatDate(group.MatchedAt) }}\n </span>\n </div>\n </div>\n </div>\n }\n @if (RejectedGroups.length === 0) {\n <div class=\"column-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No rejected items</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Saving overlay -->\n @if (IsSaving) {\n <div class=\"saving-overlay\">\n <mj-loading text=\"Saving...\" size=\"small\"></mj-loading>\n </div>\n }\n\n <!-- \u2550\u2550\u2550 Comparison Slide-In Panel \u2550\u2550\u2550 -->\n @if (ComparisonGroup) {\n <div class=\"slide-backdrop\" [class.comparison-closing]=\"ComparisonClosing\" (click)=\"CloseComparison()\"></div>\n <div class=\"comparison-panel\" [class.comparison-closing]=\"ComparisonClosing\" (click)=\"$event.stopPropagation()\">\n <!-- Header -->\n <div class=\"comparison-header\">\n <div class=\"comparison-header-left\">\n <div class=\"comparison-entity-icon\">\n <i [class]=\"ComparisonGroup.EntityIcon\"></i>\n </div>\n <div>\n <div class=\"comparison-title\">{{ ComparisonGroup.RecordName }}</div>\n <span class=\"comparison-entity-badge\">{{ ComparisonGroup.EntityName }}</span>\n <span class=\"comparison-match-count\">\n {{ ComparisonGroup.MatchCount }} potential duplicate{{ ComparisonGroup.MatchCount !== 1 ? 's' : '' }}\n </span>\n </div>\n </div>\n <div class=\"comparison-header-right\">\n <div class=\"comparison-toggle\">\n <button class=\"toggle-btn\" [class.toggle-active]=\"ComparisonShowAllFields\"\n (click)=\"ComparisonShowAllFields = true\">All Fields</button>\n <button class=\"toggle-btn\" [class.toggle-active]=\"!ComparisonShowAllFields\"\n (click)=\"ComparisonShowAllFields = false\">Differences Only</button>\n </div>\n <button class=\"comparison-close-btn\" (click)=\"CloseComparison()\" title=\"Close (Esc)\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n\n <!-- Grid -->\n @if (ComparisonLoading) {\n <div class=\"comparison-loading\">\n <mj-loading text=\"Loading records for comparison...\" size=\"medium\"></mj-loading>\n </div>\n }\n <div class=\"comparison-grid-wrapper\" [hidden]=\"ComparisonLoading\">\n <div class=\"comparison-grid\"\n [style.grid-template-columns]=\"'160px repeat(' + (1 + ComparisonMatches.length) + ', minmax(180px, 1fr))'\">\n\n <!-- Corner cell -->\n <div class=\"grid-corner-cell\">Field</div>\n\n <!-- Source column header -->\n <div class=\"grid-col-header grid-col-source\">\n <span class=\"col-header-label\">Source</span>\n <span class=\"col-header-name\">{{ ComparisonGroup.RecordName }}</span>\n <div class=\"surviving-selector\">\n <input type=\"radio\" name=\"survivor\" class=\"surviving-radio\"\n [checked]=\"SurvivorColumnIndex === 0\"\n (change)=\"SetSurvivor(0)\">\n <span class=\"surviving-label\" [class.is-survivor]=\"SurvivorColumnIndex === 0\">\n {{ SurvivorColumnIndex === 0 ? 'Surviving Record' : 'Set as survivor' }}\n </span>\n </div>\n <button class=\"use-all-btn\" [class.all-selected]=\"AllFieldsSelectedFrom(0)\"\n (click)=\"UseAllFieldsFrom(0)\">\n <i class=\"fa-solid\" [class.fa-check-double]=\"AllFieldsSelectedFrom(0)\" [class.fa-clone]=\"!AllFieldsSelectedFrom(0)\"></i>\n {{ AllFieldsSelectedFrom(0) ? 'Using all fields' : 'Use all fields' }}\n </button>\n <!-- Dependencies Summary -->\n <div class=\"deps-summary\">\n <div class=\"deps-total\">\n <i class=\"fa-solid fa-link\"></i>\n <span class=\"deps-total-number\">{{ GetTotalDeps(0) }}</span>\n {{ GetTotalDeps(0) === 1 ? 'dependency' : 'dependencies' }}\n @if (GetMaxDepsColumnIndex() === 0 && GetTotalDeps(0) > 0) {\n <span class=\"deps-total-recommended\"><i class=\"fa-solid fa-star\"></i> Most deps</span>\n }\n </div>\n @if (GetGroupedDeps(0).length > 0) {\n <div class=\"deps-header\" (click)=\"ToggleDepsExpanded(0)\">\n <span>{{ IsDepsExpanded(0) ? 'Hide details' : 'Show details' }}</span>\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!IsDepsExpanded(0)\" [class.fa-chevron-up]=\"IsDepsExpanded(0)\"></i>\n </div>\n @if (IsDepsExpanded(0)) {\n <div class=\"deps-detail-list\">\n @for (dep of GetGroupedDeps(0); track dep.Entity) {\n <div class=\"deps-detail-group\">\n <div class=\"deps-detail-row\" (click)=\"ToggleDepEntityGroup(0, dep.Entity); $event.stopPropagation()\">\n <span class=\"deps-detail-entity\">\n <i class=\"fa-solid deps-expand-icon\"\n [class.fa-chevron-right]=\"!IsDepEntityGroupExpanded(0, dep.Entity)\"\n [class.fa-chevron-down]=\"IsDepEntityGroupExpanded(0, dep.Entity)\"></i>\n {{ dep.Entity }}\n </span>\n <span class=\"deps-detail-count\">{{ dep.Count }}</span>\n </div>\n @if (IsDepEntityGroupExpanded(0, dep.Entity)) {\n <div class=\"deps-records-list\">\n @if (IsDepRecordsLoading(0, dep.Entity)) {\n <div class=\"deps-record-loading\"><i class=\"fa-solid fa-spinner fa-spin\"></i> Loading...</div>\n }\n @for (record of GetDepRecords(0, dep.Entity); track $index) {\n <div class=\"deps-record-row\" (click)=\"OpenDepRecord(record); $event.stopPropagation()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square deps-record-icon\"></i>\n <span class=\"deps-record-name\">{{ record.Name }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Match column headers -->\n @for (match of ComparisonMatches; track match.Match.ID; let mi = $index) {\n <div class=\"grid-col-header\"\n [class.match-approved]=\"match.Match.ApprovalStatus === 'Approved'\"\n [class.match-rejected]=\"match.Match.ApprovalStatus === 'Rejected'\">\n <div class=\"col-header-top\">\n <span class=\"col-header-name\">{{ match.Name }}</span>\n <span class=\"score-indicator\" [class]=\"GetScoreClass(match.Score)\">\n {{ (match.Score * 100).toFixed(0) }}%\n </span>\n </div>\n <span class=\"col-header-diff-count\">{{ match.DiffCount }} difference{{ match.DiffCount !== 1 ? 's' : '' }}</span>\n <div class=\"surviving-selector\">\n <input type=\"radio\" name=\"survivor\" class=\"surviving-radio\"\n [checked]=\"SurvivorColumnIndex === mi + 1\"\n (change)=\"SetSurvivor(mi + 1)\">\n <span class=\"surviving-label\" [class.is-survivor]=\"SurvivorColumnIndex === mi + 1\">\n {{ SurvivorColumnIndex === mi + 1 ? 'Surviving Record' : 'Set as survivor' }}\n </span>\n </div>\n <button class=\"use-all-btn\" [class.all-selected]=\"AllFieldsSelectedFrom(mi + 1)\"\n (click)=\"UseAllFieldsFrom(mi + 1)\">\n <i class=\"fa-solid\" [class.fa-check-double]=\"AllFieldsSelectedFrom(mi + 1)\" [class.fa-clone]=\"!AllFieldsSelectedFrom(mi + 1)\"></i>\n {{ AllFieldsSelectedFrom(mi + 1) ? 'Using all fields' : 'Use all fields' }}\n </button>\n <!-- Dependencies Summary -->\n <div class=\"deps-summary\">\n <div class=\"deps-total\">\n <i class=\"fa-solid fa-link\"></i>\n <span class=\"deps-total-number\">{{ GetTotalDeps(mi + 1) }}</span>\n {{ GetTotalDeps(mi + 1) === 1 ? 'dependency' : 'dependencies' }}\n @if (GetMaxDepsColumnIndex() === mi + 1 && GetTotalDeps(mi + 1) > 0) {\n <span class=\"deps-total-recommended\"><i class=\"fa-solid fa-star\"></i> Most deps</span>\n }\n </div>\n @if (GetGroupedDeps(mi + 1).length > 0) {\n <div class=\"deps-header\" (click)=\"ToggleDepsExpanded(mi + 1)\">\n <span>{{ IsDepsExpanded(mi + 1) ? 'Hide details' : 'Show details' }}</span>\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!IsDepsExpanded(mi + 1)\" [class.fa-chevron-up]=\"IsDepsExpanded(mi + 1)\"></i>\n </div>\n @if (IsDepsExpanded(mi + 1)) {\n <div class=\"deps-detail-list\">\n @for (dep of GetGroupedDeps(mi + 1); track dep.Entity) {\n <div class=\"deps-detail-group\">\n <div class=\"deps-detail-row\" (click)=\"ToggleDepEntityGroup(mi + 1, dep.Entity); $event.stopPropagation()\">\n <span class=\"deps-detail-entity\">\n <i class=\"fa-solid deps-expand-icon\"\n [class.fa-chevron-right]=\"!IsDepEntityGroupExpanded(mi + 1, dep.Entity)\"\n [class.fa-chevron-down]=\"IsDepEntityGroupExpanded(mi + 1, dep.Entity)\"></i>\n {{ dep.Entity }}\n </span>\n <span class=\"deps-detail-count\">{{ dep.Count }}</span>\n </div>\n @if (IsDepEntityGroupExpanded(mi + 1, dep.Entity)) {\n <div class=\"deps-records-list\">\n @if (IsDepRecordsLoading(mi + 1, dep.Entity)) {\n <div class=\"deps-record-loading\"><i class=\"fa-solid fa-spinner fa-spin\"></i> Loading...</div>\n }\n @for (record of GetDepRecords(mi + 1, dep.Entity); track $index) {\n <div class=\"deps-record-row\" (click)=\"OpenDepRecord(record); $event.stopPropagation()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square deps-record-icon\"></i>\n <span class=\"deps-record-name\">{{ record.Name }}</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n }\n </div>\n <!-- Per-match approval actions -->\n <div class=\"match-approval-actions\">\n @if (match.Match.ApprovalStatus === 'Pending') {\n <button class=\"match-action-btn match-skip-btn\"\n title=\"Skip this match (exclude from merge)\"\n (click)=\"RejectIndividualMatch(match)\">\n <i class=\"fa-solid fa-ban\"></i> Skip\n </button>\n } @else {\n <span class=\"match-status-badge\"\n [class.status-approved]=\"match.Match.ApprovalStatus === 'Approved'\"\n [class.status-rejected]=\"match.Match.ApprovalStatus === 'Rejected'\">\n <i class=\"fa-solid\" [class.fa-check]=\"match.Match.ApprovalStatus === 'Approved'\"\n [class.fa-times]=\"match.Match.ApprovalStatus === 'Rejected'\"></i>\n {{ match.Match.ApprovalStatus === 'Rejected' ? 'Skipped' : match.Match.ApprovalStatus }}\n </span>\n @if (match.Match.ApprovalStatus === 'Rejected') {\n <button class=\"match-action-btn match-undo-btn\"\n title=\"Undo skip\"\n (click)=\"UndoRejectIndividualMatch(match)\">\n <i class=\"fa-solid fa-undo\"></i> Undo\n </button>\n }\n }\n </div>\n </div>\n }\n\n <!-- Field rows -->\n @for (field of GetVisibleFields(); track field.FieldName; let odd = $odd) {\n <!-- Label cell -->\n <div class=\"grid-label-cell\" [class.grid-row-odd]=\"odd\">\n {{ field.DisplayName }}\n </div>\n <!-- Source value cell -->\n <div class=\"grid-value-cell grid-source-cell\"\n [class.grid-row-odd]=\"odd\"\n [class.has-diff-in-row]=\"field.HasDifference\"\n [class.field-selected]=\"field.SelectedColumnIndex === 0\"\n (click)=\"SelectFieldValue(field, 0)\">\n @if (field.SourceValue != null) {\n {{ field.SourceValue }}\n } @else {\n <span class=\"field-not-available\">(not available)</span>\n }\n @if (field.HasDifference || field.SelectedColumnIndex === 0) {\n <input type=\"radio\" [name]=\"'field-' + field.FieldName\" class=\"field-select-radio\"\n [checked]=\"field.SelectedColumnIndex === 0\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"SelectFieldValue(field, 0)\">\n }\n </div>\n <!-- Match value cells -->\n @for (matchVal of field.MatchValues; track $index; let mi = $index) {\n <div class=\"grid-value-cell\"\n [class.grid-row-odd]=\"odd\"\n [class.value-same]=\"AreValuesEqual(field.SourceValue, matchVal)\"\n [class.value-different]=\"matchVal != null && field.SourceValue != null && !AreValuesEqual(field.SourceValue, matchVal)\"\n [class.field-selected]=\"field.SelectedColumnIndex === mi + 1\"\n (click)=\"matchVal != null ? SelectFieldValue(field, mi + 1) : null\">\n @if (matchVal != null) {\n {{ matchVal }}\n @if (field.HasDifference || field.SelectedColumnIndex === mi + 1) {\n <input type=\"radio\" [name]=\"'field-' + field.FieldName\" class=\"field-select-radio\"\n [checked]=\"field.SelectedColumnIndex === mi + 1\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"SelectFieldValue(field, mi + 1)\">\n }\n } @else {\n <span class=\"field-not-available\">(not available)</span>\n }\n </div>\n }\n }\n </div>\n </div>\n\n <!-- Footer -->\n <div class=\"comparison-footer\">\n <div class=\"comparison-footer-left\">\n <span class=\"comparison-summary\">\n Showing {{ GetVisibleFields().length }} of {{ ComparisonFields.length }} fields\n </span>\n <span class=\"merge-summary\">\n <i class=\"fa-solid fa-code-merge\"></i>\n Surviving: <strong>{{ SurvivorName() }}</strong>\n @if (CherryPickedCount() > 0) {\n · {{ CherryPickedCount() }} field{{ CherryPickedCount() !== 1 ? 's' : '' }} cherry-picked\n }\n </span>\n </div>\n <div class=\"comparison-footer-right\">\n <button class=\"action-btn reject-btn\" [disabled]=\"IsSaving\"\n (click)=\"RejectMatch(ComparisonGroup!); CloseComparison()\">\n <i class=\"fa-solid fa-times\"></i> Reject All\n </button>\n <button class=\"action-btn merge-btn\" [disabled]=\"IsSaving || !HasMergeableMatches || !MergeEnabled\"\n (click)=\"OpenMergeConfirm()\"\n [title]=\"!MergeEnabled ? 'Merging is not enabled for this entity' : HasMergeableMatches ? 'Merge non-skipped records' : 'All matches have been skipped'\">\n <i class=\"fa-solid fa-code-merge\"></i> Merge Records\n </button>\n @if (!MergeEnabled) {\n <span class=\"merge-disabled-hint\"><i class=\"fa-solid fa-info-circle\"></i> Merging disabled for this entity</span>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- \u2550\u2550\u2550 Merge Confirmation Panel \u2550\u2550\u2550 -->\n @if (ShowMergeConfirm && ComparisonGroup) {\n <div class=\"merge-confirm-backdrop\" (click)=\"CloseMergeConfirm()\">\n <div class=\"merge-confirm-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"merge-confirm-header\">\n <div class=\"merge-confirm-icon\"><i class=\"fa-solid fa-code-merge\"></i></div>\n <div>\n <div class=\"merge-confirm-title\">Confirm Record Merge</div>\n <div class=\"merge-confirm-subtitle\">This action cannot be undone. Please review carefully.</div>\n </div>\n </div>\n\n <div class=\"merge-confirm-body\">\n <!-- Surviving Record -->\n <div class=\"merge-survivor-card\">\n <div class=\"merge-survivor-label\"><i class=\"fa-solid fa-shield-halved\"></i> Surviving Record</div>\n <div class=\"merge-survivor-name\">{{ SurvivorName() }}</div>\n <div class=\"merge-survivor-pk\">\n <i class=\"fa-solid fa-key\"></i>\n {{ SurvivorKeyDisplay() }}\n </div>\n <div class=\"merge-survivor-detail\">This record's ID will be retained. All dependencies from merged records will be transferred here.</div>\n </div>\n\n <!-- Cherry-picked field overrides -->\n @if (GetCherryPickedFields().length > 0) {\n <div>\n <div class=\"merge-section-label\">Field Value Overrides ({{ GetCherryPickedFields().length }} field{{ GetCherryPickedFields().length !== 1 ? 's' : '' }})</div>\n @for (field of GetCherryPickedFields(); track field.FieldName) {\n <div class=\"merge-field-override\">\n <span class=\"merge-field-name\">{{ field.DisplayName }}</span>\n <span class=\"merge-field-value\">\"{{ field.Value }}\"</span>\n <span class=\"merge-field-source\">from {{ field.SourceName }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Dependency transfer -->\n @if (GetNonSurvivorColumns().length > 0) {\n <div class=\"merge-deps-transfer\">\n <div class=\"merge-deps-transfer-label\"><i class=\"fa-solid fa-arrow-right-arrow-left\"></i> Dependencies to Transfer</div>\n @for (col of GetNonSurvivorColumns(); track col.ColumnIndex) {\n <div class=\"merge-deps-transfer-row\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n <span>\n @if (col.DepCount > 0) {\n <strong>{{ col.DepCount }}</strong> {{ col.DepCount === 1 ? 'dependency' : 'dependencies' }} from <strong>{{ col.Name }}</strong> → {{ SurvivorName() }}\n } @else {\n <strong>0</strong> dependencies from <strong>{{ col.Name }}</strong>\n }\n </span>\n </div>\n }\n </div>\n }\n\n <!-- Records to be deleted -->\n <div class=\"merge-delete-card\">\n <div class=\"merge-delete-label\"><i class=\"fa-solid fa-trash\"></i> Records to Delete After Merge</div>\n @for (col of GetNonSurvivorColumns(); track col.ColumnIndex) {\n <div class=\"merge-delete-item\">\n <span class=\"merge-delete-name\">{{ col.Name }}</span>\n <span class=\"merge-delete-deps\">\n @if (col.DepCount > 0) {\n {{ col.DepCount }} dep{{ col.DepCount !== 1 ? 's' : '' }} transferring\n } @else {\n no deps\n }\n </span>\n </div>\n }\n </div>\n </div>\n\n <div class=\"merge-confirm-footer\">\n <button class=\"action-btn cancel-btn\" (click)=\"CloseMergeConfirm()\" [disabled]=\"IsMerging\">\n <i class=\"fa-solid fa-arrow-left\"></i> Back\n </button>\n <button class=\"action-btn confirm-merge-btn\" (click)=\"ExecuteMerge()\" [disabled]=\"IsMerging\">\n @if (IsMerging) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i> Merging...\n } @else {\n <i class=\"fa-solid fa-code-merge\"></i> Confirm Merge ({{ GetNonSurvivorColumns().length + 1 }} records → 1)\n }\n </button>\n </div>\n </div>\n </div>\n }\n\n</div>\n", styles: ["/* ============================================================\n Duplicate Detection Kanban Board - Resource Component Styles\n All colors use MJ design tokens (--mj-*) exclusively.\n ============================================================ */\n\napp-duplicate-detection-resource {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n}\n\n.duplicate-detection-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n padding: 16px 20px;\n background: var(--mj-bg-page);\n position: relative;\n overflow: hidden;\n}\n\n/* ---- Page Header ---- */\n\n.page-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.page-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.page-title i {\n color: var(--mj-brand-primary);\n}\n\n/* ---- Header Actions ---- */\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.run-detection-controls {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.entity-doc-select {\n padding: 8px 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n min-width: 200px;\n}\n\n.entity-doc-select:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.run-detection-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n transition: background 0.15s;\n white-space: nowrap;\n}\n\n.run-detection-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.run-detection-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Detection Progress ---- */\n\n.detection-progress-section {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n padding: 14px 18px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.progress-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 8px;\n}\n\n.progress-stage {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n}\n\n.progress-percent {\n font-size: 13px;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.progress-bar-track {\n height: 6px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n overflow: hidden;\n}\n\n.progress-bar-fill {\n height: 100%;\n border-radius: 3px;\n background: var(--mj-brand-primary);\n transition: width 0.3s ease;\n}\n\n.progress-current-item {\n display: block;\n margin-top: 6px;\n font-size: 11px;\n color: var(--mj-text-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* ---- Threshold Controls ---- */\n\n.threshold-controls {\n display: flex;\n gap: 24px;\n padding: 12px 16px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-status-info) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-subtle);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-slider-group {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.threshold-label {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n}\n\n.threshold-value {\n margin-left: auto;\n font-weight: 700;\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n}\n\n.threshold-slider {\n width: 100%;\n height: 4px;\n appearance: none;\n -webkit-appearance: none;\n background: var(--mj-border-default);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n\n.threshold-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider::-moz-range-thumb {\n width: 14px;\n height: 14px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n}\n\n.threshold-slider:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.threshold-hint {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n/* ---- Threshold Info (legacy) ---- */\n\n.threshold-info {\n display: flex;\n gap: 16px;\n padding: 8px 14px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-status-info) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-info-border);\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.threshold-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-status-info-text);\n font-weight: 500;\n}\n\n.threshold-item i {\n font-size: 11px;\n}\n\n/* ---- KPI Strip ---- */\n\n.kpi-strip {\n display: flex;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.kpi-card {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 12px 16px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.kpi-value {\n font-size: 28px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n}\n\n.kpi-label {\n font-size: 12px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-top: 2px;\n}\n\n.kpi-pending .kpi-value {\n color: var(--mj-status-warning);\n}\n\n.kpi-approved .kpi-value {\n color: var(--mj-status-success);\n}\n\n.kpi-rejected .kpi-value {\n color: var(--mj-status-error);\n}\n\n/* ---- Filter Bar ---- */\n\n.filter-bar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 16px;\n flex-shrink: 0;\n}\n\n.filter-group {\n display: flex;\n align-items: flex-end;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.filter-select {\n height: 34px;\n padding: 4px 10px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n min-width: 160px;\n}\n\n.filter-select:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.filter-range {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.filter-label {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.filter-input {\n height: 34px;\n padding: 4px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n font-size: 13px;\n outline: none;\n width: 100px;\n}\n\n.filter-input-score {\n width: 80px;\n}\n\n.filter-input-date {\n width: 140px;\n}\n\n.filter-input:focus {\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n.clear-filters-btn {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 34px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.clear-filters-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* ---- Loading & Empty States ---- */\n\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1;\n min-height: 200px;\n gap: 8px;\n}\n\n.empty-icon {\n font-size: 48px;\n color: var(--mj-text-disabled);\n}\n\n.empty-text {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.empty-subtext {\n font-size: 13px;\n color: var(--mj-text-muted);\n margin: 0;\n}\n\n/* ---- Kanban Board ---- */\n\n.kanban-board {\n display: flex;\n gap: 16px;\n flex: 1;\n min-height: 0;\n overflow-x: auto;\n}\n\n.kanban-column {\n flex: 1;\n min-width: 280px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-subtle);\n border-radius: 10px;\n overflow: hidden;\n}\n\n.column-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 16px;\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-subtle);\n flex-shrink: 0;\n}\n\n.column-header-pending {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, var(--mj-bg-surface));\n}\n\n.column-header-pending i {\n color: var(--mj-status-warning);\n}\n\n.column-header-approved {\n background: color-mix(in srgb, var(--mj-status-success) 8%, var(--mj-bg-surface));\n}\n\n.column-header-approved i {\n color: var(--mj-status-success);\n}\n\n.column-header-rejected {\n background: color-mix(in srgb, var(--mj-status-error) 8%, var(--mj-bg-surface));\n}\n\n.column-header-rejected i {\n color: var(--mj-status-error);\n}\n\n.column-title {\n flex: 1;\n}\n\n.column-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 24px;\n height: 24px;\n padding: 0 6px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n.column-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.column-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 6px;\n padding: 32px 16px;\n color: var(--mj-text-disabled);\n font-size: 13px;\n}\n\n.column-empty i {\n font-size: 24px;\n}\n\n/* ---- Kanban Cards ---- */\n\n.kanban-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n overflow: hidden;\n transition: box-shadow 0.15s ease, border-color 0.15s ease;\n flex-shrink: 0; /* Prevent cards from shrinking \u2014 column scrolls instead */\n}\n\n.kanban-card:hover {\n border-color: var(--mj-border-strong);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-text-primary) 8%, transparent);\n}\n\n/* Drag and Drop */\n.kanban-card[draggable=\"true\"] {\n cursor: grab;\n}\n\n.kanban-card[draggable=\"true\"]:active {\n cursor: grabbing;\n}\n\n.drop-target-active {\n outline: 2px dashed var(--mj-brand-primary);\n outline-offset: -2px;\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface-card)) !important;\n}\n\n.drop-target-active .column-body {\n min-height: 100px;\n}\n\n.card-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n padding: 10px 12px;\n border-bottom: 1px solid var(--mj-border-subtle);\n gap: 8px;\n}\n\n.card-header-left {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n min-width: 0;\n flex: 1;\n}\n\n.card-icon {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n flex-shrink: 0;\n}\n\n.card-title-block {\n min-width: 0;\n flex: 1;\n}\n\n.card-record-name {\n font-size: 0.85rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-bottom: 2px;\n}\n\n.entity-badge {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border-radius: 3px;\n font-size: 10px;\n font-weight: 500;\n color: var(--mj-text-muted);\n letter-spacing: 0.2px;\n}\n\n/* Score indicator colors */\n\n.score-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 40px;\n padding: 2px 8px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 700;\n}\n\n.score-high {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.score-medium {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n}\n\n.score-low {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.card-body {\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.match-summaries {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.match-summary-row {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n}\n\n.match-score {\n flex-shrink: 0;\n font-weight: 600;\n font-size: 11px;\n color: var(--mj-text-muted);\n min-width: 30px;\n}\n\n.match-name {\n color: var(--mj-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.match-summary-more {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n padding-left: 38px;\n}\n\n.card-meta-row {\n display: flex;\n align-items: center;\n gap: 12px;\n font-size: 11px;\n color: var(--mj-text-muted);\n border-top: 1px solid var(--mj-border-subtle);\n padding-top: 6px;\n}\n\n.card-meta-item {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.card-meta-item i {\n font-size: 10px;\n}\n font-size: 12px;\n max-width: 180px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Comparison Slide-In Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.slide-backdrop {\n position: fixed;\n inset: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: fadeIn 0.2s ease;\n}\n\n.slide-backdrop.comparison-closing {\n animation: fadeOut 0.25s ease forwards;\n}\n\n@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n@keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }\n\n.comparison-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 82vw;\n max-width: 1300px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0,0,0,0.4);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n overflow: hidden;\n}\n\n.comparison-panel.comparison-closing {\n animation: slideOut 0.25s cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }\n@keyframes slideOut { from { transform: translateX(0); } to { transform: translateX(100%); } }\n\n/* Header */\n.comparison-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 20px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 12px;\n}\n\n.comparison-header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n min-width: 0;\n}\n\n.comparison-entity-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 1rem;\n flex-shrink: 0;\n}\n\n.comparison-title {\n font-size: 1rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.comparison-entity-badge {\n display: inline-block;\n padding: 1px 7px;\n border-radius: 10px;\n font-size: 0.65rem;\n font-weight: 500;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n margin-right: 6px;\n}\n\n.comparison-match-count {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.comparison-header-right {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n}\n\n/* Toggle */\n.comparison-toggle {\n display: flex;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n overflow: hidden;\n}\n\n.toggle-btn {\n padding: 5px 12px;\n font-size: 0.7rem;\n font-weight: 500;\n border: none;\n cursor: pointer;\n transition: all 0.15s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn:first-child {\n border-right: 1px solid var(--mj-border-default);\n}\n\n.toggle-btn.toggle-active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.comparison-close-btn {\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.85rem;\n transition: all 0.15s ease;\n}\n\n.comparison-close-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Loading state */\n.comparison-loading {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Grid wrapper */\n.comparison-grid-wrapper {\n flex: 1;\n overflow: auto;\n min-height: 0;\n}\n\n/* Grid */\n.comparison-grid {\n display: grid;\n min-width: 100%;\n}\n\n.comparison-grid > div {\n padding: 8px 12px;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n border-right: 1px solid var(--mj-border-subtle);\n}\n\n/* Corner cell */\n.grid-corner-cell {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 4;\n background: var(--mj-bg-surface-elevated);\n font-size: 0.65rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-muted);\n display: flex;\n align-items: flex-end;\n padding-bottom: 6px;\n}\n\n/* Column headers */\n.grid-col-header {\n position: sticky;\n top: 0;\n z-index: 3;\n background: var(--mj-bg-surface-elevated);\n padding: 10px 12px;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.grid-col-source {\n border-left: 3px solid var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface-elevated));\n}\n\n.col-header-label {\n font-size: 0.6rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n}\n\n.col-header-top {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n}\n\n.col-header-name {\n font-size: 0.82rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.col-header-diff-count {\n font-size: 0.65rem;\n color: var(--mj-status-warning-text);\n}\n\n/* Surviving record selector */\n.surviving-selector {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n}\n\n.surviving-radio {\n appearance: none;\n width: 14px;\n height: 14px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\n\n.surviving-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2px var(--mj-bg-surface-elevated);\n}\n\n.surviving-label {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n}\n\n.surviving-label.is-survivor {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* Use all fields button */\n.use-all-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 0.62rem;\n cursor: pointer;\n transition: all 0.12s ease;\n margin-top: 2px;\n}\n\n.use-all-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.use-all-btn.all-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* Per-match actions */\n.comparison-match-actions {\n display: flex;\n gap: 4px;\n margin-top: 3px;\n}\n\n.action-btn-sm {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid;\n border-radius: 5px;\n cursor: pointer;\n font-size: 0.65rem;\n transition: all 0.15s ease;\n}\n\n.approve-btn-sm {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n.approve-btn-sm:hover { background: rgba(34,197,94,0.25); }\n\n.reject-btn-sm {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n.reject-btn-sm:hover { background: rgba(239,68,68,0.25); }\n\n.match-status-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.68rem;\n font-weight: 500;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.status-approved {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n}\n\n.status-rejected {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n}\n\n.match-approval-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.match-action-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 10px;\n border-radius: 6px;\n font-size: 0.7rem;\n font-weight: 500;\n border: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n\n.match-skip-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-status-error);\n border-color: color-mix(in srgb, var(--mj-status-error) 30%, var(--mj-border-default));\n}\n\n.match-skip-btn:hover {\n background: var(--mj-status-error-bg);\n border-color: var(--mj-status-error);\n}\n\n.match-undo-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n}\n\n.match-undo-btn:hover {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.match-approved {\n border-top: 3px solid var(--mj-status-success);\n}\n\n.match-rejected {\n border-top: 3px solid var(--mj-status-error);\n opacity: 0.6;\n}\n\n/* Label cells */\n.grid-label-cell {\n position: sticky;\n left: 0;\n z-index: 2;\n background: var(--mj-bg-surface);\n font-size: 0.72rem;\n font-weight: 600;\n color: var(--mj-text-secondary);\n display: flex;\n align-items: center;\n}\n\n.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n.grid-label-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface));\n}\n\n/* Value cells */\n.grid-value-cell {\n font-size: 0.78rem;\n color: var(--mj-text-primary);\n line-height: 1.45;\n word-break: break-word;\n position: relative;\n cursor: pointer;\n}\n\n.grid-source-cell {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, var(--mj-bg-surface));\n border-left: 3px solid transparent;\n}\n\n.grid-source-cell.grid-row-odd {\n background: color-mix(in srgb, var(--mj-brand-primary) 3%, color-mix(in srgb, var(--mj-bg-surface-sunken) 50%, var(--mj-bg-surface)));\n}\n\n.grid-source-cell.has-diff-in-row {\n font-weight: 600;\n}\n\n/* Diff highlighting */\n.value-same {\n color: var(--mj-text-muted);\n}\n\n.value-different {\n background: color-mix(in srgb, var(--mj-status-warning) 8%, transparent) !important;\n border-left: 3px solid var(--mj-status-warning);\n color: var(--mj-text-primary);\n}\n\n.field-not-available {\n font-style: italic;\n font-size: 0.72rem;\n color: var(--mj-text-disabled);\n}\n\n/* Field selection radio */\n.field-select-radio {\n position: absolute;\n top: 50%;\n right: 8px;\n transform: translateY(-50%);\n appearance: none;\n width: 16px;\n height: 16px;\n border: 2px solid var(--mj-border-strong);\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.12s ease;\n opacity: 0.4;\n}\n\n.field-select-radio:hover {\n opacity: 0.8;\n}\n\n.field-select-radio:checked {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-primary);\n box-shadow: inset 0 0 0 2.5px var(--mj-bg-surface);\n opacity: 1;\n}\n\n.grid-value-cell.field-selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface)) !important;\n border-left: 3px solid var(--mj-brand-primary);\n}\n\n.grid-value-cell.field-selected .field-select-radio {\n opacity: 1;\n}\n\n/* Footer */\n.comparison-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 20px;\n border-top: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.comparison-footer-left {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n\n.comparison-summary {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n}\n\n.merge-summary {\n font-size: 0.72rem;\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.merge-summary i {\n font-size: 0.65rem;\n}\n\n.comparison-footer-right {\n display: flex;\n gap: 8px;\n}\n\n.comparison-footer-right .action-btn {\n flex: none;\n padding: 7px 14px;\n}\n\n.merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.merge-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.card-actions {\n display: flex;\n gap: 8px;\n padding: 10px 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n.action-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 32px;\n padding: 0 12px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.15s ease, border-color 0.15s ease;\n}\n\n.action-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.approve-btn {\n background: color-mix(in srgb, var(--mj-status-success) 10%, var(--mj-bg-surface));\n color: var(--mj-status-success-text);\n border-color: var(--mj-status-success-border);\n}\n\n.approve-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-success) 20%, var(--mj-bg-surface));\n}\n\n.reject-btn {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface));\n color: var(--mj-status-error-text);\n border-color: var(--mj-status-error-border);\n}\n\n.reject-btn:hover:not(:disabled) {\n background: color-mix(in srgb, var(--mj-status-error) 20%, var(--mj-bg-surface));\n}\n\n/* ---- Responsive ---- */\n\n@media (max-width: 768px) {\n .kanban-board {\n flex-direction: column;\n }\n\n .kanban-column {\n min-width: auto;\n max-height: 400px;\n }\n}\n\n@media (max-width: 480px) {\n .kpi-strip {\n flex-direction: column;\n }\n\n .filter-bar {\n flex-wrap: wrap;\n }\n\n .filter-group {\n flex-direction: column;\n align-items: stretch;\n width: 100%;\n }\n\n .filter-select {\n min-width: auto;\n width: 100%;\n }\n\n .filter-input {\n width: 100%;\n }\n\n .card-actions {\n flex-direction: column;\n }\n\n .action-btn {\n width: 100%;\n }\n}\n\n/* ---- Saving Overlay ---- */\n\n.saving-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--mj-bg-overlay);\n z-index: 10;\n border-radius: 8px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Dependencies Summary (in column headers)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.deps-summary {\n margin-top: 6px;\n padding: 6px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 6px;\n font-size: 0.68rem;\n}\n\n.deps-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n cursor: pointer;\n color: var(--mj-text-secondary);\n font-weight: 600;\n}\n\n.deps-header i {\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-header:hover {\n color: var(--mj-text-primary);\n}\n\n.deps-total {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 0.72rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 2px;\n}\n\n.deps-total i {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n.deps-total-number {\n background: color-mix(in srgb, var(--mj-brand-primary) 15%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 0.7rem;\n font-weight: 700;\n}\n\n.deps-total-recommended {\n font-size: 0.58rem;\n color: var(--mj-status-success-text);\n font-weight: 600;\n margin-left: 4px;\n}\n\n.deps-total-recommended i {\n color: var(--mj-status-success-text);\n}\n\n.deps-detail-list {\n margin-top: 4px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.deps-detail-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 3px 0;\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: background 0.1s ease;\n}\n\n.deps-detail-row:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.deps-detail-entity {\n display: flex;\n align-items: center;\n gap: 4px;\n color: var(--mj-text-secondary);\n}\n\n.deps-expand-icon {\n font-size: 0.5rem;\n width: 10px;\n text-align: center;\n color: var(--mj-text-muted);\n}\n\n/* Individual dependency records list */\n.deps-records-list {\n padding-left: 14px;\n margin-bottom: 2px;\n}\n\n.deps-record-row {\n display: flex;\n align-items: center;\n gap: 5px;\n padding: 2px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n cursor: pointer;\n border-radius: 3px;\n transition: color 0.1s ease, background 0.1s ease;\n}\n\n.deps-record-row:hover {\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.deps-record-icon {\n font-size: 0.5rem;\n flex-shrink: 0;\n}\n\n.deps-record-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 0.6rem;\n}\n\n.deps-record-loading {\n padding: 3px 4px;\n font-size: 0.6rem;\n color: var(--mj-text-muted);\n}\n\n.deps-record-loading i {\n margin-right: 4px;\n}\n\n.deps-detail-count {\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n Merge Confirmation Panel\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-confirm-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.3);\n z-index: 20000;\n animation: fadeIn 0.2s ease;\n}\n\n.merge-confirm-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: 520px;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -8px 0 40px rgba(0, 0, 0, 0.4);\n z-index: 20001;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n animation: slideIn 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.merge-confirm-header {\n padding: 18px 24px;\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.merge-confirm-icon {\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 10px;\n background: color-mix(in srgb, var(--mj-status-warning) 12%, var(--mj-bg-surface));\n color: var(--mj-status-warning-text);\n font-size: 1.1rem;\n flex-shrink: 0;\n}\n\n.merge-confirm-title {\n font-size: 1.05rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n}\n\n.merge-confirm-subtitle {\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n margin-top: 2px;\n}\n\n.merge-confirm-body {\n padding: 20px 24px;\n overflow-y: auto;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n/* Surviving record card */\n\n.merge-survivor-card {\n padding: 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 6%, var(--mj-bg-surface));\n border: 1px solid var(--mj-brand-primary);\n border-radius: 8px;\n}\n\n.merge-survivor-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-brand-primary);\n margin-bottom: 4px;\n}\n\n.merge-survivor-label i {\n margin-right: 4px;\n}\n\n.merge-survivor-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.merge-survivor-pk {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-top: 4px;\n padding: 4px 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border-radius: 4px;\n font-size: 0.68rem;\n font-family: monospace;\n color: var(--mj-text-secondary);\n}\n\n.merge-survivor-pk i {\n font-size: 0.6rem;\n color: var(--mj-brand-primary);\n}\n\n.merge-survivor-detail {\n font-size: 0.72rem;\n color: var(--mj-text-muted);\n margin-top: 4px;\n}\n\n/* Cherry-picked fields section */\n\n.merge-section-label {\n font-size: 0.7rem;\n font-weight: 700;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n margin-bottom: 6px;\n}\n\n.merge-field-override {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 6px 0;\n border-bottom: 1px solid var(--mj-border-subtle);\n font-size: 0.78rem;\n}\n\n.merge-field-name {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 110px;\n flex-shrink: 0;\n}\n\n.merge-field-value {\n color: var(--mj-text-primary);\n}\n\n.merge-field-source {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n margin-left: auto;\n white-space: nowrap;\n}\n\n/* Dependency transfer summary */\n\n.merge-deps-transfer {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n}\n\n.merge-deps-transfer-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-brand-primary);\n margin-bottom: 6px;\n}\n\n.merge-deps-transfer-label i {\n margin-right: 4px;\n}\n\n.merge-deps-transfer-row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 3px 0;\n font-size: 0.75rem;\n color: var(--mj-text-secondary);\n}\n\n.merge-deps-transfer-row i {\n color: var(--mj-brand-primary);\n font-size: 0.65rem;\n width: 14px;\n text-align: center;\n}\n\n/* Records to delete */\n\n.merge-delete-card {\n padding: 10px 14px;\n background: color-mix(in srgb, var(--mj-status-error) 5%, var(--mj-bg-surface));\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n}\n\n.merge-delete-label {\n font-size: 0.65rem;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--mj-status-error-text);\n margin-bottom: 6px;\n}\n\n.merge-delete-label i {\n margin-right: 4px;\n}\n\n.merge-delete-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 5px 0;\n font-size: 0.78rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.merge-delete-item:last-child {\n border-bottom: none;\n}\n\n.merge-delete-name {\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.merge-delete-deps {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n/* Confirm footer */\n\n.merge-confirm-footer {\n padding: 14px 24px;\n border-top: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 10px;\n}\n\n.cancel-btn {\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-default);\n}\n\n.cancel-btn:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n.confirm-merge-btn {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n.confirm-merge-btn:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n}\n\n.confirm-merge-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* ---- Responsive: Merge Confirm ---- */\n\n@media (max-width: 600px) {\n .merge-confirm-panel {\n width: 100%;\n }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 Merge Disabled Hint \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-disabled-hint {\n font-size: 11.5px;\n color: var(--mj-status-warning-text, #e65100);\n display: inline-flex;\n align-items: center;\n gap: 4px;\n margin-left: 4px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550 Merge Warning Banner (inline, non-blocking) \u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.merge-warning-banner {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n margin-bottom: 12px;\n border-radius: 6px;\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning-border);\n font-size: 13px;\n font-weight: 500;\n flex-shrink: 0;\n}\n\n.merge-warning-banner i {\n font-size: 14px;\n flex-shrink: 0;\n}\n"] }]
|
|
2940
|
+
}], null, { OnEscapeKey: [{
|
|
2941
|
+
type: HostListener,
|
|
2942
|
+
args: ['document:keydown.escape']
|
|
2943
|
+
}], EmbeddedMode: [{
|
|
2677
2944
|
type: Input
|
|
2678
2945
|
}] }); })();
|
|
2679
2946
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DuplicateDetectionResourceComponent, { className: "DuplicateDetectionResourceComponent", filePath: "src/AI/components/duplicates/duplicate-detection-resource.component.ts", lineNumber: 105 }); })();
|