@memberjunction/ng-deep-diff 5.43.0 → 5.44.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/lib/deep-diff.component.js +64 -71
- package/dist/lib/deep-diff.component.js.map +1 -1
- package/dist/lib/module.d.ts +2 -1
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +7 -3
- package/dist/lib/module.js.map +1 -1
- package/package.json +5 -3
- package/dist/__tests__/exports.test.d.ts +0 -2
- package/dist/__tests__/exports.test.d.ts.map +0 -1
- package/dist/__tests__/exports.test.js +0 -17
- package/dist/__tests__/exports.test.js.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -7
- package/dist/__tests__/index.test.js.map +0 -1
- package/dist/lib/__tests__/deep-diff.component.test.d.ts +0 -2
- package/dist/lib/__tests__/deep-diff.component.test.d.ts.map +0 -1
- package/dist/lib/__tests__/deep-diff.component.test.js +0 -178
- package/dist/lib/__tests__/deep-diff.component.test.js.map +0 -1
|
@@ -3,16 +3,17 @@ import { DeepDiffer, DiffChangeType } from '@memberjunction/global';
|
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
import * as i1 from "@angular/common";
|
|
5
5
|
import * as i2 from "@angular/forms";
|
|
6
|
+
import * as i3 from "@memberjunction/ng-ui-components";
|
|
6
7
|
const _c0 = a0 => ({ item: a0, level: 0 });
|
|
7
8
|
const _c1 = (a0, a1) => ({ item: a0, level: a1 });
|
|
8
9
|
const _forTrack0 = ($index, $item) => $item.path;
|
|
9
10
|
function DeepDiffComponent_Conditional_13_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
10
|
-
i0.ɵɵelementStart(0, "div",
|
|
11
|
-
i0.ɵɵelement(1, "i",
|
|
12
|
-
i0.ɵɵelementStart(2, "span",
|
|
11
|
+
i0.ɵɵelementStart(0, "div", 35);
|
|
12
|
+
i0.ɵɵelement(1, "i", 36);
|
|
13
|
+
i0.ɵɵelementStart(2, "span", 31);
|
|
13
14
|
i0.ɵɵtext(3);
|
|
14
15
|
i0.ɵɵelementEnd();
|
|
15
|
-
i0.ɵɵelementStart(4, "span",
|
|
16
|
+
i0.ɵɵelementStart(4, "span", 32);
|
|
16
17
|
i0.ɵɵtext(5, "Unchanged");
|
|
17
18
|
i0.ɵɵelementEnd()();
|
|
18
19
|
} if (rf & 2) {
|
|
@@ -21,31 +22,31 @@ function DeepDiffComponent_Conditional_13_Conditional_19_Template(rf, ctx) { if
|
|
|
21
22
|
i0.ɵɵtextInterpolate(ctx_r1.diffResult.summary.unchanged);
|
|
22
23
|
} }
|
|
23
24
|
function DeepDiffComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
24
|
-
i0.ɵɵelementStart(0, "div", 13)(1, "div",
|
|
25
|
+
i0.ɵɵelementStart(0, "div", 13)(1, "div", 30);
|
|
25
26
|
i0.ɵɵelement(2, "i", 21);
|
|
26
|
-
i0.ɵɵelementStart(3, "span",
|
|
27
|
+
i0.ɵɵelementStart(3, "span", 31);
|
|
27
28
|
i0.ɵɵtext(4);
|
|
28
29
|
i0.ɵɵelementEnd();
|
|
29
|
-
i0.ɵɵelementStart(5, "span",
|
|
30
|
+
i0.ɵɵelementStart(5, "span", 32);
|
|
30
31
|
i0.ɵɵtext(6, "Added");
|
|
31
32
|
i0.ɵɵelementEnd()();
|
|
32
|
-
i0.ɵɵelementStart(7, "div",
|
|
33
|
+
i0.ɵɵelementStart(7, "div", 33);
|
|
33
34
|
i0.ɵɵelement(8, "i", 23);
|
|
34
|
-
i0.ɵɵelementStart(9, "span",
|
|
35
|
+
i0.ɵɵelementStart(9, "span", 31);
|
|
35
36
|
i0.ɵɵtext(10);
|
|
36
37
|
i0.ɵɵelementEnd();
|
|
37
|
-
i0.ɵɵelementStart(11, "span",
|
|
38
|
+
i0.ɵɵelementStart(11, "span", 32);
|
|
38
39
|
i0.ɵɵtext(12, "Removed");
|
|
39
40
|
i0.ɵɵelementEnd()();
|
|
40
|
-
i0.ɵɵelementStart(13, "div",
|
|
41
|
+
i0.ɵɵelementStart(13, "div", 34);
|
|
41
42
|
i0.ɵɵelement(14, "i", 25);
|
|
42
|
-
i0.ɵɵelementStart(15, "span",
|
|
43
|
+
i0.ɵɵelementStart(15, "span", 31);
|
|
43
44
|
i0.ɵɵtext(16);
|
|
44
45
|
i0.ɵɵelementEnd();
|
|
45
|
-
i0.ɵɵelementStart(17, "span",
|
|
46
|
+
i0.ɵɵelementStart(17, "span", 32);
|
|
46
47
|
i0.ɵɵtext(18, "Modified");
|
|
47
48
|
i0.ɵɵelementEnd()();
|
|
48
|
-
i0.ɵɵconditionalCreate(19, DeepDiffComponent_Conditional_13_Conditional_19_Template, 6, 1, "div",
|
|
49
|
+
i0.ɵɵconditionalCreate(19, DeepDiffComponent_Conditional_13_Conditional_19_Template, 6, 1, "div", 35);
|
|
49
50
|
i0.ɵɵelementEnd();
|
|
50
51
|
} if (rf & 2) {
|
|
51
52
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -59,24 +60,16 @@ function DeepDiffComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
|
59
60
|
i0.ɵɵconditional(ctx_r1.showUnchanged ? 19 : -1);
|
|
60
61
|
} }
|
|
61
62
|
function DeepDiffComponent_Conditional_31_Template(rf, ctx) { if (rf & 1) {
|
|
62
|
-
i0.ɵɵ
|
|
63
|
-
i0.ɵɵelement(1, "i", 36);
|
|
64
|
-
i0.ɵɵelementStart(2, "p");
|
|
65
|
-
i0.ɵɵtext(3, "No data to compare");
|
|
66
|
-
i0.ɵɵelementEnd()();
|
|
63
|
+
i0.ɵɵelement(0, "mj-empty-state", 27);
|
|
67
64
|
} }
|
|
68
65
|
function DeepDiffComponent_Conditional_32_Template(rf, ctx) { if (rf & 1) {
|
|
69
|
-
i0.ɵɵ
|
|
70
|
-
i0.ɵɵelement(1, "i", 37);
|
|
71
|
-
i0.ɵɵelementStart(2, "p");
|
|
72
|
-
i0.ɵɵtext(3, "No changes match your filter criteria");
|
|
73
|
-
i0.ɵɵelementEnd()();
|
|
66
|
+
i0.ɵɵelement(0, "mj-empty-state", 28);
|
|
74
67
|
} }
|
|
75
68
|
function DeepDiffComponent_Conditional_33_For_2_ng_container_0_Template(rf, ctx) { if (rf & 1) {
|
|
76
69
|
i0.ɵɵelementContainer(0);
|
|
77
70
|
} }
|
|
78
71
|
function DeepDiffComponent_Conditional_33_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
79
|
-
i0.ɵɵtemplate(0, DeepDiffComponent_Conditional_33_For_2_ng_container_0_Template, 1, 0, "ng-container",
|
|
72
|
+
i0.ɵɵtemplate(0, DeepDiffComponent_Conditional_33_For_2_ng_container_0_Template, 1, 0, "ng-container", 37);
|
|
80
73
|
} if (rf & 2) {
|
|
81
74
|
const item_r3 = ctx.$implicit;
|
|
82
75
|
i0.ɵɵnextContext(2);
|
|
@@ -84,7 +77,7 @@ function DeepDiffComponent_Conditional_33_For_2_Template(rf, ctx) { if (rf & 1)
|
|
|
84
77
|
i0.ɵɵproperty("ngTemplateOutlet", diffItem_r4)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, item_r3));
|
|
85
78
|
} }
|
|
86
79
|
function DeepDiffComponent_Conditional_33_Template(rf, ctx) { if (rf & 1) {
|
|
87
|
-
i0.ɵɵelementStart(0, "div",
|
|
80
|
+
i0.ɵɵelementStart(0, "div", 29);
|
|
88
81
|
i0.ɵɵrepeaterCreate(1, DeepDiffComponent_Conditional_33_For_2_Template, 1, 4, "ng-container", null, _forTrack0);
|
|
89
82
|
i0.ɵɵelementEnd();
|
|
90
83
|
} if (rf & 2) {
|
|
@@ -93,19 +86,19 @@ function DeepDiffComponent_Conditional_33_Template(rf, ctx) { if (rf & 1) {
|
|
|
93
86
|
i0.ɵɵrepeater(ctx_r1.filteredItems);
|
|
94
87
|
} }
|
|
95
88
|
function DeepDiffComponent_ng_template_34_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
96
|
-
i0.ɵɵelement(0, "i",
|
|
89
|
+
i0.ɵɵelement(0, "i", 49);
|
|
97
90
|
} if (rf & 2) {
|
|
98
91
|
const item_r6 = i0.ɵɵnextContext().item;
|
|
99
92
|
i0.ɵɵclassProp("expanded", item_r6.isExpanded);
|
|
100
93
|
} }
|
|
101
94
|
function DeepDiffComponent_ng_template_34_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
102
|
-
i0.ɵɵelement(0, "span",
|
|
95
|
+
i0.ɵɵelement(0, "span", 41);
|
|
103
96
|
} }
|
|
104
97
|
function DeepDiffComponent_ng_template_34_Conditional_11_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
105
98
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
106
|
-
i0.ɵɵelementStart(0, "button",
|
|
99
|
+
i0.ɵɵelementStart(0, "button", 56);
|
|
107
100
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_11_Conditional_8_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r8); const item_r6 = i0.ɵɵnextContext(2).item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleValueExpansion(item_r6.path + "_old", $event)); });
|
|
108
|
-
i0.ɵɵelement(1, "i",
|
|
101
|
+
i0.ɵɵelement(1, "i", 57);
|
|
109
102
|
i0.ɵɵelementEnd();
|
|
110
103
|
} if (rf & 2) {
|
|
111
104
|
const item_r6 = i0.ɵɵnextContext(2).item;
|
|
@@ -117,9 +110,9 @@ function DeepDiffComponent_ng_template_34_Conditional_11_Conditional_8_Template(
|
|
|
117
110
|
} }
|
|
118
111
|
function DeepDiffComponent_ng_template_34_Conditional_11_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
119
112
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
120
|
-
i0.ɵɵelementStart(0, "button",
|
|
113
|
+
i0.ɵɵelementStart(0, "button", 56);
|
|
121
114
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_11_Conditional_16_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r9); const item_r6 = i0.ɵɵnextContext(2).item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleValueExpansion(item_r6.path + "_new", $event)); });
|
|
122
|
-
i0.ɵɵelement(1, "i",
|
|
115
|
+
i0.ɵɵelement(1, "i", 57);
|
|
123
116
|
i0.ɵɵelementEnd();
|
|
124
117
|
} if (rf & 2) {
|
|
125
118
|
const item_r6 = i0.ɵɵnextContext(2).item;
|
|
@@ -131,29 +124,29 @@ function DeepDiffComponent_ng_template_34_Conditional_11_Conditional_16_Template
|
|
|
131
124
|
} }
|
|
132
125
|
function DeepDiffComponent_ng_template_34_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
133
126
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
134
|
-
i0.ɵɵelementStart(0, "div",
|
|
127
|
+
i0.ɵɵelementStart(0, "div", 47)(1, "div", 50)(2, "span", 51);
|
|
135
128
|
i0.ɵɵtext(3, "Old:");
|
|
136
129
|
i0.ɵɵelementEnd();
|
|
137
|
-
i0.ɵɵelementStart(4, "code",
|
|
130
|
+
i0.ɵɵelementStart(4, "code", 52);
|
|
138
131
|
i0.ɵɵtext(5);
|
|
139
132
|
i0.ɵɵelementEnd();
|
|
140
|
-
i0.ɵɵelementStart(6, "button",
|
|
133
|
+
i0.ɵɵelementStart(6, "button", 53);
|
|
141
134
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_11_Template_button_click_6_listener($event) { i0.ɵɵrestoreView(_r7); const item_r6 = i0.ɵɵnextContext().item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.copyValueToClipboard(item_r6.oldValue, $event)); });
|
|
142
|
-
i0.ɵɵelement(7, "i",
|
|
135
|
+
i0.ɵɵelement(7, "i", 46);
|
|
143
136
|
i0.ɵɵelementEnd();
|
|
144
|
-
i0.ɵɵconditionalCreate(8, DeepDiffComponent_ng_template_34_Conditional_11_Conditional_8_Template, 2, 4, "button",
|
|
137
|
+
i0.ɵɵconditionalCreate(8, DeepDiffComponent_ng_template_34_Conditional_11_Conditional_8_Template, 2, 4, "button", 54);
|
|
145
138
|
i0.ɵɵelementEnd();
|
|
146
|
-
i0.ɵɵelementStart(9, "div",
|
|
139
|
+
i0.ɵɵelementStart(9, "div", 55)(10, "span", 51);
|
|
147
140
|
i0.ɵɵtext(11, "New:");
|
|
148
141
|
i0.ɵɵelementEnd();
|
|
149
|
-
i0.ɵɵelementStart(12, "code",
|
|
142
|
+
i0.ɵɵelementStart(12, "code", 52);
|
|
150
143
|
i0.ɵɵtext(13);
|
|
151
144
|
i0.ɵɵelementEnd();
|
|
152
|
-
i0.ɵɵelementStart(14, "button",
|
|
145
|
+
i0.ɵɵelementStart(14, "button", 53);
|
|
153
146
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_11_Template_button_click_14_listener($event) { i0.ɵɵrestoreView(_r7); const item_r6 = i0.ɵɵnextContext().item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.copyValueToClipboard(item_r6.newValue, $event)); });
|
|
154
|
-
i0.ɵɵelement(15, "i",
|
|
147
|
+
i0.ɵɵelement(15, "i", 46);
|
|
155
148
|
i0.ɵɵelementEnd();
|
|
156
|
-
i0.ɵɵconditionalCreate(16, DeepDiffComponent_ng_template_34_Conditional_11_Conditional_16_Template, 2, 4, "button",
|
|
149
|
+
i0.ɵɵconditionalCreate(16, DeepDiffComponent_ng_template_34_Conditional_11_Conditional_16_Template, 2, 4, "button", 54);
|
|
157
150
|
i0.ɵɵelementEnd()();
|
|
158
151
|
} if (rf & 2) {
|
|
159
152
|
const item_r6 = i0.ɵɵnextContext().item;
|
|
@@ -169,9 +162,9 @@ function DeepDiffComponent_ng_template_34_Conditional_11_Template(rf, ctx) { if
|
|
|
169
162
|
} }
|
|
170
163
|
function DeepDiffComponent_ng_template_34_Conditional_12_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
171
164
|
const _r11 = i0.ɵɵgetCurrentView();
|
|
172
|
-
i0.ɵɵelementStart(0, "button",
|
|
165
|
+
i0.ɵɵelementStart(0, "button", 56);
|
|
173
166
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_12_Conditional_8_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r11); const item_r6 = i0.ɵɵnextContext(2).item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleValueExpansion(item_r6.path, $event)); });
|
|
174
|
-
i0.ɵɵelement(1, "i",
|
|
167
|
+
i0.ɵɵelement(1, "i", 57);
|
|
175
168
|
i0.ɵɵelementEnd();
|
|
176
169
|
} if (rf & 2) {
|
|
177
170
|
const item_r6 = i0.ɵɵnextContext(2).item;
|
|
@@ -183,17 +176,17 @@ function DeepDiffComponent_ng_template_34_Conditional_12_Conditional_8_Template(
|
|
|
183
176
|
} }
|
|
184
177
|
function DeepDiffComponent_ng_template_34_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
185
178
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
186
|
-
i0.ɵɵelementStart(0, "div",
|
|
179
|
+
i0.ɵɵelementStart(0, "div", 47)(1, "div", 55)(2, "span", 51);
|
|
187
180
|
i0.ɵɵtext(3, "Value:");
|
|
188
181
|
i0.ɵɵelementEnd();
|
|
189
|
-
i0.ɵɵelementStart(4, "code",
|
|
182
|
+
i0.ɵɵelementStart(4, "code", 52);
|
|
190
183
|
i0.ɵɵtext(5);
|
|
191
184
|
i0.ɵɵelementEnd();
|
|
192
|
-
i0.ɵɵelementStart(6, "button",
|
|
185
|
+
i0.ɵɵelementStart(6, "button", 53);
|
|
193
186
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_12_Template_button_click_6_listener($event) { i0.ɵɵrestoreView(_r10); const item_r6 = i0.ɵɵnextContext().item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.copyValueToClipboard(item_r6.newValue, $event)); });
|
|
194
|
-
i0.ɵɵelement(7, "i",
|
|
187
|
+
i0.ɵɵelement(7, "i", 46);
|
|
195
188
|
i0.ɵɵelementEnd();
|
|
196
|
-
i0.ɵɵconditionalCreate(8, DeepDiffComponent_ng_template_34_Conditional_12_Conditional_8_Template, 2, 4, "button",
|
|
189
|
+
i0.ɵɵconditionalCreate(8, DeepDiffComponent_ng_template_34_Conditional_12_Conditional_8_Template, 2, 4, "button", 54);
|
|
197
190
|
i0.ɵɵelementEnd()();
|
|
198
191
|
} if (rf & 2) {
|
|
199
192
|
const item_r6 = i0.ɵɵnextContext().item;
|
|
@@ -205,9 +198,9 @@ function DeepDiffComponent_ng_template_34_Conditional_12_Template(rf, ctx) { if
|
|
|
205
198
|
} }
|
|
206
199
|
function DeepDiffComponent_ng_template_34_Conditional_13_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
207
200
|
const _r13 = i0.ɵɵgetCurrentView();
|
|
208
|
-
i0.ɵɵelementStart(0, "button",
|
|
201
|
+
i0.ɵɵelementStart(0, "button", 56);
|
|
209
202
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_13_Conditional_8_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r13); const item_r6 = i0.ɵɵnextContext(2).item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleValueExpansion(item_r6.path, $event)); });
|
|
210
|
-
i0.ɵɵelement(1, "i",
|
|
203
|
+
i0.ɵɵelement(1, "i", 57);
|
|
211
204
|
i0.ɵɵelementEnd();
|
|
212
205
|
} if (rf & 2) {
|
|
213
206
|
const item_r6 = i0.ɵɵnextContext(2).item;
|
|
@@ -219,17 +212,17 @@ function DeepDiffComponent_ng_template_34_Conditional_13_Conditional_8_Template(
|
|
|
219
212
|
} }
|
|
220
213
|
function DeepDiffComponent_ng_template_34_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
221
214
|
const _r12 = i0.ɵɵgetCurrentView();
|
|
222
|
-
i0.ɵɵelementStart(0, "div",
|
|
215
|
+
i0.ɵɵelementStart(0, "div", 47)(1, "div", 50)(2, "span", 51);
|
|
223
216
|
i0.ɵɵtext(3, "Value:");
|
|
224
217
|
i0.ɵɵelementEnd();
|
|
225
|
-
i0.ɵɵelementStart(4, "code",
|
|
218
|
+
i0.ɵɵelementStart(4, "code", 52);
|
|
226
219
|
i0.ɵɵtext(5);
|
|
227
220
|
i0.ɵɵelementEnd();
|
|
228
|
-
i0.ɵɵelementStart(6, "button",
|
|
221
|
+
i0.ɵɵelementStart(6, "button", 53);
|
|
229
222
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Conditional_13_Template_button_click_6_listener($event) { i0.ɵɵrestoreView(_r12); const item_r6 = i0.ɵɵnextContext().item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.copyValueToClipboard(item_r6.oldValue, $event)); });
|
|
230
|
-
i0.ɵɵelement(7, "i",
|
|
223
|
+
i0.ɵɵelement(7, "i", 46);
|
|
231
224
|
i0.ɵɵelementEnd();
|
|
232
|
-
i0.ɵɵconditionalCreate(8, DeepDiffComponent_ng_template_34_Conditional_13_Conditional_8_Template, 2, 4, "button",
|
|
225
|
+
i0.ɵɵconditionalCreate(8, DeepDiffComponent_ng_template_34_Conditional_13_Conditional_8_Template, 2, 4, "button", 54);
|
|
233
226
|
i0.ɵɵelementEnd()();
|
|
234
227
|
} if (rf & 2) {
|
|
235
228
|
const item_r6 = i0.ɵɵnextContext().item;
|
|
@@ -243,7 +236,7 @@ function DeepDiffComponent_ng_template_34_Conditional_14_For_2_ng_container_0_Te
|
|
|
243
236
|
i0.ɵɵelementContainer(0);
|
|
244
237
|
} }
|
|
245
238
|
function DeepDiffComponent_ng_template_34_Conditional_14_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
246
|
-
i0.ɵɵtemplate(0, DeepDiffComponent_ng_template_34_Conditional_14_For_2_ng_container_0_Template, 1, 0, "ng-container",
|
|
239
|
+
i0.ɵɵtemplate(0, DeepDiffComponent_ng_template_34_Conditional_14_For_2_ng_container_0_Template, 1, 0, "ng-container", 37);
|
|
247
240
|
} if (rf & 2) {
|
|
248
241
|
const child_r14 = ctx.$implicit;
|
|
249
242
|
const level_r15 = i0.ɵɵnextContext(2).level;
|
|
@@ -252,7 +245,7 @@ function DeepDiffComponent_ng_template_34_Conditional_14_For_2_Template(rf, ctx)
|
|
|
252
245
|
i0.ɵɵproperty("ngTemplateOutlet", diffItem_r4)("ngTemplateOutletContext", i0.ɵɵpureFunction2(2, _c1, child_r14, level_r15 + 1));
|
|
253
246
|
} }
|
|
254
247
|
function DeepDiffComponent_ng_template_34_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
255
|
-
i0.ɵɵelementStart(0, "div",
|
|
248
|
+
i0.ɵɵelementStart(0, "div", 48);
|
|
256
249
|
i0.ɵɵrepeaterCreate(1, DeepDiffComponent_ng_template_34_Conditional_14_For_2_Template, 1, 5, "ng-container", null, _forTrack0);
|
|
257
250
|
i0.ɵɵelementEnd();
|
|
258
251
|
} if (rf & 2) {
|
|
@@ -262,22 +255,22 @@ function DeepDiffComponent_ng_template_34_Conditional_14_Template(rf, ctx) { if
|
|
|
262
255
|
} }
|
|
263
256
|
function DeepDiffComponent_ng_template_34_Template(rf, ctx) { if (rf & 1) {
|
|
264
257
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
265
|
-
i0.ɵɵelementStart(0, "div",
|
|
258
|
+
i0.ɵɵelementStart(0, "div", 38)(1, "div", 39);
|
|
266
259
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Template_div_click_1_listener() { const item_r6 = i0.ɵɵrestoreView(_r5).item; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleItem(item_r6)); });
|
|
267
|
-
i0.ɵɵconditionalCreate(2, DeepDiffComponent_ng_template_34_Conditional_2_Template, 1, 2, "i",
|
|
268
|
-
i0.ɵɵelement(4, "i",
|
|
269
|
-
i0.ɵɵelementStart(5, "span",
|
|
260
|
+
i0.ɵɵconditionalCreate(2, DeepDiffComponent_ng_template_34_Conditional_2_Template, 1, 2, "i", 40)(3, DeepDiffComponent_ng_template_34_Conditional_3_Template, 1, 0, "span", 41);
|
|
261
|
+
i0.ɵɵelement(4, "i", 42);
|
|
262
|
+
i0.ɵɵelementStart(5, "span", 43);
|
|
270
263
|
i0.ɵɵtext(6);
|
|
271
264
|
i0.ɵɵelementEnd();
|
|
272
|
-
i0.ɵɵelementStart(7, "span",
|
|
265
|
+
i0.ɵɵelementStart(7, "span", 44);
|
|
273
266
|
i0.ɵɵtext(8);
|
|
274
267
|
i0.ɵɵelementEnd();
|
|
275
|
-
i0.ɵɵelementStart(9, "button",
|
|
268
|
+
i0.ɵɵelementStart(9, "button", 45);
|
|
276
269
|
i0.ɵɵlistener("click", function DeepDiffComponent_ng_template_34_Template_button_click_9_listener($event) { const item_r6 = i0.ɵɵrestoreView(_r5).item; const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.copyToClipboard(item_r6.path); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
277
|
-
i0.ɵɵelement(10, "i",
|
|
270
|
+
i0.ɵɵelement(10, "i", 46);
|
|
278
271
|
i0.ɵɵelementEnd()();
|
|
279
|
-
i0.ɵɵconditionalCreate(11, DeepDiffComponent_ng_template_34_Conditional_11_Template, 17, 4, "div",
|
|
280
|
-
i0.ɵɵconditionalCreate(14, DeepDiffComponent_ng_template_34_Conditional_14_Template, 3, 0, "div",
|
|
272
|
+
i0.ɵɵconditionalCreate(11, DeepDiffComponent_ng_template_34_Conditional_11_Template, 17, 4, "div", 47)(12, DeepDiffComponent_ng_template_34_Conditional_12_Template, 9, 2, "div", 47)(13, DeepDiffComponent_ng_template_34_Conditional_13_Template, 9, 2, "div", 47);
|
|
273
|
+
i0.ɵɵconditionalCreate(14, DeepDiffComponent_ng_template_34_Conditional_14_Template, 3, 0, "div", 48);
|
|
281
274
|
i0.ɵɵelementEnd();
|
|
282
275
|
} if (rf & 2) {
|
|
283
276
|
const item_r6 = ctx.item;
|
|
@@ -672,7 +665,7 @@ export class DeepDiffComponent {
|
|
|
672
665
|
URL.revokeObjectURL(url);
|
|
673
666
|
}
|
|
674
667
|
static ɵfac = function DeepDiffComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DeepDiffComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
675
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DeepDiffComponent, selectors: [["mj-deep-diff"]], inputs: { oldValue: "oldValue", newValue: "newValue", showUnchanged: "showUnchanged", maxDepth: "maxDepth", maxStringLength: "maxStringLength", treatNullAsUndefined: "treatNullAsUndefined", title: "title", showSummary: "showSummary", expandAll: "expandAll", truncateValues: "truncateValues" }, standalone: false, decls: 36, vars: 13, consts: [["diffItem", ""], [1, "deep-diff-container"], [1, "diff-header"], [1, "header-content"], [1, "diff-title"], [1, "fa-solid", "fa-code-branch"], [1, "header-actions"], ["title", "Expand All", "aria-label", "Expand All", 1, "btn-icon", 3, "click"], [1, "fa-solid", "fa-expand"], ["title", "Collapse All", "aria-label", "Collapse All", 1, "btn-icon", 3, "click"], [1, "fa-solid", "fa-compress"], ["title", "Export Diff", "aria-label", "Export Diff", 1, "btn-icon", 3, "click", "disabled"], [1, "fa-solid", "fa-download"], [1, "diff-summary"], [1, "diff-filters"], [1, "filter-search"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Filter by path or description...", 1, "filter-input", 3, "ngModelChange", "ngModel"], [1, "filter-types"], [1, "filter-btn", 3, "click"], [1, "filter-btn", "added", 3, "click"], [1, "fa-solid", "fa-plus-circle"], [1, "filter-btn", "removed", 3, "click"], [1, "fa-solid", "fa-minus-circle"], [1, "filter-btn", "modified", 3, "click"], [1, "fa-solid", "fa-edit"], [1, "diff-content"], [1, "empty-state"], [
|
|
668
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DeepDiffComponent, selectors: [["mj-deep-diff"]], inputs: { oldValue: "oldValue", newValue: "newValue", showUnchanged: "showUnchanged", maxDepth: "maxDepth", maxStringLength: "maxStringLength", treatNullAsUndefined: "treatNullAsUndefined", title: "title", showSummary: "showSummary", expandAll: "expandAll", truncateValues: "truncateValues" }, standalone: false, decls: 36, vars: 13, consts: [["diffItem", ""], [1, "deep-diff-container"], [1, "diff-header"], [1, "header-content"], [1, "diff-title"], [1, "fa-solid", "fa-code-branch"], [1, "header-actions"], ["title", "Expand All", "aria-label", "Expand All", 1, "btn-icon", 3, "click"], [1, "fa-solid", "fa-expand"], ["title", "Collapse All", "aria-label", "Collapse All", 1, "btn-icon", 3, "click"], [1, "fa-solid", "fa-compress"], ["title", "Export Diff", "aria-label", "Export Diff", 1, "btn-icon", 3, "click", "disabled"], [1, "fa-solid", "fa-download"], [1, "diff-summary"], [1, "diff-filters"], [1, "filter-search"], [1, "fa-solid", "fa-search"], ["type", "text", "placeholder", "Filter by path or description...", 1, "filter-input", 3, "ngModelChange", "ngModel"], [1, "filter-types"], [1, "filter-btn", 3, "click"], [1, "filter-btn", "added", 3, "click"], [1, "fa-solid", "fa-plus-circle"], [1, "filter-btn", "removed", 3, "click"], [1, "fa-solid", "fa-minus-circle"], [1, "filter-btn", "modified", 3, "click"], [1, "fa-solid", "fa-edit"], [1, "diff-content"], ["Icon", "fa-solid fa-code-compare", "Title", "No data to compare", 1, "empty-state-fill"], ["Variant", "no-results", "Icon", "fa-solid fa-filter", "Title", "No changes match your filter criteria", 1, "empty-state-fill"], [1, "diff-tree"], [1, "summary-item", "added"], [1, "count"], [1, "label"], [1, "summary-item", "removed"], [1, "summary-item", "modified"], [1, "summary-item", "unchanged"], [1, "fa-solid", "fa-check-circle"], [4, "ngTemplateOutlet", "ngTemplateOutletContext"], [1, "diff-item"], [1, "item-header", 3, "click"], [1, "fa-solid", "fa-chevron-right", "expand-icon", 3, "expanded"], [1, "expand-spacer"], [1, "fa-solid", "type-icon", 3, "ngClass"], [1, "item-path"], [1, "item-description"], ["title", "Copy path", "aria-label", "Copy path", 1, "btn-copy", 3, "click"], [1, "fa-solid", "fa-copy"], [1, "value-details"], [1, "item-children"], [1, "fa-solid", "fa-chevron-right", "expand-icon"], [1, "value-row", "old"], [1, "value-label"], [1, "value-content"], ["title", "Copy value", "aria-label", "Copy value", 1, "btn-copy", 3, "click"], [1, "btn-expand-value", 3, "title"], [1, "value-row", "new"], [1, "btn-expand-value", 3, "click", "title"], [1, "fa-solid", 3, "ngClass"]], template: function DeepDiffComponent_Template(rf, ctx) { if (rf & 1) {
|
|
676
669
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
677
670
|
i0.ɵɵelementStart(0, "div", 1)(1, "div", 2)(2, "div", 3)(3, "h2", 4);
|
|
678
671
|
i0.ɵɵelement(4, "i", 5);
|
|
@@ -717,7 +710,7 @@ export class DeepDiffComponent {
|
|
|
717
710
|
i0.ɵɵtext(29, " Modified ");
|
|
718
711
|
i0.ɵɵelementEnd()()();
|
|
719
712
|
i0.ɵɵelementStart(30, "div", 26);
|
|
720
|
-
i0.ɵɵconditionalCreate(31, DeepDiffComponent_Conditional_31_Template,
|
|
713
|
+
i0.ɵɵconditionalCreate(31, DeepDiffComponent_Conditional_31_Template, 1, 0, "mj-empty-state", 27)(32, DeepDiffComponent_Conditional_32_Template, 1, 0, "mj-empty-state", 28)(33, DeepDiffComponent_Conditional_33_Template, 3, 0, "div", 29);
|
|
721
714
|
i0.ɵɵelementEnd()();
|
|
722
715
|
i0.ɵɵtemplate(34, DeepDiffComponent_ng_template_34_Template, 15, 10, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
|
|
723
716
|
} if (rf & 2) {
|
|
@@ -739,11 +732,11 @@ export class DeepDiffComponent {
|
|
|
739
732
|
i0.ɵɵclassProp("active", ctx.filterType === "modified");
|
|
740
733
|
i0.ɵɵadvance(4);
|
|
741
734
|
i0.ɵɵconditional(!ctx.diffResult ? 31 : ctx.filteredItems.length === 0 ? 32 : 33);
|
|
742
|
-
} }, dependencies: [i1.NgClass, i1.NgTemplateOutlet, i2.DefaultValueAccessor, i2.NgControlStatus, i2.NgModel], styles: ["\n\n.deep-diff-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n}\n\n\n\n.diff-header[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-bg-surface) 0%, var(--mj-bg-surface-sunken) 100%);\n padding: 20px;\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);\n}\n\n.header-content[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.diff-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-xl);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.diff-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.btn-icon[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n\n\n.diff-summary[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n}\n\n.summary-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.summary-item[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.summary-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-base);\n}\n\n.summary-item[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: var(--mj-text-base);\n}\n\n.summary-item[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.summary-item.added[_ngcontent-%COMP%] {\n border-color: var(--mj-status-success-subtle);\n background: var(--mj-status-success-subtle);\n}\n\n.summary-item.added[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.added[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.summary-item.removed[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error-subtle);\n background: var(--mj-status-error-subtle);\n}\n\n.summary-item.removed[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.removed[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.summary-item.modified[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary-subtle);\n background: var(--mj-brand-primary-subtle);\n}\n\n.summary-item.modified[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.modified[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.summary-item.unchanged[_ngcontent-%COMP%] {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.summary-item.unchanged[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.unchanged[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n.diff-filters[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n gap: 16px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.filter-search[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 250px;\n position: relative;\n}\n\n.filter-search[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px 8px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.filter-types[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.filter-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-btn.added.active[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.filter-btn.removed.active[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.filter-btn.modified.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n\n\n.diff-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n padding: 16px;\n}\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 300px;\n color: var(--mj-text-muted);\n gap: 16px;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n opacity: 0.2;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-base);\n}\n\n\n\n.diff-tree[_ngcontent-%COMP%] {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-sm);\n}\n\n.diff-item[_ngcontent-%COMP%] {\n margin-bottom: 2px;\n transition: all 0.2s ease;\n}\n\n.item-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n}\n\n.item-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.expand-icon[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n width: 12px;\n flex-shrink: 0;\n}\n\n.expand-icon.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.expand-spacer[_ngcontent-%COMP%] {\n width: 12px;\n flex-shrink: 0;\n}\n\n.type-icon[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.item-path[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-right: 8px;\n word-break: break-word;\n}\n\n.item-description[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n flex: 1;\n}\n\n.btn-copy[_ngcontent-%COMP%] {\n opacity: 0;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n}\n\n.item-header[_ngcontent-%COMP%]:hover .btn-copy[_ngcontent-%COMP%], \n.value-row[_ngcontent-%COMP%]:hover .btn-copy[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.btn-copy[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n\n\n.value-row[_ngcontent-%COMP%] .btn-copy[_ngcontent-%COMP%] {\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n\n\n.diff-item.added[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.diff-item.removed[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.diff-item.modified[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.diff-item.unchanged[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n.value-details[_ngcontent-%COMP%] {\n margin: 8px 0 0 44px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n}\n\n.value-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n margin-bottom: 8px;\n align-items: flex-start;\n position: relative;\n}\n\n.value-row[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.value-label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 40px;\n font-size: var(--mj-text-xs);\n padding-top: 2px;\n}\n\n.value-content[_ngcontent-%COMP%] {\n flex: 1;\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-xs);\n line-height: 1.5;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n word-break: break-word;\n white-space: pre-wrap;\n}\n\n.value-row.old[_ngcontent-%COMP%] .value-content[_ngcontent-%COMP%] {\n background: var(--mj-status-error-subtle);\n border-color: var(--mj-status-error-subtle);\n color: var(--mj-status-error);\n}\n\n.value-row.new[_ngcontent-%COMP%] .value-content[_ngcontent-%COMP%] {\n background: var(--mj-status-success-subtle);\n border-color: var(--mj-status-success-subtle);\n color: var(--mj-status-success);\n}\n\n\n\n.btn-expand-value[_ngcontent-%COMP%] {\n background: none;\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.btn-expand-value[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-strong);\n}\n\n.btn-expand-value[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n}\n\n\n\n.item-children[_ngcontent-%COMP%] {\n margin-top: 2px;\n position: relative;\n}\n\n.item-children[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: 6px;\n top: 0;\n bottom: 0;\n width: 1px;\n background: var(--mj-border-default);\n}\n\n\n\n@media (max-width: 768px) {\n .diff-header[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .header-content[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 12px;\n align-items: flex-start;\n }\n\n .diff-filters[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n }\n\n .filter-search[_ngcontent-%COMP%] {\n min-width: 100%;\n }\n\n .filter-types[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .value-details[_ngcontent-%COMP%] {\n margin-left: 20px;\n }\n}"], changeDetection: 0 });
|
|
735
|
+
} }, dependencies: [i1.NgClass, i1.NgTemplateOutlet, i2.DefaultValueAccessor, i2.NgControlStatus, i2.NgModel, i3.MJEmptyStateComponent], styles: ["\n\n.deep-diff-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n}\n\n\n\n.diff-header[_ngcontent-%COMP%] {\n background: linear-gradient(135deg, var(--mj-bg-surface) 0%, var(--mj-bg-surface-sunken) 100%);\n padding: 20px;\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);\n}\n\n.header-content[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.diff-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-xl);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.diff-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.btn-icon[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.btn-icon[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.btn-icon[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n\n\n.diff-summary[_ngcontent-%COMP%] {\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n}\n\n.summary-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.summary-item[_ngcontent-%COMP%]:hover {\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.summary-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-base);\n}\n\n.summary-item[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: var(--mj-text-base);\n}\n\n.summary-item[_ngcontent-%COMP%] .label[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.summary-item.added[_ngcontent-%COMP%] {\n border-color: var(--mj-status-success-subtle);\n background: var(--mj-status-success-subtle);\n}\n\n.summary-item.added[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.added[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.summary-item.removed[_ngcontent-%COMP%] {\n border-color: var(--mj-status-error-subtle);\n background: var(--mj-status-error-subtle);\n}\n\n.summary-item.removed[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.removed[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.summary-item.modified[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary-subtle);\n background: var(--mj-brand-primary-subtle);\n}\n\n.summary-item.modified[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.modified[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.summary-item.unchanged[_ngcontent-%COMP%] {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.summary-item.unchanged[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n.summary-item.unchanged[_ngcontent-%COMP%] .count[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n.diff-filters[_ngcontent-%COMP%] {\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n gap: 16px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.filter-search[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 250px;\n position: relative;\n}\n\n.filter-search[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 12px 8px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.filter-types[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.filter-btn[_ngcontent-%COMP%] {\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.filter-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-btn.added.active[_ngcontent-%COMP%] {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.filter-btn.removed.active[_ngcontent-%COMP%] {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.filter-btn.modified.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n\n\n.diff-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n padding: 16px;\n}\n\n\n\n.empty-state-fill[_ngcontent-%COMP%] {\n height: 100%;\n min-height: 300px;\n}\n\n\n\n.diff-tree[_ngcontent-%COMP%] {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-sm);\n}\n\n.diff-item[_ngcontent-%COMP%] {\n margin-bottom: 2px;\n transition: all 0.2s ease;\n}\n\n.item-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n}\n\n.item-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.expand-icon[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n width: 12px;\n flex-shrink: 0;\n}\n\n.expand-icon.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.expand-spacer[_ngcontent-%COMP%] {\n width: 12px;\n flex-shrink: 0;\n}\n\n.type-icon[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.item-path[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-right: 8px;\n word-break: break-word;\n}\n\n.item-description[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n flex: 1;\n}\n\n.btn-copy[_ngcontent-%COMP%] {\n opacity: 0;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n}\n\n.item-header[_ngcontent-%COMP%]:hover .btn-copy[_ngcontent-%COMP%], \n.value-row[_ngcontent-%COMP%]:hover .btn-copy[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.btn-copy[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n\n\n.value-row[_ngcontent-%COMP%] .btn-copy[_ngcontent-%COMP%] {\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n\n\n.diff-item.added[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.diff-item.removed[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.diff-item.modified[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.diff-item.unchanged[_ngcontent-%COMP%] .type-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n.value-details[_ngcontent-%COMP%] {\n margin: 8px 0 0 44px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n}\n\n.value-row[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n margin-bottom: 8px;\n align-items: flex-start;\n position: relative;\n}\n\n.value-row[_ngcontent-%COMP%]:last-child {\n margin-bottom: 0;\n}\n\n.value-label[_ngcontent-%COMP%] {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 40px;\n font-size: var(--mj-text-xs);\n padding-top: 2px;\n}\n\n.value-content[_ngcontent-%COMP%] {\n flex: 1;\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-xs);\n line-height: 1.5;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n word-break: break-word;\n white-space: pre-wrap;\n}\n\n.value-row.old[_ngcontent-%COMP%] .value-content[_ngcontent-%COMP%] {\n background: var(--mj-status-error-subtle);\n border-color: var(--mj-status-error-subtle);\n color: var(--mj-status-error);\n}\n\n.value-row.new[_ngcontent-%COMP%] .value-content[_ngcontent-%COMP%] {\n background: var(--mj-status-success-subtle);\n border-color: var(--mj-status-success-subtle);\n color: var(--mj-status-success);\n}\n\n\n\n.btn-expand-value[_ngcontent-%COMP%] {\n background: none;\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.btn-expand-value[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-strong);\n}\n\n.btn-expand-value[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n}\n\n\n\n.item-children[_ngcontent-%COMP%] {\n margin-top: 2px;\n position: relative;\n}\n\n.item-children[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: 6px;\n top: 0;\n bottom: 0;\n width: 1px;\n background: var(--mj-border-default);\n}\n\n\n\n@media (max-width: 768px) {\n .diff-header[_ngcontent-%COMP%] {\n padding: 16px;\n }\n\n .header-content[_ngcontent-%COMP%] {\n flex-direction: column;\n gap: 12px;\n align-items: flex-start;\n }\n\n .diff-filters[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: stretch;\n }\n\n .filter-search[_ngcontent-%COMP%] {\n min-width: 100%;\n }\n\n .filter-types[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .value-details[_ngcontent-%COMP%] {\n margin-left: 20px;\n }\n}"], changeDetection: 0 });
|
|
743
736
|
}
|
|
744
737
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DeepDiffComponent, [{
|
|
745
738
|
type: Component,
|
|
746
|
-
args: [{ standalone: false, selector: 'mj-deep-diff', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"deep-diff-container\">\n <!-- Header -->\n <div class=\"diff-header\">\n <div class=\"header-content\">\n <h2 class=\"diff-title\">\n <i class=\"fa-solid fa-code-branch\"></i>\n {{ title }}\n </h2>\n <div class=\"header-actions\">\n <button class=\"btn-icon\" (click)=\"expandAllItems()\" title=\"Expand All\" aria-label=\"Expand All\">\n <i class=\"fa-solid fa-expand\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAllItems()\" title=\"Collapse All\" aria-label=\"Collapse All\">\n <i class=\"fa-solid fa-compress\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"exportDiff()\" title=\"Export Diff\" aria-label=\"Export Diff\" [disabled]=\"!diffResult\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n </div>\n </div>\n\n <!-- Summary -->\n @if (showSummary && diffResult) {\n <div class=\"diff-summary\">\n <div class=\"summary-item added\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.added }}</span>\n <span class=\"label\">Added</span>\n </div>\n <div class=\"summary-item removed\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.removed }}</span>\n <span class=\"label\">Removed</span>\n </div>\n <div class=\"summary-item modified\">\n <i class=\"fa-solid fa-edit\"></i>\n <span class=\"count\">{{ diffResult.summary.modified }}</span>\n <span class=\"label\">Modified</span>\n </div>\n @if (showUnchanged) {\n <div class=\"summary-item unchanged\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.unchanged }}</span>\n <span class=\"label\">Unchanged</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Filters -->\n <div class=\"diff-filters\">\n <div class=\"filter-search\">\n <i class=\"fa-solid fa-search\"></i>\n <input \n type=\"text\" \n [(ngModel)]=\"filter\" \n placeholder=\"Filter by path or description...\"\n class=\"filter-input\">\n </div>\n <div class=\"filter-types\">\n <button \n class=\"filter-btn\"\n [class.active]=\"filterType === 'all'\"\n (click)=\"filterType = 'all'\">\n All Changes\n </button>\n <button \n class=\"filter-btn added\"\n [class.active]=\"filterType === 'added'\"\n (click)=\"filterType = 'added'\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n Added\n </button>\n <button \n class=\"filter-btn removed\"\n [class.active]=\"filterType === 'removed'\"\n (click)=\"filterType = 'removed'\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n Removed\n </button>\n <button \n class=\"filter-btn modified\"\n [class.active]=\"filterType === 'modified'\"\n (click)=\"filterType = 'modified'\">\n <i class=\"fa-solid fa-edit\"></i>\n Modified\n </button>\n </div>\n </div>\n\n <!-- Diff Content -->\n <div class=\"diff-content\">\n @if (!diffResult) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-code-compare fa-3x\"></i>\n <p>No data to compare</p>\n </div>\n } @else if (filteredItems.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-filter fa-3x\"></i>\n <p>No changes match your filter criteria</p>\n </div>\n } @else {\n <div class=\"diff-tree\">\n @for (item of filteredItems; track item.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: item, level: 0 }\"></ng-container>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Recursive Template for Diff Items -->\n<ng-template #diffItem let-item=\"item\" let-level=\"level\">\n <div class=\"diff-item\" [class]=\"getTypeClass(item.type)\" [style.padding-left.px]=\"level * 24\">\n <div class=\"item-header\" (click)=\"toggleItem(item)\">\n @if (item.children.length > 0) {\n <i class=\"fa-solid fa-chevron-right expand-icon\" [class.expanded]=\"item.isExpanded\"></i>\n } @else {\n <span class=\"expand-spacer\"></span>\n }\n \n <i class=\"fa-solid type-icon\" [ngClass]=\"getIcon(item.type)\"></i>\n \n <span class=\"item-path\">{{ item.path }}</span>\n \n <span class=\"item-description\">{{ item.description }}</span>\n \n <button class=\"btn-copy\" (click)=\"copyToClipboard(item.path); $event.stopPropagation()\" title=\"Copy path\" aria-label=\"Copy path\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n\n <!-- Value Details -->\n @if (item.type === 'modified') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Old:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path + '_old') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path + '_old') || isExpanded(item.path + '_old')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_old', $event)\" \n title=\"{{ isExpanded(item.path + '_old') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_old') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_old') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n <div class=\"value-row new\">\n <span class=\"value-label\">New:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path + '_new') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path + '_new') || isExpanded(item.path + '_new')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_new', $event)\"\n title=\"{{ isExpanded(item.path + '_new') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_new') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_new') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'added') {\n <div class=\"value-details\">\n <div class=\"value-row new\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'removed') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Children -->\n @if (item.isExpanded && item.children.length > 0) {\n <div class=\"item-children\">\n @for (child of item.children; track child.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: child, level: level + 1 }\"></ng-container>\n }\n </div>\n }\n </div>\n</ng-template>", styles: ["/* Deep Diff Component Styles */\n.deep-diff-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n}\n\n/* Header */\n.diff-header {\n background: linear-gradient(135deg, var(--mj-bg-surface) 0%, var(--mj-bg-surface-sunken) 100%);\n padding: 20px;\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.diff-title {\n margin: 0;\n font-size: var(--mj-text-xl);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.diff-title i {\n color: var(--mj-brand-primary);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n.btn-icon {\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.btn-icon:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.btn-icon:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Summary */\n.diff-summary {\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n}\n\n.summary-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.summary-item:hover {\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.summary-item i {\n font-size: var(--mj-text-base);\n}\n\n.summary-item .count {\n font-weight: 600;\n font-size: var(--mj-text-base);\n}\n\n.summary-item .label {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.summary-item.added {\n border-color: var(--mj-status-success-subtle);\n background: var(--mj-status-success-subtle);\n}\n\n.summary-item.added i,\n.summary-item.added .count {\n color: var(--mj-status-success);\n}\n\n.summary-item.removed {\n border-color: var(--mj-status-error-subtle);\n background: var(--mj-status-error-subtle);\n}\n\n.summary-item.removed i,\n.summary-item.removed .count {\n color: var(--mj-status-error);\n}\n\n.summary-item.modified {\n border-color: var(--mj-brand-primary-subtle);\n background: var(--mj-brand-primary-subtle);\n}\n\n.summary-item.modified i,\n.summary-item.modified .count {\n color: var(--mj-brand-primary);\n}\n\n.summary-item.unchanged {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.summary-item.unchanged i,\n.summary-item.unchanged .count {\n color: var(--mj-text-muted);\n}\n\n/* Filters */\n.diff-filters {\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n gap: 16px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.filter-search {\n flex: 1;\n min-width: 250px;\n position: relative;\n}\n\n.filter-search i {\n position: absolute;\n left: 12px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.filter-input {\n width: 100%;\n padding: 8px 12px 8px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.filter-types {\n display: flex;\n gap: 8px;\n}\n\n.filter-btn {\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-btn:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.filter-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-btn.added.active {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.filter-btn.removed.active {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.filter-btn.modified.active {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* Content Area */\n.diff-content {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n padding: 16px;\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n min-height: 300px;\n color: var(--mj-text-muted);\n gap: 16px;\n}\n\n.empty-state i {\n opacity: 0.2;\n}\n\n.empty-state p {\n margin: 0;\n font-size: var(--mj-text-base);\n}\n\n/* Diff Tree */\n.diff-tree {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-sm);\n}\n\n.diff-item {\n margin-bottom: 2px;\n transition: all 0.2s ease;\n}\n\n.item-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n}\n\n.item-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.expand-icon {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n width: 12px;\n flex-shrink: 0;\n}\n\n.expand-icon.expanded {\n transform: rotate(90deg);\n}\n\n.expand-spacer {\n width: 12px;\n flex-shrink: 0;\n}\n\n.type-icon {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.item-path {\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-right: 8px;\n word-break: break-word;\n}\n\n.item-description {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n flex: 1;\n}\n\n.btn-copy {\n opacity: 0;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n}\n\n.item-header:hover .btn-copy,\n.value-row:hover .btn-copy {\n opacity: 1;\n}\n\n.btn-copy:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n/* Value row copy button */\n.value-row .btn-copy {\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n/* Type-specific styling */\n.diff-item.added .type-icon {\n color: var(--mj-status-success);\n}\n\n.diff-item.removed .type-icon {\n color: var(--mj-status-error);\n}\n\n.diff-item.modified .type-icon {\n color: var(--mj-brand-primary);\n}\n\n.diff-item.unchanged .type-icon {\n color: var(--mj-text-muted);\n}\n\n/* Value Details */\n.value-details {\n margin: 8px 0 0 44px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n}\n\n.value-row {\n display: flex;\n gap: 12px;\n margin-bottom: 8px;\n align-items: flex-start;\n position: relative;\n}\n\n.value-row:last-child {\n margin-bottom: 0;\n}\n\n.value-label {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 40px;\n font-size: var(--mj-text-xs);\n padding-top: 2px;\n}\n\n.value-content {\n flex: 1;\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-xs);\n line-height: 1.5;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n word-break: break-word;\n white-space: pre-wrap;\n}\n\n.value-row.old .value-content {\n background: var(--mj-status-error-subtle);\n border-color: var(--mj-status-error-subtle);\n color: var(--mj-status-error);\n}\n\n.value-row.new .value-content {\n background: var(--mj-status-success-subtle);\n border-color: var(--mj-status-success-subtle);\n color: var(--mj-status-success);\n}\n\n/* Expand/Collapse Value Button */\n.btn-expand-value {\n background: none;\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.btn-expand-value:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-strong);\n}\n\n.btn-expand-value i {\n font-size: var(--mj-text-xs);\n}\n\n/* Children */\n.item-children {\n margin-top: 2px;\n position: relative;\n}\n\n.item-children::before {\n content: '';\n position: absolute;\n left: 6px;\n top: 0;\n bottom: 0;\n width: 1px;\n background: var(--mj-border-default);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .diff-header {\n padding: 16px;\n }\n\n .header-content {\n flex-direction: column;\n gap: 12px;\n align-items: flex-start;\n }\n\n .diff-filters {\n flex-direction: column;\n align-items: stretch;\n }\n\n .filter-search {\n min-width: 100%;\n }\n\n .filter-types {\n flex-wrap: wrap;\n }\n\n .value-details {\n margin-left: 20px;\n }\n}"] }]
|
|
739
|
+
args: [{ standalone: false, selector: 'mj-deep-diff', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"deep-diff-container\">\n <!-- Header -->\n <div class=\"diff-header\">\n <div class=\"header-content\">\n <h2 class=\"diff-title\">\n <i class=\"fa-solid fa-code-branch\"></i>\n {{ title }}\n </h2>\n <div class=\"header-actions\">\n <button class=\"btn-icon\" (click)=\"expandAllItems()\" title=\"Expand All\" aria-label=\"Expand All\">\n <i class=\"fa-solid fa-expand\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAllItems()\" title=\"Collapse All\" aria-label=\"Collapse All\">\n <i class=\"fa-solid fa-compress\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"exportDiff()\" title=\"Export Diff\" aria-label=\"Export Diff\" [disabled]=\"!diffResult\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n </div>\n </div>\n\n <!-- Summary -->\n @if (showSummary && diffResult) {\n <div class=\"diff-summary\">\n <div class=\"summary-item added\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.added }}</span>\n <span class=\"label\">Added</span>\n </div>\n <div class=\"summary-item removed\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.removed }}</span>\n <span class=\"label\">Removed</span>\n </div>\n <div class=\"summary-item modified\">\n <i class=\"fa-solid fa-edit\"></i>\n <span class=\"count\">{{ diffResult.summary.modified }}</span>\n <span class=\"label\">Modified</span>\n </div>\n @if (showUnchanged) {\n <div class=\"summary-item unchanged\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.unchanged }}</span>\n <span class=\"label\">Unchanged</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Filters -->\n <div class=\"diff-filters\">\n <div class=\"filter-search\">\n <i class=\"fa-solid fa-search\"></i>\n <input \n type=\"text\" \n [(ngModel)]=\"filter\" \n placeholder=\"Filter by path or description...\"\n class=\"filter-input\">\n </div>\n <div class=\"filter-types\">\n <button \n class=\"filter-btn\"\n [class.active]=\"filterType === 'all'\"\n (click)=\"filterType = 'all'\">\n All Changes\n </button>\n <button \n class=\"filter-btn added\"\n [class.active]=\"filterType === 'added'\"\n (click)=\"filterType = 'added'\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n Added\n </button>\n <button \n class=\"filter-btn removed\"\n [class.active]=\"filterType === 'removed'\"\n (click)=\"filterType = 'removed'\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n Removed\n </button>\n <button \n class=\"filter-btn modified\"\n [class.active]=\"filterType === 'modified'\"\n (click)=\"filterType = 'modified'\">\n <i class=\"fa-solid fa-edit\"></i>\n Modified\n </button>\n </div>\n </div>\n\n <!-- Diff Content -->\n <div class=\"diff-content\">\n @if (!diffResult) {\n <mj-empty-state\n class=\"empty-state-fill\"\n Icon=\"fa-solid fa-code-compare\"\n Title=\"No data to compare\" />\n } @else if (filteredItems.length === 0) {\n <mj-empty-state\n class=\"empty-state-fill\"\n Variant=\"no-results\"\n Icon=\"fa-solid fa-filter\"\n Title=\"No changes match your filter criteria\" />\n } @else {\n <div class=\"diff-tree\">\n @for (item of filteredItems; track item.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: item, level: 0 }\"></ng-container>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Recursive Template for Diff Items -->\n<ng-template #diffItem let-item=\"item\" let-level=\"level\">\n <div class=\"diff-item\" [class]=\"getTypeClass(item.type)\" [style.padding-left.px]=\"level * 24\">\n <div class=\"item-header\" (click)=\"toggleItem(item)\">\n @if (item.children.length > 0) {\n <i class=\"fa-solid fa-chevron-right expand-icon\" [class.expanded]=\"item.isExpanded\"></i>\n } @else {\n <span class=\"expand-spacer\"></span>\n }\n \n <i class=\"fa-solid type-icon\" [ngClass]=\"getIcon(item.type)\"></i>\n \n <span class=\"item-path\">{{ item.path }}</span>\n \n <span class=\"item-description\">{{ item.description }}</span>\n \n <button class=\"btn-copy\" (click)=\"copyToClipboard(item.path); $event.stopPropagation()\" title=\"Copy path\" aria-label=\"Copy path\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n\n <!-- Value Details -->\n @if (item.type === 'modified') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Old:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path + '_old') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path + '_old') || isExpanded(item.path + '_old')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_old', $event)\" \n title=\"{{ isExpanded(item.path + '_old') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_old') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_old') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n <div class=\"value-row new\">\n <span class=\"value-label\">New:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path + '_new') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path + '_new') || isExpanded(item.path + '_new')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_new', $event)\"\n title=\"{{ isExpanded(item.path + '_new') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_new') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_new') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'added') {\n <div class=\"value-details\">\n <div class=\"value-row new\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'removed') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Children -->\n @if (item.isExpanded && item.children.length > 0) {\n <div class=\"item-children\">\n @for (child of item.children; track child.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: child, level: level + 1 }\"></ng-container>\n }\n </div>\n }\n </div>\n</ng-template>", styles: ["/* Deep Diff Component Styles */\n.deep-diff-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n}\n\n/* Header */\n.diff-header {\n background: linear-gradient(135deg, var(--mj-bg-surface) 0%, var(--mj-bg-surface-sunken) 100%);\n padding: 20px;\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);\n}\n\n.header-content {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n}\n\n.diff-title {\n margin: 0;\n font-size: var(--mj-text-xl);\n font-weight: 600;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n.diff-title i {\n color: var(--mj-brand-primary);\n}\n\n.header-actions {\n display: flex;\n gap: 8px;\n}\n\n.btn-icon {\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 0.2s ease;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.btn-icon:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n color: var(--mj-text-secondary);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);\n}\n\n.btn-icon:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n/* Summary */\n.diff-summary {\n display: flex;\n gap: 20px;\n flex-wrap: wrap;\n}\n\n.summary-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n transition: all 0.2s ease;\n}\n\n.summary-item:hover {\n transform: translateY(-1px);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n\n.summary-item i {\n font-size: var(--mj-text-base);\n}\n\n.summary-item .count {\n font-weight: 600;\n font-size: var(--mj-text-base);\n}\n\n.summary-item .label {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.summary-item.added {\n border-color: var(--mj-status-success-subtle);\n background: var(--mj-status-success-subtle);\n}\n\n.summary-item.added i,\n.summary-item.added .count {\n color: var(--mj-status-success);\n}\n\n.summary-item.removed {\n border-color: var(--mj-status-error-subtle);\n background: var(--mj-status-error-subtle);\n}\n\n.summary-item.removed i,\n.summary-item.removed .count {\n color: var(--mj-status-error);\n}\n\n.summary-item.modified {\n border-color: var(--mj-brand-primary-subtle);\n background: var(--mj-brand-primary-subtle);\n}\n\n.summary-item.modified i,\n.summary-item.modified .count {\n color: var(--mj-brand-primary);\n}\n\n.summary-item.unchanged {\n border-color: var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n.summary-item.unchanged i,\n.summary-item.unchanged .count {\n color: var(--mj-text-muted);\n}\n\n/* Filters */\n.diff-filters {\n padding: 16px 20px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n gap: 16px;\n align-items: center;\n flex-wrap: wrap;\n}\n\n.filter-search {\n flex: 1;\n min-width: 250px;\n position: relative;\n}\n\n.filter-search i {\n position: absolute;\n left: 12px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.filter-input {\n width: 100%;\n padding: 8px 12px 8px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n transition: all 0.2s ease;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n}\n\n.filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.filter-types {\n display: flex;\n gap: 8px;\n}\n\n.filter-btn {\n padding: 6px 14px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-md);\n font-size: var(--mj-text-sm);\n font-weight: 500;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s ease;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-btn:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-strong);\n}\n\n.filter-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-btn.added.active {\n background: var(--mj-status-success);\n border-color: var(--mj-status-success);\n}\n\n.filter-btn.removed.active {\n background: var(--mj-status-error);\n border-color: var(--mj-status-error);\n}\n\n.filter-btn.modified.active {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n/* Content Area */\n.diff-content {\n flex: 1;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n padding: 16px;\n}\n\n/* Empty state \u2014 fill the diff content area */\n.empty-state-fill {\n height: 100%;\n min-height: 300px;\n}\n\n/* Diff Tree */\n.diff-tree {\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-sm);\n}\n\n.diff-item {\n margin-bottom: 2px;\n transition: all 0.2s ease;\n}\n\n.item-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: all 0.2s ease;\n position: relative;\n}\n\n.item-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.expand-icon {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n transition: transform 0.2s ease;\n width: 12px;\n flex-shrink: 0;\n}\n\n.expand-icon.expanded {\n transform: rotate(90deg);\n}\n\n.expand-spacer {\n width: 12px;\n flex-shrink: 0;\n}\n\n.type-icon {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.item-path {\n font-weight: 600;\n color: var(--mj-text-primary);\n margin-right: 8px;\n word-break: break-word;\n}\n\n.item-description {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-xs);\n flex: 1;\n}\n\n.btn-copy {\n opacity: 0;\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n}\n\n.item-header:hover .btn-copy,\n.value-row:hover .btn-copy {\n opacity: 1;\n}\n\n.btn-copy:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n}\n\n/* Value row copy button */\n.value-row .btn-copy {\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n/* Type-specific styling */\n.diff-item.added .type-icon {\n color: var(--mj-status-success);\n}\n\n.diff-item.removed .type-icon {\n color: var(--mj-status-error);\n}\n\n.diff-item.modified .type-icon {\n color: var(--mj-brand-primary);\n}\n\n.diff-item.unchanged .type-icon {\n color: var(--mj-text-muted);\n}\n\n/* Value Details */\n.value-details {\n margin: 8px 0 0 44px;\n padding: 12px;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n border: 1px solid var(--mj-border-default);\n}\n\n.value-row {\n display: flex;\n gap: 12px;\n margin-bottom: 8px;\n align-items: flex-start;\n position: relative;\n}\n\n.value-row:last-child {\n margin-bottom: 0;\n}\n\n.value-label {\n font-weight: 600;\n color: var(--mj-text-secondary);\n min-width: 40px;\n font-size: var(--mj-text-xs);\n padding-top: 2px;\n}\n\n.value-content {\n flex: 1;\n font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;\n font-size: var(--mj-text-xs);\n line-height: 1.5;\n color: var(--mj-text-primary);\n background: var(--mj-bg-surface);\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n border: 1px solid var(--mj-border-default);\n word-break: break-word;\n white-space: pre-wrap;\n}\n\n.value-row.old .value-content {\n background: var(--mj-status-error-subtle);\n border-color: var(--mj-status-error-subtle);\n color: var(--mj-status-error);\n}\n\n.value-row.new .value-content {\n background: var(--mj-status-success-subtle);\n border-color: var(--mj-status-success-subtle);\n color: var(--mj-status-success);\n}\n\n/* Expand/Collapse Value Button */\n.btn-expand-value {\n background: none;\n border: 1px solid var(--mj-border-default);\n color: var(--mj-text-muted);\n cursor: pointer;\n padding: 4px 8px;\n border-radius: var(--mj-radius-sm);\n transition: all 0.2s ease;\n font-size: var(--mj-text-xs);\n flex-shrink: 0;\n margin-left: 8px;\n}\n\n.btn-expand-value:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-secondary);\n border-color: var(--mj-border-strong);\n}\n\n.btn-expand-value i {\n font-size: var(--mj-text-xs);\n}\n\n/* Children */\n.item-children {\n margin-top: 2px;\n position: relative;\n}\n\n.item-children::before {\n content: '';\n position: absolute;\n left: 6px;\n top: 0;\n bottom: 0;\n width: 1px;\n background: var(--mj-border-default);\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .diff-header {\n padding: 16px;\n }\n\n .header-content {\n flex-direction: column;\n gap: 12px;\n align-items: flex-start;\n }\n\n .diff-filters {\n flex-direction: column;\n align-items: stretch;\n }\n\n .filter-search {\n min-width: 100%;\n }\n\n .filter-types {\n flex-wrap: wrap;\n }\n\n .value-details {\n margin-left: 20px;\n }\n}"] }]
|
|
747
740
|
}], () => [{ type: i0.ChangeDetectorRef }], { oldValue: [{
|
|
748
741
|
type: Input
|
|
749
742
|
}], newValue: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deep-diff.component.js","sourceRoot":"","sources":["../../src/lib/deep-diff.component.ts","../../src/lib/deep-diff.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, OnInit, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';\nimport { DeepDiffer, DeepDiffResult, DiffChangeType, DiffChange } from '@memberjunction/global';\n\nexport interface DeepDiffItem extends DiffChange {\n level: number;\n isExpanded: boolean;\n children: DeepDiffItem[];\n parentPath: string;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-deep-diff',\n templateUrl: './deep-diff.component.html',\n styleUrls: ['./deep-diff.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class DeepDiffComponent implements OnInit {\n private _oldValue: any;\n private _newValue: any;\n private _showUnchanged: boolean = false;\n private _maxDepth: number = 10;\n private _maxStringLength: number = 100;\n private _treatNullAsUndefined: boolean = false;\n\n @Input()\n get oldValue(): any {\n return this._oldValue;\n }\n set oldValue(value: any) {\n this._oldValue = value;\n this.generateDiff();\n }\n\n @Input()\n get newValue(): any {\n return this._newValue;\n }\n set newValue(value: any) {\n this._newValue = value;\n this.generateDiff();\n }\n\n @Input()\n get showUnchanged(): boolean {\n return this._showUnchanged;\n }\n set showUnchanged(value: boolean) {\n this._showUnchanged = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input()\n get maxDepth(): number {\n return this._maxDepth;\n }\n set maxDepth(value: number) {\n this._maxDepth = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input()\n get maxStringLength(): number {\n return this._maxStringLength;\n }\n set maxStringLength(value: number) {\n this._maxStringLength = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input()\n get treatNullAsUndefined(): boolean {\n return this._treatNullAsUndefined;\n }\n set treatNullAsUndefined(value: boolean) {\n this._treatNullAsUndefined = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input() title: string = 'Deep Diff Analysis';\n @Input() showSummary: boolean = true;\n @Input() expandAll: boolean = false;\n @Input() truncateValues: boolean = true;\n\n diffResult: DeepDiffResult | null = null;\n diffItems: DeepDiffItem[] = [];\n\n private _filter: string = '';\n get filter(): string {\n return this._filter;\n }\n set filter(value: string) {\n this._filter = value;\n this.recomputeFilteredItems();\n }\n\n private _filterType: 'all' | 'added' | 'removed' | 'modified' | 'unchanged' = 'all';\n get filterType(): 'all' | 'added' | 'removed' | 'modified' | 'unchanged' {\n return this._filterType;\n }\n set filterType(value: 'all' | 'added' | 'removed' | 'modified' | 'unchanged') {\n this._filterType = value;\n this.recomputeFilteredItems();\n }\n\n /**\n * Precomputed filtered diff tree. Recomputed only when the source data\n * (`diffItems`) or the filter inputs (`filter` / `filterType`) change —\n * never on every change-detection cycle. Bound directly by the template's\n * `@for` and empty-state length check, which preserves `@for` referential\n * stability between CD passes (the recursive walk no longer runs >= 2x/CD).\n */\n filteredItems: DeepDiffItem[] = [];\n\n expandedValuesMap: { [key: string]: boolean } = {};\n\n /**\n * Memoization cache for {@link formatValue} / {@link isValueTruncated}. Keyed\n * by `${path}|${expanded}` so the expensive `JSON.stringify` of object values\n * runs at most once per (path, expansion-state) instead of on every\n * change-detection cycle (the template binds these in a recursive `@for`).\n * Invalidated whenever the source data is regenerated.\n */\n private formatValueCache = new Map<string, string>();\n private truncatedCache = new Map<string, boolean>();\n\n private differ: DeepDiffer;\n\n constructor(private cdr: ChangeDetectorRef) {\n this.differ = new DeepDiffer({\n includeUnchanged: false,\n maxDepth: this.maxDepth,\n maxStringLength: this.maxStringLength,\n treatNullAsUndefined: this.treatNullAsUndefined\n });\n }\n\n ngOnInit(): void {\n this.generateDiff();\n }\n\n\n private updateDifferConfig(): void {\n this.differ.updateConfig({\n includeUnchanged: this.showUnchanged,\n maxDepth: this.maxDepth,\n maxStringLength: this.maxStringLength,\n treatNullAsUndefined: this.treatNullAsUndefined\n });\n }\n\n private generateDiff(): void {\n if (this.oldValue === undefined && this.newValue === undefined) {\n this.formatValueCache.clear();\n this.truncatedCache.clear();\n this.diffResult = null;\n this.diffItems = [];\n this.recomputeFilteredItems();\n return;\n }\n\n this.formatValueCache.clear();\n this.truncatedCache.clear();\n this.diffResult = this.differ.diff(this.oldValue, this.newValue);\n this.diffItems = this.buildHierarchicalItems(this.diffResult.changes);\n\n if (this.expandAll) {\n this.expandAllItems();\n }\n\n this.recomputeFilteredItems();\n }\n\n private buildHierarchicalItems(changes: DiffChange[]): DeepDiffItem[] {\n const rootItems: DeepDiffItem[] = [];\n const itemMap = new Map<string, DeepDiffItem>();\n\n // Sort by path to ensure parents come before children\n const sortedChanges = [...changes].sort((a, b) => {\n const aDepth = a.path.split('.').length;\n const bDepth = b.path.split('.').length;\n if (aDepth !== bDepth) return aDepth - bDepth;\n return a.path.localeCompare(b.path);\n });\n\n for (const change of sortedChanges) {\n const pathParts = change.path === 'root' ? [] : change.path.split('.');\n const level = pathParts.length;\n const parentPath = pathParts.slice(0, -1).join('.');\n \n const item: DeepDiffItem = {\n ...change,\n level,\n isExpanded: level === 0, // Expand only root level items by default\n children: [],\n parentPath\n };\n\n itemMap.set(change.path, item);\n\n if (parentPath && itemMap.has(parentPath)) {\n itemMap.get(parentPath)!.children.push(item);\n } else {\n rootItems.push(item);\n }\n }\n\n return rootItems;\n }\n\n toggleItem(item: DeepDiffItem): void {\n item.isExpanded = !item.isExpanded;\n this.cdr.markForCheck();\n }\n\n expandAllItems(): void {\n const expand = (items: DeepDiffItem[]) => {\n for (const item of items) {\n item.isExpanded = true;\n if (item.children.length > 0) {\n expand(item.children);\n }\n }\n };\n expand(this.diffItems);\n this.cdr.markForCheck();\n }\n\n collapseAllItems(): void {\n const collapse = (items: DeepDiffItem[]) => {\n for (const item of items) {\n item.isExpanded = false;\n if (item.children.length > 0) {\n collapse(item.children);\n }\n }\n };\n collapse(this.diffItems);\n this.cdr.markForCheck();\n }\n\n /**\n * Recomputes {@link filteredItems} from the current `diffItems` + filter\n * inputs. Called from `generateDiff()` (data change) and from the\n * `filter` / `filterType` setters (filter change) — NOT per CD cycle.\n */\n private recomputeFilteredItems(): void {\n if (!this.filter && this.filterType === 'all') {\n this.filteredItems = this.diffItems;\n this.cdr.markForCheck();\n return;\n }\n\n const filterFn = (item: DeepDiffItem): boolean => {\n const matchesType = this.filterType === 'all' || \n (this.filterType === 'added' && item.type === DiffChangeType.Added) ||\n (this.filterType === 'removed' && item.type === DiffChangeType.Removed) ||\n (this.filterType === 'modified' && item.type === DiffChangeType.Modified) ||\n (this.filterType === 'unchanged' && item.type === DiffChangeType.Unchanged);\n const matchesText = !this.filter || \n item.path.toLowerCase().includes(this.filter.toLowerCase()) ||\n item.description.toLowerCase().includes(this.filter.toLowerCase());\n \n return matchesType && matchesText;\n };\n\n const filterRecursive = (items: DeepDiffItem[]): DeepDiffItem[] => {\n return items.reduce((acc, item) => {\n const childMatches = filterRecursive(item.children);\n if (filterFn(item) || childMatches.length > 0) {\n acc.push({\n ...item,\n children: childMatches,\n isExpanded: item.isExpanded // Preserve the original expanded state\n });\n }\n return acc;\n }, [] as DeepDiffItem[]);\n };\n\n this.filteredItems = filterRecursive(this.diffItems);\n this.cdr.markForCheck();\n }\n\n getIcon(type: DiffChangeType): string {\n switch (type) {\n case DiffChangeType.Added: return 'fa-plus-circle';\n case DiffChangeType.Removed: return 'fa-minus-circle';\n case DiffChangeType.Modified: return 'fa-edit';\n case DiffChangeType.Unchanged: return 'fa-check-circle';\n default: return 'fa-question-circle';\n }\n }\n\n getTypeClass(type: DiffChangeType): string {\n switch (type) {\n case DiffChangeType.Added: return 'added';\n case DiffChangeType.Removed: return 'removed';\n case DiffChangeType.Modified: return 'modified';\n case DiffChangeType.Unchanged: return 'unchanged';\n default: return '';\n }\n }\n\n formatValue(value: any, path: string): string {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n\n const isExpanded = !!this.expandedValuesMap[path];\n const cacheKey = `${path}|${isExpanded ? 1 : 0}`;\n const cached = this.formatValueCache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n const formatted = this.computeFormattedValue(value, isExpanded);\n this.formatValueCache.set(cacheKey, formatted);\n return formatted;\n }\n\n private computeFormattedValue(value: any, isExpanded: boolean): string {\n const shouldTruncate = this.truncateValues && !isExpanded;\n\n if (typeof value === 'string') {\n if (shouldTruncate && value.length > this.maxStringLength) {\n return `\"${value.substring(0, this.maxStringLength)}...\"`;\n }\n return `\"${value}\"`;\n }\n \n if (typeof value === 'object') {\n try {\n const json = JSON.stringify(value, null, 2);\n if (shouldTruncate && json.length > 200) {\n // Show a preview for objects\n const preview = JSON.stringify(value).substring(0, 50);\n return `${preview}... (${this.getObjectSize(value)} properties)`;\n }\n return json;\n } catch {\n return String(value);\n }\n }\n \n return String(value);\n }\n \n isValueTruncated(value: any, path: string): boolean {\n if (!this.truncateValues || this.expandedValuesMap[path]) {\n return false;\n }\n\n const cacheKey = `${path}|0`;\n const cached = this.truncatedCache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n const result = this.computeValueTruncated(value);\n this.truncatedCache.set(cacheKey, result);\n return result;\n }\n\n private computeValueTruncated(value: any): boolean {\n if (typeof value === 'string') {\n return value.length > this.maxStringLength;\n }\n \n if (typeof value === 'object' && value !== null) {\n try {\n const json = JSON.stringify(value, null, 2);\n return json.length > 200;\n } catch {\n return false;\n }\n }\n \n return false;\n }\n \n toggleValueExpansion(path: string, event: Event): void {\n event.stopPropagation();\n \n // Create a new object to trigger change detection\n this.expandedValuesMap = {\n ...this.expandedValuesMap,\n [path]: !this.expandedValuesMap[path]\n };\n \n // Force change detection\n this.cdr.markForCheck();\n }\n \n private getObjectSize(obj: any): number {\n if (Array.isArray(obj)) {\n return obj.length;\n }\n return Object.keys(obj).length;\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard.writeText(text).then(() => {\n // Could add a toast notification here\n });\n }\n \n isExpanded(path: string): boolean {\n return !!this.expandedValuesMap[path];\n }\n \n copyValueToClipboard(value: any, event: Event): void {\n event.stopPropagation();\n let textToCopy: string;\n \n if (value === undefined) {\n textToCopy = 'undefined';\n } else if (value === null) {\n textToCopy = 'null';\n } else if (typeof value === 'object') {\n try {\n textToCopy = JSON.stringify(value, null, 2);\n } catch {\n textToCopy = String(value);\n }\n } else {\n textToCopy = String(value);\n }\n \n navigator.clipboard.writeText(textToCopy).then(() => {\n // Could add a toast notification here\n });\n }\n\n exportDiff(): void {\n if (!this.diffResult) return;\n \n const blob = new Blob([JSON.stringify(this.diffResult, null, 2)], \n { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `diff-${new Date().toISOString()}.json`;\n a.click();\n URL.revokeObjectURL(url);\n }\n}","<div class=\"deep-diff-container\">\n <!-- Header -->\n <div class=\"diff-header\">\n <div class=\"header-content\">\n <h2 class=\"diff-title\">\n <i class=\"fa-solid fa-code-branch\"></i>\n {{ title }}\n </h2>\n <div class=\"header-actions\">\n <button class=\"btn-icon\" (click)=\"expandAllItems()\" title=\"Expand All\" aria-label=\"Expand All\">\n <i class=\"fa-solid fa-expand\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAllItems()\" title=\"Collapse All\" aria-label=\"Collapse All\">\n <i class=\"fa-solid fa-compress\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"exportDiff()\" title=\"Export Diff\" aria-label=\"Export Diff\" [disabled]=\"!diffResult\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n </div>\n </div>\n\n <!-- Summary -->\n @if (showSummary && diffResult) {\n <div class=\"diff-summary\">\n <div class=\"summary-item added\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.added }}</span>\n <span class=\"label\">Added</span>\n </div>\n <div class=\"summary-item removed\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.removed }}</span>\n <span class=\"label\">Removed</span>\n </div>\n <div class=\"summary-item modified\">\n <i class=\"fa-solid fa-edit\"></i>\n <span class=\"count\">{{ diffResult.summary.modified }}</span>\n <span class=\"label\">Modified</span>\n </div>\n @if (showUnchanged) {\n <div class=\"summary-item unchanged\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.unchanged }}</span>\n <span class=\"label\">Unchanged</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Filters -->\n <div class=\"diff-filters\">\n <div class=\"filter-search\">\n <i class=\"fa-solid fa-search\"></i>\n <input \n type=\"text\" \n [(ngModel)]=\"filter\" \n placeholder=\"Filter by path or description...\"\n class=\"filter-input\">\n </div>\n <div class=\"filter-types\">\n <button \n class=\"filter-btn\"\n [class.active]=\"filterType === 'all'\"\n (click)=\"filterType = 'all'\">\n All Changes\n </button>\n <button \n class=\"filter-btn added\"\n [class.active]=\"filterType === 'added'\"\n (click)=\"filterType = 'added'\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n Added\n </button>\n <button \n class=\"filter-btn removed\"\n [class.active]=\"filterType === 'removed'\"\n (click)=\"filterType = 'removed'\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n Removed\n </button>\n <button \n class=\"filter-btn modified\"\n [class.active]=\"filterType === 'modified'\"\n (click)=\"filterType = 'modified'\">\n <i class=\"fa-solid fa-edit\"></i>\n Modified\n </button>\n </div>\n </div>\n\n <!-- Diff Content -->\n <div class=\"diff-content\">\n @if (!diffResult) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-code-compare fa-3x\"></i>\n <p>No data to compare</p>\n </div>\n } @else if (filteredItems.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-filter fa-3x\"></i>\n <p>No changes match your filter criteria</p>\n </div>\n } @else {\n <div class=\"diff-tree\">\n @for (item of filteredItems; track item.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: item, level: 0 }\"></ng-container>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Recursive Template for Diff Items -->\n<ng-template #diffItem let-item=\"item\" let-level=\"level\">\n <div class=\"diff-item\" [class]=\"getTypeClass(item.type)\" [style.padding-left.px]=\"level * 24\">\n <div class=\"item-header\" (click)=\"toggleItem(item)\">\n @if (item.children.length > 0) {\n <i class=\"fa-solid fa-chevron-right expand-icon\" [class.expanded]=\"item.isExpanded\"></i>\n } @else {\n <span class=\"expand-spacer\"></span>\n }\n \n <i class=\"fa-solid type-icon\" [ngClass]=\"getIcon(item.type)\"></i>\n \n <span class=\"item-path\">{{ item.path }}</span>\n \n <span class=\"item-description\">{{ item.description }}</span>\n \n <button class=\"btn-copy\" (click)=\"copyToClipboard(item.path); $event.stopPropagation()\" title=\"Copy path\" aria-label=\"Copy path\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n\n <!-- Value Details -->\n @if (item.type === 'modified') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Old:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path + '_old') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path + '_old') || isExpanded(item.path + '_old')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_old', $event)\" \n title=\"{{ isExpanded(item.path + '_old') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_old') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_old') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n <div class=\"value-row new\">\n <span class=\"value-label\">New:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path + '_new') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path + '_new') || isExpanded(item.path + '_new')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_new', $event)\"\n title=\"{{ isExpanded(item.path + '_new') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_new') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_new') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'added') {\n <div class=\"value-details\">\n <div class=\"value-row new\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'removed') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Children -->\n @if (item.isExpanded && item.children.length > 0) {\n <div class=\"item-children\">\n @for (child of item.children; track child.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: child, level: level + 1 }\"></ng-container>\n }\n </div>\n }\n </div>\n</ng-template>"]}
|
|
1
|
+
{"version":3,"file":"deep-diff.component.js","sourceRoot":"","sources":["../../src/lib/deep-diff.component.ts","../../src/lib/deep-diff.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, OnInit, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';\nimport { DeepDiffer, DeepDiffResult, DiffChangeType, DiffChange } from '@memberjunction/global';\n\nexport interface DeepDiffItem extends DiffChange {\n level: number;\n isExpanded: boolean;\n children: DeepDiffItem[];\n parentPath: string;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-deep-diff',\n templateUrl: './deep-diff.component.html',\n styleUrls: ['./deep-diff.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class DeepDiffComponent implements OnInit {\n private _oldValue: any;\n private _newValue: any;\n private _showUnchanged: boolean = false;\n private _maxDepth: number = 10;\n private _maxStringLength: number = 100;\n private _treatNullAsUndefined: boolean = false;\n\n @Input()\n get oldValue(): any {\n return this._oldValue;\n }\n set oldValue(value: any) {\n this._oldValue = value;\n this.generateDiff();\n }\n\n @Input()\n get newValue(): any {\n return this._newValue;\n }\n set newValue(value: any) {\n this._newValue = value;\n this.generateDiff();\n }\n\n @Input()\n get showUnchanged(): boolean {\n return this._showUnchanged;\n }\n set showUnchanged(value: boolean) {\n this._showUnchanged = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input()\n get maxDepth(): number {\n return this._maxDepth;\n }\n set maxDepth(value: number) {\n this._maxDepth = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input()\n get maxStringLength(): number {\n return this._maxStringLength;\n }\n set maxStringLength(value: number) {\n this._maxStringLength = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input()\n get treatNullAsUndefined(): boolean {\n return this._treatNullAsUndefined;\n }\n set treatNullAsUndefined(value: boolean) {\n this._treatNullAsUndefined = value;\n this.updateDifferConfig();\n this.generateDiff();\n }\n\n @Input() title: string = 'Deep Diff Analysis';\n @Input() showSummary: boolean = true;\n @Input() expandAll: boolean = false;\n @Input() truncateValues: boolean = true;\n\n diffResult: DeepDiffResult | null = null;\n diffItems: DeepDiffItem[] = [];\n\n private _filter: string = '';\n get filter(): string {\n return this._filter;\n }\n set filter(value: string) {\n this._filter = value;\n this.recomputeFilteredItems();\n }\n\n private _filterType: 'all' | 'added' | 'removed' | 'modified' | 'unchanged' = 'all';\n get filterType(): 'all' | 'added' | 'removed' | 'modified' | 'unchanged' {\n return this._filterType;\n }\n set filterType(value: 'all' | 'added' | 'removed' | 'modified' | 'unchanged') {\n this._filterType = value;\n this.recomputeFilteredItems();\n }\n\n /**\n * Precomputed filtered diff tree. Recomputed only when the source data\n * (`diffItems`) or the filter inputs (`filter` / `filterType`) change —\n * never on every change-detection cycle. Bound directly by the template's\n * `@for` and empty-state length check, which preserves `@for` referential\n * stability between CD passes (the recursive walk no longer runs >= 2x/CD).\n */\n filteredItems: DeepDiffItem[] = [];\n\n expandedValuesMap: { [key: string]: boolean } = {};\n\n /**\n * Memoization cache for {@link formatValue} / {@link isValueTruncated}. Keyed\n * by `${path}|${expanded}` so the expensive `JSON.stringify` of object values\n * runs at most once per (path, expansion-state) instead of on every\n * change-detection cycle (the template binds these in a recursive `@for`).\n * Invalidated whenever the source data is regenerated.\n */\n private formatValueCache = new Map<string, string>();\n private truncatedCache = new Map<string, boolean>();\n\n private differ: DeepDiffer;\n\n constructor(private cdr: ChangeDetectorRef) {\n this.differ = new DeepDiffer({\n includeUnchanged: false,\n maxDepth: this.maxDepth,\n maxStringLength: this.maxStringLength,\n treatNullAsUndefined: this.treatNullAsUndefined\n });\n }\n\n ngOnInit(): void {\n this.generateDiff();\n }\n\n\n private updateDifferConfig(): void {\n this.differ.updateConfig({\n includeUnchanged: this.showUnchanged,\n maxDepth: this.maxDepth,\n maxStringLength: this.maxStringLength,\n treatNullAsUndefined: this.treatNullAsUndefined\n });\n }\n\n private generateDiff(): void {\n if (this.oldValue === undefined && this.newValue === undefined) {\n this.formatValueCache.clear();\n this.truncatedCache.clear();\n this.diffResult = null;\n this.diffItems = [];\n this.recomputeFilteredItems();\n return;\n }\n\n this.formatValueCache.clear();\n this.truncatedCache.clear();\n this.diffResult = this.differ.diff(this.oldValue, this.newValue);\n this.diffItems = this.buildHierarchicalItems(this.diffResult.changes);\n\n if (this.expandAll) {\n this.expandAllItems();\n }\n\n this.recomputeFilteredItems();\n }\n\n private buildHierarchicalItems(changes: DiffChange[]): DeepDiffItem[] {\n const rootItems: DeepDiffItem[] = [];\n const itemMap = new Map<string, DeepDiffItem>();\n\n // Sort by path to ensure parents come before children\n const sortedChanges = [...changes].sort((a, b) => {\n const aDepth = a.path.split('.').length;\n const bDepth = b.path.split('.').length;\n if (aDepth !== bDepth) return aDepth - bDepth;\n return a.path.localeCompare(b.path);\n });\n\n for (const change of sortedChanges) {\n const pathParts = change.path === 'root' ? [] : change.path.split('.');\n const level = pathParts.length;\n const parentPath = pathParts.slice(0, -1).join('.');\n \n const item: DeepDiffItem = {\n ...change,\n level,\n isExpanded: level === 0, // Expand only root level items by default\n children: [],\n parentPath\n };\n\n itemMap.set(change.path, item);\n\n if (parentPath && itemMap.has(parentPath)) {\n itemMap.get(parentPath)!.children.push(item);\n } else {\n rootItems.push(item);\n }\n }\n\n return rootItems;\n }\n\n toggleItem(item: DeepDiffItem): void {\n item.isExpanded = !item.isExpanded;\n this.cdr.markForCheck();\n }\n\n expandAllItems(): void {\n const expand = (items: DeepDiffItem[]) => {\n for (const item of items) {\n item.isExpanded = true;\n if (item.children.length > 0) {\n expand(item.children);\n }\n }\n };\n expand(this.diffItems);\n this.cdr.markForCheck();\n }\n\n collapseAllItems(): void {\n const collapse = (items: DeepDiffItem[]) => {\n for (const item of items) {\n item.isExpanded = false;\n if (item.children.length > 0) {\n collapse(item.children);\n }\n }\n };\n collapse(this.diffItems);\n this.cdr.markForCheck();\n }\n\n /**\n * Recomputes {@link filteredItems} from the current `diffItems` + filter\n * inputs. Called from `generateDiff()` (data change) and from the\n * `filter` / `filterType` setters (filter change) — NOT per CD cycle.\n */\n private recomputeFilteredItems(): void {\n if (!this.filter && this.filterType === 'all') {\n this.filteredItems = this.diffItems;\n this.cdr.markForCheck();\n return;\n }\n\n const filterFn = (item: DeepDiffItem): boolean => {\n const matchesType = this.filterType === 'all' || \n (this.filterType === 'added' && item.type === DiffChangeType.Added) ||\n (this.filterType === 'removed' && item.type === DiffChangeType.Removed) ||\n (this.filterType === 'modified' && item.type === DiffChangeType.Modified) ||\n (this.filterType === 'unchanged' && item.type === DiffChangeType.Unchanged);\n const matchesText = !this.filter || \n item.path.toLowerCase().includes(this.filter.toLowerCase()) ||\n item.description.toLowerCase().includes(this.filter.toLowerCase());\n \n return matchesType && matchesText;\n };\n\n const filterRecursive = (items: DeepDiffItem[]): DeepDiffItem[] => {\n return items.reduce((acc, item) => {\n const childMatches = filterRecursive(item.children);\n if (filterFn(item) || childMatches.length > 0) {\n acc.push({\n ...item,\n children: childMatches,\n isExpanded: item.isExpanded // Preserve the original expanded state\n });\n }\n return acc;\n }, [] as DeepDiffItem[]);\n };\n\n this.filteredItems = filterRecursive(this.diffItems);\n this.cdr.markForCheck();\n }\n\n getIcon(type: DiffChangeType): string {\n switch (type) {\n case DiffChangeType.Added: return 'fa-plus-circle';\n case DiffChangeType.Removed: return 'fa-minus-circle';\n case DiffChangeType.Modified: return 'fa-edit';\n case DiffChangeType.Unchanged: return 'fa-check-circle';\n default: return 'fa-question-circle';\n }\n }\n\n getTypeClass(type: DiffChangeType): string {\n switch (type) {\n case DiffChangeType.Added: return 'added';\n case DiffChangeType.Removed: return 'removed';\n case DiffChangeType.Modified: return 'modified';\n case DiffChangeType.Unchanged: return 'unchanged';\n default: return '';\n }\n }\n\n formatValue(value: any, path: string): string {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n\n const isExpanded = !!this.expandedValuesMap[path];\n const cacheKey = `${path}|${isExpanded ? 1 : 0}`;\n const cached = this.formatValueCache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n const formatted = this.computeFormattedValue(value, isExpanded);\n this.formatValueCache.set(cacheKey, formatted);\n return formatted;\n }\n\n private computeFormattedValue(value: any, isExpanded: boolean): string {\n const shouldTruncate = this.truncateValues && !isExpanded;\n\n if (typeof value === 'string') {\n if (shouldTruncate && value.length > this.maxStringLength) {\n return `\"${value.substring(0, this.maxStringLength)}...\"`;\n }\n return `\"${value}\"`;\n }\n \n if (typeof value === 'object') {\n try {\n const json = JSON.stringify(value, null, 2);\n if (shouldTruncate && json.length > 200) {\n // Show a preview for objects\n const preview = JSON.stringify(value).substring(0, 50);\n return `${preview}... (${this.getObjectSize(value)} properties)`;\n }\n return json;\n } catch {\n return String(value);\n }\n }\n \n return String(value);\n }\n \n isValueTruncated(value: any, path: string): boolean {\n if (!this.truncateValues || this.expandedValuesMap[path]) {\n return false;\n }\n\n const cacheKey = `${path}|0`;\n const cached = this.truncatedCache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n const result = this.computeValueTruncated(value);\n this.truncatedCache.set(cacheKey, result);\n return result;\n }\n\n private computeValueTruncated(value: any): boolean {\n if (typeof value === 'string') {\n return value.length > this.maxStringLength;\n }\n \n if (typeof value === 'object' && value !== null) {\n try {\n const json = JSON.stringify(value, null, 2);\n return json.length > 200;\n } catch {\n return false;\n }\n }\n \n return false;\n }\n \n toggleValueExpansion(path: string, event: Event): void {\n event.stopPropagation();\n \n // Create a new object to trigger change detection\n this.expandedValuesMap = {\n ...this.expandedValuesMap,\n [path]: !this.expandedValuesMap[path]\n };\n \n // Force change detection\n this.cdr.markForCheck();\n }\n \n private getObjectSize(obj: any): number {\n if (Array.isArray(obj)) {\n return obj.length;\n }\n return Object.keys(obj).length;\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard.writeText(text).then(() => {\n // Could add a toast notification here\n });\n }\n \n isExpanded(path: string): boolean {\n return !!this.expandedValuesMap[path];\n }\n \n copyValueToClipboard(value: any, event: Event): void {\n event.stopPropagation();\n let textToCopy: string;\n \n if (value === undefined) {\n textToCopy = 'undefined';\n } else if (value === null) {\n textToCopy = 'null';\n } else if (typeof value === 'object') {\n try {\n textToCopy = JSON.stringify(value, null, 2);\n } catch {\n textToCopy = String(value);\n }\n } else {\n textToCopy = String(value);\n }\n \n navigator.clipboard.writeText(textToCopy).then(() => {\n // Could add a toast notification here\n });\n }\n\n exportDiff(): void {\n if (!this.diffResult) return;\n \n const blob = new Blob([JSON.stringify(this.diffResult, null, 2)], \n { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `diff-${new Date().toISOString()}.json`;\n a.click();\n URL.revokeObjectURL(url);\n }\n}","<div class=\"deep-diff-container\">\n <!-- Header -->\n <div class=\"diff-header\">\n <div class=\"header-content\">\n <h2 class=\"diff-title\">\n <i class=\"fa-solid fa-code-branch\"></i>\n {{ title }}\n </h2>\n <div class=\"header-actions\">\n <button class=\"btn-icon\" (click)=\"expandAllItems()\" title=\"Expand All\" aria-label=\"Expand All\">\n <i class=\"fa-solid fa-expand\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"collapseAllItems()\" title=\"Collapse All\" aria-label=\"Collapse All\">\n <i class=\"fa-solid fa-compress\"></i>\n </button>\n <button class=\"btn-icon\" (click)=\"exportDiff()\" title=\"Export Diff\" aria-label=\"Export Diff\" [disabled]=\"!diffResult\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n </div>\n </div>\n\n <!-- Summary -->\n @if (showSummary && diffResult) {\n <div class=\"diff-summary\">\n <div class=\"summary-item added\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.added }}</span>\n <span class=\"label\">Added</span>\n </div>\n <div class=\"summary-item removed\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.removed }}</span>\n <span class=\"label\">Removed</span>\n </div>\n <div class=\"summary-item modified\">\n <i class=\"fa-solid fa-edit\"></i>\n <span class=\"count\">{{ diffResult.summary.modified }}</span>\n <span class=\"label\">Modified</span>\n </div>\n @if (showUnchanged) {\n <div class=\"summary-item unchanged\">\n <i class=\"fa-solid fa-check-circle\"></i>\n <span class=\"count\">{{ diffResult.summary.unchanged }}</span>\n <span class=\"label\">Unchanged</span>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Filters -->\n <div class=\"diff-filters\">\n <div class=\"filter-search\">\n <i class=\"fa-solid fa-search\"></i>\n <input \n type=\"text\" \n [(ngModel)]=\"filter\" \n placeholder=\"Filter by path or description...\"\n class=\"filter-input\">\n </div>\n <div class=\"filter-types\">\n <button \n class=\"filter-btn\"\n [class.active]=\"filterType === 'all'\"\n (click)=\"filterType = 'all'\">\n All Changes\n </button>\n <button \n class=\"filter-btn added\"\n [class.active]=\"filterType === 'added'\"\n (click)=\"filterType = 'added'\">\n <i class=\"fa-solid fa-plus-circle\"></i>\n Added\n </button>\n <button \n class=\"filter-btn removed\"\n [class.active]=\"filterType === 'removed'\"\n (click)=\"filterType = 'removed'\">\n <i class=\"fa-solid fa-minus-circle\"></i>\n Removed\n </button>\n <button \n class=\"filter-btn modified\"\n [class.active]=\"filterType === 'modified'\"\n (click)=\"filterType = 'modified'\">\n <i class=\"fa-solid fa-edit\"></i>\n Modified\n </button>\n </div>\n </div>\n\n <!-- Diff Content -->\n <div class=\"diff-content\">\n @if (!diffResult) {\n <mj-empty-state\n class=\"empty-state-fill\"\n Icon=\"fa-solid fa-code-compare\"\n Title=\"No data to compare\" />\n } @else if (filteredItems.length === 0) {\n <mj-empty-state\n class=\"empty-state-fill\"\n Variant=\"no-results\"\n Icon=\"fa-solid fa-filter\"\n Title=\"No changes match your filter criteria\" />\n } @else {\n <div class=\"diff-tree\">\n @for (item of filteredItems; track item.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: item, level: 0 }\"></ng-container>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Recursive Template for Diff Items -->\n<ng-template #diffItem let-item=\"item\" let-level=\"level\">\n <div class=\"diff-item\" [class]=\"getTypeClass(item.type)\" [style.padding-left.px]=\"level * 24\">\n <div class=\"item-header\" (click)=\"toggleItem(item)\">\n @if (item.children.length > 0) {\n <i class=\"fa-solid fa-chevron-right expand-icon\" [class.expanded]=\"item.isExpanded\"></i>\n } @else {\n <span class=\"expand-spacer\"></span>\n }\n \n <i class=\"fa-solid type-icon\" [ngClass]=\"getIcon(item.type)\"></i>\n \n <span class=\"item-path\">{{ item.path }}</span>\n \n <span class=\"item-description\">{{ item.description }}</span>\n \n <button class=\"btn-copy\" (click)=\"copyToClipboard(item.path); $event.stopPropagation()\" title=\"Copy path\" aria-label=\"Copy path\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n </div>\n\n <!-- Value Details -->\n @if (item.type === 'modified') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Old:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path + '_old') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path + '_old') || isExpanded(item.path + '_old')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_old', $event)\" \n title=\"{{ isExpanded(item.path + '_old') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_old') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_old') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n <div class=\"value-row new\">\n <span class=\"value-label\">New:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path + '_new') }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path + '_new') || isExpanded(item.path + '_new')) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path + '_new', $event)\"\n title=\"{{ isExpanded(item.path + '_new') ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path + '_new') ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path + '_new') ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'added') {\n <div class=\"value-details\">\n <div class=\"value-row new\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.newValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.newValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.newValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n } @else if (item.type === 'removed') {\n <div class=\"value-details\">\n <div class=\"value-row old\">\n <span class=\"value-label\">Value:</span>\n <code class=\"value-content\">{{ formatValue(item.oldValue, item.path) }}</code>\n <button class=\"btn-copy\" (click)=\"copyValueToClipboard(item.oldValue, $event)\" title=\"Copy value\" aria-label=\"Copy value\">\n <i class=\"fa-solid fa-copy\"></i>\n </button>\n @if (isValueTruncated(item.oldValue, item.path) || isExpanded(item.path)) {\n <button class=\"btn-expand-value\" \n (click)=\"toggleValueExpansion(item.path, $event)\"\n title=\"{{ isExpanded(item.path) ? 'Collapse' : 'Expand' }}\"\n [attr.aria-label]=\"isExpanded(item.path) ? 'Collapse value' : 'Expand value'\">\n <i class=\"fa-solid\" \n [ngClass]=\"isExpanded(item.path) ? 'fa-compress-alt' : 'fa-expand-alt'\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Children -->\n @if (item.isExpanded && item.children.length > 0) {\n <div class=\"item-children\">\n @for (child of item.children; track child.path) {\n <ng-container *ngTemplateOutlet=\"diffItem; context: { item: child, level: level + 1 }\"></ng-container>\n }\n </div>\n }\n </div>\n</ng-template>"]}
|
package/dist/lib/module.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ import * as i1 from "./deep-diff.component";
|
|
|
3
3
|
import * as i2 from "./deep-diff-dialog.component";
|
|
4
4
|
import * as i3 from "@angular/common";
|
|
5
5
|
import * as i4 from "@angular/forms";
|
|
6
|
+
import * as i5 from "@memberjunction/ng-ui-components";
|
|
6
7
|
export declare class DeepDiffModule {
|
|
7
8
|
static ɵfac: i0.ɵɵFactoryDeclaration<DeepDiffModule, never>;
|
|
8
|
-
static ɵmod: i0.ɵɵNgModuleDeclaration<DeepDiffModule, [typeof i1.DeepDiffComponent, typeof i2.DeepDiffDialogComponent], [typeof i3.CommonModule, typeof i4.FormsModule], [typeof i1.DeepDiffComponent, typeof i2.DeepDiffDialogComponent]>;
|
|
9
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<DeepDiffModule, [typeof i1.DeepDiffComponent, typeof i2.DeepDiffDialogComponent], [typeof i3.CommonModule, typeof i4.FormsModule, typeof i5.MJEmptyStateComponent], [typeof i1.DeepDiffComponent, typeof i2.DeepDiffDialogComponent]>;
|
|
9
10
|
static ɵinj: i0.ɵɵInjectorDeclaration<DeepDiffModule>;
|
|
10
11
|
}
|
|
11
12
|
//# sourceMappingURL=module.d.ts.map
|
package/dist/lib/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":";;;;;;AAQA,qBAea,cAAc;yCAAd,cAAc;0CAAd,cAAc;0CAAd,cAAc;CAAI"}
|
package/dist/lib/module.js
CHANGED
|
@@ -3,12 +3,14 @@ import { CommonModule } from '@angular/common';
|
|
|
3
3
|
import { FormsModule } from '@angular/forms';
|
|
4
4
|
import { DeepDiffDialogComponent } from './deep-diff-dialog.component';
|
|
5
5
|
import { DeepDiffComponent } from './deep-diff.component';
|
|
6
|
+
import { MJEmptyStateComponent } from '@memberjunction/ng-ui-components';
|
|
6
7
|
import * as i0 from "@angular/core";
|
|
7
8
|
export class DeepDiffModule {
|
|
8
9
|
static ɵfac = function DeepDiffModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DeepDiffModule)(); };
|
|
9
10
|
static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: DeepDiffModule });
|
|
10
11
|
static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
|
|
11
|
-
FormsModule
|
|
12
|
+
FormsModule,
|
|
13
|
+
MJEmptyStateComponent] });
|
|
12
14
|
}
|
|
13
15
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DeepDiffModule, [{
|
|
14
16
|
type: NgModule,
|
|
@@ -19,7 +21,8 @@ export class DeepDiffModule {
|
|
|
19
21
|
],
|
|
20
22
|
imports: [
|
|
21
23
|
CommonModule,
|
|
22
|
-
FormsModule
|
|
24
|
+
FormsModule,
|
|
25
|
+
MJEmptyStateComponent
|
|
23
26
|
],
|
|
24
27
|
exports: [
|
|
25
28
|
DeepDiffComponent,
|
|
@@ -29,6 +32,7 @@ export class DeepDiffModule {
|
|
|
29
32
|
}], null, null); })();
|
|
30
33
|
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(DeepDiffModule, { declarations: [DeepDiffComponent,
|
|
31
34
|
DeepDiffDialogComponent], imports: [CommonModule,
|
|
32
|
-
FormsModule
|
|
35
|
+
FormsModule,
|
|
36
|
+
MJEmptyStateComponent], exports: [DeepDiffComponent,
|
|
33
37
|
DeepDiffDialogComponent] }); })();
|
|
34
38
|
//# sourceMappingURL=module.js.map
|
package/dist/lib/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;;
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;;AAiBzE,MAAM,OAAO,cAAc;wGAAd,cAAc;4DAAd,cAAc;gEATvB,YAAY;YACZ,WAAW;YACX,qBAAqB;;iFAOZ,cAAc;cAf1B,QAAQ;eAAC;gBACR,YAAY,EAAE;oBACZ,iBAAiB;oBACjB,uBAAuB;iBACxB;gBACD,OAAO,EAAE;oBACP,YAAY;oBACZ,WAAW;oBACX,qBAAqB;iBACtB;gBACD,OAAO,EAAE;oBACP,iBAAiB;oBACjB,uBAAuB;iBACxB;aACF;;wFACY,cAAc,mBAbvB,iBAAiB;QACjB,uBAAuB,aAGvB,YAAY;QACZ,WAAW;QACX,qBAAqB,aAGrB,iBAAiB;QACjB,uBAAuB","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\n\nimport { DeepDiffDialogComponent } from './deep-diff-dialog.component';\nimport { DeepDiffComponent } from './deep-diff.component';\nimport { MJEmptyStateComponent } from '@memberjunction/ng-ui-components';\n\n@NgModule({\n declarations: [\n DeepDiffComponent,\n DeepDiffDialogComponent\n ],\n imports: [\n CommonModule,\n FormsModule,\n MJEmptyStateComponent\n ],\n exports: [\n DeepDiffComponent,\n DeepDiffDialogComponent\n ]\n})\nexport class DeepDiffModule { }"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-deep-diff",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.44.0",
|
|
4
4
|
"description": "MemberJunction: Generic Angular component to display the differences between two objects, using the non-visual functionality from the @memberjunction/global package",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@angular/compiler": "21.1.3",
|
|
20
20
|
"@angular/compiler-cli": "21.1.3",
|
|
21
|
+
"@memberjunction/ng-test-utils": "5.44.0",
|
|
21
22
|
"vitest": "^4.0.18"
|
|
22
23
|
},
|
|
23
24
|
"peerDependencies": {
|
|
@@ -25,9 +26,10 @@
|
|
|
25
26
|
"@angular/core": "21.1.3"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
29
|
+
"@memberjunction/ng-ui-components": "5.44.0",
|
|
28
30
|
"@angular/forms": "21.1.3",
|
|
29
|
-
"@memberjunction/core": "5.
|
|
30
|
-
"@memberjunction/global": "5.
|
|
31
|
+
"@memberjunction/core": "5.44.0",
|
|
32
|
+
"@memberjunction/global": "5.44.0",
|
|
31
33
|
"tslib": "^2.8.1"
|
|
32
34
|
},
|
|
33
35
|
"sideEffects": false,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exports.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/exports.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { existsSync } from 'fs';
|
|
3
|
-
import { resolve } from 'path';
|
|
4
|
-
describe('@memberjunction/ng-deep-diff', () => {
|
|
5
|
-
it('should have a public API entry point', () => {
|
|
6
|
-
const pkgRoot = resolve(__dirname, '../..');
|
|
7
|
-
const hasPublicApi = existsSync(resolve(pkgRoot, 'src/public-api.ts'));
|
|
8
|
-
const hasIndex = existsSync(resolve(pkgRoot, 'src/index.ts'));
|
|
9
|
-
expect(hasPublicApi || hasIndex).toBe(true);
|
|
10
|
-
});
|
|
11
|
-
it('should have a package.json with correct name', () => {
|
|
12
|
-
const pkgRoot = resolve(__dirname, '../..');
|
|
13
|
-
const pkg = require(resolve(pkgRoot, 'package.json'));
|
|
14
|
-
expect(pkg.name).toBe('@memberjunction/ng-deep-diff');
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
//# sourceMappingURL=exports.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exports.test.js","sourceRoot":"","sources":["../../src/__tests__/exports.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,YAAY,IAAI,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, it, expect } from 'vitest';\nimport { existsSync } from 'fs';\nimport { resolve } from 'path';\n\ndescribe('@memberjunction/ng-deep-diff', () => {\n it('should have a public API entry point', () => {\n const pkgRoot = resolve(__dirname, '../..');\n const hasPublicApi = existsSync(resolve(pkgRoot, 'src/public-api.ts'));\n const hasIndex = existsSync(resolve(pkgRoot, 'src/index.ts'));\n expect(hasPublicApi || hasIndex).toBe(true);\n });\n\n it('should have a package.json with correct name', () => {\n const pkgRoot = resolve(__dirname, '../..');\n const pkg = require(resolve(pkgRoot, 'package.json'));\n expect(pkg.name).toBe('@memberjunction/ng-deep-diff');\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, it, expect } from 'vitest';\n\ndescribe('@memberjunction/ng-deep-diff', () => {\n it('should have a passing test', () => {\n expect(true).toBe(true);\n });\n});\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deep-diff.component.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/deep-diff.component.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
-
/**
|
|
3
|
-
* Recompute-trigger coverage for the DeepDiffComponent precomputes (PR #2841):
|
|
4
|
-
*
|
|
5
|
-
* - `filteredItems`: a precomputed array (was a getter that re-walked the tree
|
|
6
|
-
* every CD pass). Must recompute on the `filter` / `filterType` setters AND on
|
|
7
|
-
* `generateDiff()` (data change via oldValue/newValue setters), and must match
|
|
8
|
-
* the naive filter the old getter produced.
|
|
9
|
-
*
|
|
10
|
-
* - `formatValue` / `isValueTruncated`: memoized by `${path}|${expanded}`. The
|
|
11
|
-
* cache must (a) hit on repeat calls, (b) be keyed by expansion state so an
|
|
12
|
-
* expand/collapse yields the correct (truncated vs full) value, and (c) be
|
|
13
|
-
* INVALIDATED when the source data regenerates — a stale cached value must not
|
|
14
|
-
* leak after new data lands.
|
|
15
|
-
*
|
|
16
|
-
* Uses the REAL DeepDiffer (`@memberjunction/global`); only Angular's decorator
|
|
17
|
-
* surface is stubbed so the component can be `new`'d in a node unit test.
|
|
18
|
-
*/
|
|
19
|
-
vi.mock('@angular/core', () => ({
|
|
20
|
-
Component: () => (t) => t,
|
|
21
|
-
Input: () => () => { },
|
|
22
|
-
Output: () => () => { },
|
|
23
|
-
EventEmitter: class {
|
|
24
|
-
emit() { }
|
|
25
|
-
},
|
|
26
|
-
ChangeDetectorRef: class {
|
|
27
|
-
detectChanges() { }
|
|
28
|
-
markForCheck() { }
|
|
29
|
-
},
|
|
30
|
-
ChangeDetectionStrategy: { OnPush: 1 },
|
|
31
|
-
OnInit: class {
|
|
32
|
-
},
|
|
33
|
-
}));
|
|
34
|
-
import { DeepDiffComponent } from '../deep-diff.component';
|
|
35
|
-
function makeComponent() {
|
|
36
|
-
const cdr = { detectChanges: vi.fn(), markForCheck: vi.fn() };
|
|
37
|
-
return new DeepDiffComponent(cdr);
|
|
38
|
-
}
|
|
39
|
-
/** Flatten the filtered tree to its paths (order-preserving) for stable assertions. */
|
|
40
|
-
function paths(items) {
|
|
41
|
-
const out = [];
|
|
42
|
-
const walk = (list) => {
|
|
43
|
-
for (const i of list) {
|
|
44
|
-
out.push(i.path);
|
|
45
|
-
walk(i.children);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
walk(items);
|
|
49
|
-
return out;
|
|
50
|
-
}
|
|
51
|
-
describe('DeepDiffComponent — filteredItems recompute', () => {
|
|
52
|
-
let component;
|
|
53
|
-
beforeEach(() => {
|
|
54
|
-
component = makeComponent();
|
|
55
|
-
// A representative object diff with several change types.
|
|
56
|
-
component.oldValue = { name: 'alpha', count: 1, removed: 'gone', nested: { keep: 1 } };
|
|
57
|
-
component.newValue = { name: 'beta', count: 1, added: 'fresh', nested: { keep: 1 } };
|
|
58
|
-
component.ngOnInit();
|
|
59
|
-
});
|
|
60
|
-
it('builds filteredItems on data change (generateDiff) — non-empty for a real diff', () => {
|
|
61
|
-
expect(component.diffItems.length).toBeGreaterThan(0);
|
|
62
|
-
// filter='' + type='all' → filteredItems is exactly diffItems (identity fast-path)
|
|
63
|
-
expect(component.filteredItems).toBe(component.diffItems);
|
|
64
|
-
});
|
|
65
|
-
it('recomputes filteredItems when the filterType setter changes', () => {
|
|
66
|
-
const before = component.filteredItems;
|
|
67
|
-
component.filterType = 'added';
|
|
68
|
-
const after = component.filteredItems;
|
|
69
|
-
expect(after).not.toBe(before);
|
|
70
|
-
// every surviving leaf (no children kept) should be an "added" path, and 'added' must appear
|
|
71
|
-
const ps = paths(after);
|
|
72
|
-
expect(ps.some((p) => p.includes('added'))).toBe(true);
|
|
73
|
-
expect(ps.some((p) => p.includes('removed'))).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
it('recomputes filteredItems when the text filter setter changes', () => {
|
|
76
|
-
component.filter = 'name';
|
|
77
|
-
const ps = paths(component.filteredItems);
|
|
78
|
-
expect(ps).toContain('name');
|
|
79
|
-
expect(ps).not.toContain('removed');
|
|
80
|
-
});
|
|
81
|
-
it('text filter is case-insensitive on path', () => {
|
|
82
|
-
component.filter = 'NAME';
|
|
83
|
-
expect(paths(component.filteredItems)).toContain('name');
|
|
84
|
-
});
|
|
85
|
-
it('reverts to the identity fast-path when filters are cleared', () => {
|
|
86
|
-
component.filter = 'name';
|
|
87
|
-
expect(component.filteredItems).not.toBe(component.diffItems);
|
|
88
|
-
component.filter = '';
|
|
89
|
-
component.filterType = 'all';
|
|
90
|
-
expect(component.filteredItems).toBe(component.diffItems);
|
|
91
|
-
});
|
|
92
|
-
it('matches the old getter baseline (naive recursive filter) under an active filter', () => {
|
|
93
|
-
component.filterType = 'modified';
|
|
94
|
-
// Baseline: keep an item if it is modified OR any descendant survives.
|
|
95
|
-
const baseline = (items) => items.reduce((acc, item) => {
|
|
96
|
-
const kids = baseline(item.children);
|
|
97
|
-
const isModified = String(item.type) === 'modified';
|
|
98
|
-
if (isModified || kids.length > 0)
|
|
99
|
-
acc.push({ ...item, children: kids });
|
|
100
|
-
return acc;
|
|
101
|
-
}, []);
|
|
102
|
-
expect(paths(component.filteredItems)).toEqual(paths(baseline(component.diffItems)));
|
|
103
|
-
});
|
|
104
|
-
it('re-derives filteredItems when new source data is set (regen trigger)', () => {
|
|
105
|
-
component.filterType = 'added';
|
|
106
|
-
const firstAddedPaths = paths(component.filteredItems);
|
|
107
|
-
// brand-new data with a DIFFERENT added key
|
|
108
|
-
component.oldValue = { x: 1 };
|
|
109
|
-
component.newValue = { x: 1, brandNew: 'v' };
|
|
110
|
-
// generateDiff ran via the setter; the active 'added' filter re-applied to NEW data
|
|
111
|
-
const secondAddedPaths = paths(component.filteredItems);
|
|
112
|
-
expect(secondAddedPaths).not.toEqual(firstAddedPaths);
|
|
113
|
-
expect(secondAddedPaths.some((p) => p.includes('brandNew'))).toBe(true);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
describe('DeepDiffComponent — formatValue / isValueTruncated memoization', () => {
|
|
117
|
-
let component;
|
|
118
|
-
beforeEach(() => {
|
|
119
|
-
component = makeComponent();
|
|
120
|
-
component.maxStringLength = 10;
|
|
121
|
-
component.truncateValues = true;
|
|
122
|
-
});
|
|
123
|
-
it('returns the same cached string on repeat formatValue calls for a (path, expanded) key', () => {
|
|
124
|
-
const longString = 'x'.repeat(50);
|
|
125
|
-
const first = component.formatValue(longString, 'a.b');
|
|
126
|
-
const second = component.formatValue(longString, 'a.b');
|
|
127
|
-
expect(first).toBe(second);
|
|
128
|
-
// truncated form (maxStringLength=10) ends with the ellipsis marker
|
|
129
|
-
expect(first.endsWith('..."')).toBe(true);
|
|
130
|
-
});
|
|
131
|
-
it('keys the cache by expansion state — expanded path yields the FULL value, collapsed the truncated one', () => {
|
|
132
|
-
const longString = 'y'.repeat(50);
|
|
133
|
-
// collapsed → truncated
|
|
134
|
-
const collapsed = component.formatValue(longString, 'p');
|
|
135
|
-
expect(collapsed.endsWith('..."')).toBe(true);
|
|
136
|
-
// expand that path, then re-format: must NOT serve the collapsed cache entry
|
|
137
|
-
component.toggleValueExpansion('p', { stopPropagation: vi.fn() });
|
|
138
|
-
const expanded = component.formatValue(longString, 'p');
|
|
139
|
-
expect(expanded).toBe(`"${longString}"`);
|
|
140
|
-
expect(expanded).not.toBe(collapsed);
|
|
141
|
-
});
|
|
142
|
-
it('isValueTruncated reports truncation for long strings and caches the result', () => {
|
|
143
|
-
const longString = 'z'.repeat(50);
|
|
144
|
-
expect(component.isValueTruncated(longString, 'q')).toBe(true);
|
|
145
|
-
// short string under the cap is not truncated
|
|
146
|
-
expect(component.isValueTruncated('short', 'r')).toBe(false);
|
|
147
|
-
});
|
|
148
|
-
it('isValueTruncated returns false once the path is expanded', () => {
|
|
149
|
-
const longString = 'w'.repeat(50);
|
|
150
|
-
expect(component.isValueTruncated(longString, 's')).toBe(true);
|
|
151
|
-
component.toggleValueExpansion('s', { stopPropagation: vi.fn() });
|
|
152
|
-
expect(component.isValueTruncated(longString, 's')).toBe(false);
|
|
153
|
-
});
|
|
154
|
-
it('does NOT leak a stale cached value after the source data regenerates', () => {
|
|
155
|
-
// Prime the cache for path 'root' under the first dataset.
|
|
156
|
-
component.oldValue = { root: 'a'.repeat(50) };
|
|
157
|
-
component.newValue = { root: 'a'.repeat(50) };
|
|
158
|
-
component.ngOnInit();
|
|
159
|
-
const firstFormatted = component.formatValue('a'.repeat(50), 'root');
|
|
160
|
-
expect(firstFormatted.endsWith('..."')).toBe(true);
|
|
161
|
-
// Regenerate with a DIFFERENT value at the same path. generateDiff clears the
|
|
162
|
-
// memo caches, so formatting 'root' again must reflect the NEW value, not the
|
|
163
|
-
// stale cached string.
|
|
164
|
-
const newVal = 'b'.repeat(50);
|
|
165
|
-
component.oldValue = { root: newVal };
|
|
166
|
-
component.newValue = { root: 'changed-' + newVal };
|
|
167
|
-
const afterRegen = component.formatValue('changed-' + newVal, 'root');
|
|
168
|
-
expect(afterRegen).toContain('changed-');
|
|
169
|
-
expect(afterRegen).not.toBe(firstFormatted);
|
|
170
|
-
});
|
|
171
|
-
it('caches object formatting (computeFormattedValue runs once per (path, expanded))', () => {
|
|
172
|
-
const obj = { a: 1, b: 2, c: 3, d: 'x'.repeat(300) };
|
|
173
|
-
const first = component.formatValue(obj, 'obj');
|
|
174
|
-
const second = component.formatValue(obj, 'obj');
|
|
175
|
-
expect(second).toBe(first);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
//# sourceMappingURL=deep-diff.component.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deep-diff.component.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/deep-diff.component.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, beforeEach, vi } from 'vitest';\n\n/**\n * Recompute-trigger coverage for the DeepDiffComponent precomputes (PR #2841):\n *\n * - `filteredItems`: a precomputed array (was a getter that re-walked the tree\n * every CD pass). Must recompute on the `filter` / `filterType` setters AND on\n * `generateDiff()` (data change via oldValue/newValue setters), and must match\n * the naive filter the old getter produced.\n *\n * - `formatValue` / `isValueTruncated`: memoized by `${path}|${expanded}`. The\n * cache must (a) hit on repeat calls, (b) be keyed by expansion state so an\n * expand/collapse yields the correct (truncated vs full) value, and (c) be\n * INVALIDATED when the source data regenerates — a stale cached value must not\n * leak after new data lands.\n *\n * Uses the REAL DeepDiffer (`@memberjunction/global`); only Angular's decorator\n * surface is stubbed so the component can be `new`'d in a node unit test.\n */\n\nvi.mock('@angular/core', () => ({\n Component: () => (t: Function) => t,\n Input: () => () => {},\n Output: () => () => {},\n EventEmitter: class { emit() {} },\n ChangeDetectorRef: class { detectChanges() {} markForCheck() {} },\n ChangeDetectionStrategy: { OnPush: 1 },\n OnInit: class {},\n}));\n\nimport { DeepDiffComponent, DeepDiffItem } from '../deep-diff.component';\nimport { ChangeDetectorRef } from '@angular/core';\n\nfunction makeComponent(): DeepDiffComponent {\n const cdr = { detectChanges: vi.fn(), markForCheck: vi.fn() } as unknown as ChangeDetectorRef;\n return new DeepDiffComponent(cdr);\n}\n\n/** Flatten the filtered tree to its paths (order-preserving) for stable assertions. */\nfunction paths(items: DeepDiffItem[]): string[] {\n const out: string[] = [];\n const walk = (list: DeepDiffItem[]) => {\n for (const i of list) {\n out.push(i.path);\n walk(i.children);\n }\n };\n walk(items);\n return out;\n}\n\ndescribe('DeepDiffComponent — filteredItems recompute', () => {\n let component: DeepDiffComponent;\n\n beforeEach(() => {\n component = makeComponent();\n // A representative object diff with several change types.\n component.oldValue = { name: 'alpha', count: 1, removed: 'gone', nested: { keep: 1 } };\n component.newValue = { name: 'beta', count: 1, added: 'fresh', nested: { keep: 1 } };\n component.ngOnInit();\n });\n\n it('builds filteredItems on data change (generateDiff) — non-empty for a real diff', () => {\n expect(component.diffItems.length).toBeGreaterThan(0);\n // filter='' + type='all' → filteredItems is exactly diffItems (identity fast-path)\n expect(component.filteredItems).toBe(component.diffItems);\n });\n\n it('recomputes filteredItems when the filterType setter changes', () => {\n const before = component.filteredItems;\n component.filterType = 'added';\n const after = component.filteredItems;\n expect(after).not.toBe(before);\n // every surviving leaf (no children kept) should be an \"added\" path, and 'added' must appear\n const ps = paths(after);\n expect(ps.some((p) => p.includes('added'))).toBe(true);\n expect(ps.some((p) => p.includes('removed'))).toBe(false);\n });\n\n it('recomputes filteredItems when the text filter setter changes', () => {\n component.filter = 'name';\n const ps = paths(component.filteredItems);\n expect(ps).toContain('name');\n expect(ps).not.toContain('removed');\n });\n\n it('text filter is case-insensitive on path', () => {\n component.filter = 'NAME';\n expect(paths(component.filteredItems)).toContain('name');\n });\n\n it('reverts to the identity fast-path when filters are cleared', () => {\n component.filter = 'name';\n expect(component.filteredItems).not.toBe(component.diffItems);\n component.filter = '';\n component.filterType = 'all';\n expect(component.filteredItems).toBe(component.diffItems);\n });\n\n it('matches the old getter baseline (naive recursive filter) under an active filter', () => {\n component.filterType = 'modified';\n // Baseline: keep an item if it is modified OR any descendant survives.\n const baseline = (items: DeepDiffItem[]): DeepDiffItem[] =>\n items.reduce<DeepDiffItem[]>((acc, item) => {\n const kids = baseline(item.children);\n const isModified = String(item.type) === 'modified';\n if (isModified || kids.length > 0) acc.push({ ...item, children: kids });\n return acc;\n }, []);\n expect(paths(component.filteredItems)).toEqual(paths(baseline(component.diffItems)));\n });\n\n it('re-derives filteredItems when new source data is set (regen trigger)', () => {\n component.filterType = 'added';\n const firstAddedPaths = paths(component.filteredItems);\n\n // brand-new data with a DIFFERENT added key\n component.oldValue = { x: 1 };\n component.newValue = { x: 1, brandNew: 'v' };\n // generateDiff ran via the setter; the active 'added' filter re-applied to NEW data\n const secondAddedPaths = paths(component.filteredItems);\n expect(secondAddedPaths).not.toEqual(firstAddedPaths);\n expect(secondAddedPaths.some((p) => p.includes('brandNew'))).toBe(true);\n });\n});\n\ndescribe('DeepDiffComponent — formatValue / isValueTruncated memoization', () => {\n let component: DeepDiffComponent;\n\n beforeEach(() => {\n component = makeComponent();\n component.maxStringLength = 10;\n component.truncateValues = true;\n });\n\n it('returns the same cached string on repeat formatValue calls for a (path, expanded) key', () => {\n const longString = 'x'.repeat(50);\n const first = component.formatValue(longString, 'a.b');\n const second = component.formatValue(longString, 'a.b');\n expect(first).toBe(second);\n // truncated form (maxStringLength=10) ends with the ellipsis marker\n expect(first.endsWith('...\"')).toBe(true);\n });\n\n it('keys the cache by expansion state — expanded path yields the FULL value, collapsed the truncated one', () => {\n const longString = 'y'.repeat(50);\n // collapsed → truncated\n const collapsed = component.formatValue(longString, 'p');\n expect(collapsed.endsWith('...\"')).toBe(true);\n\n // expand that path, then re-format: must NOT serve the collapsed cache entry\n component.toggleValueExpansion('p', { stopPropagation: vi.fn() } as unknown as Event);\n const expanded = component.formatValue(longString, 'p');\n expect(expanded).toBe(`\"${longString}\"`);\n expect(expanded).not.toBe(collapsed);\n });\n\n it('isValueTruncated reports truncation for long strings and caches the result', () => {\n const longString = 'z'.repeat(50);\n expect(component.isValueTruncated(longString, 'q')).toBe(true);\n // short string under the cap is not truncated\n expect(component.isValueTruncated('short', 'r')).toBe(false);\n });\n\n it('isValueTruncated returns false once the path is expanded', () => {\n const longString = 'w'.repeat(50);\n expect(component.isValueTruncated(longString, 's')).toBe(true);\n component.toggleValueExpansion('s', { stopPropagation: vi.fn() } as unknown as Event);\n expect(component.isValueTruncated(longString, 's')).toBe(false);\n });\n\n it('does NOT leak a stale cached value after the source data regenerates', () => {\n // Prime the cache for path 'root' under the first dataset.\n component.oldValue = { root: 'a'.repeat(50) };\n component.newValue = { root: 'a'.repeat(50) };\n component.ngOnInit();\n const firstFormatted = component.formatValue('a'.repeat(50), 'root');\n expect(firstFormatted.endsWith('...\"')).toBe(true);\n\n // Regenerate with a DIFFERENT value at the same path. generateDiff clears the\n // memo caches, so formatting 'root' again must reflect the NEW value, not the\n // stale cached string.\n const newVal = 'b'.repeat(50);\n component.oldValue = { root: newVal };\n component.newValue = { root: 'changed-' + newVal };\n const afterRegen = component.formatValue('changed-' + newVal, 'root');\n expect(afterRegen).toContain('changed-');\n expect(afterRegen).not.toBe(firstFormatted);\n });\n\n it('caches object formatting (computeFormattedValue runs once per (path, expanded))', () => {\n const obj = { a: 1, b: 2, c: 3, d: 'x'.repeat(300) };\n const first = component.formatValue(obj, 'obj');\n const second = component.formatValue(obj, 'obj');\n expect(second).toBe(first);\n });\n});\n"]}
|