@memberjunction/ng-record-clone 0.0.1-seed.1 → 6.2.0-edge.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +183 -0
  2. package/README.md +241 -3
  3. package/dist/lib/clone-lineage-chip.component.d.ts +50 -0
  4. package/dist/lib/clone-lineage-chip.component.d.ts.map +1 -0
  5. package/dist/lib/clone-lineage-chip.component.js +448 -0
  6. package/dist/lib/clone-lineage-chip.component.js.map +1 -0
  7. package/dist/lib/clone-plan-tree.component.d.ts +51 -0
  8. package/dist/lib/clone-plan-tree.component.d.ts.map +1 -0
  9. package/dist/lib/clone-plan-tree.component.js +634 -0
  10. package/dist/lib/clone-plan-tree.component.js.map +1 -0
  11. package/dist/lib/clone-progress.component.d.ts +12 -0
  12. package/dist/lib/clone-progress.component.d.ts.map +1 -0
  13. package/dist/lib/clone-progress.component.js +151 -0
  14. package/dist/lib/clone-progress.component.js.map +1 -0
  15. package/dist/lib/clone-result.component.d.ts +40 -0
  16. package/dist/lib/clone-result.component.d.ts.map +1 -0
  17. package/dist/lib/clone-result.component.js +357 -0
  18. package/dist/lib/clone-result.component.js.map +1 -0
  19. package/dist/lib/clone-review.component.d.ts +58 -0
  20. package/dist/lib/clone-review.component.d.ts.map +1 -0
  21. package/dist/lib/clone-review.component.js +581 -0
  22. package/dist/lib/clone-review.component.js.map +1 -0
  23. package/dist/lib/clone-scope-controls.component.d.ts +81 -0
  24. package/dist/lib/clone-scope-controls.component.d.ts.map +1 -0
  25. package/dist/lib/clone-scope-controls.component.js +394 -0
  26. package/dist/lib/clone-scope-controls.component.js.map +1 -0
  27. package/dist/lib/clone-values.component.d.ts +55 -0
  28. package/dist/lib/clone-values.component.d.ts.map +1 -0
  29. package/dist/lib/clone-values.component.js +493 -0
  30. package/dist/lib/clone-values.component.js.map +1 -0
  31. package/dist/lib/record-clone-panel.component.d.ts +247 -0
  32. package/dist/lib/record-clone-panel.component.d.ts.map +1 -0
  33. package/dist/lib/record-clone-panel.component.js +1252 -0
  34. package/dist/lib/record-clone-panel.component.js.map +1 -0
  35. package/dist/lib/record-clone-slide-in.component.d.ts +83 -0
  36. package/dist/lib/record-clone-slide-in.component.d.ts.map +1 -0
  37. package/dist/lib/record-clone-slide-in.component.js +206 -0
  38. package/dist/lib/record-clone-slide-in.component.js.map +1 -0
  39. package/dist/lib/record-clone-types.d.ts +89 -0
  40. package/dist/lib/record-clone-types.d.ts.map +1 -0
  41. package/dist/lib/record-clone-types.js +29 -0
  42. package/dist/lib/record-clone-types.js.map +1 -0
  43. package/dist/lib/record-clone.module.d.ts +16 -0
  44. package/dist/lib/record-clone.module.d.ts.map +1 -0
  45. package/dist/lib/record-clone.module.js +69 -0
  46. package/dist/lib/record-clone.module.js.map +1 -0
  47. package/dist/lib/record-clone.service.d.ts +42 -0
  48. package/dist/lib/record-clone.service.d.ts.map +1 -0
  49. package/dist/lib/record-clone.service.js +123 -0
  50. package/dist/lib/record-clone.service.js.map +1 -0
  51. package/dist/public-api.d.ts +16 -0
  52. package/dist/public-api.d.ts.map +1 -0
  53. package/dist/public-api.js +16 -0
  54. package/dist/public-api.js.map +1 -0
  55. package/package.json +47 -5
@@ -0,0 +1,634 @@
1
+ /**
2
+ * @fileoverview Expandable hierarchical tree rendering a RecordClonePlan.
3
+ *
4
+ * Implements §12.3 & §12.4 of the Record Cloning architectural blueprint. Renders the
5
+ * planned record graph as an interactive tree with per-edge policy pills (Deep/Reference/Skip)
6
+ * with lock tooltips, per-node action badges, entity counts summary, and live search.
7
+ */
8
+ import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, ChangeDetectorRef, inject, } from '@angular/core';
9
+ import { CommonModule } from '@angular/common';
10
+ import { FormsModule } from '@angular/forms';
11
+ import { MJButtonDirective } from '@memberjunction/ng-ui-components';
12
+ import * as i0 from "@angular/core";
13
+ import * as i1 from "@angular/forms";
14
+ const _forTrack0 = ($index, $item) => $item.Node.Key;
15
+ function ClonePlanTreeComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
16
+ const _r1 = i0.ɵɵgetCurrentView();
17
+ i0.ɵɵelementStart(0, "button", 11);
18
+ i0.ɵɵlistener("click", function ClonePlanTreeComponent_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnSearchTermChange("")); });
19
+ i0.ɵɵelement(1, "i", 12);
20
+ i0.ɵɵelementEnd();
21
+ } }
22
+ function ClonePlanTreeComponent_Conditional_11_Conditional_10_Template(rf, ctx) { if (rf & 1) {
23
+ i0.ɵɵelementStart(0, "span", 16);
24
+ i0.ɵɵelement(1, "i", 18);
25
+ i0.ɵɵelementStart(2, "strong");
26
+ i0.ɵɵtext(3);
27
+ i0.ɵɵelementEnd();
28
+ i0.ɵɵtext(4, " Reference ");
29
+ i0.ɵɵelementEnd();
30
+ } if (rf & 2) {
31
+ const ctx_r1 = i0.ɵɵnextContext(2);
32
+ i0.ɵɵadvance(3);
33
+ i0.ɵɵtextInterpolate(ctx_r1.ReferenceCount);
34
+ } }
35
+ function ClonePlanTreeComponent_Conditional_11_Conditional_11_Template(rf, ctx) { if (rf & 1) {
36
+ i0.ɵɵelementStart(0, "span", 17);
37
+ i0.ɵɵelement(1, "i", 19);
38
+ i0.ɵɵelementStart(2, "strong");
39
+ i0.ɵɵtext(3);
40
+ i0.ɵɵelementEnd();
41
+ i0.ɵɵtext(4, " Skip ");
42
+ i0.ɵɵelementEnd();
43
+ } if (rf & 2) {
44
+ const ctx_r1 = i0.ɵɵnextContext(2);
45
+ i0.ɵɵadvance(3);
46
+ i0.ɵɵtextInterpolate(ctx_r1.SkipCount);
47
+ } }
48
+ function ClonePlanTreeComponent_Conditional_11_Conditional_12_Conditional_0_Template(rf, ctx) { if (rf & 1) {
49
+ i0.ɵɵelementStart(0, "span", 20);
50
+ i0.ɵɵelement(1, "i", 22);
51
+ i0.ɵɵelementStart(2, "strong");
52
+ i0.ɵɵtext(3, "Needs values");
53
+ i0.ɵɵelementEnd()();
54
+ } }
55
+ function ClonePlanTreeComponent_Conditional_11_Conditional_12_Conditional_1_Template(rf, ctx) { if (rf & 1) {
56
+ i0.ɵɵelementStart(0, "span", 21);
57
+ i0.ɵɵelement(1, "i", 23);
58
+ i0.ɵɵelementStart(2, "strong");
59
+ i0.ɵɵtext(3, "Blocked");
60
+ i0.ɵɵelementEnd()();
61
+ } }
62
+ function ClonePlanTreeComponent_Conditional_11_Conditional_12_Template(rf, ctx) { if (rf & 1) {
63
+ i0.ɵɵconditionalCreate(0, ClonePlanTreeComponent_Conditional_11_Conditional_12_Conditional_0_Template, 4, 0, "span", 20)(1, ClonePlanTreeComponent_Conditional_11_Conditional_12_Conditional_1_Template, 4, 0, "span", 21);
64
+ } if (rf & 2) {
65
+ const ctx_r1 = i0.ɵɵnextContext(2);
66
+ i0.ɵɵconditional(ctx_r1.NeedsValuesOnly ? 0 : 1);
67
+ } }
68
+ function ClonePlanTreeComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
69
+ i0.ɵɵelementStart(0, "div", 8)(1, "span", 13)(2, "strong");
70
+ i0.ɵɵtext(3);
71
+ i0.ɵɵelementEnd();
72
+ i0.ɵɵtext(4, " Total ");
73
+ i0.ɵɵelementEnd();
74
+ i0.ɵɵelementStart(5, "span", 14);
75
+ i0.ɵɵelement(6, "i", 15);
76
+ i0.ɵɵelementStart(7, "strong");
77
+ i0.ɵɵtext(8);
78
+ i0.ɵɵelementEnd();
79
+ i0.ɵɵtext(9, " Create ");
80
+ i0.ɵɵelementEnd();
81
+ i0.ɵɵconditionalCreate(10, ClonePlanTreeComponent_Conditional_11_Conditional_10_Template, 5, 1, "span", 16);
82
+ i0.ɵɵconditionalCreate(11, ClonePlanTreeComponent_Conditional_11_Conditional_11_Template, 5, 1, "span", 17);
83
+ i0.ɵɵconditionalCreate(12, ClonePlanTreeComponent_Conditional_11_Conditional_12_Template, 2, 1);
84
+ i0.ɵɵelementEnd();
85
+ } if (rf & 2) {
86
+ const ctx_r1 = i0.ɵɵnextContext();
87
+ i0.ɵɵadvance(3);
88
+ i0.ɵɵtextInterpolate(ctx_r1.Plan.Counts.Total);
89
+ i0.ɵɵadvance(5);
90
+ i0.ɵɵtextInterpolate(ctx_r1.Plan.Counts.Create);
91
+ i0.ɵɵadvance(2);
92
+ i0.ɵɵconditional(ctx_r1.ReferenceCount > 0 ? 10 : -1);
93
+ i0.ɵɵadvance();
94
+ i0.ɵɵconditional(ctx_r1.SkipCount > 0 ? 11 : -1);
95
+ i0.ɵɵadvance();
96
+ i0.ɵɵconditional(ctx_r1.Plan.Blocked ? 12 : -1);
97
+ } }
98
+ function ClonePlanTreeComponent_Conditional_13_Conditional_1_Template(rf, ctx) { if (rf & 1) {
99
+ i0.ɵɵtext(0, " No matching records found in the clone plan. ");
100
+ } }
101
+ function ClonePlanTreeComponent_Conditional_13_Conditional_2_Template(rf, ctx) { if (rf & 1) {
102
+ i0.ɵɵtext(0, " No records planned for cloning. ");
103
+ } }
104
+ function ClonePlanTreeComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
105
+ i0.ɵɵelementStart(0, "div", 10);
106
+ i0.ɵɵconditionalCreate(1, ClonePlanTreeComponent_Conditional_13_Conditional_1_Template, 1, 0)(2, ClonePlanTreeComponent_Conditional_13_Conditional_2_Template, 1, 0);
107
+ i0.ɵɵelementEnd();
108
+ } if (rf & 2) {
109
+ const ctx_r1 = i0.ɵɵnextContext();
110
+ i0.ɵɵadvance();
111
+ i0.ɵɵconditional(ctx_r1.SearchTerm ? 1 : 2);
112
+ } }
113
+ function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
114
+ const _r5 = i0.ɵɵgetCurrentView();
115
+ i0.ɵɵelementStart(0, "button", 35);
116
+ i0.ɵɵlistener("click", function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_2_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const item_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnToggleExpand(item_r4, $event)); });
117
+ i0.ɵɵelement(1, "i", 36);
118
+ i0.ɵɵelementEnd();
119
+ } if (rf & 2) {
120
+ const item_r4 = i0.ɵɵnextContext().$implicit;
121
+ i0.ɵɵproperty("title", item_r4.Expanded ? "Collapse" : "Expand");
122
+ i0.ɵɵattribute("aria-expanded", item_r4.Expanded)("aria-label", (item_r4.Expanded ? "Collapse " : "Expand ") + (item_r4.Node.DisplayName || item_r4.Node.EntityName));
123
+ i0.ɵɵadvance();
124
+ i0.ɵɵclassProp("fa-chevron-down", item_r4.Expanded)("fa-chevron-right", !item_r4.Expanded);
125
+ } }
126
+ function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
127
+ const _r6 = i0.ɵɵgetCurrentView();
128
+ i0.ɵɵelementStart(0, "button", 39);
129
+ i0.ɵɵlistener("click", function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Conditional_1_Template_button_click_0_listener($event) { const next_r7 = i0.ɵɵrestoreView(_r6); const item_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnPolicyToggle(item_r4.ParentEdge, next_r7, $event)); });
130
+ i0.ɵɵtext(1);
131
+ i0.ɵɵelementEnd();
132
+ } if (rf & 2) {
133
+ const next_r7 = ctx;
134
+ const item_r4 = i0.ɵɵnextContext(2).$implicit;
135
+ const ctx_r1 = i0.ɵɵnextContext(2);
136
+ i0.ɵɵclassProp("policy-deep", item_r4.ParentEdge.Policy === "Deep")("policy-ref", item_r4.ParentEdge.Policy === "Reference")("policy-skip", item_r4.ParentEdge.Policy === "Skip");
137
+ i0.ɵɵproperty("title", ctx_r1.GetEdgeTooltip(item_r4.ParentEdge) + (next_r7 === "Skip" ? " Click to skip every " + item_r4.ParentEdge.RelatedEntityName + " row." : " Click to copy these rows."));
138
+ i0.ɵɵattribute("aria-label", (next_r7 === "Skip" ? "Skip every " : "Copy every ") + item_r4.ParentEdge.RelatedEntityName + " row");
139
+ i0.ɵɵadvance();
140
+ i0.ɵɵtextInterpolate1(" ", item_r4.ParentEdge.Policy, " ");
141
+ } }
142
+ function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Conditional_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
143
+ i0.ɵɵelement(0, "i", 41);
144
+ } }
145
+ function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Conditional_2_Template(rf, ctx) { if (rf & 1) {
146
+ i0.ɵɵelementStart(0, "span", 40);
147
+ i0.ɵɵconditionalCreate(1, ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Conditional_2_Conditional_1_Template, 1, 0, "i", 41);
148
+ i0.ɵɵtext(2);
149
+ i0.ɵɵelementEnd();
150
+ } if (rf & 2) {
151
+ const item_r4 = i0.ɵɵnextContext(2).$implicit;
152
+ const ctx_r1 = i0.ɵɵnextContext(2);
153
+ i0.ɵɵclassProp("policy-deep", item_r4.ParentEdge.Policy === "Deep")("policy-ref", item_r4.ParentEdge.Policy === "Reference")("policy-skip", item_r4.ParentEdge.Policy === "Skip");
154
+ i0.ɵɵproperty("title", ctx_r1.GetEdgeTooltip(item_r4.ParentEdge));
155
+ i0.ɵɵadvance();
156
+ i0.ɵɵconditional(item_r4.ParentEdge.Locked ? 1 : -1);
157
+ i0.ɵɵadvance();
158
+ i0.ɵɵtextInterpolate1(" ", item_r4.ParentEdge.Policy, " ");
159
+ } }
160
+ function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
161
+ i0.ɵɵelementStart(0, "div", 28);
162
+ i0.ɵɵconditionalCreate(1, ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Conditional_1_Template, 2, 9, "button", 37)(2, ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Conditional_2_Template, 3, 9, "span", 38);
163
+ i0.ɵɵelementEnd();
164
+ } if (rf & 2) {
165
+ let tmp_12_0;
166
+ const item_r4 = i0.ɵɵnextContext().$implicit;
167
+ const ctx_r1 = i0.ɵɵnextContext(2);
168
+ i0.ɵɵadvance();
169
+ i0.ɵɵconditional((tmp_12_0 = ctx_r1.NextPolicy(item_r4.ParentEdge)) ? 1 : 2, tmp_12_0);
170
+ } }
171
+ function ClonePlanTreeComponent_Conditional_14_For_1_Conditional_12_Template(rf, ctx) { if (rf & 1) {
172
+ i0.ɵɵelementStart(0, "span", 34);
173
+ i0.ɵɵelement(1, "i", 42);
174
+ i0.ɵɵtext(2);
175
+ i0.ɵɵelementEnd();
176
+ } if (rf & 2) {
177
+ const item_r4 = i0.ɵɵnextContext().$implicit;
178
+ i0.ɵɵproperty("title", item_r4.Node.Warnings.length + " warning(s)");
179
+ i0.ɵɵadvance(2);
180
+ i0.ɵɵtextInterpolate1(" ", item_r4.Node.Warnings.length, " ");
181
+ } }
182
+ function ClonePlanTreeComponent_Conditional_14_For_1_Template(rf, ctx) { if (rf & 1) {
183
+ const _r3 = i0.ɵɵgetCurrentView();
184
+ i0.ɵɵelementStart(0, "div", 25);
185
+ i0.ɵɵlistener("click", function ClonePlanTreeComponent_Conditional_14_For_1_Template_div_click_0_listener() { const item_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnSelectNode(item_r4.Node)); });
186
+ i0.ɵɵelementStart(1, "div", 26);
187
+ i0.ɵɵconditionalCreate(2, ClonePlanTreeComponent_Conditional_14_For_1_Conditional_2_Template, 2, 7, "button", 27);
188
+ i0.ɵɵelementEnd();
189
+ i0.ɵɵconditionalCreate(3, ClonePlanTreeComponent_Conditional_14_For_1_Conditional_3_Template, 3, 1, "div", 28);
190
+ i0.ɵɵelementStart(4, "div", 29)(5, "span", 30);
191
+ i0.ɵɵtext(6);
192
+ i0.ɵɵelementEnd()();
193
+ i0.ɵɵelementStart(7, "div", 31)(8, "span", 32);
194
+ i0.ɵɵtext(9);
195
+ i0.ɵɵelementEnd();
196
+ i0.ɵɵelementStart(10, "span", 33);
197
+ i0.ɵɵtext(11);
198
+ i0.ɵɵelementEnd();
199
+ i0.ɵɵconditionalCreate(12, ClonePlanTreeComponent_Conditional_14_For_1_Conditional_12_Template, 3, 2, "span", 34);
200
+ i0.ɵɵelementEnd()();
201
+ } if (rf & 2) {
202
+ const item_r4 = ctx.$implicit;
203
+ const ctx_r1 = i0.ɵɵnextContext(2);
204
+ i0.ɵɵstyleProp("padding-left", item_r4.Level * 20 + 8, "px");
205
+ i0.ɵɵclassProp("selected", ctx_r1.SelectedNodeKey === item_r4.Node.Key)("is-subtype", item_r4.Node.IsSubtypeRow);
206
+ i0.ɵɵattribute("aria-level", item_r4.Level + 1);
207
+ i0.ɵɵadvance(2);
208
+ i0.ɵɵconditional(item_r4.Children.length > 0 ? 2 : -1);
209
+ i0.ɵɵadvance();
210
+ i0.ɵɵconditional(item_r4.ParentEdge ? 3 : -1);
211
+ i0.ɵɵadvance(2);
212
+ i0.ɵɵclassProp("action-create", item_r4.Node.Action === "Create")("action-ref", item_r4.Node.Action === "Reference")("action-skip", item_r4.Node.Action === "Skip")("action-blocked", item_r4.Node.Action === "Blocked");
213
+ i0.ɵɵadvance();
214
+ i0.ɵɵtextInterpolate1(" ", item_r4.Node.Action, " ");
215
+ i0.ɵɵadvance(3);
216
+ i0.ɵɵtextInterpolate(item_r4.Node.EntityName);
217
+ i0.ɵɵadvance();
218
+ i0.ɵɵproperty("title", item_r4.Node.DisplayName);
219
+ i0.ɵɵadvance();
220
+ i0.ɵɵtextInterpolate1(" ", item_r4.Node.DisplayName, " ");
221
+ i0.ɵɵadvance();
222
+ i0.ɵɵconditional(item_r4.Node.Warnings && item_r4.Node.Warnings.length > 0 ? 12 : -1);
223
+ } }
224
+ function ClonePlanTreeComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
225
+ i0.ɵɵrepeaterCreate(0, ClonePlanTreeComponent_Conditional_14_For_1_Template, 13, 22, "div", 24, _forTrack0);
226
+ } if (rf & 2) {
227
+ const ctx_r1 = i0.ɵɵnextContext();
228
+ i0.ɵɵrepeater(ctx_r1.FlatVisibleNodes);
229
+ } }
230
+ export class ClonePlanTreeComponent {
231
+ _plan = null;
232
+ cdr = inject(ChangeDetectorRef);
233
+ /** The plan to render. Setting it rebuilds the tree. */
234
+ set Plan(value) {
235
+ this._plan = value;
236
+ this.rebuildTree();
237
+ }
238
+ get Plan() {
239
+ return this._plan;
240
+ }
241
+ /** Key of the node to highlight, e.g. when the review step links back to it. */
242
+ SelectedNodeKey = null;
243
+ /** Let the user switch unlocked Deep branches to Skip (narrowing). Default false (read-only tree). */
244
+ AllowNarrowing = false;
245
+ /** Also let the user switch Skip branches to Deep (widening; needs Clone Records: Override Scope). */
246
+ AllowWidening = false;
247
+ /** Fires when the user selects a node row. */
248
+ NodeSelected = new EventEmitter();
249
+ /** Fires when the user switches a branch's policy; the host re-plans with it as an edge override. */
250
+ EdgePolicyChanged = new EventEmitter();
251
+ SearchTerm = '';
252
+ TreeNodes = [];
253
+ FlatVisibleNodes = [];
254
+ get ReferenceCount() {
255
+ if (!this.Plan)
256
+ return 0;
257
+ return this.Plan.Nodes.filter(n => n.Action === 'Reference').length;
258
+ }
259
+ /** Blocked only because prompted values haven't been entered yet: not a problem on the Scope step. */
260
+ get NeedsValuesOnly() {
261
+ const errors = (this.Plan?.Warnings ?? []).filter((w) => w.Severity === 'Error');
262
+ return errors.length > 0 && errors.every((w) => w.Code === 'UNIQUE_PROMPT_REQUIRED');
263
+ }
264
+ get SkipCount() {
265
+ if (!this.Plan)
266
+ return 0;
267
+ return this.Plan.Nodes.filter(n => n.Action === 'Skip').length;
268
+ }
269
+ OnSearchTermChange(term) {
270
+ this.SearchTerm = term;
271
+ this.updateVisibleNodes();
272
+ this.cdr.markForCheck();
273
+ }
274
+ OnSelectNode(node) {
275
+ this.SelectedNodeKey = node.Key;
276
+ this.NodeSelected.emit(node);
277
+ this.cdr.markForCheck();
278
+ }
279
+ OnToggleExpand(item, event) {
280
+ event.stopPropagation();
281
+ item.Expanded = !item.Expanded;
282
+ this.updateVisibleNodes();
283
+ this.cdr.markForCheck();
284
+ }
285
+ ExpandAll() {
286
+ this.setAllExpanded(this.TreeNodes, true);
287
+ this.updateVisibleNodes();
288
+ this.cdr.markForCheck();
289
+ }
290
+ CollapseAll() {
291
+ this.setAllExpanded(this.TreeNodes, false);
292
+ this.updateVisibleNodes();
293
+ this.cdr.markForCheck();
294
+ }
295
+ /** The policy a click on this edge's pill would switch to, or null when the pill is read-only. */
296
+ NextPolicy(edge) {
297
+ if (edge.Locked || !edge.RelationshipID)
298
+ return null;
299
+ if (edge.Policy === 'Deep' && this.AllowNarrowing)
300
+ return 'Skip';
301
+ // A branch the user skipped themselves can always be put back; the host drops that override.
302
+ if (edge.Policy === 'Skip' && (this.AllowWidening || edge.PolicySource === 'Request'))
303
+ return 'Deep';
304
+ return null;
305
+ }
306
+ OnPolicyToggle(edge, policy, event) {
307
+ event.stopPropagation();
308
+ if (!edge.RelationshipID)
309
+ return;
310
+ this.EdgePolicyChanged.emit({ RelationshipID: edge.RelationshipID, Policy: policy, RelatedEntityName: edge.RelatedEntityName });
311
+ }
312
+ GetEdgeTooltip(edge) {
313
+ if (edge.Locked) {
314
+ return `Policy is locked (${edge.PolicySource || 'system constraint'}). Cannot be modified.`;
315
+ }
316
+ return `Relationship policy: ${edge.Policy} (${edge.PolicySource || 'default'})`;
317
+ }
318
+ setAllExpanded(nodes, expanded) {
319
+ for (const node of nodes) {
320
+ node.Expanded = expanded;
321
+ if (node.Children.length > 0) {
322
+ this.setAllExpanded(node.Children, expanded);
323
+ }
324
+ }
325
+ }
326
+ rebuildTree() {
327
+ if (!this._plan || !this._plan.Nodes || this._plan.Nodes.length === 0) {
328
+ this.TreeNodes = [];
329
+ this.FlatVisibleNodes = [];
330
+ this.cdr.markForCheck();
331
+ return;
332
+ }
333
+ const nodesByKey = new Map();
334
+ const edgesByToKey = new Map();
335
+ if (this._plan.Edges) {
336
+ for (const edge of this._plan.Edges) {
337
+ edgesByToKey.set(edge.ToKey, edge);
338
+ }
339
+ }
340
+ for (const node of this._plan.Nodes) {
341
+ const edge = edgesByToKey.get(node.Key) || null;
342
+ nodesByKey.set(node.Key, {
343
+ Node: node,
344
+ ParentEdge: edge,
345
+ Children: [],
346
+ Expanded: true, // Expanded by default
347
+ Level: node.Depth ?? 0,
348
+ });
349
+ }
350
+ const roots = [];
351
+ for (const [key, item] of nodesByKey.entries()) {
352
+ if (item.Node.ParentKey && nodesByKey.has(item.Node.ParentKey)) {
353
+ const parent = nodesByKey.get(item.Node.ParentKey);
354
+ parent.Children.push(item);
355
+ }
356
+ else {
357
+ roots.push(item);
358
+ }
359
+ }
360
+ this.TreeNodes = roots;
361
+ this.updateVisibleNodes();
362
+ this.cdr.markForCheck();
363
+ }
364
+ updateVisibleNodes() {
365
+ const flat = [];
366
+ const term = this.SearchTerm.trim().toLowerCase();
367
+ const traverse = (node) => {
368
+ const matchesSearch = !term ||
369
+ node.Node.EntityName.toLowerCase().includes(term) ||
370
+ (node.Node.DisplayName && node.Node.DisplayName.toLowerCase().includes(term));
371
+ if (matchesSearch || this.subtreeMatches(node, term)) {
372
+ flat.push(node);
373
+ if (node.Expanded || term) { // auto-expand matching paths on search
374
+ for (const child of node.Children) {
375
+ traverse(child);
376
+ }
377
+ }
378
+ }
379
+ };
380
+ for (const root of this.TreeNodes) {
381
+ traverse(root);
382
+ }
383
+ this.FlatVisibleNodes = flat;
384
+ }
385
+ subtreeMatches(node, term) {
386
+ if (!term)
387
+ return true;
388
+ for (const child of node.Children) {
389
+ if (child.Node.EntityName.toLowerCase().includes(term) ||
390
+ (child.Node.DisplayName && child.Node.DisplayName.toLowerCase().includes(term)) ||
391
+ this.subtreeMatches(child, term)) {
392
+ return true;
393
+ }
394
+ }
395
+ return false;
396
+ }
397
+ static ɵfac = function ClonePlanTreeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ClonePlanTreeComponent)(); };
398
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ClonePlanTreeComponent, selectors: [["mj-clone-plan-tree"]], inputs: { Plan: "Plan", SelectedNodeKey: "SelectedNodeKey", AllowNarrowing: "AllowNarrowing", AllowWidening: "AllowWidening" }, outputs: { NodeSelected: "NodeSelected", EdgePolicyChanged: "EdgePolicyChanged" }, decls: 15, vars: 4, consts: [[1, "plan-tree-container"], [1, "tree-toolbar"], [1, "search-box"], [1, "fa-solid", "fa-magnifying-glass", "search-icon"], ["type", "text", "placeholder", "Search entities or records...", 1, "mj-input", "search-input", 3, "ngModelChange", "ngModel"], ["type", "button", "title", "Clear search", 1, "clear-search-btn"], [1, "tree-actions"], ["type", "button", "mjButton", "", "variant", "outline", "size", "sm", 3, "click"], [1, "counts-bar"], ["role", "list", "aria-label", "Records in the clone plan", 1, "tree-content"], [1, "empty-tree-message"], ["type", "button", "title", "Clear search", 1, "clear-search-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "count-item", "total"], [1, "count-item", "create"], [1, "fa-solid", "fa-plus-circle"], [1, "count-item", "reference"], [1, "count-item", "skip"], [1, "fa-solid", "fa-link"], [1, "fa-solid", "fa-forward"], ["title", "Enter the required values on the Values step", 1, "count-item", "skip"], [1, "count-item", "blocked"], [1, "fa-solid", "fa-pen-to-square"], [1, "fa-solid", "fa-ban"], ["role", "listitem", 1, "tree-row", 3, "selected", "is-subtype", "padding-left"], ["role", "listitem", 1, "tree-row", 3, "click"], [1, "chevron-cell"], ["type", "button", 1, "chevron-btn", 3, "title"], [1, "edge-cell"], [1, "action-cell"], [1, "action-badge"], [1, "node-label-cell"], [1, "entity-badge"], [1, "record-title", 3, "title"], [1, "node-warning-badge", 3, "title"], ["type", "button", 1, "chevron-btn", 3, "click", "title"], [1, "fa-solid"], ["type", "button", 1, "policy-pill", "policy-pill--toggle", 3, "policy-deep", "policy-ref", "policy-skip", "title"], [1, "policy-pill", 3, "policy-deep", "policy-ref", "policy-skip", "title"], ["type", "button", 1, "policy-pill", "policy-pill--toggle", 3, "click", "title"], [1, "policy-pill", 3, "title"], [1, "fa-solid", "fa-lock", "lock-icon"], [1, "fa-solid", "fa-triangle-exclamation"]], template: function ClonePlanTreeComponent_Template(rf, ctx) { if (rf & 1) {
399
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2);
400
+ i0.ɵɵelement(3, "i", 3);
401
+ i0.ɵɵelementStart(4, "input", 4);
402
+ i0.ɵɵlistener("ngModelChange", function ClonePlanTreeComponent_Template_input_ngModelChange_4_listener($event) { return ctx.OnSearchTermChange($event); });
403
+ i0.ɵɵelementEnd();
404
+ i0.ɵɵconditionalCreate(5, ClonePlanTreeComponent_Conditional_5_Template, 2, 0, "button", 5);
405
+ i0.ɵɵelementEnd();
406
+ i0.ɵɵelementStart(6, "div", 6)(7, "button", 7);
407
+ i0.ɵɵlistener("click", function ClonePlanTreeComponent_Template_button_click_7_listener() { return ctx.ExpandAll(); });
408
+ i0.ɵɵtext(8, " Expand All ");
409
+ i0.ɵɵelementEnd();
410
+ i0.ɵɵelementStart(9, "button", 7);
411
+ i0.ɵɵlistener("click", function ClonePlanTreeComponent_Template_button_click_9_listener() { return ctx.CollapseAll(); });
412
+ i0.ɵɵtext(10, " Collapse All ");
413
+ i0.ɵɵelementEnd()()();
414
+ i0.ɵɵconditionalCreate(11, ClonePlanTreeComponent_Conditional_11_Template, 13, 5, "div", 8);
415
+ i0.ɵɵelementStart(12, "div", 9);
416
+ i0.ɵɵconditionalCreate(13, ClonePlanTreeComponent_Conditional_13_Template, 3, 1, "div", 10)(14, ClonePlanTreeComponent_Conditional_14_Template, 2, 0);
417
+ i0.ɵɵelementEnd()();
418
+ } if (rf & 2) {
419
+ i0.ɵɵadvance(4);
420
+ i0.ɵɵproperty("ngModel", ctx.SearchTerm);
421
+ i0.ɵɵadvance();
422
+ i0.ɵɵconditional(ctx.SearchTerm ? 5 : -1);
423
+ i0.ɵɵadvance(6);
424
+ i0.ɵɵconditional(ctx.Plan ? 11 : -1);
425
+ i0.ɵɵadvance(2);
426
+ i0.ɵɵconditional(ctx.TreeNodes.length === 0 ? 13 : 14);
427
+ } }, dependencies: [CommonModule,
428
+ FormsModule, i1.DefaultValueAccessor, i1.NgControlStatus, i1.NgModel, MJButtonDirective], styles: [".plan-tree-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n }\n\n .tree-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) var(--mj-space-3);\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .search-box[_ngcontent-%COMP%] {\n position: relative;\n flex: 1;\n max-width: 320px;\n display: flex;\n align-items: center;\n }\n\n .search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n pointer-events: none;\n }\n\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 5px 28px 5px 30px;\n font-size: var(--mj-text-xs);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n }\n\n .search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n }\n\n .clear-search-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 2px;\n }\n\n .tree-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: var(--mj-space-1-5);\n }\n\n .counts-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--mj-space-3);\n padding: 6px var(--mj-space-3);\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: var(--mj-text-xs);\n }\n\n .count-item[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n }\n\n .count-item.create[_ngcontent-%COMP%] {\n color: var(--mj-status-success-text);\n }\n\n .count-item.reference[_ngcontent-%COMP%] {\n color: var(--mj-status-info-text);\n }\n\n .count-item.skip[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n }\n\n .count-item.blocked[_ngcontent-%COMP%] {\n color: var(--mj-status-error-text);\n }\n\n .tree-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n max-height: 480px;\n overflow-y: auto;\n padding: var(--mj-space-1) 0;\n }\n\n .empty-tree-message[_ngcontent-%COMP%] {\n padding: var(--mj-space-6);\n text-align: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n }\n\n .tree-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding-top: 6px;\n padding-bottom: 6px;\n padding-right: var(--mj-space-3);\n cursor: pointer;\n user-select: none;\n border-left: 3px solid transparent;\n transition: background-color 0.1s ease;\n }\n\n .tree-row[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .tree-row.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-left-color: var(--mj-brand-primary);\n }\n\n .tree-row.is-subtype[_ngcontent-%COMP%] {\n font-style: italic;\n }\n\n .chevron-cell[_ngcontent-%COMP%] {\n width: 18px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chevron-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 2px;\n font-size: 11px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .edge-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n }\n\n .policy-pill[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .policy-pill--toggle[_ngcontent-%COMP%] {\n border: 1px solid transparent;\n cursor: pointer;\n font-family: inherit;\n line-height: inherit;\n }\n\n .policy-pill--toggle[_ngcontent-%COMP%]:hover, \n .policy-pill--toggle[_ngcontent-%COMP%]:focus-visible {\n border-color: var(--mj-border-focus);\n outline: none;\n }\n\n .policy-pill.policy-deep[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n }\n\n .policy-pill.policy-ref[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n }\n\n .policy-pill.policy-skip[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .lock-icon[_ngcontent-%COMP%] {\n font-size: 9px;\n }\n\n .action-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n }\n\n .action-badge[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 2px 6px;\n border-radius: var(--mj-radius-sm);\n font-size: 11px;\n font-weight: 600;\n }\n\n .action-badge.action-create[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n }\n\n .action-badge.action-ref[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n }\n\n .action-badge.action-skip[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .action-badge.action-blocked[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n }\n\n .node-label-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1-5);\n flex: 1;\n min-width: 0;\n }\n\n .entity-badge[_ngcontent-%COMP%] {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n padding: 1px 6px;\n border-radius: var(--mj-radius-sm);\n white-space: nowrap;\n }\n\n .record-title[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .node-warning-badge[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-size: 10px;\n color: var(--mj-status-warning-text);\n background: var(--mj-status-warning-bg);\n padding: 1px 5px;\n border-radius: 8px;\n margin-left: 4px;\n }"], changeDetection: 0 });
429
+ }
430
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClonePlanTreeComponent, [{
431
+ type: Component,
432
+ args: [{ standalone: true, selector: 'mj-clone-plan-tree', template: `
433
+ <div class="plan-tree-container">
434
+ <!-- Search & Toolbar -->
435
+ <div class="tree-toolbar">
436
+ <div class="search-box">
437
+ <i class="fa-solid fa-magnifying-glass search-icon"></i>
438
+ <input
439
+ type="text"
440
+ class="mj-input search-input"
441
+ placeholder="Search entities or records..."
442
+ [ngModel]="SearchTerm"
443
+ (ngModelChange)="OnSearchTermChange($event)" />
444
+ @if (SearchTerm) {
445
+ <button
446
+ type="button"
447
+ class="clear-search-btn"
448
+ (click)="OnSearchTermChange('')"
449
+ title="Clear search">
450
+ <i class="fa-solid fa-xmark"></i>
451
+ </button>
452
+ }
453
+ </div>
454
+ <div class="tree-actions">
455
+ <button
456
+ type="button"
457
+ mjButton
458
+ variant="outline"
459
+ size="sm"
460
+ (click)="ExpandAll()">
461
+ Expand All
462
+ </button>
463
+ <button
464
+ type="button"
465
+ mjButton
466
+ variant="outline"
467
+ size="sm"
468
+ (click)="CollapseAll()">
469
+ Collapse All
470
+ </button>
471
+ </div>
472
+ </div>
473
+
474
+ <!-- Aggregate Counts Bar -->
475
+ @if (Plan) {
476
+ <div class="counts-bar">
477
+ <span class="count-item total">
478
+ <strong>{{Plan.Counts.Total}}</strong> Total
479
+ </span>
480
+ <span class="count-item create">
481
+ <i class="fa-solid fa-plus-circle"></i>
482
+ <strong>{{Plan.Counts.Create}}</strong> Create
483
+ </span>
484
+ @if (ReferenceCount > 0) {
485
+ <span class="count-item reference">
486
+ <i class="fa-solid fa-link"></i>
487
+ <strong>{{ReferenceCount}}</strong> Reference
488
+ </span>
489
+ }
490
+ @if (SkipCount > 0) {
491
+ <span class="count-item skip">
492
+ <i class="fa-solid fa-forward"></i>
493
+ <strong>{{SkipCount}}</strong> Skip
494
+ </span>
495
+ }
496
+ @if (Plan.Blocked) {
497
+ @if (NeedsValuesOnly) {
498
+ <span class="count-item skip" title="Enter the required values on the Values step">
499
+ <i class="fa-solid fa-pen-to-square"></i>
500
+ <strong>Needs values</strong>
501
+ </span>
502
+ } @else {
503
+ <span class="count-item blocked">
504
+ <i class="fa-solid fa-ban"></i>
505
+ <strong>Blocked</strong>
506
+ </span>
507
+ }
508
+ }
509
+ </div>
510
+ }
511
+
512
+ <!-- Hierarchical Node Tree -->
513
+ <div class="tree-content" role="list" aria-label="Records in the clone plan">
514
+ @if (TreeNodes.length === 0) {
515
+ <div class="empty-tree-message">
516
+ @if (SearchTerm) {
517
+ No matching records found in the clone plan.
518
+ } @else {
519
+ No records planned for cloning.
520
+ }
521
+ </div>
522
+ } @else {
523
+ @for (item of FlatVisibleNodes; track item.Node.Key) {
524
+ <div
525
+ class="tree-row"
526
+ [class.selected]="SelectedNodeKey === item.Node.Key"
527
+ [class.is-subtype]="item.Node.IsSubtypeRow"
528
+ [style.padding-left.px]="item.Level * 20 + 8"
529
+ role="listitem"
530
+ [attr.aria-level]="item.Level + 1"
531
+ (click)="OnSelectNode(item.Node)">
532
+
533
+ <!-- Expand/Collapse Chevron -->
534
+ <div class="chevron-cell">
535
+ @if (item.Children.length > 0) {
536
+ <button
537
+ type="button"
538
+ class="chevron-btn"
539
+ (click)="OnToggleExpand(item, $event)"
540
+ [attr.aria-expanded]="item.Expanded"
541
+ [attr.aria-label]="(item.Expanded ? 'Collapse ' : 'Expand ') + (item.Node.DisplayName || item.Node.EntityName)"
542
+ [title]="item.Expanded ? 'Collapse' : 'Expand'">
543
+ <i
544
+ class="fa-solid"
545
+ [class.fa-chevron-down]="item.Expanded"
546
+ [class.fa-chevron-right]="!item.Expanded">
547
+ </i>
548
+ </button>
549
+ }
550
+ </div>
551
+
552
+ <!-- Policy Pill (if edge connects to parent) -->
553
+ @if (item.ParentEdge) {
554
+ <div class="edge-cell">
555
+ @if (NextPolicy(item.ParentEdge); as next) {
556
+ <button
557
+ type="button"
558
+ class="policy-pill policy-pill--toggle"
559
+ [class.policy-deep]="item.ParentEdge.Policy === 'Deep'"
560
+ [class.policy-ref]="item.ParentEdge.Policy === 'Reference'"
561
+ [class.policy-skip]="item.ParentEdge.Policy === 'Skip'"
562
+ [title]="GetEdgeTooltip(item.ParentEdge) + (next === 'Skip' ? ' Click to skip every ' + item.ParentEdge.RelatedEntityName + ' row.' : ' Click to copy these rows.')"
563
+ [attr.aria-label]="(next === 'Skip' ? 'Skip every ' : 'Copy every ') + item.ParentEdge.RelatedEntityName + ' row'"
564
+ (click)="OnPolicyToggle(item.ParentEdge, next, $event)">
565
+ {{item.ParentEdge.Policy}}
566
+ </button>
567
+ } @else {
568
+ <span
569
+ class="policy-pill"
570
+ [class.policy-deep]="item.ParentEdge.Policy === 'Deep'"
571
+ [class.policy-ref]="item.ParentEdge.Policy === 'Reference'"
572
+ [class.policy-skip]="item.ParentEdge.Policy === 'Skip'"
573
+ [title]="GetEdgeTooltip(item.ParentEdge)">
574
+ @if (item.ParentEdge.Locked) {
575
+ <i class="fa-solid fa-lock lock-icon"></i>
576
+ }
577
+ {{item.ParentEdge.Policy}}
578
+ </span>
579
+ }
580
+ </div>
581
+ }
582
+
583
+ <!-- Action Badge -->
584
+ <div class="action-cell">
585
+ <span
586
+ class="action-badge"
587
+ [class.action-create]="item.Node.Action === 'Create'"
588
+ [class.action-ref]="item.Node.Action === 'Reference'"
589
+ [class.action-skip]="item.Node.Action === 'Skip'"
590
+ [class.action-blocked]="item.Node.Action === 'Blocked'">
591
+ {{item.Node.Action}}
592
+ </span>
593
+ </div>
594
+
595
+ <!-- Entity & Record Label -->
596
+ <div class="node-label-cell">
597
+ <span class="entity-badge">{{item.Node.EntityName}}</span>
598
+ <span class="record-title" [title]="item.Node.DisplayName">
599
+ {{item.Node.DisplayName}}
600
+ </span>
601
+ @if (item.Node.Warnings && item.Node.Warnings.length > 0) {
602
+ <span
603
+ class="node-warning-badge"
604
+ [title]="item.Node.Warnings.length + ' warning(s)'">
605
+ <i class="fa-solid fa-triangle-exclamation"></i>
606
+ {{item.Node.Warnings.length}}
607
+ </span>
608
+ }
609
+ </div>
610
+ </div>
611
+ }
612
+ }
613
+ </div>
614
+ </div>
615
+ `, imports: [
616
+ CommonModule,
617
+ FormsModule,
618
+ MJButtonDirective,
619
+ ], changeDetection: ChangeDetectionStrategy.OnPush, styles: ["\n .plan-tree-container {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n overflow: hidden;\n }\n\n .tree-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--mj-space-2);\n padding: var(--mj-space-2) var(--mj-space-3);\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n }\n\n .search-box {\n position: relative;\n flex: 1;\n max-width: 320px;\n display: flex;\n align-items: center;\n }\n\n .search-icon {\n position: absolute;\n left: 10px;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n pointer-events: none;\n }\n\n .search-input {\n width: 100%;\n padding: 5px 28px 5px 30px;\n font-size: var(--mj-text-xs);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n }\n\n .search-input:focus {\n border-color: var(--mj-brand-primary);\n }\n\n .clear-search-btn {\n position: absolute;\n right: 8px;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 2px;\n }\n\n .tree-actions {\n display: flex;\n gap: var(--mj-space-1-5);\n }\n\n .counts-bar {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--mj-space-3);\n padding: 6px var(--mj-space-3);\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n font-size: var(--mj-text-xs);\n }\n\n .count-item {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n }\n\n .count-item.create {\n color: var(--mj-status-success-text);\n }\n\n .count-item.reference {\n color: var(--mj-status-info-text);\n }\n\n .count-item.skip {\n color: var(--mj-text-muted);\n }\n\n .count-item.blocked {\n color: var(--mj-status-error-text);\n }\n\n .tree-content {\n display: flex;\n flex-direction: column;\n max-height: 480px;\n overflow-y: auto;\n padding: var(--mj-space-1) 0;\n }\n\n .empty-tree-message {\n padding: var(--mj-space-6);\n text-align: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n }\n\n .tree-row {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding-top: 6px;\n padding-bottom: 6px;\n padding-right: var(--mj-space-3);\n cursor: pointer;\n user-select: none;\n border-left: 3px solid transparent;\n transition: background-color 0.1s ease;\n }\n\n .tree-row:hover {\n background: var(--mj-bg-surface-hover);\n }\n\n .tree-row.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-left-color: var(--mj-brand-primary);\n }\n\n .tree-row.is-subtype {\n font-style: italic;\n }\n\n .chevron-cell {\n width: 18px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chevron-btn {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 2px;\n font-size: 11px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .edge-cell {\n display: flex;\n align-items: center;\n }\n\n .policy-pill {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 1px 6px;\n border-radius: 10px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .policy-pill--toggle {\n border: 1px solid transparent;\n cursor: pointer;\n font-family: inherit;\n line-height: inherit;\n }\n\n .policy-pill--toggle:hover,\n .policy-pill--toggle:focus-visible {\n border-color: var(--mj-border-focus);\n outline: none;\n }\n\n .policy-pill.policy-deep {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n }\n\n .policy-pill.policy-ref {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n }\n\n .policy-pill.policy-skip {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .lock-icon {\n font-size: 9px;\n }\n\n .action-cell {\n display: flex;\n align-items: center;\n }\n\n .action-badge {\n display: inline-block;\n padding: 2px 6px;\n border-radius: var(--mj-radius-sm);\n font-size: 11px;\n font-weight: 600;\n }\n\n .action-badge.action-create {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n }\n\n .action-badge.action-ref {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n }\n\n .action-badge.action-skip {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n }\n\n .action-badge.action-blocked {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n }\n\n .node-label-cell {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1-5);\n flex: 1;\n min-width: 0;\n }\n\n .entity-badge {\n font-size: 11px;\n font-weight: 500;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n padding: 1px 6px;\n border-radius: var(--mj-radius-sm);\n white-space: nowrap;\n }\n\n .record-title {\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n font-weight: 500;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .node-warning-badge {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n font-size: 10px;\n color: var(--mj-status-warning-text);\n background: var(--mj-status-warning-bg);\n padding: 1px 5px;\n border-radius: 8px;\n margin-left: 4px;\n }\n "] }]
620
+ }], null, { Plan: [{
621
+ type: Input
622
+ }], SelectedNodeKey: [{
623
+ type: Input
624
+ }], AllowNarrowing: [{
625
+ type: Input
626
+ }], AllowWidening: [{
627
+ type: Input
628
+ }], NodeSelected: [{
629
+ type: Output
630
+ }], EdgePolicyChanged: [{
631
+ type: Output
632
+ }] }); })();
633
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ClonePlanTreeComponent, { className: "ClonePlanTreeComponent", filePath: "src/lib/clone-plan-tree.component.ts", lineNumber: 503 }); })();
634
+ //# sourceMappingURL=clone-plan-tree.component.js.map