@memberjunction/ng-entity-viewer 3.2.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +118 -0
  2. package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -0
  3. package/dist/lib/aggregate-panel/aggregate-panel.component.js +366 -0
  4. package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -0
  5. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts +196 -0
  6. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts.map +1 -0
  7. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js +948 -0
  8. package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js.map +1 -0
  9. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +134 -8
  10. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
  11. package/dist/lib/entity-data-grid/entity-data-grid.component.js +769 -150
  12. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
  13. package/dist/lib/entity-data-grid/models/grid-types.d.ts +15 -1
  14. package/dist/lib/entity-data-grid/models/grid-types.d.ts.map +1 -1
  15. package/dist/lib/entity-data-grid/models/grid-types.js.map +1 -1
  16. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +12 -3
  17. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  18. package/dist/lib/entity-viewer/entity-viewer.component.js +29 -4
  19. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  20. package/dist/lib/types.d.ts +9 -21
  21. package/dist/lib/types.d.ts.map +1 -1
  22. package/dist/lib/types.js.map +1 -1
  23. package/dist/lib/view-config-panel/view-config-panel.component.d.ts +71 -3
  24. package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -1
  25. package/dist/lib/view-config-panel/view-config-panel.component.js +726 -320
  26. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
  27. package/dist/module.d.ts +9 -7
  28. package/dist/module.d.ts.map +1 -1
  29. package/dist/module.js +14 -4
  30. package/dist/module.js.map +1 -1
  31. package/dist/public-api.d.ts +2 -0
  32. package/dist/public-api.d.ts.map +1 -1
  33. package/dist/public-api.js +4 -0
  34. package/dist/public-api.js.map +1 -1
  35. package/package.json +9 -9
@@ -17,19 +17,19 @@ import * as i4 from "@memberjunction/ng-shared-generic";
17
17
  const _c0 = ["gridContainer"];
18
18
  function EntityDataGridComponent_div_2_div_2_button_3_Template(rf, ctx) { if (rf & 1) {
19
19
  const _r4 = i0.ɵɵgetCurrentView();
20
- i0.ɵɵelementStart(0, "button", 36);
20
+ i0.ɵɵelementStart(0, "button", 38);
21
21
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_div_2_button_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.FilterText = ""); });
22
- i0.ɵɵelement(1, "i", 37);
22
+ i0.ɵɵelement(1, "i", 39);
23
23
  i0.ɵɵelementEnd();
24
24
  } }
25
25
  function EntityDataGridComponent_div_2_div_2_Template(rf, ctx) { if (rf & 1) {
26
26
  const _r2 = i0.ɵɵgetCurrentView();
27
- i0.ɵɵelementStart(0, "div", 32);
28
- i0.ɵɵelement(1, "i", 33);
29
- i0.ɵɵelementStart(2, "input", 34);
27
+ i0.ɵɵelementStart(0, "div", 34);
28
+ i0.ɵɵelement(1, "i", 35);
29
+ i0.ɵɵelementStart(2, "input", 36);
30
30
  i0.ɵɵlistener("input", function EntityDataGridComponent_div_2_div_2_Template_input_input_2_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.FilterText = $event.target.value); });
31
31
  i0.ɵɵelementEnd();
32
- i0.ɵɵtemplate(3, EntityDataGridComponent_div_2_div_2_button_3_Template, 2, 0, "button", 35);
32
+ i0.ɵɵtemplate(3, EntityDataGridComponent_div_2_div_2_button_3_Template, 2, 0, "button", 37);
33
33
  i0.ɵɵelementEnd();
34
34
  } if (rf & 2) {
35
35
  const ctx_r2 = i0.ɵɵnextContext(2);
@@ -55,9 +55,9 @@ function EntityDataGridComponent_div_2_ng_container_3_button_1_span_2_Template(r
55
55
  } }
56
56
  function EntityDataGridComponent_div_2_ng_container_3_button_1_Template(rf, ctx) { if (rf & 1) {
57
57
  const _r5 = i0.ɵɵgetCurrentView();
58
- i0.ɵɵelementStart(0, "button", 39);
58
+ i0.ɵɵelementStart(0, "button", 41);
59
59
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_ng_container_3_button_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const button_r6 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onToolbarButtonClick(button_r6)); });
60
- i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_3_button_1_i_1_Template, 1, 2, "i", 40)(2, EntityDataGridComponent_div_2_ng_container_3_button_1_span_2_Template, 2, 1, "span", 41);
60
+ i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_3_button_1_i_1_Template, 1, 2, "i", 42)(2, EntityDataGridComponent_div_2_ng_container_3_button_1_span_2_Template, 2, 1, "span", 43);
61
61
  i0.ɵɵelementEnd();
62
62
  } if (rf & 2) {
63
63
  const button_r6 = i0.ɵɵnextContext().$implicit;
@@ -71,7 +71,7 @@ function EntityDataGridComponent_div_2_ng_container_3_button_1_Template(rf, ctx)
71
71
  } }
72
72
  function EntityDataGridComponent_div_2_ng_container_3_Template(rf, ctx) { if (rf & 1) {
73
73
  i0.ɵɵelementContainerStart(0);
74
- i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_3_button_1_Template, 3, 6, "button", 38);
74
+ i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_3_button_1_Template, 3, 6, "button", 40);
75
75
  i0.ɵɵelementContainerEnd();
76
76
  } if (rf & 2) {
77
77
  const button_r6 = ctx.$implicit;
@@ -80,7 +80,7 @@ function EntityDataGridComponent_div_2_ng_container_3_Template(rf, ctx) { if (rf
80
80
  i0.ɵɵproperty("ngIf", button_r6.position !== "right" && ctx_r2.isButtonVisible(button_r6));
81
81
  } }
82
82
  function EntityDataGridComponent_div_2_span_5_Template(rf, ctx) { if (rf & 1) {
83
- i0.ɵɵelementStart(0, "span", 42);
83
+ i0.ɵɵelementStart(0, "span", 44);
84
84
  i0.ɵɵtext(1);
85
85
  i0.ɵɵelementEnd();
86
86
  } if (rf & 2) {
@@ -89,7 +89,7 @@ function EntityDataGridComponent_div_2_span_5_Template(rf, ctx) { if (rf & 1) {
89
89
  i0.ɵɵtextInterpolate2(" ", ctx_r2.totalRowCount, " ", ctx_r2.totalRowCount === 1 ? "row" : "rows", " ");
90
90
  } }
91
91
  function EntityDataGridComponent_div_2_span_6_Template(rf, ctx) { if (rf & 1) {
92
- i0.ɵɵelementStart(0, "span", 43);
92
+ i0.ɵɵelementStart(0, "span", 45);
93
93
  i0.ɵɵtext(1);
94
94
  i0.ɵɵelementEnd();
95
95
  } if (rf & 2) {
@@ -99,19 +99,19 @@ function EntityDataGridComponent_div_2_span_6_Template(rf, ctx) { if (rf & 1) {
99
99
  } }
100
100
  function EntityDataGridComponent_div_2_button_8_Template(rf, ctx) { if (rf & 1) {
101
101
  const _r7 = i0.ɵɵgetCurrentView();
102
- i0.ɵɵelementStart(0, "button", 44);
102
+ i0.ɵɵelementStart(0, "button", 46);
103
103
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onAddClick()); });
104
- i0.ɵɵelement(1, "i", 45);
105
- i0.ɵɵelementStart(2, "span", 46);
104
+ i0.ɵɵelement(1, "i", 47);
105
+ i0.ɵɵelementStart(2, "span", 48);
106
106
  i0.ɵɵtext(3, "New");
107
107
  i0.ɵɵelementEnd()();
108
108
  } }
109
109
  function EntityDataGridComponent_div_2_button_9_Template(rf, ctx) { if (rf & 1) {
110
110
  const _r8 = i0.ɵɵgetCurrentView();
111
- i0.ɵɵelementStart(0, "button", 47);
111
+ i0.ɵɵelementStart(0, "button", 49);
112
112
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_9_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onRefreshClick()); });
113
- i0.ɵɵelement(1, "i", 48);
114
- i0.ɵɵelementStart(2, "span", 46);
113
+ i0.ɵɵelement(1, "i", 50);
114
+ i0.ɵɵelementStart(2, "span", 48);
115
115
  i0.ɵɵtext(3, "Refresh");
116
116
  i0.ɵɵelementEnd()();
117
117
  } if (rf & 2) {
@@ -122,28 +122,28 @@ function EntityDataGridComponent_div_2_button_9_Template(rf, ctx) { if (rf & 1)
122
122
  } }
123
123
  function EntityDataGridComponent_div_2_button_10_Template(rf, ctx) { if (rf & 1) {
124
124
  const _r9 = i0.ɵɵgetCurrentView();
125
- i0.ɵɵelementStart(0, "button", 49);
125
+ i0.ɵɵelementStart(0, "button", 51);
126
126
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onExportClick()); });
127
- i0.ɵɵelement(1, "i", 50);
128
- i0.ɵɵelementStart(2, "span", 46);
127
+ i0.ɵɵelement(1, "i", 52);
128
+ i0.ɵɵelementStart(2, "span", 48);
129
129
  i0.ɵɵtext(3, "Export");
130
130
  i0.ɵɵelementEnd()();
131
131
  } }
132
132
  function EntityDataGridComponent_div_2_button_11_Template(rf, ctx) { if (rf & 1) {
133
133
  const _r10 = i0.ɵɵgetCurrentView();
134
- i0.ɵɵelementStart(0, "button", 51);
134
+ i0.ɵɵelementStart(0, "button", 53);
135
135
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_11_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onDeleteClick()); });
136
- i0.ɵɵelement(1, "i", 52);
137
- i0.ɵɵelementStart(2, "span", 46);
136
+ i0.ɵɵelement(1, "i", 54);
137
+ i0.ɵɵelementStart(2, "span", 48);
138
138
  i0.ɵɵtext(3, "Delete");
139
139
  i0.ɵɵelementEnd()();
140
140
  } }
141
141
  function EntityDataGridComponent_div_2_button_12_Template(rf, ctx) { if (rf & 1) {
142
142
  const _r11 = i0.ɵɵgetCurrentView();
143
- i0.ɵɵelementStart(0, "button", 53);
143
+ i0.ɵɵelementStart(0, "button", 55);
144
144
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onCompareClick()); });
145
- i0.ɵɵelement(1, "i", 54);
146
- i0.ɵɵelementStart(2, "span", 46);
145
+ i0.ɵɵelement(1, "i", 56);
146
+ i0.ɵɵelementStart(2, "span", 48);
147
147
  i0.ɵɵtext(3, "Compare");
148
148
  i0.ɵɵelementEnd()();
149
149
  } if (rf & 2) {
@@ -152,10 +152,10 @@ function EntityDataGridComponent_div_2_button_12_Template(rf, ctx) { if (rf & 1)
152
152
  } }
153
153
  function EntityDataGridComponent_div_2_button_13_Template(rf, ctx) { if (rf & 1) {
154
154
  const _r12 = i0.ɵɵgetCurrentView();
155
- i0.ɵɵelementStart(0, "button", 55);
155
+ i0.ɵɵelementStart(0, "button", 57);
156
156
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_13_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r12); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onMergeClick()); });
157
- i0.ɵɵelement(1, "i", 56);
158
- i0.ɵɵelementStart(2, "span", 46);
157
+ i0.ɵɵelement(1, "i", 58);
158
+ i0.ɵɵelementStart(2, "span", 48);
159
159
  i0.ɵɵtext(3, "Merge");
160
160
  i0.ɵɵelementEnd()();
161
161
  } if (rf & 2) {
@@ -164,10 +164,10 @@ function EntityDataGridComponent_div_2_button_13_Template(rf, ctx) { if (rf & 1)
164
164
  } }
165
165
  function EntityDataGridComponent_div_2_button_14_Template(rf, ctx) { if (rf & 1) {
166
166
  const _r13 = i0.ɵɵgetCurrentView();
167
- i0.ɵɵelementStart(0, "button", 57);
167
+ i0.ɵɵelementStart(0, "button", 59);
168
168
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onAddToListClick()); });
169
- i0.ɵɵelement(1, "i", 58);
170
- i0.ɵɵelementStart(2, "span", 46);
169
+ i0.ɵɵelement(1, "i", 60);
170
+ i0.ɵɵelementStart(2, "span", 48);
171
171
  i0.ɵɵtext(3, "Add to List");
172
172
  i0.ɵɵelementEnd()();
173
173
  } if (rf & 2) {
@@ -176,10 +176,10 @@ function EntityDataGridComponent_div_2_button_14_Template(rf, ctx) { if (rf & 1)
176
176
  } }
177
177
  function EntityDataGridComponent_div_2_button_15_Template(rf, ctx) { if (rf & 1) {
178
178
  const _r14 = i0.ɵɵgetCurrentView();
179
- i0.ɵɵelementStart(0, "button", 59);
179
+ i0.ɵɵelementStart(0, "button", 61);
180
180
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_15_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onDuplicateSearchClick()); });
181
- i0.ɵɵelement(1, "i", 60);
182
- i0.ɵɵelementStart(2, "span", 46);
181
+ i0.ɵɵelement(1, "i", 62);
182
+ i0.ɵɵelementStart(2, "span", 48);
183
183
  i0.ɵɵtext(3, "Find Duplicates");
184
184
  i0.ɵɵelementEnd()();
185
185
  } if (rf & 2) {
@@ -188,10 +188,10 @@ function EntityDataGridComponent_div_2_button_15_Template(rf, ctx) { if (rf & 1)
188
188
  } }
189
189
  function EntityDataGridComponent_div_2_button_16_Template(rf, ctx) { if (rf & 1) {
190
190
  const _r15 = i0.ɵɵgetCurrentView();
191
- i0.ɵɵelementStart(0, "button", 61);
191
+ i0.ɵɵelementStart(0, "button", 63);
192
192
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_16_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r15); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onCommunicationClick()); });
193
- i0.ɵɵelement(1, "i", 62);
194
- i0.ɵɵelementStart(2, "span", 46);
193
+ i0.ɵɵelement(1, "i", 64);
194
+ i0.ɵɵelementStart(2, "span", 48);
195
195
  i0.ɵɵtext(3, "Send Message");
196
196
  i0.ɵɵelementEnd()();
197
197
  } if (rf & 2) {
@@ -200,16 +200,16 @@ function EntityDataGridComponent_div_2_button_16_Template(rf, ctx) { if (rf & 1)
200
200
  } }
201
201
  function EntityDataGridComponent_div_2_button_17_Template(rf, ctx) { if (rf & 1) {
202
202
  const _r16 = i0.ɵɵgetCurrentView();
203
- i0.ɵɵelementStart(0, "button", 63);
203
+ i0.ɵɵelementStart(0, "button", 65);
204
204
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_17_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r16); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onAddClick()); });
205
- i0.ɵɵelement(1, "i", 45);
205
+ i0.ɵɵelement(1, "i", 47);
206
206
  i0.ɵɵelementEnd();
207
207
  } }
208
208
  function EntityDataGridComponent_div_2_button_18_Template(rf, ctx) { if (rf & 1) {
209
209
  const _r17 = i0.ɵɵgetCurrentView();
210
- i0.ɵɵelementStart(0, "button", 64);
210
+ i0.ɵɵelementStart(0, "button", 66);
211
211
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_18_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onRefreshClick()); });
212
- i0.ɵɵelement(1, "i", 65);
212
+ i0.ɵɵelement(1, "i", 67);
213
213
  i0.ɵɵelementEnd();
214
214
  } if (rf & 2) {
215
215
  const ctx_r2 = i0.ɵɵnextContext(2);
@@ -219,23 +219,23 @@ function EntityDataGridComponent_div_2_button_18_Template(rf, ctx) { if (rf & 1)
219
219
  } }
220
220
  function EntityDataGridComponent_div_2_button_19_Template(rf, ctx) { if (rf & 1) {
221
221
  const _r18 = i0.ɵɵgetCurrentView();
222
- i0.ɵɵelementStart(0, "button", 66);
222
+ i0.ɵɵelementStart(0, "button", 68);
223
223
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_19_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r18); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onDeleteClick()); });
224
- i0.ɵɵelement(1, "i", 52);
224
+ i0.ɵɵelement(1, "i", 54);
225
225
  i0.ɵɵelementEnd();
226
226
  } }
227
227
  function EntityDataGridComponent_div_2_button_20_Template(rf, ctx) { if (rf & 1) {
228
228
  const _r19 = i0.ɵɵgetCurrentView();
229
- i0.ɵɵelementStart(0, "button", 67);
229
+ i0.ɵɵelementStart(0, "button", 69);
230
230
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_20_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r19); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onExportClick()); });
231
- i0.ɵɵelement(1, "i", 68);
231
+ i0.ɵɵelement(1, "i", 70);
232
232
  i0.ɵɵelementEnd();
233
233
  } }
234
234
  function EntityDataGridComponent_div_2_button_21_Template(rf, ctx) { if (rf & 1) {
235
235
  const _r20 = i0.ɵɵgetCurrentView();
236
- i0.ɵɵelementStart(0, "button", 69);
236
+ i0.ɵɵelementStart(0, "button", 71);
237
237
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_button_21_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r20); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onColumnChooserClick()); });
238
- i0.ɵɵelement(1, "i", 70);
238
+ i0.ɵɵelement(1, "i", 72);
239
239
  i0.ɵɵelementEnd();
240
240
  } }
241
241
  function EntityDataGridComponent_div_2_ng_container_22_button_1_i_1_Template(rf, ctx) { if (rf & 1) {
@@ -255,9 +255,9 @@ function EntityDataGridComponent_div_2_ng_container_22_button_1_span_2_Template(
255
255
  } }
256
256
  function EntityDataGridComponent_div_2_ng_container_22_button_1_Template(rf, ctx) { if (rf & 1) {
257
257
  const _r21 = i0.ɵɵgetCurrentView();
258
- i0.ɵɵelementStart(0, "button", 39);
258
+ i0.ɵɵelementStart(0, "button", 41);
259
259
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_ng_container_22_button_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r21); const button_r22 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onToolbarButtonClick(button_r22)); });
260
- i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_22_button_1_i_1_Template, 1, 2, "i", 40)(2, EntityDataGridComponent_div_2_ng_container_22_button_1_span_2_Template, 2, 1, "span", 41);
260
+ i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_22_button_1_i_1_Template, 1, 2, "i", 42)(2, EntityDataGridComponent_div_2_ng_container_22_button_1_span_2_Template, 2, 1, "span", 43);
261
261
  i0.ɵɵelementEnd();
262
262
  } if (rf & 2) {
263
263
  const button_r22 = i0.ɵɵnextContext().$implicit;
@@ -271,7 +271,7 @@ function EntityDataGridComponent_div_2_ng_container_22_button_1_Template(rf, ctx
271
271
  } }
272
272
  function EntityDataGridComponent_div_2_ng_container_22_Template(rf, ctx) { if (rf & 1) {
273
273
  i0.ɵɵelementContainerStart(0);
274
- i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_22_button_1_Template, 3, 6, "button", 38);
274
+ i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_ng_container_22_button_1_Template, 3, 6, "button", 40);
275
275
  i0.ɵɵelementContainerEnd();
276
276
  } if (rf & 2) {
277
277
  const button_r22 = ctx.$implicit;
@@ -281,16 +281,16 @@ function EntityDataGridComponent_div_2_ng_container_22_Template(rf, ctx) { if (r
281
281
  } }
282
282
  function EntityDataGridComponent_div_2_div_23_div_3_button_1_Template(rf, ctx) { if (rf & 1) {
283
283
  const _r24 = i0.ɵɵgetCurrentView();
284
- i0.ɵɵelementStart(0, "button", 78);
284
+ i0.ɵɵelementStart(0, "button", 80);
285
285
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_div_23_div_3_button_1_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r24); const ctx_r2 = i0.ɵɵnextContext(4); ctx_r2.onExportClick(); return i0.ɵɵresetView(ctx_r2.closeOverflowMenu()); });
286
- i0.ɵɵelement(1, "i", 50);
286
+ i0.ɵɵelement(1, "i", 52);
287
287
  i0.ɵɵelementStart(2, "span");
288
288
  i0.ɵɵtext(3, "Export to Excel");
289
289
  i0.ɵɵelementEnd()();
290
290
  } }
291
291
  function EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_button_4_Template(rf, ctx) { if (rf & 1) {
292
292
  const _r25 = i0.ɵɵgetCurrentView();
293
- i0.ɵɵelementStart(0, "button", 82);
293
+ i0.ɵɵelementStart(0, "button", 84);
294
294
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_button_4_Template_button_click_0_listener() { const action_r26 = i0.ɵɵrestoreView(_r25).$implicit; const ctx_r2 = i0.ɵɵnextContext(5); ctx_r2.onEntityActionClick(action_r26); return i0.ɵɵresetView(ctx_r2.closeOverflowMenu()); });
295
295
  i0.ɵɵelement(1, "i");
296
296
  i0.ɵɵelementStart(2, "span");
@@ -307,11 +307,11 @@ function EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_button_4_Temp
307
307
  } }
308
308
  function EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_Template(rf, ctx) { if (rf & 1) {
309
309
  i0.ɵɵelementContainerStart(0);
310
- i0.ɵɵelement(1, "div", 79);
311
- i0.ɵɵelementStart(2, "div", 80);
310
+ i0.ɵɵelement(1, "div", 81);
311
+ i0.ɵɵelementStart(2, "div", 82);
312
312
  i0.ɵɵtext(3, "Actions");
313
313
  i0.ɵɵelementEnd();
314
- i0.ɵɵtemplate(4, EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_button_4_Template, 4, 4, "button", 81);
314
+ i0.ɵɵtemplate(4, EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_button_4_Template, 4, 4, "button", 83);
315
315
  i0.ɵɵelementContainerEnd();
316
316
  } if (rf & 2) {
317
317
  const ctx_r2 = i0.ɵɵnextContext(4);
@@ -319,30 +319,30 @@ function EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_Template(rf,
319
319
  i0.ɵɵproperty("ngForOf", ctx_r2.EntityActions);
320
320
  } }
321
321
  function EntityDataGridComponent_div_2_div_23_div_3_div_3_Template(rf, ctx) { if (rf & 1) {
322
- i0.ɵɵelement(0, "div", 79);
322
+ i0.ɵɵelement(0, "div", 81);
323
323
  } }
324
324
  function EntityDataGridComponent_div_2_div_23_div_3_button_4_Template(rf, ctx) { if (rf & 1) {
325
325
  const _r27 = i0.ɵɵgetCurrentView();
326
- i0.ɵɵelementStart(0, "button", 78);
326
+ i0.ɵɵelementStart(0, "button", 80);
327
327
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_div_23_div_3_button_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r27); const ctx_r2 = i0.ɵɵnextContext(4); ctx_r2.onColumnChooserClick(); return i0.ɵɵresetView(ctx_r2.closeOverflowMenu()); });
328
- i0.ɵɵelement(1, "i", 70);
328
+ i0.ɵɵelement(1, "i", 72);
329
329
  i0.ɵɵelementStart(2, "span");
330
330
  i0.ɵɵtext(3, "Manage Columns");
331
331
  i0.ɵɵelementEnd()();
332
332
  } }
333
333
  function EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_button_2_Template(rf, ctx) { if (rf & 1) {
334
334
  const _r28 = i0.ɵɵgetCurrentView();
335
- i0.ɵɵelementStart(0, "button", 78);
335
+ i0.ɵɵelementStart(0, "button", 80);
336
336
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_button_2_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r28); const ctx_r2 = i0.ɵɵnextContext(5); ctx_r2.onCommunicationClick(); return i0.ɵɵresetView(ctx_r2.closeOverflowMenu()); });
337
- i0.ɵɵelement(1, "i", 62);
337
+ i0.ɵɵelement(1, "i", 64);
338
338
  i0.ɵɵelementStart(2, "span");
339
339
  i0.ɵɵtext(3, "Send Message");
340
340
  i0.ɵɵelementEnd()();
341
341
  } }
342
342
  function EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_Template(rf, ctx) { if (rf & 1) {
343
343
  i0.ɵɵelementContainerStart(0);
344
- i0.ɵɵelement(1, "div", 79);
345
- i0.ɵɵtemplate(2, EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_button_2_Template, 4, 0, "button", 76);
344
+ i0.ɵɵelement(1, "div", 81);
345
+ i0.ɵɵtemplate(2, EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_button_2_Template, 4, 0, "button", 78);
346
346
  i0.ɵɵelementContainerEnd();
347
347
  } if (rf & 2) {
348
348
  const ctx_r2 = i0.ɵɵnextContext(4);
@@ -350,8 +350,8 @@ function EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_Template(rf,
350
350
  i0.ɵɵproperty("ngIf", ctx_r2.showCommunicationInOverflow);
351
351
  } }
352
352
  function EntityDataGridComponent_div_2_div_23_div_3_Template(rf, ctx) { if (rf & 1) {
353
- i0.ɵɵelementStart(0, "div", 75);
354
- i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_div_23_div_3_button_1_Template, 4, 0, "button", 76)(2, EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_Template, 5, 1, "ng-container", 41)(3, EntityDataGridComponent_div_2_div_23_div_3_div_3_Template, 1, 0, "div", 77)(4, EntityDataGridComponent_div_2_div_23_div_3_button_4_Template, 4, 0, "button", 76)(5, EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_Template, 3, 1, "ng-container", 41);
353
+ i0.ɵɵelementStart(0, "div", 77);
354
+ i0.ɵɵtemplate(1, EntityDataGridComponent_div_2_div_23_div_3_button_1_Template, 4, 0, "button", 78)(2, EntityDataGridComponent_div_2_div_23_div_3_ng_container_2_Template, 5, 1, "ng-container", 43)(3, EntityDataGridComponent_div_2_div_23_div_3_div_3_Template, 1, 0, "div", 79)(4, EntityDataGridComponent_div_2_div_23_div_3_button_4_Template, 4, 0, "button", 78)(5, EntityDataGridComponent_div_2_div_23_div_3_ng_container_5_Template, 3, 1, "ng-container", 43);
355
355
  i0.ɵɵelementEnd();
356
356
  } if (rf & 2) {
357
357
  const ctx_r2 = i0.ɵɵnextContext(3);
@@ -369,13 +369,13 @@ function EntityDataGridComponent_div_2_div_23_div_3_Template(rf, ctx) { if (rf &
369
369
  } }
370
370
  function EntityDataGridComponent_div_2_div_23_Template(rf, ctx) { if (rf & 1) {
371
371
  const _r23 = i0.ɵɵgetCurrentView();
372
- i0.ɵɵelementStart(0, "div", 71);
372
+ i0.ɵɵelementStart(0, "div", 73);
373
373
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_div_23_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r23); return i0.ɵɵresetView($event.stopPropagation()); });
374
- i0.ɵɵelementStart(1, "button", 72);
374
+ i0.ɵɵelementStart(1, "button", 74);
375
375
  i0.ɵɵlistener("click", function EntityDataGridComponent_div_2_div_23_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r23); const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.toggleOverflowMenu()); });
376
- i0.ɵɵelement(2, "i", 73);
376
+ i0.ɵɵelement(2, "i", 75);
377
377
  i0.ɵɵelementEnd();
378
- i0.ɵɵtemplate(3, EntityDataGridComponent_div_2_div_23_div_3_Template, 6, 6, "div", 74);
378
+ i0.ɵɵtemplate(3, EntityDataGridComponent_div_2_div_23_div_3_Template, 6, 6, "div", 76);
379
379
  i0.ɵɵelementEnd();
380
380
  } if (rf & 2) {
381
381
  const ctx_r2 = i0.ɵɵnextContext(2);
@@ -383,14 +383,14 @@ function EntityDataGridComponent_div_2_div_23_Template(rf, ctx) { if (rf & 1) {
383
383
  i0.ɵɵproperty("ngIf", ctx_r2.showOverflowMenu);
384
384
  } }
385
385
  function EntityDataGridComponent_div_2_Template(rf, ctx) { if (rf & 1) {
386
- i0.ɵɵelementStart(0, "div", 9)(1, "div", 10);
387
- i0.ɵɵtemplate(2, EntityDataGridComponent_div_2_div_2_Template, 4, 3, "div", 11)(3, EntityDataGridComponent_div_2_ng_container_3_Template, 2, 1, "ng-container", 12);
386
+ i0.ɵɵelementStart(0, "div", 11)(1, "div", 12);
387
+ i0.ɵɵtemplate(2, EntityDataGridComponent_div_2_div_2_Template, 4, 3, "div", 13)(3, EntityDataGridComponent_div_2_ng_container_3_Template, 2, 1, "ng-container", 14);
388
388
  i0.ɵɵelementEnd();
389
- i0.ɵɵelementStart(4, "div", 13);
390
- i0.ɵɵtemplate(5, EntityDataGridComponent_div_2_span_5_Template, 2, 2, "span", 14)(6, EntityDataGridComponent_div_2_span_6_Template, 2, 1, "span", 15);
389
+ i0.ɵɵelementStart(4, "div", 15);
390
+ i0.ɵɵtemplate(5, EntityDataGridComponent_div_2_span_5_Template, 2, 2, "span", 16)(6, EntityDataGridComponent_div_2_span_6_Template, 2, 1, "span", 17);
391
391
  i0.ɵɵelementEnd();
392
- i0.ɵɵelementStart(7, "div", 16);
393
- i0.ɵɵtemplate(8, EntityDataGridComponent_div_2_button_8_Template, 4, 0, "button", 17)(9, EntityDataGridComponent_div_2_button_9_Template, 4, 3, "button", 18)(10, EntityDataGridComponent_div_2_button_10_Template, 4, 0, "button", 19)(11, EntityDataGridComponent_div_2_button_11_Template, 4, 0, "button", 20)(12, EntityDataGridComponent_div_2_button_12_Template, 4, 1, "button", 21)(13, EntityDataGridComponent_div_2_button_13_Template, 4, 1, "button", 22)(14, EntityDataGridComponent_div_2_button_14_Template, 4, 1, "button", 23)(15, EntityDataGridComponent_div_2_button_15_Template, 4, 1, "button", 24)(16, EntityDataGridComponent_div_2_button_16_Template, 4, 1, "button", 25)(17, EntityDataGridComponent_div_2_button_17_Template, 2, 0, "button", 26)(18, EntityDataGridComponent_div_2_button_18_Template, 2, 3, "button", 27)(19, EntityDataGridComponent_div_2_button_19_Template, 2, 0, "button", 28)(20, EntityDataGridComponent_div_2_button_20_Template, 2, 0, "button", 29)(21, EntityDataGridComponent_div_2_button_21_Template, 2, 0, "button", 30)(22, EntityDataGridComponent_div_2_ng_container_22_Template, 2, 1, "ng-container", 12)(23, EntityDataGridComponent_div_2_div_23_Template, 4, 1, "div", 31);
392
+ i0.ɵɵelementStart(7, "div", 18);
393
+ i0.ɵɵtemplate(8, EntityDataGridComponent_div_2_button_8_Template, 4, 0, "button", 19)(9, EntityDataGridComponent_div_2_button_9_Template, 4, 3, "button", 20)(10, EntityDataGridComponent_div_2_button_10_Template, 4, 0, "button", 21)(11, EntityDataGridComponent_div_2_button_11_Template, 4, 0, "button", 22)(12, EntityDataGridComponent_div_2_button_12_Template, 4, 1, "button", 23)(13, EntityDataGridComponent_div_2_button_13_Template, 4, 1, "button", 24)(14, EntityDataGridComponent_div_2_button_14_Template, 4, 1, "button", 25)(15, EntityDataGridComponent_div_2_button_15_Template, 4, 1, "button", 26)(16, EntityDataGridComponent_div_2_button_16_Template, 4, 1, "button", 27)(17, EntityDataGridComponent_div_2_button_17_Template, 2, 0, "button", 28)(18, EntityDataGridComponent_div_2_button_18_Template, 2, 3, "button", 29)(19, EntityDataGridComponent_div_2_button_19_Template, 2, 0, "button", 30)(20, EntityDataGridComponent_div_2_button_20_Template, 2, 0, "button", 31)(21, EntityDataGridComponent_div_2_button_21_Template, 2, 0, "button", 32)(22, EntityDataGridComponent_div_2_ng_container_22_Template, 2, 1, "ng-container", 14)(23, EntityDataGridComponent_div_2_div_23_Template, 4, 1, "div", 33);
394
394
  i0.ɵɵelementEnd()();
395
395
  } if (rf & 2) {
396
396
  const ctx_r2 = i0.ɵɵnextContext();
@@ -435,20 +435,66 @@ function EntityDataGridComponent_div_2_Template(rf, ctx) { if (rf & 1) {
435
435
  i0.ɵɵadvance();
436
436
  i0.ɵɵproperty("ngIf", ctx_r2.hasOverflowMenuItems);
437
437
  } }
438
- function EntityDataGridComponent_div_4_Template(rf, ctx) { if (rf & 1) {
439
- i0.ɵɵelementStart(0, "div", 83);
440
- i0.ɵɵelement(1, "mj-loading", 84);
438
+ function EntityDataGridComponent_div_3_ng_container_1_div_2_Template(rf, ctx) { if (rf & 1) {
439
+ i0.ɵɵelementStart(0, "div", 92);
440
+ i0.ɵɵelement(1, "i");
441
441
  i0.ɵɵelementEnd();
442
+ } if (rf & 2) {
443
+ const agg_r29 = i0.ɵɵnextContext().$implicit;
444
+ i0.ɵɵadvance();
445
+ i0.ɵɵclassMap(agg_r29.icon);
442
446
  } }
443
- function EntityDataGridComponent_div_5_Template(rf, ctx) { if (rf & 1) {
444
- const _r29 = i0.ɵɵgetCurrentView();
447
+ function EntityDataGridComponent_div_3_ng_container_1_Template(rf, ctx) { if (rf & 1) {
448
+ i0.ɵɵelementContainerStart(0);
449
+ i0.ɵɵelementStart(1, "div", 87);
450
+ i0.ɵɵtemplate(2, EntityDataGridComponent_div_3_ng_container_1_div_2_Template, 2, 2, "div", 88);
451
+ i0.ɵɵelementStart(3, "div", 89)(4, "span", 90);
452
+ i0.ɵɵtext(5);
453
+ i0.ɵɵelementEnd();
454
+ i0.ɵɵelementStart(6, "span", 91);
455
+ i0.ɵɵtext(7);
456
+ i0.ɵɵelementEnd()()();
457
+ i0.ɵɵelementContainerEnd();
458
+ } if (rf & 2) {
459
+ const agg_r29 = ctx.$implicit;
460
+ const ctx_r2 = i0.ɵɵnextContext(2);
461
+ i0.ɵɵadvance(2);
462
+ i0.ɵɵproperty("ngIf", agg_r29.icon);
463
+ i0.ɵɵadvance(3);
464
+ i0.ɵɵtextInterpolate(agg_r29.label);
465
+ i0.ɵɵadvance(2);
466
+ i0.ɵɵtextInterpolate(ctx_r2.getAggregateValue(agg_r29));
467
+ } }
468
+ function EntityDataGridComponent_div_3_div_2_Template(rf, ctx) { if (rf & 1) {
469
+ i0.ɵɵelementStart(0, "div", 93);
470
+ i0.ɵɵelement(1, "i", 94);
471
+ i0.ɵɵelementEnd();
472
+ } }
473
+ function EntityDataGridComponent_div_3_Template(rf, ctx) { if (rf & 1) {
445
474
  i0.ɵɵelementStart(0, "div", 85);
446
- i0.ɵɵelement(1, "i", 86);
475
+ i0.ɵɵtemplate(1, EntityDataGridComponent_div_3_ng_container_1_Template, 8, 3, "ng-container", 14)(2, EntityDataGridComponent_div_3_div_2_Template, 2, 0, "div", 86);
476
+ i0.ɵɵelementEnd();
477
+ } if (rf & 2) {
478
+ const ctx_r2 = i0.ɵɵnextContext();
479
+ i0.ɵɵadvance();
480
+ i0.ɵɵproperty("ngForOf", ctx_r2.CardAggregates);
481
+ i0.ɵɵadvance();
482
+ i0.ɵɵproperty("ngIf", ctx_r2.AggregatesLoading);
483
+ } }
484
+ function EntityDataGridComponent_div_5_Template(rf, ctx) { if (rf & 1) {
485
+ i0.ɵɵelementStart(0, "div", 95);
486
+ i0.ɵɵelement(1, "mj-loading", 96);
487
+ i0.ɵɵelementEnd();
488
+ } }
489
+ function EntityDataGridComponent_div_6_Template(rf, ctx) { if (rf & 1) {
490
+ const _r30 = i0.ɵɵgetCurrentView();
491
+ i0.ɵɵelementStart(0, "div", 97);
492
+ i0.ɵɵelement(1, "i", 98);
447
493
  i0.ɵɵelementStart(2, "span");
448
494
  i0.ɵɵtext(3);
449
495
  i0.ɵɵelementEnd();
450
- i0.ɵɵelementStart(4, "button", 87);
451
- i0.ɵɵlistener("click", function EntityDataGridComponent_div_5_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r29); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.Refresh()); });
496
+ i0.ɵɵelementStart(4, "button", 99);
497
+ i0.ɵɵlistener("click", function EntityDataGridComponent_div_6_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.Refresh()); });
452
498
  i0.ɵɵtext(5, "Retry");
453
499
  i0.ɵɵelementEnd()();
454
500
  } if (rf & 2) {
@@ -456,31 +502,76 @@ function EntityDataGridComponent_div_5_Template(rf, ctx) { if (rf & 1) {
456
502
  i0.ɵɵadvance(3);
457
503
  i0.ɵɵtextInterpolate(ctx_r2.errorMessage);
458
504
  } }
459
- function EntityDataGridComponent_div_6_Template(rf, ctx) { if (rf & 1) {
460
- i0.ɵɵelementStart(0, "div", 88);
461
- i0.ɵɵelement(1, "i", 89);
505
+ function EntityDataGridComponent_div_7_Template(rf, ctx) { if (rf & 1) {
506
+ i0.ɵɵelementStart(0, "div", 100);
507
+ i0.ɵɵelement(1, "i", 101);
462
508
  i0.ɵɵelementStart(2, "span");
463
509
  i0.ɵɵtext(3, "No data to display");
464
510
  i0.ɵɵelementEnd()();
465
511
  } }
466
- function EntityDataGridComponent_ag_grid_angular_7_Template(rf, ctx) { if (rf & 1) {
467
- const _r30 = i0.ɵɵgetCurrentView();
468
- i0.ɵɵelementStart(0, "ag-grid-angular", 90);
469
- i0.ɵɵlistener("gridReady", function EntityDataGridComponent_ag_grid_angular_7_Template_ag_grid_angular_gridReady_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onGridReady($event)); })("rowClicked", function EntityDataGridComponent_ag_grid_angular_7_Template_ag_grid_angular_rowClicked_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowClicked($event)); })("rowDoubleClicked", function EntityDataGridComponent_ag_grid_angular_7_Template_ag_grid_angular_rowDoubleClicked_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowDoubleClicked($event)); })("sortChanged", function EntityDataGridComponent_ag_grid_angular_7_Template_ag_grid_angular_sortChanged_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSortChanged($event)); })("selectionChanged", function EntityDataGridComponent_ag_grid_angular_7_Template_ag_grid_angular_selectionChanged_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSelectionChanged($event)); })("columnResized", function EntityDataGridComponent_ag_grid_angular_7_Template_ag_grid_angular_columnResized_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnResized($event)); })("columnMoved", function EntityDataGridComponent_ag_grid_angular_7_Template_ag_grid_angular_columnMoved_0_listener($event) { i0.ɵɵrestoreView(_r30); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnMoved($event)); });
512
+ function EntityDataGridComponent_ag_grid_angular_8_Template(rf, ctx) { if (rf & 1) {
513
+ const _r31 = i0.ɵɵgetCurrentView();
514
+ i0.ɵɵelementStart(0, "ag-grid-angular", 102);
515
+ i0.ɵɵlistener("gridReady", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_gridReady_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onGridReady($event)); })("cellClicked", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_cellClicked_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgCellClicked($event)); })("rowClicked", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_rowClicked_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowClicked($event)); })("rowDoubleClicked", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_rowDoubleClicked_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowDoubleClicked($event)); })("sortChanged", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_sortChanged_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSortChanged($event)); })("selectionChanged", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_selectionChanged_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSelectionChanged($event)); })("columnResized", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_columnResized_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnResized($event)); })("columnMoved", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_columnMoved_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnMoved($event)); });
470
516
  i0.ɵɵelementEnd();
471
517
  } if (rf & 2) {
472
518
  const ctx_r2 = i0.ɵɵnextContext();
473
519
  i0.ɵɵproperty("theme", ctx_r2.agGridTheme)("columnDefs", ctx_r2.agColumnDefs)("rowData", ctx_r2.rowData)("defaultColDef", ctx_r2.defaultColDef)("rowSelection", ctx_r2.agRowSelection)("getRowId", ctx_r2.getRowId)("suppressCellFocus", true)("rowHeight", ctx_r2.RowHeight)("headerHeight", ctx_r2.ShowHeader ? undefined : 0);
474
520
  } }
475
- function EntityDataGridComponent_ag_grid_angular_8_Template(rf, ctx) { if (rf & 1) {
476
- const _r31 = i0.ɵɵgetCurrentView();
477
- i0.ɵɵelementStart(0, "ag-grid-angular", 91);
478
- i0.ɵɵlistener("gridReady", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_gridReady_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onGridReady($event)); })("rowClicked", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_rowClicked_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowClicked($event)); })("rowDoubleClicked", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_rowDoubleClicked_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowDoubleClicked($event)); })("sortChanged", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_sortChanged_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSortChanged($event)); })("selectionChanged", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_selectionChanged_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSelectionChanged($event)); })("columnResized", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_columnResized_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnResized($event)); })("columnMoved", function EntityDataGridComponent_ag_grid_angular_8_Template_ag_grid_angular_columnMoved_0_listener($event) { i0.ɵɵrestoreView(_r31); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnMoved($event)); });
521
+ function EntityDataGridComponent_ag_grid_angular_9_Template(rf, ctx) { if (rf & 1) {
522
+ const _r32 = i0.ɵɵgetCurrentView();
523
+ i0.ɵɵelementStart(0, "ag-grid-angular", 103);
524
+ i0.ɵɵlistener("gridReady", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_gridReady_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onGridReady($event)); })("cellClicked", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_cellClicked_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgCellClicked($event)); })("rowClicked", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_rowClicked_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowClicked($event)); })("rowDoubleClicked", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_rowDoubleClicked_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgRowDoubleClicked($event)); })("sortChanged", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_sortChanged_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSortChanged($event)); })("selectionChanged", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_selectionChanged_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgSelectionChanged($event)); })("columnResized", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_columnResized_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnResized($event)); })("columnMoved", function EntityDataGridComponent_ag_grid_angular_9_Template_ag_grid_angular_columnMoved_0_listener($event) { i0.ɵɵrestoreView(_r32); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onAgColumnMoved($event)); });
479
525
  i0.ɵɵelementEnd();
480
526
  } if (rf & 2) {
481
527
  const ctx_r2 = i0.ɵɵnextContext();
482
528
  i0.ɵɵproperty("theme", ctx_r2.agGridTheme)("columnDefs", ctx_r2.agColumnDefs)("defaultColDef", ctx_r2.defaultColDef)("rowSelection", ctx_r2.agRowSelection)("getRowId", ctx_r2.getRowId)("suppressCellFocus", true)("rowHeight", ctx_r2.RowHeight)("headerHeight", ctx_r2.ShowHeader ? undefined : 0)("rowModelType", "infinite")("cacheBlockSize", ctx_r2.CacheBlockSize)("maxBlocksInCache", ctx_r2.MaxBlocksInCache)("infiniteInitialRowCount", 1)("cacheOverflowSize", 2);
483
529
  } }
530
+ function EntityDataGridComponent_div_10_ng_container_2_i_2_Template(rf, ctx) { if (rf & 1) {
531
+ i0.ɵɵelement(0, "i");
532
+ } if (rf & 2) {
533
+ const agg_r33 = i0.ɵɵnextContext().$implicit;
534
+ i0.ɵɵclassMap(agg_r33.icon);
535
+ } }
536
+ function EntityDataGridComponent_div_10_ng_container_2_Template(rf, ctx) { if (rf & 1) {
537
+ i0.ɵɵelementContainerStart(0);
538
+ i0.ɵɵelementStart(1, "div", 107);
539
+ i0.ɵɵtemplate(2, EntityDataGridComponent_div_10_ng_container_2_i_2_Template, 1, 2, "i", 42);
540
+ i0.ɵɵelementStart(3, "span", 108);
541
+ i0.ɵɵtext(4);
542
+ i0.ɵɵelementEnd();
543
+ i0.ɵɵelementStart(5, "span", 109);
544
+ i0.ɵɵtext(6);
545
+ i0.ɵɵelementEnd()();
546
+ i0.ɵɵelementContainerEnd();
547
+ } if (rf & 2) {
548
+ const agg_r33 = ctx.$implicit;
549
+ const ctx_r2 = i0.ɵɵnextContext(2);
550
+ i0.ɵɵadvance(2);
551
+ i0.ɵɵproperty("ngIf", agg_r33.icon);
552
+ i0.ɵɵadvance(2);
553
+ i0.ɵɵtextInterpolate1("", agg_r33.label, ":");
554
+ i0.ɵɵadvance(2);
555
+ i0.ɵɵtextInterpolate(ctx_r2.getAggregateValue(agg_r33));
556
+ } }
557
+ function EntityDataGridComponent_div_10_div_3_Template(rf, ctx) { if (rf & 1) {
558
+ i0.ɵɵelementStart(0, "div", 110);
559
+ i0.ɵɵelement(1, "i", 94);
560
+ i0.ɵɵelementEnd();
561
+ } }
562
+ function EntityDataGridComponent_div_10_Template(rf, ctx) { if (rf & 1) {
563
+ i0.ɵɵelementStart(0, "div", 104)(1, "div", 105);
564
+ i0.ɵɵtemplate(2, EntityDataGridComponent_div_10_ng_container_2_Template, 7, 3, "ng-container", 14);
565
+ i0.ɵɵelementEnd();
566
+ i0.ɵɵtemplate(3, EntityDataGridComponent_div_10_div_3_Template, 2, 0, "div", 106);
567
+ i0.ɵɵelementEnd();
568
+ } if (rf & 2) {
569
+ const ctx_r2 = i0.ɵɵnextContext();
570
+ i0.ɵɵadvance(2);
571
+ i0.ɵɵproperty("ngForOf", ctx_r2.ColumnAggregates);
572
+ i0.ɵɵadvance();
573
+ i0.ɵɵproperty("ngIf", ctx_r2.AggregatesLoading);
574
+ } }
484
575
  // Register AG Grid modules (required for v34+)
485
576
  ModuleRegistry.registerModules([AllCommunityModule]);
486
577
  /**
@@ -496,7 +587,7 @@ ModuleRegistry.registerModules([AllCommunityModule]);
496
587
  * - Inline cell and row editing
497
588
  * - Column reordering, resizing, and visibility toggle
498
589
  * - State persistence to User Settings
499
- * - Compatible with ViewGridStateConfig from User Views
590
+ * - Compatible with ViewGridState from User Views
500
591
  *
501
592
  * @example
502
593
  * ```html
@@ -823,6 +914,21 @@ export class EntityDataGridComponent {
823
914
  get RowHeight() {
824
915
  return this._rowHeight;
825
916
  }
917
+ /**
918
+ * Enable text wrapping in grid cells
919
+ * When true, long text will wrap to multiple lines and rows will auto-size
920
+ * Note: This disables fixed row height and may impact performance with large datasets
921
+ */
922
+ _wrapText = false;
923
+ set WrapText(value) {
924
+ if (this._wrapText !== value) {
925
+ this._wrapText = value;
926
+ this.updateDefaultColDefForWrapping();
927
+ }
928
+ }
929
+ get WrapText() {
930
+ return this._wrapText;
931
+ }
826
932
  _virtualScroll = true;
827
933
  set VirtualScroll(value) {
828
934
  this._virtualScroll = value;
@@ -1127,8 +1233,111 @@ export class EntityDataGridComponent {
1127
1233
  return this._entityActions;
1128
1234
  }
1129
1235
  // ========================================
1236
+ // Aggregate Inputs
1237
+ // ========================================
1238
+ /**
1239
+ * Aggregate configuration for the grid.
1240
+ * When provided, aggregate expressions are calculated alongside data and displayed:
1241
+ * - Column-bound aggregates appear in a pinned bottom row
1242
+ * - Card-bound aggregates are exposed via AggregateValues for use with AggregatePanelComponent
1243
+ */
1244
+ set AggregatesConfig(value) {
1245
+ this._aggregatesConfig = value;
1246
+ }
1247
+ get AggregatesConfig() {
1248
+ return this._aggregatesConfig;
1249
+ }
1250
+ /**
1251
+ * Returns the aggregate values map, keyed by expression or id.
1252
+ * Use this to pass values to AggregatePanelComponent.
1253
+ */
1254
+ get AggregateValuesMap() {
1255
+ return this._aggregateValues;
1256
+ }
1257
+ /**
1258
+ * Returns the raw aggregate results from the last RunView call.
1259
+ */
1260
+ get AggregateResultsList() {
1261
+ return this._aggregateResults;
1262
+ }
1263
+ /**
1264
+ * Whether aggregates are currently loading.
1265
+ */
1266
+ get AggregatesLoading() {
1267
+ return this._aggregatesLoading;
1268
+ }
1269
+ /**
1270
+ * Returns the effective aggregates config, preferring _aggregatesConfig but falling back to _gridState.aggregates.
1271
+ * This ensures aggregates work regardless of whether they came from explicit config or from view's GridState.
1272
+ */
1273
+ get EffectiveAggregatesConfig() {
1274
+ return this._aggregatesConfig || this._gridState?.aggregates;
1275
+ }
1276
+ /**
1277
+ * Returns enabled aggregates configured for card display.
1278
+ */
1279
+ get CardAggregates() {
1280
+ const config = this.EffectiveAggregatesConfig;
1281
+ if (!config?.expressions)
1282
+ return [];
1283
+ return config.expressions
1284
+ .filter(a => a.enabled !== false && a.displayType === 'card')
1285
+ .sort((a, b) => (a.order || 0) - (b.order || 0));
1286
+ }
1287
+ /**
1288
+ * Returns enabled aggregates configured for column footer display.
1289
+ */
1290
+ get ColumnAggregates() {
1291
+ const config = this.EffectiveAggregatesConfig;
1292
+ if (!config?.expressions)
1293
+ return [];
1294
+ return config.expressions
1295
+ .filter(a => a.enabled !== false && a.displayType === 'column')
1296
+ .sort((a, b) => (a.order || 0) - (b.order || 0));
1297
+ }
1298
+ /**
1299
+ * Whether to show aggregate summary row (has column-type aggregates with values).
1300
+ */
1301
+ get ShowAggregateSummary() {
1302
+ const hasColumnAggs = this.ColumnAggregates.length > 0;
1303
+ const hasValues = this._aggregateValues.size > 0;
1304
+ return hasColumnAggs && hasValues;
1305
+ }
1306
+ /**
1307
+ * Whether to show aggregate panel (has card-type aggregates with values).
1308
+ */
1309
+ get ShowAggregatePanel() {
1310
+ return this.CardAggregates.length > 0 && this._aggregateValues.size > 0;
1311
+ }
1312
+ /**
1313
+ * Get formatted aggregate value for display
1314
+ */
1315
+ getAggregateValue(agg) {
1316
+ const key = agg.id || agg.expression;
1317
+ const value = this._aggregateValues.get(key);
1318
+ if (value == null)
1319
+ return '—';
1320
+ // Format based on value type
1321
+ if (typeof value === 'number') {
1322
+ return value.toLocaleString('en-US', {
1323
+ maximumFractionDigits: 2,
1324
+ minimumFractionDigits: 0
1325
+ });
1326
+ }
1327
+ if (value instanceof Date) {
1328
+ return value.toLocaleDateString();
1329
+ }
1330
+ return String(value);
1331
+ }
1332
+ // ========================================
1130
1333
  // Event Outputs
1131
1334
  // ========================================
1335
+ // Aggregate Results
1336
+ /**
1337
+ * Emitted when aggregate results are loaded.
1338
+ * Contains the array of AggregateResult objects and a values map for easy lookup.
1339
+ */
1340
+ AggregatesLoaded = new EventEmitter();
1132
1341
  // Row Selection
1133
1342
  BeforeRowSelect = new EventEmitter();
1134
1343
  AfterRowSelect = new EventEmitter();
@@ -1140,6 +1349,12 @@ export class EntityDataGridComponent {
1140
1349
  AfterRowClick = new EventEmitter();
1141
1350
  BeforeRowDoubleClick = new EventEmitter();
1142
1351
  AfterRowDoubleClick = new EventEmitter();
1352
+ // Foreign Key Link Click
1353
+ /**
1354
+ * Emitted when a foreign key link is clicked in the grid.
1355
+ * Parent components should handle this to navigate to the related record.
1356
+ */
1357
+ ForeignKeyClick = new EventEmitter();
1143
1358
  // Editing
1144
1359
  BeforeCellEdit = new EventEmitter();
1145
1360
  AfterCellEditBegin = new EventEmitter();
@@ -1262,6 +1477,30 @@ export class EntityDataGridComponent {
1262
1477
  resizable: true,
1263
1478
  minWidth: 80
1264
1479
  };
1480
+ /**
1481
+ * Update defaultColDef when text wrapping setting changes
1482
+ * Enables/disables auto row height and cell text wrapping
1483
+ */
1484
+ updateDefaultColDefForWrapping() {
1485
+ if (this._wrapText) {
1486
+ this.defaultColDef = {
1487
+ ...this.defaultColDef,
1488
+ wrapText: true,
1489
+ autoHeight: true,
1490
+ cellClass: 'cell-wrap-text'
1491
+ };
1492
+ }
1493
+ else {
1494
+ // Remove wrapping properties
1495
+ const { wrapText, autoHeight, cellClass, ...rest } = this.defaultColDef;
1496
+ this.defaultColDef = rest;
1497
+ }
1498
+ // Refresh the grid to apply changes
1499
+ if (this.gridApi) {
1500
+ this.gridApi.setGridOption('defaultColDef', this.defaultColDef);
1501
+ this.gridApi.refreshCells({ force: true });
1502
+ }
1503
+ }
1265
1504
  /** Get row ID function for AG Grid */
1266
1505
  getRowId = (params) => params.data['__pk'];
1267
1506
  /** Suppress sort changed events during programmatic updates */
@@ -1284,6 +1523,11 @@ export class EntityDataGridComponent {
1284
1523
  _editingRowKey = null;
1285
1524
  _editingField = null;
1286
1525
  _pendingChanges = [];
1526
+ // Aggregate state
1527
+ _aggregatesConfig = null;
1528
+ _aggregateResults = [];
1529
+ _aggregateValues = new Map();
1530
+ _aggregatesLoading = false;
1287
1531
  // ========================================
1288
1532
  // Public Read-Only Properties
1289
1533
  // ========================================
@@ -1439,6 +1683,13 @@ export class EntityDataGridComponent {
1439
1683
  // carry over column/sort settings from a previous view when switching views
1440
1684
  this._gridState = null;
1441
1685
  this._sortState = [];
1686
+ // Reset aggregates when switching views - don't carry over from previous view
1687
+ this._aggregatesConfig = null;
1688
+ this._aggregateResults = [];
1689
+ this._aggregateValues.clear();
1690
+ // Reset allowLoad to true when params change - this ensures the new view gets to load
1691
+ // (The parent may have set allowLoad=false for the previous view, which shouldn't prevent loading the new view)
1692
+ this._allowLoad = true;
1442
1693
  try {
1443
1694
  // If using a stored view, load the view entity first
1444
1695
  if (this._params.ViewEntity) {
@@ -1578,7 +1829,8 @@ export class EntityDataGridComponent {
1578
1829
  if (!this._gridState && gridState.columnSettings?.length) {
1579
1830
  this._gridState = {
1580
1831
  columnSettings: gridState.columnSettings,
1581
- sortSettings: gridState.sortSettings || []
1832
+ sortSettings: gridState.sortSettings || [],
1833
+ aggregates: gridState.aggregates
1582
1834
  };
1583
1835
  }
1584
1836
  // Apply sort state if not already set
@@ -1589,6 +1841,10 @@ export class EntityDataGridComponent {
1589
1841
  index
1590
1842
  }));
1591
1843
  }
1844
+ // Apply aggregates from user defaults if present and not already set
1845
+ if (gridState.aggregates && !this._aggregatesConfig) {
1846
+ this._aggregatesConfig = gridState.aggregates;
1847
+ }
1592
1848
  }
1593
1849
  }
1594
1850
  catch (error) {
@@ -1608,7 +1864,8 @@ export class EntityDataGridComponent {
1608
1864
  const settingKey = `default-view-setting/${this._entityInfo.Name}`;
1609
1865
  const gridStateJson = {
1610
1866
  columnSettings: state.columnSettings,
1611
- sortSettings: state.sortSettings
1867
+ sortSettings: state.sortSettings,
1868
+ aggregates: state.aggregates
1612
1869
  };
1613
1870
  await UserInfoEngine.Instance.SetSetting(settingKey, JSON.stringify(gridStateJson));
1614
1871
  // Clear pending state and reset dirty flag after successful save
@@ -1639,9 +1896,14 @@ export class EntityDataGridComponent {
1639
1896
  if (gridState.columnSettings?.length) {
1640
1897
  this._gridState = {
1641
1898
  columnSettings: gridState.columnSettings,
1642
- sortSettings: gridState.sortSettings || []
1899
+ sortSettings: gridState.sortSettings || [],
1900
+ aggregates: gridState.aggregates
1643
1901
  };
1644
1902
  }
1903
+ // Apply aggregates from view's GridState if present
1904
+ if (gridState.aggregates && !this._aggregatesConfig) {
1905
+ this._aggregatesConfig = gridState.aggregates;
1906
+ }
1645
1907
  }
1646
1908
  catch (e) {
1647
1909
  console.warn('Failed to parse view GridState:', e);
@@ -1681,6 +1943,76 @@ export class EntityDataGridComponent {
1681
1943
  }));
1682
1944
  this.applySortStateToGrid();
1683
1945
  }
1946
+ // Apply aggregates from GridState if present and fetch their values
1947
+ if (this._gridState.aggregates) {
1948
+ this._aggregatesConfig = this._gridState.aggregates;
1949
+ // Fetch aggregate values when gridState aggregates change
1950
+ this.refreshAggregates();
1951
+ }
1952
+ }
1953
+ }
1954
+ /**
1955
+ * Fetch aggregate values without reloading data.
1956
+ * Used when gridState changes and includes new aggregate config.
1957
+ * This runs a RunView with MaxRows=0 to get only aggregate results.
1958
+ */
1959
+ async refreshAggregates() {
1960
+ const effectiveAggConfig = this.EffectiveAggregatesConfig;
1961
+ if (!effectiveAggConfig?.expressions?.length) {
1962
+ this._aggregateResults = [];
1963
+ this._aggregateValues.clear();
1964
+ this._aggregatesLoading = false;
1965
+ this.cdr.detectChanges();
1966
+ return;
1967
+ }
1968
+ // Need entity info to run the query
1969
+ if (!this._entityInfo) {
1970
+ return;
1971
+ }
1972
+ this._aggregatesLoading = true;
1973
+ this.cdr.detectChanges();
1974
+ try {
1975
+ // Build aggregate expressions
1976
+ const aggregateExpressions = effectiveAggConfig.expressions
1977
+ .filter(agg => agg.enabled !== false && agg.expression)
1978
+ .map(agg => ({
1979
+ expression: agg.expression,
1980
+ alias: agg.id || agg.label || agg.expression
1981
+ }));
1982
+ if (aggregateExpressions.length === 0) {
1983
+ this._aggregateResults = [];
1984
+ this._aggregateValues.clear();
1985
+ this._aggregatesLoading = false;
1986
+ this.cdr.detectChanges();
1987
+ return;
1988
+ }
1989
+ const rv = new RunView();
1990
+ // Build the ExtraFilter from params or view entity
1991
+ let extraFilter;
1992
+ if (this._params?.ExtraFilter) {
1993
+ extraFilter = this._params.ExtraFilter;
1994
+ }
1995
+ else if (this._viewEntity?.WhereClause) {
1996
+ extraFilter = this._viewEntity.WhereClause;
1997
+ }
1998
+ const result = await rv.RunView({
1999
+ EntityName: this._entityInfo.Name,
2000
+ MaxRows: 0, // Only get aggregates, no row data
2001
+ ExtraFilter: extraFilter,
2002
+ Aggregates: aggregateExpressions
2003
+ });
2004
+ if (result.Success) {
2005
+ this.processAggregateResults(result.AggregateResults, result.AggregateExecutionTime);
2006
+ }
2007
+ else {
2008
+ this._aggregatesLoading = false;
2009
+ this.cdr.detectChanges();
2010
+ }
2011
+ }
2012
+ catch (error) {
2013
+ console.error('[EntityDataGrid] Error fetching aggregates:', error);
2014
+ this._aggregatesLoading = false;
2015
+ this.cdr.detectChanges();
1684
2016
  }
1685
2017
  }
1686
2018
  onFilterTextChanged() {
@@ -1711,77 +2043,122 @@ export class EntityDataGridComponent {
1711
2043
  this.initializeColumnStates();
1712
2044
  this.buildAgColumnDefs();
1713
2045
  }
2046
+ /**
2047
+ * Determines if a field should be shown by default when no saved view exists.
2048
+ * This logic is aligned with UserViewEntity.SetDefaultsFromEntity() to ensure
2049
+ * consistent column visibility between initial load and saved views.
2050
+ */
1714
2051
  shouldShowField(field) {
2052
+ // Always exclude system fields
1715
2053
  if (field.Name.startsWith('__mj_'))
1716
2054
  return false;
2055
+ // Always exclude UUID primary keys (they're not useful to display)
1717
2056
  if (field.IsPrimaryKey && field.SQLFullType?.toLowerCase() === 'uniqueidentifier') {
1718
2057
  return false;
1719
2058
  }
1720
- if (field.DefaultInView === true)
1721
- return true;
1722
- if (field.Length > 500)
1723
- return false;
1724
- return true;
2059
+ // Only show fields explicitly marked as DefaultInView
2060
+ // This aligns with UserViewEntity.SetDefaultsFromEntity() behavior
2061
+ // ensuring users see the same columns before and after saving a view
2062
+ return field.DefaultInView === true;
1725
2063
  }
2064
+ /**
2065
+ * Estimate an appropriate column width based on field metadata.
2066
+ * Takes into account: metadata DefaultColumnWidth, header text length, data type, and field patterns.
2067
+ */
1726
2068
  estimateColumnWidth(field) {
2069
+ // Priority 1: Use metadata-defined width if set
2070
+ if (field.DefaultColumnWidth && field.DefaultColumnWidth > 0) {
2071
+ return field.DefaultColumnWidth;
2072
+ }
2073
+ // Calculate minimum width needed for header text
2074
+ const headerText = field.DisplayName || field.Name;
2075
+ const headerWidth = this.calculateHeaderWidth(headerText);
2076
+ // Calculate estimated data width based on field type
2077
+ const dataWidth = this.calculateDataWidth(field);
2078
+ // Use the larger of header or data width, with bounds
2079
+ const estimatedWidth = Math.max(headerWidth, dataWidth);
2080
+ // Apply min/max bounds: minimum 80px, maximum 350px
2081
+ return Math.max(Math.min(estimatedWidth, 350), 80);
2082
+ }
2083
+ /**
2084
+ * Calculate minimum width needed to display header text without truncation.
2085
+ */
2086
+ calculateHeaderWidth(text) {
2087
+ // Average char width ~7.5px for typical grid font
2088
+ const charWidth = 7.5;
2089
+ // Padding for sort icon and cell padding
2090
+ const sortIconPadding = 24;
2091
+ const cellPadding = 16;
2092
+ return Math.ceil(text.length * charWidth + sortIconPadding + cellPadding);
2093
+ }
2094
+ /**
2095
+ * Calculate estimated data width based on field type and patterns.
2096
+ */
2097
+ calculateDataWidth(field) {
1727
2098
  const fieldNameLower = field.Name.toLowerCase();
1728
- const displayNameLower = (field.DisplayName || field.Name).toLowerCase();
2099
+ const tsType = field.TSType;
1729
2100
  // Fixed-width types
1730
- if (field.TSType === 'boolean')
1731
- return 80;
1732
- if (field.TSType === 'Date')
1733
- return 120;
2101
+ if (tsType === 'boolean')
2102
+ return 90;
2103
+ if (tsType === 'Date')
2104
+ return 130;
1734
2105
  // Numeric fields - compact
1735
- if (field.TSType === 'number') {
2106
+ if (tsType === 'number') {
1736
2107
  if (fieldNameLower.includes('year') || fieldNameLower.includes('age'))
1737
2108
  return 80;
1738
- if (fieldNameLower.includes('amount') || fieldNameLower.includes('price') || fieldNameLower.includes('total'))
1739
- return 120;
2109
+ if (fieldNameLower.includes('amount') || fieldNameLower.includes('price') ||
2110
+ fieldNameLower.includes('cost') || fieldNameLower.includes('total'))
2111
+ return 130;
1740
2112
  return 100;
1741
2113
  }
1742
- // ID fields - compact
2114
+ // ID fields (typically UUIDs shown truncated or as links)
1743
2115
  if (fieldNameLower.endsWith('id') && field.Length <= 50)
1744
- return 80;
2116
+ return 100;
1745
2117
  // Email - needs more space
1746
2118
  if (fieldNameLower.includes('email'))
1747
2119
  return 220;
1748
2120
  // Phone numbers
1749
2121
  if (fieldNameLower.includes('phone') || fieldNameLower.includes('mobile') || fieldNameLower.includes('fax'))
1750
- return 130;
2122
+ return 140;
2123
+ // Description fields - give them adequate room (increased from 150)
2124
+ if (fieldNameLower.includes('description'))
2125
+ return 250;
1751
2126
  // Name fields - medium width
1752
2127
  if (fieldNameLower.includes('name') || fieldNameLower.includes('title')) {
1753
- if (fieldNameLower === 'firstname' || fieldNameLower === 'lastname' || fieldNameLower === 'first name' || fieldNameLower === 'last name')
1754
- return 120;
1755
- return 160;
2128
+ if (fieldNameLower === 'firstname' || fieldNameLower === 'lastname' ||
2129
+ fieldNameLower === 'first name' || fieldNameLower === 'last name')
2130
+ return 130;
2131
+ return 180;
1756
2132
  }
1757
2133
  // Location fields
1758
2134
  if (fieldNameLower.includes('city'))
1759
- return 120;
2135
+ return 130;
1760
2136
  if (fieldNameLower.includes('state') || fieldNameLower.includes('country'))
1761
- return 100;
2137
+ return 110;
1762
2138
  if (fieldNameLower.includes('zip') || fieldNameLower.includes('postal'))
1763
- return 90;
2139
+ return 100;
1764
2140
  if (fieldNameLower.includes('address'))
1765
- return 200;
2141
+ return 220;
1766
2142
  // Date-like strings
1767
2143
  if (fieldNameLower.includes('date') || fieldNameLower.includes('time'))
1768
- return 120;
1769
- // Status/Type fields - usually short values
1770
- if (fieldNameLower.includes('status') || fieldNameLower.includes('type') || fieldNameLower.includes('category'))
1771
- return 110;
2144
+ return 130;
2145
+ // Status/Type/Category fields
2146
+ if (fieldNameLower.includes('status') || fieldNameLower.includes('type') ||
2147
+ fieldNameLower.includes('category') || fieldNameLower.includes('mode'))
2148
+ return 130;
1772
2149
  // Code/abbreviation fields
1773
2150
  if (fieldNameLower.includes('code') || fieldNameLower.includes('abbr'))
1774
- return 100;
1775
- // Long text fields - limit width, they'll truncate
2151
+ return 110;
2152
+ // Long text fields - give them more room (nvarchar(max) has Length < 0)
2153
+ if (field.Length < 0)
2154
+ return 250; // nvarchar(max)
1776
2155
  if (field.Length > 500)
1777
- return 150;
2156
+ return 220;
1778
2157
  if (field.Length > 200)
1779
- return 180;
1780
- // Default: estimate based on field length but with tighter bounds
1781
- const estimatedChars = Math.min(field.Length, 50);
1782
- const charWidth = 7;
1783
- const padding = 24;
1784
- return Math.min(Math.max(estimatedChars * charWidth / 2 + padding, 80), 200);
2158
+ return 200;
2159
+ // Default: estimate based on field length with reasonable bounds
2160
+ const estimatedChars = Math.min(field.Length || 50, 40);
2161
+ return Math.max(estimatedChars * 6 + 24, 100);
1785
2162
  }
1786
2163
  mapFieldTypeToGridType(fieldType) {
1787
2164
  switch (fieldType.toLowerCase()) {
@@ -1899,20 +2276,108 @@ export class EntityDataGridComponent {
1899
2276
  }
1900
2277
  generateAgColumnDefs(entity) {
1901
2278
  const cols = [];
1902
- const visibleFields = entity.Fields.filter(f => this.shouldShowField(f));
2279
+ let visibleFields = entity.Fields.filter(f => this.shouldShowField(f));
2280
+ // Fallback: if no DefaultInView fields are defined, show first 10 non-system fields
2281
+ // sorted by importance to give users a reasonable starting point
2282
+ if (visibleFields.length === 0) {
2283
+ visibleFields = this.getDefaultFieldsFallback(entity);
2284
+ }
2285
+ // Sort fields by importance for better default ordering
2286
+ visibleFields = this.sortFieldsByImportance(visibleFields);
1903
2287
  for (const field of visibleFields) {
1904
2288
  const colDef = {
1905
2289
  field: field.Name,
1906
2290
  headerName: field.DisplayNameOrName,
1907
2291
  width: this.estimateColumnWidth(field),
1908
2292
  sortable: this._allowSorting,
1909
- resizable: this._allowColumnResize
2293
+ resizable: this._allowColumnResize,
2294
+ headerTooltip: this.buildHeaderTooltip(field)
1910
2295
  };
1911
2296
  this.applyFieldFormatter(colDef, field);
1912
2297
  cols.push(colDef);
1913
2298
  }
1914
2299
  return cols;
1915
2300
  }
2301
+ /**
2302
+ * When no DefaultInView fields are set, fall back to showing the first 10
2303
+ * non-system, non-PK fields to give users something reasonable to start with.
2304
+ */
2305
+ getDefaultFieldsFallback(entity) {
2306
+ return entity.Fields
2307
+ .filter(f => !f.Name.startsWith('__mj_') &&
2308
+ !(f.IsPrimaryKey && f.SQLFullType?.toLowerCase() === 'uniqueidentifier') &&
2309
+ (f.Length <= 500 || f.Length < 0) // Exclude very long text unless nvarchar(max)
2310
+ )
2311
+ .slice(0, 10);
2312
+ }
2313
+ /**
2314
+ * Sort fields by importance for better default column ordering.
2315
+ * Name fields first, then status/type, then other fields, with system fields last.
2316
+ */
2317
+ sortFieldsByImportance(fields) {
2318
+ return [...fields].sort((a, b) => {
2319
+ const priorityA = this.getFieldPriority(a);
2320
+ const priorityB = this.getFieldPriority(b);
2321
+ return priorityA - priorityB;
2322
+ });
2323
+ }
2324
+ getFieldPriority(field) {
2325
+ const nameLower = field.Name.toLowerCase();
2326
+ // Name fields first
2327
+ if (field.IsNameField)
2328
+ return 0;
2329
+ if (nameLower === 'name' || nameLower === 'title')
2330
+ return 1;
2331
+ // Status and type fields are important
2332
+ if (nameLower === 'status')
2333
+ return 2;
2334
+ if (nameLower === 'type' || nameLower === 'category')
2335
+ return 3;
2336
+ // Other name-like fields
2337
+ if (nameLower.endsWith('name') && !nameLower.endsWith('typename'))
2338
+ return 4;
2339
+ // Description fields
2340
+ if (nameLower.includes('description'))
2341
+ return 5;
2342
+ // Date fields
2343
+ if (field.TSType === 'Date')
2344
+ return 50;
2345
+ // Foreign keys (usually IDs pointing to other entities)
2346
+ if (field.RelatedEntityID)
2347
+ return 60;
2348
+ // Numbers
2349
+ if (field.TSType === 'number')
2350
+ return 70;
2351
+ // Booleans toward the end
2352
+ if (field.TSType === 'boolean')
2353
+ return 80;
2354
+ // Long text fields at the end
2355
+ if ((field.Length > 500 || field.Length < 0))
2356
+ return 90;
2357
+ // System fields last (though they should be filtered out already)
2358
+ if (field.Name.startsWith('__mj_'))
2359
+ return 100;
2360
+ // Default priority
2361
+ return 40;
2362
+ }
2363
+ /**
2364
+ * Build a tooltip for the column header showing field details.
2365
+ */
2366
+ buildHeaderTooltip(field) {
2367
+ const parts = [];
2368
+ // Show internal field name if different from display name
2369
+ if (field.DisplayName && field.DisplayName !== field.Name) {
2370
+ parts.push(`Field: ${field.Name}`);
2371
+ }
2372
+ // Show description if available
2373
+ if (field.Description) {
2374
+ parts.push(field.Description);
2375
+ }
2376
+ // Show type info
2377
+ const typeInfo = field.Type + (field.Length && field.Length > 0 ? `(${field.Length})` : '');
2378
+ parts.push(`Type: ${typeInfo}`);
2379
+ return parts.join('\n');
2380
+ }
1916
2381
  applyFieldFormatter(colDef, field, customFormat) {
1917
2382
  // Store type info for use in cell renderer
1918
2383
  const fieldType = field.TSType;
@@ -1938,6 +2403,22 @@ export class EntityDataGridComponent {
1938
2403
  (!extendedType && (fieldNameLower.includes('phone') ||
1939
2404
  fieldNameLower.includes('mobile') ||
1940
2405
  fieldNameLower.includes('fax')));
2406
+ // Check if this is a foreign key field (has a related entity)
2407
+ // Also check if this is a virtual display field that corresponds to an FK field
2408
+ let isForeignKey = !!field.RelatedEntityID;
2409
+ let fkField = field;
2410
+ let relatedEntityName = isForeignKey ? field.RelatedEntity : undefined;
2411
+ // If this field doesn't have RelatedEntityID but is virtual, check for a corresponding FK field
2412
+ // Pattern: for a field named "Category", look for "CategoryID" with RelatedEntityID
2413
+ if (!isForeignKey && field.IsVirtual && this._entityInfo) {
2414
+ const potentialFkFieldName = field.Name + 'ID';
2415
+ const correspondingFkField = this._entityInfo.Fields.find(f => f.Name.toLowerCase() === potentialFkFieldName.toLowerCase() && f.RelatedEntityID);
2416
+ if (correspondingFkField) {
2417
+ isForeignKey = true;
2418
+ fkField = correspondingFkField;
2419
+ relatedEntityName = correspondingFkField.RelatedEntity;
2420
+ }
2421
+ }
1941
2422
  // Apply alignment - use custom format alignment if provided, otherwise default to right for numbers
1942
2423
  const customAlign = customFormat?.align;
1943
2424
  if (customAlign) {
@@ -1962,6 +2443,40 @@ export class EntityDataGridComponent {
1962
2443
  if (params.value === null || params.value === undefined) {
1963
2444
  return '<span class="cell-empty">—</span>';
1964
2445
  }
2446
+ // Handle foreign key fields - render as clickable links
2447
+ // Only apply FK rendering if no custom format is specified
2448
+ if (isForeignKey && !customFormat && fkField?.RelatedEntityID) {
2449
+ // For virtual display fields, we show the display value but link to the FK value
2450
+ // For direct FK fields, the value IS the FK value
2451
+ const isVirtualDisplay = field.IsVirtual && fkField !== field;
2452
+ const displayValue = String(params.value);
2453
+ // Get the actual FK value - for virtual fields, look it up from row data
2454
+ let fkValue;
2455
+ if (isVirtualDisplay && params.data) {
2456
+ // Get the FK value from the corresponding FK field in the row data
2457
+ fkValue = String(params.data[fkField.Name] ?? '');
2458
+ }
2459
+ else {
2460
+ fkValue = displayValue;
2461
+ }
2462
+ // Skip if we don't have a valid FK value
2463
+ if (!fkValue) {
2464
+ return `<span>${HighlightUtil.escapeHtml(displayValue)}</span>`;
2465
+ }
2466
+ const escapedDisplayValue = HighlightUtil.escapeHtml(displayValue);
2467
+ const escapedFieldName = HighlightUtil.escapeHtml(fkField.Name);
2468
+ const escapedRelatedEntityId = HighlightUtil.escapeHtml(fkField.RelatedEntityID);
2469
+ const escapedRelatedEntityName = relatedEntityName ? HighlightUtil.escapeHtml(relatedEntityName) : '';
2470
+ // Build data attributes for the click handler
2471
+ const dataAttrs = `data-related-entity-id="${escapedRelatedEntityId}" data-record-id="${fkValue}" data-field-name="${escapedFieldName}"${relatedEntityName ? ` data-related-entity-name="${escapedRelatedEntityName}"` : ''}`;
2472
+ // Apply highlighting if filter text is set
2473
+ const displayText = this._filterText
2474
+ ? HighlightUtil.highlight(displayValue, this._filterText, true)
2475
+ : escapedDisplayValue;
2476
+ // NOTE: Do NOT add onclick="event.stopPropagation()" here - it prevents AG Grid's cellClicked from firing
2477
+ const linkHtml = `<a href="javascript:void(0)" class="cell-link cell-fk-link" ${dataAttrs}>${displayText}</a>`;
2478
+ return linkHtml;
2479
+ }
1965
2480
  let displayValue = '';
1966
2481
  let extraClass = '';
1967
2482
  let inlineStyle = '';
@@ -2348,20 +2863,36 @@ export class EntityDataGridComponent {
2348
2863
  }
2349
2864
  }
2350
2865
  this.loading = true;
2866
+ this._aggregatesLoading = true;
2351
2867
  this.errorMessage = '';
2352
2868
  this.cdr.detectChanges();
2353
2869
  const startTime = performance.now();
2354
2870
  try {
2871
+ // Build aggregate expressions from config if present
2872
+ // Use EffectiveAggregatesConfig to check both _aggregatesConfig and _gridState.aggregates
2873
+ const effectiveAggConfig = this.EffectiveAggregatesConfig;
2874
+ let aggregateExpressions;
2875
+ if (effectiveAggConfig?.expressions?.length) {
2876
+ aggregateExpressions = effectiveAggConfig.expressions
2877
+ .filter(agg => agg.enabled !== false && agg.expression)
2878
+ .map(agg => ({
2879
+ expression: agg.expression,
2880
+ alias: agg.id || agg.label || agg.expression
2881
+ }));
2882
+ }
2355
2883
  const rv = new RunView();
2356
2884
  const result = await rv.RunView({
2357
2885
  ...runViewParams,
2358
- ResultType: 'entity_object'
2886
+ ResultType: 'entity_object',
2887
+ Aggregates: aggregateExpressions
2359
2888
  });
2360
2889
  const loadTimeMs = performance.now() - startTime;
2361
2890
  if (result.Success) {
2362
2891
  this._allData = result.Results || [];
2363
2892
  this.totalRowCount = result.TotalRowCount || this._allData.length;
2364
2893
  this.processData();
2894
+ // Process aggregate results
2895
+ this.processAggregateResults(result.AggregateResults, result.AggregateExecutionTime);
2365
2896
  // Reapply sort state to grid after data load to maintain visual indicators
2366
2897
  // Use Promise.resolve() to defer until after Angular's change detection cycle
2367
2898
  // has completed and AG Grid has processed the new row data
@@ -2557,6 +3088,39 @@ export class EntityDataGridComponent {
2557
3088
  });
2558
3089
  this.cdr.detectChanges();
2559
3090
  }
3091
+ /**
3092
+ * Process aggregate results from RunView and emit the AggregatesLoaded event.
3093
+ * Builds the value map for easy lookup by expression or id.
3094
+ */
3095
+ processAggregateResults(results, executionTime) {
3096
+ this._aggregatesLoading = false;
3097
+ if (!results || results.length === 0) {
3098
+ this._aggregateResults = [];
3099
+ this._aggregateValues.clear();
3100
+ return;
3101
+ }
3102
+ this._aggregateResults = results;
3103
+ this._aggregateValues.clear();
3104
+ // Build the values map, keyed by alias (which is set to id or expression)
3105
+ for (const result of results) {
3106
+ if (!result.error) {
3107
+ this._aggregateValues.set(result.alias, result.value);
3108
+ }
3109
+ }
3110
+ // Also map by expression for easy lookup
3111
+ for (const result of results) {
3112
+ if (!result.error && result.expression !== result.alias) {
3113
+ this._aggregateValues.set(result.expression, result.value);
3114
+ }
3115
+ }
3116
+ // Emit the aggregates loaded event
3117
+ this.AggregatesLoaded.emit({
3118
+ results: this._aggregateResults,
3119
+ values: this._aggregateValues,
3120
+ executionTime
3121
+ });
3122
+ this.cdr.detectChanges();
3123
+ }
2560
3124
  getRowKey(entity) {
2561
3125
  // Use composite key if available
2562
3126
  if (entity.PrimaryKey) {
@@ -2658,6 +3222,41 @@ export class EntityDataGridComponent {
2658
3222
  this.emitNavigationRequest(rowData.entity, pkString);
2659
3223
  }
2660
3224
  }
3225
+ /**
3226
+ * Handles cell click events to detect FK link clicks.
3227
+ * When a user clicks on a foreign key link, emits ForeignKeyClick event
3228
+ * for the parent component to handle navigation.
3229
+ */
3230
+ onAgCellClicked(event) {
3231
+ // Check if the click was on an FK link
3232
+ const target = event.event?.target;
3233
+ if (!target) {
3234
+ return;
3235
+ }
3236
+ // Look for the FK link element (may be the target or a parent)
3237
+ const fkLink = target.closest('.cell-fk-link');
3238
+ if (!fkLink) {
3239
+ return;
3240
+ }
3241
+ // Prevent the row click handler from firing
3242
+ event.event?.stopPropagation();
3243
+ // Extract FK data from data attributes
3244
+ const relatedEntityId = fkLink.dataset['relatedEntityId'];
3245
+ const recordId = fkLink.dataset['recordId'];
3246
+ const fieldName = fkLink.dataset['fieldName'];
3247
+ const relatedEntityName = fkLink.dataset['relatedEntityName'];
3248
+ if (relatedEntityId && recordId && fieldName) {
3249
+ this.ForeignKeyClick.emit({
3250
+ relatedEntityId,
3251
+ recordId,
3252
+ fieldName,
3253
+ relatedEntityName
3254
+ });
3255
+ }
3256
+ else {
3257
+ //console.log('[FK Debug] Missing required data attributes, not emitting');
3258
+ }
3259
+ }
2661
3260
  /**
2662
3261
  * Emits a navigation request for the given entity record.
2663
3262
  */
@@ -2829,7 +3428,8 @@ export class EntityDataGridComponent {
2829
3428
  // Build the grid state JSON matching ViewGridState format
2830
3429
  const gridStateJson = {
2831
3430
  columnSettings: state.columnSettings,
2832
- sortSettings: state.sortSettings
3431
+ sortSettings: state.sortSettings,
3432
+ aggregates: state.aggregates
2833
3433
  };
2834
3434
  // Update the view entity's GridState
2835
3435
  this._viewEntity.GridState = JSON.stringify(gridStateJson);
@@ -2927,7 +3527,12 @@ export class EntityDataGridComponent {
2927
3527
  field: s.field,
2928
3528
  dir: s.dir
2929
3529
  }));
2930
- return { columnSettings, sortSettings };
3530
+ // Include current aggregates config in the state
3531
+ return {
3532
+ columnSettings,
3533
+ sortSettings,
3534
+ aggregates: this._aggregatesConfig || this._gridState?.aggregates
3535
+ };
2931
3536
  }
2932
3537
  applySortStateToGrid() {
2933
3538
  if (!this.gridApi || this._sortState.length === 0) {
@@ -3554,21 +4159,25 @@ export class EntityDataGridComponent {
3554
4159
  } if (rf & 2) {
3555
4160
  let _t;
3556
4161
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.gridContainer = _t.first);
3557
- } }, inputs: { Params: "Params", AllowLoad: "AllowLoad", AutoRefreshOnParamsChange: "AutoRefreshOnParamsChange", PaginationMode: "PaginationMode", PageSize: "PageSize", CacheBlockSize: "CacheBlockSize", MaxBlocksInCache: "MaxBlocksInCache", Data: "Data", Columns: "Columns", GridState: "GridState", AllowColumnReorder: "AllowColumnReorder", AllowColumnResize: "AllowColumnResize", AllowColumnToggle: "AllowColumnToggle", ShowHeader: "ShowHeader", AllowSorting: "AllowSorting", AllowMultiSort: "AllowMultiSort", ServerSideSorting: "ServerSideSorting", AllowColumnFilters: "AllowColumnFilters", ShowSearch: "ShowSearch", SelectionMode: "SelectionMode", SelectedKeys: "SelectedKeys", KeyField: "KeyField", EditMode: "EditMode", AllowAdd: "AllowAdd", AllowDelete: "AllowDelete", Height: "Height", RowHeight: "RowHeight", VirtualScroll: "VirtualScroll", ShowRowNumbers: "ShowRowNumbers", Striped: "Striped", GridLines: "GridLines", VisualConfig: "VisualConfig", ShowToolbar: "ShowToolbar", ToolbarConfig: "ToolbarConfig", StateKey: "StateKey", AutoPersistState: "AutoPersistState", StatePersistDebounce: "StatePersistDebounce", RefreshDebounce: "RefreshDebounce", FilterText: "FilterText", ShowNewButton: "ShowNewButton", ShowRefreshButton: "ShowRefreshButton", ShowExportButton: "ShowExportButton", ShowDeleteButton: "ShowDeleteButton", ShowCompareButton: "ShowCompareButton", ShowMergeButton: "ShowMergeButton", ShowAddToListButton: "ShowAddToListButton", ShowDuplicateSearchButton: "ShowDuplicateSearchButton", ShowCommunicationButton: "ShowCommunicationButton", AutoNavigate: "AutoNavigate", NavigateOnDoubleClick: "NavigateOnDoubleClick", CreateRecordMode: "CreateRecordMode", NewRecordValues: "NewRecordValues", ShowEntityActionButtons: "ShowEntityActionButtons", EntityActions: "EntityActions" }, outputs: { BeforeRowSelect: "BeforeRowSelect", AfterRowSelect: "AfterRowSelect", BeforeRowDeselect: "BeforeRowDeselect", AfterRowDeselect: "AfterRowDeselect", SelectionChange: "SelectionChange", BeforeRowClick: "BeforeRowClick", AfterRowClick: "AfterRowClick", BeforeRowDoubleClick: "BeforeRowDoubleClick", AfterRowDoubleClick: "AfterRowDoubleClick", BeforeCellEdit: "BeforeCellEdit", AfterCellEditBegin: "AfterCellEditBegin", BeforeCellEditCommit: "BeforeCellEditCommit", AfterCellEditCommit: "AfterCellEditCommit", BeforeCellEditCancel: "BeforeCellEditCancel", AfterCellEditCancel: "AfterCellEditCancel", BeforeRowSave: "BeforeRowSave", AfterRowSave: "AfterRowSave", BeforeRowDelete: "BeforeRowDelete", AfterRowDelete: "AfterRowDelete", BeforeDataLoad: "BeforeDataLoad", AfterDataLoad: "AfterDataLoad", BeforeDataRefresh: "BeforeDataRefresh", AfterDataRefresh: "AfterDataRefresh", BeforeSort: "BeforeSort", AfterSort: "AfterSort", BeforeColumnReorder: "BeforeColumnReorder", AfterColumnReorder: "AfterColumnReorder", BeforeColumnResize: "BeforeColumnResize", AfterColumnResize: "AfterColumnResize", BeforeColumnVisibilityChange: "BeforeColumnVisibilityChange", AfterColumnVisibilityChange: "AfterColumnVisibilityChange", GridStateChanged: "GridStateChanged", AddRequested: "AddRequested", DeleteRequested: "DeleteRequested", ExportRequested: "ExportRequested", NewButtonClick: "NewButtonClick", RefreshButtonClick: "RefreshButtonClick", ExportButtonClick: "ExportButtonClick", DeleteButtonClick: "DeleteButtonClick", CompareButtonClick: "CompareButtonClick", MergeButtonClick: "MergeButtonClick", AddToListButtonClick: "AddToListButtonClick", DuplicateSearchButtonClick: "DuplicateSearchButtonClick", CommunicationButtonClick: "CommunicationButtonClick", NavigationRequested: "NavigationRequested", NewRecordDialogRequested: "NewRecordDialogRequested", NewRecordTabRequested: "NewRecordTabRequested", CompareRecordsRequested: "CompareRecordsRequested", MergeRecordsRequested: "MergeRecordsRequested", CommunicationRequested: "CommunicationRequested", DuplicateSearchRequested: "DuplicateSearchRequested", AddToListRequested: "AddToListRequested", LoadEntityActionsRequested: "LoadEntityActionsRequested", EntityActionRequested: "EntityActionRequested" }, decls: 10, vars: 12, consts: [["gridContainer", ""], ["class", "mj-grid-toolbar", 4, "ngIf"], [1, "mj-grid-content"], ["class", "mj-grid-loading-overlay", 4, "ngIf"], ["class", "mj-grid-error", 4, "ngIf"], ["class", "mj-grid-empty", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize", "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], [3, "closed", "visible", "config"], [1, "mj-grid-toolbar"], [1, "toolbar-left"], ["class", "toolbar-search", 4, "ngIf"], [4, "ngFor", "ngForOf"], [1, "toolbar-center"], ["class", "row-count", 4, "ngIf"], ["class", "selection-count", 4, "ngIf"], [1, "toolbar-right"], ["class", "toolbar-button", "title", "Create new record", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh data", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export to Excel", 3, "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete selected records", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Compare selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Merge selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add selected records to a list", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Search for duplicate records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Send message to selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add New", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete Selected", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Column Chooser", 3, "click", 4, "ngIf"], ["class", "toolbar-overflow", 3, "click", 4, "ngIf"], [1, "toolbar-search"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", 1, "search-input", 3, "input", "placeholder", "value"], ["class", "search-clear", 3, "click", 4, "ngIf"], [1, "search-clear", 3, "click"], [1, "fa-solid", "fa-times"], ["class", "toolbar-button", 3, "class", "disabled", "title", "click", 4, "ngIf"], [1, "toolbar-button", 3, "click", "disabled", "title"], [3, "class", 4, "ngIf"], [4, "ngIf"], [1, "row-count"], [1, "selection-count"], ["title", "Create new record", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "button-text"], ["title", "Refresh data", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-arrows-rotate"], ["title", "Export to Excel", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-file-excel"], ["title", "Delete selected records", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["title", "Compare selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-compare"], ["title", "Merge selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-merge"], ["title", "Add selected records to a list", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-list-check"], ["title", "Search for duplicate records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-magnifying-glass-plus"], ["title", "Send message to selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-envelope"], ["title", "Add New", 1, "toolbar-button", 3, "click"], ["title", "Refresh", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], ["title", "Delete Selected", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], ["title", "Export", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-download"], ["title", "Column Chooser", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-columns"], [1, "toolbar-overflow", 3, "click"], ["title", "More actions", 1, "toolbar-button", "overflow-trigger", 3, "click"], [1, "fa-solid", "fa-ellipsis-vertical"], ["class", "overflow-menu", 4, "ngIf"], [1, "overflow-menu"], ["class", "overflow-item", 3, "click", 4, "ngIf"], ["class", "overflow-divider", 4, "ngIf"], [1, "overflow-item", 3, "click"], [1, "overflow-divider"], [1, "overflow-section-label"], ["class", "overflow-item", 3, "disabled", "click", 4, "ngFor", "ngForOf"], [1, "overflow-item", 3, "click", "disabled"], [1, "mj-grid-loading-overlay"], ["text", "Loading..."], [1, "mj-grid-error"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "error-retry", 3, "click"], [1, "mj-grid-empty"], [1, "fa-solid", "fa-inbox"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize"]], template: function EntityDataGridComponent_Template(rf, ctx) { if (rf & 1) {
4162
+ } }, inputs: { Params: "Params", AllowLoad: "AllowLoad", AutoRefreshOnParamsChange: "AutoRefreshOnParamsChange", PaginationMode: "PaginationMode", PageSize: "PageSize", CacheBlockSize: "CacheBlockSize", MaxBlocksInCache: "MaxBlocksInCache", Data: "Data", Columns: "Columns", GridState: "GridState", AllowColumnReorder: "AllowColumnReorder", AllowColumnResize: "AllowColumnResize", AllowColumnToggle: "AllowColumnToggle", ShowHeader: "ShowHeader", AllowSorting: "AllowSorting", AllowMultiSort: "AllowMultiSort", ServerSideSorting: "ServerSideSorting", AllowColumnFilters: "AllowColumnFilters", ShowSearch: "ShowSearch", SelectionMode: "SelectionMode", SelectedKeys: "SelectedKeys", KeyField: "KeyField", EditMode: "EditMode", AllowAdd: "AllowAdd", AllowDelete: "AllowDelete", Height: "Height", RowHeight: "RowHeight", WrapText: "WrapText", VirtualScroll: "VirtualScroll", ShowRowNumbers: "ShowRowNumbers", Striped: "Striped", GridLines: "GridLines", VisualConfig: "VisualConfig", ShowToolbar: "ShowToolbar", ToolbarConfig: "ToolbarConfig", StateKey: "StateKey", AutoPersistState: "AutoPersistState", StatePersistDebounce: "StatePersistDebounce", RefreshDebounce: "RefreshDebounce", FilterText: "FilterText", ShowNewButton: "ShowNewButton", ShowRefreshButton: "ShowRefreshButton", ShowExportButton: "ShowExportButton", ShowDeleteButton: "ShowDeleteButton", ShowCompareButton: "ShowCompareButton", ShowMergeButton: "ShowMergeButton", ShowAddToListButton: "ShowAddToListButton", ShowDuplicateSearchButton: "ShowDuplicateSearchButton", ShowCommunicationButton: "ShowCommunicationButton", AutoNavigate: "AutoNavigate", NavigateOnDoubleClick: "NavigateOnDoubleClick", CreateRecordMode: "CreateRecordMode", NewRecordValues: "NewRecordValues", ShowEntityActionButtons: "ShowEntityActionButtons", EntityActions: "EntityActions", AggregatesConfig: "AggregatesConfig" }, outputs: { AggregatesLoaded: "AggregatesLoaded", BeforeRowSelect: "BeforeRowSelect", AfterRowSelect: "AfterRowSelect", BeforeRowDeselect: "BeforeRowDeselect", AfterRowDeselect: "AfterRowDeselect", SelectionChange: "SelectionChange", BeforeRowClick: "BeforeRowClick", AfterRowClick: "AfterRowClick", BeforeRowDoubleClick: "BeforeRowDoubleClick", AfterRowDoubleClick: "AfterRowDoubleClick", ForeignKeyClick: "ForeignKeyClick", BeforeCellEdit: "BeforeCellEdit", AfterCellEditBegin: "AfterCellEditBegin", BeforeCellEditCommit: "BeforeCellEditCommit", AfterCellEditCommit: "AfterCellEditCommit", BeforeCellEditCancel: "BeforeCellEditCancel", AfterCellEditCancel: "AfterCellEditCancel", BeforeRowSave: "BeforeRowSave", AfterRowSave: "AfterRowSave", BeforeRowDelete: "BeforeRowDelete", AfterRowDelete: "AfterRowDelete", BeforeDataLoad: "BeforeDataLoad", AfterDataLoad: "AfterDataLoad", BeforeDataRefresh: "BeforeDataRefresh", AfterDataRefresh: "AfterDataRefresh", BeforeSort: "BeforeSort", AfterSort: "AfterSort", BeforeColumnReorder: "BeforeColumnReorder", AfterColumnReorder: "AfterColumnReorder", BeforeColumnResize: "BeforeColumnResize", AfterColumnResize: "AfterColumnResize", BeforeColumnVisibilityChange: "BeforeColumnVisibilityChange", AfterColumnVisibilityChange: "AfterColumnVisibilityChange", GridStateChanged: "GridStateChanged", AddRequested: "AddRequested", DeleteRequested: "DeleteRequested", ExportRequested: "ExportRequested", NewButtonClick: "NewButtonClick", RefreshButtonClick: "RefreshButtonClick", ExportButtonClick: "ExportButtonClick", DeleteButtonClick: "DeleteButtonClick", CompareButtonClick: "CompareButtonClick", MergeButtonClick: "MergeButtonClick", AddToListButtonClick: "AddToListButtonClick", DuplicateSearchButtonClick: "DuplicateSearchButtonClick", CommunicationButtonClick: "CommunicationButtonClick", NavigationRequested: "NavigationRequested", NewRecordDialogRequested: "NewRecordDialogRequested", NewRecordTabRequested: "NewRecordTabRequested", CompareRecordsRequested: "CompareRecordsRequested", MergeRecordsRequested: "MergeRecordsRequested", CommunicationRequested: "CommunicationRequested", DuplicateSearchRequested: "DuplicateSearchRequested", AddToListRequested: "AddToListRequested", LoadEntityActionsRequested: "LoadEntityActionsRequested", EntityActionRequested: "EntityActionRequested" }, decls: 12, vars: 14, consts: [["gridContainer", ""], ["class", "mj-grid-toolbar", 4, "ngIf"], ["class", "mj-aggregate-cards", 4, "ngIf"], [1, "mj-grid-content"], ["class", "mj-grid-loading-overlay", 4, "ngIf"], ["class", "mj-grid-error", 4, "ngIf"], ["class", "mj-grid-empty", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "gridReady", "cellClicked", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], ["class", "mj-ag-grid ag-theme-alpine", 3, "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize", "gridReady", "cellClicked", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", 4, "ngIf"], ["class", "mj-aggregate-summary", 4, "ngIf"], [3, "closed", "visible", "config"], [1, "mj-grid-toolbar"], [1, "toolbar-left"], ["class", "toolbar-search", 4, "ngIf"], [4, "ngFor", "ngForOf"], [1, "toolbar-center"], ["class", "row-count", 4, "ngIf"], ["class", "selection-count", 4, "ngIf"], [1, "toolbar-right"], ["class", "toolbar-button", "title", "Create new record", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh data", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export to Excel", 3, "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete selected records", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Compare selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Merge selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add selected records to a list", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Search for duplicate records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Send message to selected records", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Add New", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Refresh", 3, "disabled", "click", 4, "ngIf"], ["class", "toolbar-button toolbar-button-danger", "title", "Delete Selected", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Export", 3, "click", 4, "ngIf"], ["class", "toolbar-button", "title", "Column Chooser", 3, "click", 4, "ngIf"], ["class", "toolbar-overflow", 3, "click", 4, "ngIf"], [1, "toolbar-search"], [1, "fa-solid", "fa-search", "search-icon"], ["type", "text", 1, "search-input", 3, "input", "placeholder", "value"], ["class", "search-clear", 3, "click", 4, "ngIf"], [1, "search-clear", 3, "click"], [1, "fa-solid", "fa-times"], ["class", "toolbar-button", 3, "class", "disabled", "title", "click", 4, "ngIf"], [1, "toolbar-button", 3, "click", "disabled", "title"], [3, "class", 4, "ngIf"], [4, "ngIf"], [1, "row-count"], [1, "selection-count"], ["title", "Create new record", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "button-text"], ["title", "Refresh data", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-arrows-rotate"], ["title", "Export to Excel", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-file-excel"], ["title", "Delete selected records", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], [1, "fa-solid", "fa-trash"], ["title", "Compare selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-compare"], ["title", "Merge selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-code-merge"], ["title", "Add selected records to a list", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-list-check"], ["title", "Search for duplicate records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-magnifying-glass-plus"], ["title", "Send message to selected records", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-envelope"], ["title", "Add New", 1, "toolbar-button", 3, "click"], ["title", "Refresh", 1, "toolbar-button", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], ["title", "Delete Selected", 1, "toolbar-button", "toolbar-button-danger", 3, "click"], ["title", "Export", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-download"], ["title", "Column Chooser", 1, "toolbar-button", 3, "click"], [1, "fa-solid", "fa-columns"], [1, "toolbar-overflow", 3, "click"], ["title", "More actions", 1, "toolbar-button", "overflow-trigger", 3, "click"], [1, "fa-solid", "fa-ellipsis-vertical"], ["class", "overflow-menu", 4, "ngIf"], [1, "overflow-menu"], ["class", "overflow-item", 3, "click", 4, "ngIf"], ["class", "overflow-divider", 4, "ngIf"], [1, "overflow-item", 3, "click"], [1, "overflow-divider"], [1, "overflow-section-label"], ["class", "overflow-item", 3, "disabled", "click", 4, "ngFor", "ngForOf"], [1, "overflow-item", 3, "click", "disabled"], [1, "mj-aggregate-cards"], ["class", "aggregate-card-loading", 4, "ngIf"], [1, "aggregate-card"], ["class", "aggregate-card-icon", 4, "ngIf"], [1, "aggregate-card-content"], [1, "aggregate-card-label"], [1, "aggregate-card-value"], [1, "aggregate-card-icon"], [1, "aggregate-card-loading"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "mj-grid-loading-overlay"], ["text", "Loading..."], [1, "mj-grid-error"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "error-retry", 3, "click"], [1, "mj-grid-empty"], [1, "fa-solid", "fa-inbox"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "cellClicked", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "rowData", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight"], [1, "mj-ag-grid", "ag-theme-alpine", 3, "gridReady", "cellClicked", "rowClicked", "rowDoubleClicked", "sortChanged", "selectionChanged", "columnResized", "columnMoved", "theme", "columnDefs", "defaultColDef", "rowSelection", "getRowId", "suppressCellFocus", "rowHeight", "headerHeight", "rowModelType", "cacheBlockSize", "maxBlocksInCache", "infiniteInitialRowCount", "cacheOverflowSize"], [1, "mj-aggregate-summary"], [1, "aggregate-summary-content"], ["class", "aggregate-loading", 4, "ngIf"], [1, "aggregate-summary-item"], [1, "agg-summary-label"], [1, "agg-summary-value"], [1, "aggregate-loading"]], template: function EntityDataGridComponent_Template(rf, ctx) { if (rf & 1) {
3558
4163
  const _r1 = i0.ɵɵgetCurrentView();
3559
4164
  i0.ɵɵelementStart(0, "div", null, 0);
3560
- i0.ɵɵtemplate(2, EntityDataGridComponent_div_2_Template, 24, 20, "div", 1);
3561
- i0.ɵɵelementStart(3, "div", 2);
3562
- i0.ɵɵtemplate(4, EntityDataGridComponent_div_4_Template, 2, 0, "div", 3)(5, EntityDataGridComponent_div_5_Template, 6, 1, "div", 4)(6, EntityDataGridComponent_div_6_Template, 4, 0, "div", 5)(7, EntityDataGridComponent_ag_grid_angular_7_Template, 1, 9, "ag-grid-angular", 6)(8, EntityDataGridComponent_ag_grid_angular_8_Template, 1, 13, "ag-grid-angular", 7);
3563
- i0.ɵɵelementEnd()();
3564
- i0.ɵɵelementStart(9, "mj-export-dialog", 8);
3565
- i0.ɵɵlistener("closed", function EntityDataGridComponent_Template_mj_export_dialog_closed_9_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onExportDialogClosed($event)); });
4165
+ i0.ɵɵtemplate(2, EntityDataGridComponent_div_2_Template, 24, 20, "div", 1)(3, EntityDataGridComponent_div_3_Template, 3, 2, "div", 2);
4166
+ i0.ɵɵelementStart(4, "div", 3);
4167
+ i0.ɵɵtemplate(5, EntityDataGridComponent_div_5_Template, 2, 0, "div", 4)(6, EntityDataGridComponent_div_6_Template, 6, 1, "div", 5)(7, EntityDataGridComponent_div_7_Template, 4, 0, "div", 6)(8, EntityDataGridComponent_ag_grid_angular_8_Template, 1, 9, "ag-grid-angular", 7)(9, EntityDataGridComponent_ag_grid_angular_9_Template, 1, 13, "ag-grid-angular", 8);
4168
+ i0.ɵɵelementEnd();
4169
+ i0.ɵɵtemplate(10, EntityDataGridComponent_div_10_Template, 4, 2, "div", 9);
4170
+ i0.ɵɵelementEnd();
4171
+ i0.ɵɵelementStart(11, "mj-export-dialog", 10);
4172
+ i0.ɵɵlistener("closed", function EntityDataGridComponent_Template_mj_export_dialog_closed_11_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onExportDialogClosed($event)); });
3566
4173
  i0.ɵɵelementEnd();
3567
4174
  } if (rf & 2) {
3568
4175
  i0.ɵɵclassMap(ctx.gridContainerClasses.join(" "));
3569
4176
  i0.ɵɵstyleProp("height", ctx.gridHeightStyle);
3570
4177
  i0.ɵɵadvance(2);
3571
4178
  i0.ɵɵproperty("ngIf", ctx.ShowToolbar);
4179
+ i0.ɵɵadvance();
4180
+ i0.ɵɵproperty("ngIf", ctx.ShowAggregatePanel);
3572
4181
  i0.ɵɵadvance(2);
3573
4182
  i0.ɵɵproperty("ngIf", ctx.loading && ctx.rowData.length === 0);
3574
4183
  i0.ɵɵadvance();
@@ -3580,8 +4189,10 @@ export class EntityDataGridComponent {
3580
4189
  i0.ɵɵadvance();
3581
4190
  i0.ɵɵproperty("ngIf", !ctx.errorMessage && ctx.PaginationMode === "infinite");
3582
4191
  i0.ɵɵadvance();
4192
+ i0.ɵɵproperty("ngIf", ctx.ShowAggregateSummary);
4193
+ i0.ɵɵadvance();
3583
4194
  i0.ɵɵproperty("visible", ctx.showExportDialog)("config", ctx.exportDialogConfig);
3584
- } }, dependencies: [i2.NgForOf, i2.NgIf, i3.AgGridAngular, i4.LoadingComponent, i1.ExportDialogComponent], styles: ["\n\n\n\n\n[_nghost-%COMP%] {\n \n\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n \n\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n \n\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n \n\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n \n\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n \n\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n \n\n --grid-sort-indicator-color: #2196F3;\n\n \n\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n \n\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n \n\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n\n\n\n\n\n.mj-grid-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n\n\n\n\n\n.mj-grid-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left[_ngcontent-%COMP%], \n.toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input[_ngcontent-%COMP%] {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear[_ngcontent-%COMP%]:hover {\n color: #666;\n}\n\n.toolbar-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%] {\n color: #d32f2f;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count[_ngcontent-%COMP%], \n.selection-count[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n\n\n\n\n\n.mj-grid-content[_ngcontent-%COMP%] {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container[_ngcontent-%COMP%] {\n height: 100%;\n overflow: auto;\n}\n\n\n\n\n\n\n.mj-grid-loading-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n\n\n\n\n\n.mj-grid-error[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n}\n\n.error-retry[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry[_ngcontent-%COMP%]:hover {\n background: #c62828;\n}\n\n\n\n\n\n\n.mj-grid-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n\n\n\n\n\n.mj-grid-header[_ngcontent-%COMP%] {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.sort-index[_ngcontent-%COMP%] {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n\n\n\n\n\n.mj-grid-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%] {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%] {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing[_ngcontent-%COMP%] {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty[_ngcontent-%COMP%] {\n border-left: 3px solid #ff9800;\n}\n\n\n\n\n\n\n.mj-grid-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n\n\n.grid-lines-horizontal[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n\n\n.mj-grid-cell.align-left[_ngcontent-%COMP%] {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center[_ngcontent-%COMP%] {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right[_ngcontent-%COMP%] {\n justify-content: flex-end;\n}\n\n.cell-content[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.row-number-cell[_ngcontent-%COMP%] {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell[_ngcontent-%COMP%] {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n\n\n\n\n\n.mj-grid-virtual-spacer[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n\n\n\n\n\n@media (max-width: 768px) {\n .mj-grid-toolbar[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search[_ngcontent-%COMP%] {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .toolbar-center[_ngcontent-%COMP%] {\n order: 2;\n }\n\n \n\n .toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n\n.toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n.toolbar-overflow[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.overflow-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.overflow-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label[_ngcontent-%COMP%] {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n\n\n.overflow-item.action-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196F3;\n}\n\n\n\n\n\n\n .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n\n\n\n\n\n.mj-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n .ag-theme-alpine {\n \n\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n \n\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n \n\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n\n\n .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n\n\n .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n\n\n\n\n\n\n\n.header-style-flat[_ngcontent-%COMP%] .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n\n\n.header-style-elevated[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n\n\n.header-style-gradient[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n\n\n .ag-header-cell-sorted-asc .ag-icon-asc, \n .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n\n\n\n\n\n\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n\n\n\n.hover-transitions[_ngcontent-%COMP%] .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions[_ngcontent-%COMP%] .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n\n\n\n\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n\n\n\n\n\n\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n\n\n\n\n\n\n\n .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n\n\n .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n\n\n .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n\n\n .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n\n\n .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n\n\n .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n\n\n .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row[_ngcontent-%COMP%] {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell[_ngcontent-%COMP%] {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: _ngcontent-%COMP%_skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short[_ngcontent-%COMP%] {\n width: 60px;\n}\n\n.skeleton-cell-medium[_ngcontent-%COMP%] {\n width: 120px;\n}\n\n.skeleton-cell-long[_ngcontent-%COMP%] {\n width: 180px;\n}\n\n\n\n .ag-header-select-all {\n margin-right: 0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n\n\n\n\n\n .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc {\n background: linear-gradient(180deg, rgba(25, 118, 210, 0.15) 0%, rgba(25, 118, 210, 0.08) 100%) !important;\n position: relative;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc {\n background: linear-gradient(180deg, rgba(216, 27, 96, 0.15) 0%, rgba(216, 27, 96, 0.08) 100%) !important;\n position: relative;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #1976d2;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #d81b60;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc .ag-header-cell-text {\n color: #1976d2 !important;\n font-weight: 700 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc .ag-header-cell-text {\n color: #d81b60 !important;\n font-weight: 700 !important;\n}\n\n\n\n\n\n[_nghost-%COMP%] .ag-sort-ascending-icon {\n color: #1976d2 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-sort-descending-icon {\n color: #d81b60 !important;\n}\n\n[_nghost-%COMP%] .ag-sort-ascending-icon .ag-icon, \n[_nghost-%COMP%] .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: #1976d2 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc .ag-sort-order {\n color: #d81b60 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n[_nghost-%COMP%] .ag-header-cell-sortable:hover .ag-header-cell-text {\n color: #1976d2;\n}"], data: { animation: [
4195
+ } }, dependencies: [i2.NgForOf, i2.NgIf, i3.AgGridAngular, i4.LoadingComponent, i1.ExportDialogComponent], styles: ["\n\n\n\n\n[_nghost-%COMP%] {\n \n\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n \n\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n \n\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n \n\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n \n\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n \n\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n \n\n --grid-sort-indicator-color: #2196F3;\n\n \n\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n \n\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n \n\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n\n\n\n\n\n.mj-grid-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n\n\n\n\n\n.mj-grid-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left[_ngcontent-%COMP%], \n.toolbar-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input[_ngcontent-%COMP%] {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear[_ngcontent-%COMP%]:hover {\n color: #666;\n}\n\n.toolbar-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%] {\n color: #d32f2f;\n}\n\n.toolbar-button-danger[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count[_ngcontent-%COMP%], \n.selection-count[_ngcontent-%COMP%] {\n font-weight: 500;\n}\n\n\n\n\n\n\n.mj-grid-content[_ngcontent-%COMP%] {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container[_ngcontent-%COMP%] {\n height: 100%;\n overflow: auto;\n}\n\n\n\n\n\n\n.mj-grid-loading-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n\n\n\n\n\n.mj-grid-error[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 32px;\n}\n\n.error-retry[_ngcontent-%COMP%] {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry[_ngcontent-%COMP%]:hover {\n background: #c62828;\n}\n\n\n\n\n\n\n.mj-grid-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n\n\n\n\n\n.mj-grid-header[_ngcontent-%COMP%] {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.sort-index[_ngcontent-%COMP%] {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n\n\n\n\n\n.mj-grid-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%] {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%] {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected[_ngcontent-%COMP%]:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing[_ngcontent-%COMP%] {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty[_ngcontent-%COMP%] {\n border-left: 3px solid #ff9800;\n}\n\n\n\n\n\n\n.mj-grid-cell[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell[_ngcontent-%COMP%]:last-child {\n border-right: none;\n}\n\n\n\n.grid-lines-horizontal[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-row[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both[_ngcontent-%COMP%] .mj-grid-cell[_ngcontent-%COMP%] {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n\n\n.mj-grid-cell.align-left[_ngcontent-%COMP%] {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center[_ngcontent-%COMP%] {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right[_ngcontent-%COMP%] {\n justify-content: flex-end;\n}\n\n.cell-content[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.row-number-cell[_ngcontent-%COMP%] {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell[_ngcontent-%COMP%] {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell[_ngcontent-%COMP%] input[type=\"checkbox\"][_ngcontent-%COMP%] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n\n\n\n\n\n.mj-grid-virtual-spacer[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n\n\n\n\n\n@media (max-width: 768px) {\n .mj-grid-toolbar[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search[_ngcontent-%COMP%] {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .toolbar-center[_ngcontent-%COMP%] {\n order: 2;\n }\n\n \n\n .toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n display: none;\n }\n}\n\n\n\n\n\n\n.toolbar-button[_ngcontent-%COMP%] .button-text[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n.toolbar-overflow[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.overflow-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n.overflow-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label[_ngcontent-%COMP%] {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n\n\n.overflow-item.action-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #2196F3;\n}\n\n\n\n\n\n\n .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n\n\n\n\n\n.mj-ag-grid[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n}\n\n .ag-theme-alpine {\n \n\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n \n\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n \n\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n\n\n .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n\n\n .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n\n\n\n\n\n\n\n.header-style-flat[_ngcontent-%COMP%] .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n\n\n.header-style-elevated[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n\n\n.header-style-gradient[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow[_ngcontent-%COMP%] .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold[_ngcontent-%COMP%] .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n\n\n .ag-header-cell-sorted-asc .ag-icon-asc, \n .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n\n\n\n\n\n\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong[_ngcontent-%COMP%] .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n\n\n\n\n\n.hover-transitions[_ngcontent-%COMP%] .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions[_ngcontent-%COMP%] .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n\n\n\n\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable[_ngcontent-%COMP%] .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n\n\n\n\n\n\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded[_ngcontent-%COMP%] .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled[_ngcontent-%COMP%] .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n\n\n\n\n\n\n\n .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n\n\n .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n\n\n .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n\n\n .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n\n\n .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n\n\n .cell-fk-link {\n color: var(--grid-accent-color, #1976D2);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.15s, text-decoration 0.15s;\n}\n\n .cell-fk-link:hover {\n color: #1565C0;\n text-decoration: underline;\n}\n\n .cell-fk-link:active {\n color: #0D47A1;\n}\n\n\n\n .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n\n\n .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n\n\n\n\n\n@keyframes _ngcontent-%COMP%_skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row[_ngcontent-%COMP%] {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell[_ngcontent-%COMP%] {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: _ngcontent-%COMP%_skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short[_ngcontent-%COMP%] {\n width: 60px;\n}\n\n.skeleton-cell-medium[_ngcontent-%COMP%] {\n width: 120px;\n}\n\n.skeleton-cell-long[_ngcontent-%COMP%] {\n width: 180px;\n}\n\n\n\n .ag-header-select-all {\n margin-right: 0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n\n\n\n\n\n .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n\n\n\n\n\n .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n\n\n .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}\n\n\n\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc {\n background: linear-gradient(180deg, rgba(25, 118, 210, 0.15) 0%, rgba(25, 118, 210, 0.08) 100%) !important;\n position: relative;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc {\n background: linear-gradient(180deg, rgba(216, 27, 96, 0.15) 0%, rgba(216, 27, 96, 0.08) 100%) !important;\n position: relative;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #1976d2;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #d81b60;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-asc .ag-header-cell-text {\n color: #1976d2 !important;\n font-weight: 700 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc .ag-header-cell-text {\n color: #d81b60 !important;\n font-weight: 700 !important;\n}\n\n\n\n\n\n[_nghost-%COMP%] .ag-sort-ascending-icon {\n color: #1976d2 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-sort-descending-icon {\n color: #d81b60 !important;\n}\n\n[_nghost-%COMP%] .ag-sort-ascending-icon .ag-icon, \n[_nghost-%COMP%] .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n\n\n\n\n\n\n\n\n[_nghost-%COMP%] .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: #1976d2 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sorted-desc .ag-sort-order {\n color: #d81b60 !important;\n}\n\n\n\n[_nghost-%COMP%] .ag-header-cell-sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n[_nghost-%COMP%] .ag-header-cell-sortable:hover .ag-header-cell-text {\n color: #1976d2;\n}\n\n\n\n\n\n\n.mj-aggregate-summary[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 16px;\n background: linear-gradient(to bottom, #f8fafc, #f1f5f9);\n border-top: 1px solid #e2e8f0;\n font-size: 13px;\n min-height: 44px;\n}\n\n.aggregate-summary-content[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 20px;\n align-items: center;\n}\n\n.aggregate-summary-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n}\n\n.aggregate-summary-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n color: #64748b;\n}\n\n.agg-summary-label[_ngcontent-%COMP%] {\n color: #64748b;\n font-weight: 500;\n}\n\n.agg-summary-value[_ngcontent-%COMP%] {\n color: #1e293b;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n}\n\n.aggregate-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n color: #94a3b8;\n}\n\n.aggregate-loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n\n\n\n\n\n\n.mj-aggregate-cards[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding: 12px 16px;\n background: linear-gradient(to bottom, #f8fafc, #f1f5f9);\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.aggregate-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);\n min-width: 140px;\n transition: all 0.15s ease;\n}\n\n.aggregate-card[_ngcontent-%COMP%]:hover {\n border-color: #cbd5e1;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);\n}\n\n.aggregate-card-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: linear-gradient(135deg, #e0f2fe 0%, #bae6fd 100%);\n border-radius: 10px;\n color: #0284c7;\n font-size: 16px;\n flex-shrink: 0;\n}\n\n.aggregate-card-content[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.aggregate-card-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n color: #64748b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.aggregate-card-value[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 700;\n color: #0f172a;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n.aggregate-card-loading[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n color: #94a3b8;\n}\n\n.aggregate-card-loading[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n\n\n\n\n\n\n\n .cell-wrap-text {\n white-space: normal !important;\n word-wrap: break-word;\n line-height: 1.4;\n padding-top: 8px !important;\n padding-bottom: 8px !important;\n}\n\n\n\n .ag-cell.cell-wrap-text {\n overflow: visible;\n text-overflow: clip;\n}\n\n\n\n .ag-row[style*=\"auto-height\"] {\n min-height: 40px;\n}"], data: { animation: [
3585
4196
  trigger('fadeIn', [
3586
4197
  transition(':enter', [
3587
4198
  style({ opacity: 0, transform: 'translateY(-8px)' }),
@@ -3605,7 +4216,7 @@ export class EntityDataGridComponent {
3605
4216
  animate('100ms ease-in', style({ opacity: 0, transform: 'translateY(-8px)' }))
3606
4217
  ])
3607
4218
  ])
3608
- ], template: "<!-- Grid Container -->\n<div\n #gridContainer\n [class]=\"gridContainerClasses.join(' ')\"\n [style.height]=\"gridHeightStyle\">\n\n <!-- Toolbar -->\n <div *ngIf=\"ShowToolbar\" class=\"mj-grid-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Search -->\n <div *ngIf=\"ShowSearch\" class=\"toolbar-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n [placeholder]=\"ToolbarConfig.searchPlaceholder || 'Search...'\"\n [value]=\"FilterText\"\n (input)=\"FilterText = $any($event.target).value\" />\n <button\n *ngIf=\"FilterText\"\n class=\"search-clear\"\n (click)=\"FilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Custom Left Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position !== 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n </div>\n\n <div class=\"toolbar-center\">\n <!-- Row Count -->\n <span *ngIf=\"ToolbarConfig.showRowCount !== false\" class=\"row-count\">\n {{ totalRowCount }} {{ totalRowCount === 1 ? 'row' : 'rows' }}\n </span>\n\n <!-- Selection Count -->\n <span *ngIf=\"ToolbarConfig.showSelectionCount && SelectedKeys.length > 0\" class=\"selection-count\">\n ({{ SelectedKeys.length }} selected)\n </span>\n </div>\n\n <div class=\"toolbar-right\">\n <!-- New/Add Button (predefined) -->\n <button\n *ngIf=\"ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Create new record\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span class=\"button-text\">New</span>\n </button>\n\n <!-- Refresh Button (predefined) -->\n <button\n *ngIf=\"ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh data\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"loading\"></i>\n <span class=\"button-text\">Refresh</span>\n </button>\n\n <!-- Export Button (predefined) -->\n <button\n *ngIf=\"ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export to Excel\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span class=\"button-text\">Export</span>\n </button>\n\n <!-- Delete Button (predefined) -->\n <button\n *ngIf=\"ShowDeleteButton && HasSelection\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete selected records\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n <span class=\"button-text\">Delete</span>\n </button>\n\n <!-- Compare Button (predefined) -->\n <button\n *ngIf=\"ShowCompareButton\"\n class=\"toolbar-button\"\n title=\"Compare selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onCompareClick()\">\n <i class=\"fa-solid fa-code-compare\"></i>\n <span class=\"button-text\">Compare</span>\n </button>\n\n <!-- Merge Button (predefined) -->\n <button\n *ngIf=\"ShowMergeButton\"\n class=\"toolbar-button\"\n title=\"Merge selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onMergeClick()\">\n <i class=\"fa-solid fa-code-merge\"></i>\n <span class=\"button-text\">Merge</span>\n </button>\n\n <!-- Add to List Button (predefined) -->\n <button\n *ngIf=\"ShowAddToListButton\"\n class=\"toolbar-button\"\n title=\"Add selected records to a list\"\n [disabled]=\"!HasSelection\"\n (click)=\"onAddToListClick()\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span class=\"button-text\">Add to List</span>\n </button>\n\n <!-- Search for Duplicates Button (predefined) -->\n <button\n *ngIf=\"ShowDuplicateSearchButton\"\n class=\"toolbar-button\"\n title=\"Search for duplicate records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onDuplicateSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass-plus\"></i>\n <span class=\"button-text\">Find Duplicates</span>\n </button>\n\n <!-- Communication Button (predefined) -->\n <button\n *ngIf=\"ShowCommunicationButton\"\n class=\"toolbar-button\"\n title=\"Send message to selected records\"\n [disabled]=\"!HasSelection\"\n (click)=\"onCommunicationClick()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span class=\"button-text\">Send Message</span>\n </button>\n\n <!-- Legacy ToolbarConfig buttons -->\n <!-- Add Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showAdd && AllowAdd && !ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Add New\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Refresh Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showRefresh !== false && !ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"loading\"></i>\n </button>\n\n <!-- Delete Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showDelete && AllowDelete && HasSelection && !ShowDeleteButton\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete Selected\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n\n <!-- Export Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showExport && !ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n\n <!-- Column Chooser Button -->\n <button\n *ngIf=\"ToolbarConfig.showColumnChooser && AllowColumnToggle\"\n class=\"toolbar-button\"\n title=\"Column Chooser\"\n (click)=\"onColumnChooserClick()\">\n <i class=\"fa-solid fa-columns\"></i>\n </button>\n\n <!-- Custom Right Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position === 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n\n <!-- Overflow Menu -->\n <div *ngIf=\"hasOverflowMenuItems\" class=\"toolbar-overflow\" (click)=\"$event.stopPropagation()\">\n <button\n class=\"toolbar-button overflow-trigger\"\n title=\"More actions\"\n (click)=\"toggleOverflowMenu()\">\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </button>\n\n <div *ngIf=\"showOverflowMenu\" class=\"overflow-menu\" [@fadeIn]>\n <!-- Export (if in overflow) -->\n <button *ngIf=\"showExportInOverflow\" class=\"overflow-item\" (click)=\"onExportClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span>Export to Excel</span>\n </button>\n\n <!-- Entity Actions -->\n <ng-container *ngIf=\"ShowEntityActionButtons && EntityActions.length > 0\">\n <div class=\"overflow-divider\"></div>\n <div class=\"overflow-section-label\">Actions</div>\n <button\n *ngFor=\"let action of EntityActions\"\n class=\"overflow-item\"\n [disabled]=\"!isEntityActionEnabled(action)\"\n (click)=\"onEntityActionClick(action); closeOverflowMenu()\">\n <i [class]=\"action.icon || 'fa-solid fa-bolt'\"></i>\n <span>{{ action.name }}</span>\n </button>\n </ng-container>\n\n <!-- Column Chooser (if in overflow) -->\n <div *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-divider\"></div>\n <button *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-item\" (click)=\"onColumnChooserClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-columns\"></i>\n <span>Manage Columns</span>\n </button>\n\n <!-- Selection-dependent actions in overflow -->\n <ng-container *ngIf=\"HasSelection && hasSelectionDependentOverflowActions\">\n <div class=\"overflow-divider\"></div>\n <button *ngIf=\"showCommunicationInOverflow\" class=\"overflow-item\" (click)=\"onCommunicationClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span>Send Message</span>\n </button>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Grid Content -->\n <div class=\"mj-grid-content\">\n <!-- Loading Overlay -->\n <div *ngIf=\"loading && rowData.length === 0\" class=\"mj-grid-loading-overlay\">\n <mj-loading text=\"Loading...\"></mj-loading>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !loading\" class=\"mj-grid-error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n <button class=\"error-retry\" (click)=\"Refresh()\">Retry</button>\n </div>\n\n <!-- Empty State -->\n <div *ngIf=\"!loading && !errorMessage && rowData.length === 0\" class=\"mj-grid-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No data to display</span>\n </div>\n\n <!-- AG Grid (Client-side mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'client' && (rowData.length > 0 || loading)\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [rowData]=\"rowData\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n\n <!-- AG Grid (Infinite Scroll mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'infinite'\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n [rowModelType]=\"'infinite'\"\n [cacheBlockSize]=\"CacheBlockSize\"\n [maxBlocksInCache]=\"MaxBlocksInCache\"\n [infiniteInitialRowCount]=\"1\"\n [cacheOverflowSize]=\"2\"\n (gridReady)=\"onGridReady($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n </div>\n</div>\n\n<!-- Export Dialog -->\n<mj-export-dialog\n [visible]=\"showExportDialog\"\n [config]=\"exportDialogConfig\"\n (closed)=\"onExportDialogClosed($event)\">\n</mj-export-dialog>\n", styles: ["/* ========================================\n CSS Custom Properties (Theme Variables)\n ======================================== */\n\n:host {\n /* Grid container */\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n /* Header */\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n /* Rows */\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n /* Cells */\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n /* Selection - mellow yellow to avoid conflict with blue hyperlinks */\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n /* Editing */\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n /* Sorting */\n --grid-sort-indicator-color: #2196F3;\n\n /* Toolbar */\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n /* Loading */\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n /* Empty state */\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n/* ========================================\n Grid Container\n ======================================== */\n\n.mj-grid-container {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.mj-grid-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear:hover {\n color: #666;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n.toolbar-button-danger {\n color: #d32f2f;\n}\n\n.toolbar-button-danger:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count,\n.selection-count {\n font-weight: 500;\n}\n\n/* ========================================\n Grid Content\n ======================================== */\n\n.mj-grid-content {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container {\n height: 100%;\n overflow: auto;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.mj-grid-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n/* ========================================\n Error State\n ======================================== */\n\n.mj-grid-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error i {\n font-size: 32px;\n}\n\n.error-retry {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry:hover {\n background: #c62828;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.mj-grid-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty i {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n/* ========================================\n Header Row\n ======================================== */\n\n.mj-grid-header {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator i {\n font-size: 12px;\n}\n\n.sort-index {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n/* ========================================\n Data Rows\n ======================================== */\n\n.mj-grid-row {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty {\n border-left: 3px solid #ff9800;\n}\n\n/* ========================================\n Data Cells\n ======================================== */\n\n.mj-grid-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell:last-child {\n border-right: none;\n}\n\n/* Grid lines modes */\n.grid-lines-horizontal .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n/* Cell alignment */\n.mj-grid-cell.align-left {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right {\n justify-content: flex-end;\n}\n\n.cell-content {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Special cells */\n.row-number-cell {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell input[type=\"checkbox\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n/* ========================================\n Virtual Scrolling\n ======================================== */\n\n.mj-grid-virtual-spacer {\n flex-shrink: 0;\n}\n\n/* ========================================\n Responsive Adjustments\n ======================================== */\n\n@media (max-width: 768px) {\n .mj-grid-toolbar {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input {\n width: 100%;\n }\n\n .toolbar-center {\n order: 2;\n }\n\n /* Hide button text on mobile */\n .toolbar-button .button-text {\n display: none;\n }\n}\n\n/* ========================================\n Toolbar Button Text\n ======================================== */\n\n.toolbar-button .button-text {\n font-size: 13px;\n}\n\n/* ========================================\n Overflow Menu\n ======================================== */\n\n.toolbar-overflow {\n position: relative;\n}\n\n.overflow-trigger {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger i {\n font-size: 16px;\n}\n\n.overflow-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item i {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item span {\n flex: 1;\n}\n\n.overflow-divider {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n/* Entity Actions submenu styling */\n.overflow-item.action-item i {\n color: #2196F3;\n}\n\n/* ========================================\n Highlight Matches\n ======================================== */\n\n::ng-deep .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n/* ========================================\n AG Grid Customizations\n ======================================== */\n\n.mj-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n::ng-deep .ag-theme-alpine {\n /* Row colors */\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n /* Selection accent colors - mellow yellow */\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n /* Ensure borders are visible */\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n/* Selected row styling - left indicator bar only, background handled by AG Grid theme */\n::ng-deep .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n/* Selection checkbox styling */\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n/* Row hover effect */\n::ng-deep .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n/* ========================================\n Visual Config: Header Styles\n ======================================== */\n\n/* Flat header (minimal) */\n.header-style-flat ::ng-deep .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n/* Elevated header (default - subtle shadow) */\n.header-style-elevated ::ng-deep .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n/* Gradient header (more prominent) */\n.header-style-gradient ::ng-deep .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n/* Bold header (high contrast) */\n.header-style-bold ::ng-deep .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold ::ng-deep .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold ::ng-deep .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold ::ng-deep .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n/* Header sort icons enhancement */\n::ng-deep .ag-header-cell-sorted-asc .ag-icon-asc,\n::ng-deep .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n/* ========================================\n Visual Config: Zebra Striping\n ======================================== */\n\n/* Subtle contrast */\n.alternate-rows-subtle ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Medium contrast (default) */\n.alternate-rows-medium ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Strong contrast */\n.alternate-rows-strong ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* ========================================\n Visual Config: Hover Transitions\n ======================================== */\n\n.hover-transitions ::ng-deep .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions ::ng-deep .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n/* ========================================\n Visual Config: Cell Padding\n ======================================== */\n\n.cell-padding-compact ::ng-deep .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact ::ng-deep .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal ::ng-deep .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal ::ng-deep .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n/* ========================================\n Visual Config: Checkbox Styles\n ======================================== */\n\n/* Rounded checkbox */\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n/* Filled checkbox */\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n/* ========================================\n Cell Content Formatting\n ======================================== */\n\n/* Right-aligned cells (numbers) */\n::ng-deep .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n::ng-deep .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n/* Empty cell placeholder */\n::ng-deep .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n/* Boolean icons */\n::ng-deep .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n::ng-deep .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n/* Clickable links */\n::ng-deep .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n::ng-deep .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n/* Email cells */\n::ng-deep .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n/* URL cells */\n::ng-deep .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n/* Phone cells */\n::ng-deep .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n/* ========================================\n Skeleton Loading Animation\n ======================================== */\n\n@keyframes skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short {\n width: 60px;\n}\n\n.skeleton-cell-medium {\n width: 120px;\n}\n\n.skeleton-cell-long {\n width: 180px;\n}\n\n/* Selection checkbox column header */\n::ng-deep .ag-header-select-all {\n margin-right: 0;\n}\n\n/* ========================================\n Row Border Enhancement\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n::ng-deep .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n/* ========================================\n Focus States\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n/* ========================================\n Pinned Column Styling\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n::ng-deep .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n/* ========================================\n Header Cell Enhancements\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n/* Sort icon animation */\n::ng-deep .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}\n\n/* ========================================\n Enhanced Multi-Sort Indicators\n These styles use :host to ensure they're scoped to this component\n and !important to override AG Grid's built-in styles\n ======================================== */\n\n/* Highlight sorted column headers with eye-catching background */\n/* Ascending = blue tint */\n:host ::ng-deep .ag-header-cell-sorted-asc {\n background: linear-gradient(180deg, rgba(25, 118, 210, 0.15) 0%, rgba(25, 118, 210, 0.08) 100%) !important;\n position: relative;\n}\n\n/* Descending = pink tint */\n:host ::ng-deep .ag-header-cell-sorted-desc {\n background: linear-gradient(180deg, rgba(216, 27, 96, 0.15) 0%, rgba(216, 27, 96, 0.08) 100%) !important;\n position: relative;\n}\n\n/* Bottom border accent for sorted columns - ascending = blue */\n:host ::ng-deep .ag-header-cell-sorted-asc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #1976d2;\n}\n\n/* Bottom border accent for sorted columns - descending = pink */\n:host ::ng-deep .ag-header-cell-sorted-desc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #d81b60;\n}\n\n/* Sorted column header text - ascending = blue, bold */\n:host ::ng-deep .ag-header-cell-sorted-asc .ag-header-cell-text {\n color: #1976d2 !important;\n font-weight: 700 !important;\n}\n\n/* Sorted column header text - descending = pink, bold */\n:host ::ng-deep .ag-header-cell-sorted-desc .ag-header-cell-text {\n color: #d81b60 !important;\n font-weight: 700 !important;\n}\n\n/* Sort icons - larger and more prominent */\n/* Ascending = blue */\n:host ::ng-deep .ag-sort-ascending-icon {\n color: #1976d2 !important;\n}\n\n/* Descending = pink/magenta */\n:host ::ng-deep .ag-sort-descending-icon {\n color: #d81b60 !important;\n}\n\n:host ::ng-deep .ag-sort-ascending-icon .ag-icon,\n:host ::ng-deep .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n/* Sort order number (1, 2, 3) - show as plain number, no bubble */\n/* This avoids AG Grid bug where .ag-sort-order is always present but empty when unsorted */\n/* The number is only visible when AG Grid populates it (i.e., when column is sorted) */\n/* Default blue for ascending */\n:host ::ng-deep .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: #1976d2 !important;\n}\n\n/* Sort order number - pink for descending */\n:host ::ng-deep .ag-header-cell-sorted-desc .ag-sort-order {\n color: #d81b60 !important;\n}\n\n/* Hover state for sortable headers */\n:host ::ng-deep .ag-header-cell-sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n:host ::ng-deep .ag-header-cell-sortable:hover .ag-header-cell-text {\n color: #1976d2;\n}\n"] }]
4219
+ ], template: "<!-- Grid Container -->\n<div\n #gridContainer\n [class]=\"gridContainerClasses.join(' ')\"\n [style.height]=\"gridHeightStyle\">\n\n <!-- Toolbar -->\n <div *ngIf=\"ShowToolbar\" class=\"mj-grid-toolbar\">\n <div class=\"toolbar-left\">\n <!-- Search -->\n <div *ngIf=\"ShowSearch\" class=\"toolbar-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n [placeholder]=\"ToolbarConfig.searchPlaceholder || 'Search...'\"\n [value]=\"FilterText\"\n (input)=\"FilterText = $any($event.target).value\" />\n <button\n *ngIf=\"FilterText\"\n class=\"search-clear\"\n (click)=\"FilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n\n <!-- Custom Left Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position !== 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n </div>\n\n <div class=\"toolbar-center\">\n <!-- Row Count -->\n <span *ngIf=\"ToolbarConfig.showRowCount !== false\" class=\"row-count\">\n {{ totalRowCount }} {{ totalRowCount === 1 ? 'row' : 'rows' }}\n </span>\n\n <!-- Selection Count -->\n <span *ngIf=\"ToolbarConfig.showSelectionCount && SelectedKeys.length > 0\" class=\"selection-count\">\n ({{ SelectedKeys.length }} selected)\n </span>\n </div>\n\n <div class=\"toolbar-right\">\n <!-- New/Add Button (predefined) -->\n <button\n *ngIf=\"ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Create new record\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n <span class=\"button-text\">New</span>\n </button>\n\n <!-- Refresh Button (predefined) -->\n <button\n *ngIf=\"ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh data\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-arrows-rotate\" [class.fa-spin]=\"loading\"></i>\n <span class=\"button-text\">Refresh</span>\n </button>\n\n <!-- Export Button (predefined) -->\n <button\n *ngIf=\"ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export to Excel\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span class=\"button-text\">Export</span>\n </button>\n\n <!-- Delete Button (predefined) -->\n <button\n *ngIf=\"ShowDeleteButton && HasSelection\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete selected records\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n <span class=\"button-text\">Delete</span>\n </button>\n\n <!-- Compare Button (predefined) -->\n <button\n *ngIf=\"ShowCompareButton\"\n class=\"toolbar-button\"\n title=\"Compare selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onCompareClick()\">\n <i class=\"fa-solid fa-code-compare\"></i>\n <span class=\"button-text\">Compare</span>\n </button>\n\n <!-- Merge Button (predefined) -->\n <button\n *ngIf=\"ShowMergeButton\"\n class=\"toolbar-button\"\n title=\"Merge selected records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onMergeClick()\">\n <i class=\"fa-solid fa-code-merge\"></i>\n <span class=\"button-text\">Merge</span>\n </button>\n\n <!-- Add to List Button (predefined) -->\n <button\n *ngIf=\"ShowAddToListButton\"\n class=\"toolbar-button\"\n title=\"Add selected records to a list\"\n [disabled]=\"!HasSelection\"\n (click)=\"onAddToListClick()\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span class=\"button-text\">Add to List</span>\n </button>\n\n <!-- Search for Duplicates Button (predefined) -->\n <button\n *ngIf=\"ShowDuplicateSearchButton\"\n class=\"toolbar-button\"\n title=\"Search for duplicate records\"\n [disabled]=\"!HasMultipleSelection\"\n (click)=\"onDuplicateSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass-plus\"></i>\n <span class=\"button-text\">Find Duplicates</span>\n </button>\n\n <!-- Communication Button (predefined) -->\n <button\n *ngIf=\"ShowCommunicationButton\"\n class=\"toolbar-button\"\n title=\"Send message to selected records\"\n [disabled]=\"!HasSelection\"\n (click)=\"onCommunicationClick()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span class=\"button-text\">Send Message</span>\n </button>\n\n <!-- Legacy ToolbarConfig buttons -->\n <!-- Add Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showAdd && AllowAdd && !ShowNewButton\"\n class=\"toolbar-button\"\n title=\"Add New\"\n (click)=\"onAddClick()\">\n <i class=\"fa-solid fa-plus\"></i>\n </button>\n\n <!-- Refresh Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showRefresh !== false && !ShowRefreshButton\"\n class=\"toolbar-button\"\n title=\"Refresh\"\n [disabled]=\"loading\"\n (click)=\"onRefreshClick()\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"loading\"></i>\n </button>\n\n <!-- Delete Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showDelete && AllowDelete && HasSelection && !ShowDeleteButton\"\n class=\"toolbar-button toolbar-button-danger\"\n title=\"Delete Selected\"\n (click)=\"onDeleteClick()\">\n <i class=\"fa-solid fa-trash\"></i>\n </button>\n\n <!-- Export Button (legacy) -->\n <button\n *ngIf=\"ToolbarConfig.showExport && !ShowExportButton\"\n class=\"toolbar-button\"\n title=\"Export\"\n (click)=\"onExportClick()\">\n <i class=\"fa-solid fa-download\"></i>\n </button>\n\n <!-- Column Chooser Button -->\n <button\n *ngIf=\"ToolbarConfig.showColumnChooser && AllowColumnToggle\"\n class=\"toolbar-button\"\n title=\"Column Chooser\"\n (click)=\"onColumnChooserClick()\">\n <i class=\"fa-solid fa-columns\"></i>\n </button>\n\n <!-- Custom Right Buttons -->\n <ng-container *ngFor=\"let button of ToolbarConfig.customButtons\">\n <button\n *ngIf=\"button.position === 'right' && isButtonVisible(button)\"\n class=\"toolbar-button\"\n [class]=\"button.cssClass\"\n [disabled]=\"isButtonDisabled(button)\"\n [title]=\"button.tooltip || ''\"\n (click)=\"onToolbarButtonClick(button)\">\n <i *ngIf=\"button.icon\" [class]=\"button.icon\"></i>\n <span *ngIf=\"button.text\">{{ button.text }}</span>\n </button>\n </ng-container>\n\n <!-- Overflow Menu -->\n <div *ngIf=\"hasOverflowMenuItems\" class=\"toolbar-overflow\" (click)=\"$event.stopPropagation()\">\n <button\n class=\"toolbar-button overflow-trigger\"\n title=\"More actions\"\n (click)=\"toggleOverflowMenu()\">\n <i class=\"fa-solid fa-ellipsis-vertical\"></i>\n </button>\n\n <div *ngIf=\"showOverflowMenu\" class=\"overflow-menu\" [@fadeIn]>\n <!-- Export (if in overflow) -->\n <button *ngIf=\"showExportInOverflow\" class=\"overflow-item\" (click)=\"onExportClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-file-excel\"></i>\n <span>Export to Excel</span>\n </button>\n\n <!-- Entity Actions -->\n <ng-container *ngIf=\"ShowEntityActionButtons && EntityActions.length > 0\">\n <div class=\"overflow-divider\"></div>\n <div class=\"overflow-section-label\">Actions</div>\n <button\n *ngFor=\"let action of EntityActions\"\n class=\"overflow-item\"\n [disabled]=\"!isEntityActionEnabled(action)\"\n (click)=\"onEntityActionClick(action); closeOverflowMenu()\">\n <i [class]=\"action.icon || 'fa-solid fa-bolt'\"></i>\n <span>{{ action.name }}</span>\n </button>\n </ng-container>\n\n <!-- Column Chooser (if in overflow) -->\n <div *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-divider\"></div>\n <button *ngIf=\"showColumnChooserInOverflow\" class=\"overflow-item\" (click)=\"onColumnChooserClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-columns\"></i>\n <span>Manage Columns</span>\n </button>\n\n <!-- Selection-dependent actions in overflow -->\n <ng-container *ngIf=\"HasSelection && hasSelectionDependentOverflowActions\">\n <div class=\"overflow-divider\"></div>\n <button *ngIf=\"showCommunicationInOverflow\" class=\"overflow-item\" (click)=\"onCommunicationClick(); closeOverflowMenu()\">\n <i class=\"fa-solid fa-envelope\"></i>\n <span>Send Message</span>\n </button>\n </ng-container>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Aggregate Cards (displayed as summary cards above the grid) -->\n <div *ngIf=\"ShowAggregatePanel\" class=\"mj-aggregate-cards\">\n <ng-container *ngFor=\"let agg of CardAggregates\">\n <div class=\"aggregate-card\">\n <div class=\"aggregate-card-icon\" *ngIf=\"agg.icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n <div class=\"aggregate-card-content\">\n <span class=\"aggregate-card-label\">{{ agg.label }}</span>\n <span class=\"aggregate-card-value\">{{ getAggregateValue(agg) }}</span>\n </div>\n </div>\n </ng-container>\n <div *ngIf=\"AggregatesLoading\" class=\"aggregate-card-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </div>\n </div>\n\n <!-- Grid Content -->\n <div class=\"mj-grid-content\">\n <!-- Loading Overlay -->\n <div *ngIf=\"loading && rowData.length === 0\" class=\"mj-grid-loading-overlay\">\n <mj-loading text=\"Loading...\"></mj-loading>\n </div>\n\n <!-- Error State -->\n <div *ngIf=\"errorMessage && !loading\" class=\"mj-grid-error\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ errorMessage }}</span>\n <button class=\"error-retry\" (click)=\"Refresh()\">Retry</button>\n </div>\n\n <!-- Empty State -->\n <div *ngIf=\"!loading && !errorMessage && rowData.length === 0\" class=\"mj-grid-empty\">\n <i class=\"fa-solid fa-inbox\"></i>\n <span>No data to display</span>\n </div>\n\n <!-- AG Grid (Client-side mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'client' && (rowData.length > 0 || loading)\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [rowData]=\"rowData\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n (gridReady)=\"onGridReady($event)\"\n (cellClicked)=\"onAgCellClicked($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n\n <!-- AG Grid (Infinite Scroll mode) -->\n <ag-grid-angular\n *ngIf=\"!errorMessage && PaginationMode === 'infinite'\"\n class=\"mj-ag-grid ag-theme-alpine\"\n [theme]=\"agGridTheme\"\n [columnDefs]=\"agColumnDefs\"\n [defaultColDef]=\"defaultColDef\"\n [rowSelection]=\"agRowSelection\"\n [getRowId]=\"getRowId\"\n [suppressCellFocus]=\"true\"\n [rowHeight]=\"RowHeight\"\n [headerHeight]=\"ShowHeader ? undefined : 0\"\n [rowModelType]=\"'infinite'\"\n [cacheBlockSize]=\"CacheBlockSize\"\n [maxBlocksInCache]=\"MaxBlocksInCache\"\n [infiniteInitialRowCount]=\"1\"\n [cacheOverflowSize]=\"2\"\n (gridReady)=\"onGridReady($event)\"\n (cellClicked)=\"onAgCellClicked($event)\"\n (rowClicked)=\"onAgRowClicked($event)\"\n (rowDoubleClicked)=\"onAgRowDoubleClicked($event)\"\n (sortChanged)=\"onAgSortChanged($event)\"\n (selectionChanged)=\"onAgSelectionChanged($event)\"\n (columnResized)=\"onAgColumnResized($event)\"\n (columnMoved)=\"onAgColumnMoved($event)\">\n </ag-grid-angular>\n\n </div>\n\n <!-- Aggregate Summary Row (outside mj-grid-content so it's always visible) -->\n <div *ngIf=\"ShowAggregateSummary\" class=\"mj-aggregate-summary\">\n <div class=\"aggregate-summary-content\">\n <ng-container *ngFor=\"let agg of ColumnAggregates\">\n <div class=\"aggregate-summary-item\">\n <i *ngIf=\"agg.icon\" [class]=\"agg.icon\"></i>\n <span class=\"agg-summary-label\">{{ agg.label }}:</span>\n <span class=\"agg-summary-value\">{{ getAggregateValue(agg) }}</span>\n </div>\n </ng-container>\n </div>\n <div *ngIf=\"AggregatesLoading\" class=\"aggregate-loading\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </div>\n </div>\n</div>\n\n<!-- Export Dialog -->\n<mj-export-dialog\n [visible]=\"showExportDialog\"\n [config]=\"exportDialogConfig\"\n (closed)=\"onExportDialogClosed($event)\">\n</mj-export-dialog>\n", styles: ["/* ========================================\n CSS Custom Properties (Theme Variables)\n ======================================== */\n\n:host {\n /* Grid container */\n --grid-border-color: #e0e0e0;\n --grid-border-radius: 0px;\n --grid-background: #ffffff;\n\n /* Header */\n --grid-header-bg: #fafafa;\n --grid-header-text: #333333;\n --grid-header-font-weight: 600;\n --grid-header-height: 40px;\n --grid-header-border-color: #e0e0e0;\n\n /* Rows */\n --grid-row-height: 40px;\n --grid-row-bg: #ffffff;\n --grid-row-bg-alt: #fafafa;\n --grid-row-hover-bg: #f5f5f5;\n --grid-row-selected-bg: #fff9e6;\n --grid-row-selected-hover-bg: #fff3cc;\n\n /* Cells */\n --grid-cell-padding: 8px 12px;\n --grid-cell-text: #333333;\n --grid-cell-border-color: #f0f0f0;\n\n /* Selection - mellow yellow to avoid conflict with blue hyperlinks */\n --grid-checkbox-color: #2196F3;\n --grid-selection-indicator-color: #f9a825;\n\n /* Editing */\n --grid-edit-cell-bg: #ffffff;\n --grid-edit-cell-border: #2196F3;\n --grid-edit-cell-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n\n /* Sorting */\n --grid-sort-indicator-color: #2196F3;\n\n /* Toolbar */\n --grid-toolbar-bg: #ffffff;\n --grid-toolbar-height: 48px;\n --grid-toolbar-border-color: #e0e0e0;\n\n /* Loading */\n --grid-loading-overlay-bg: rgba(255, 255, 255, 0.8);\n\n /* Empty state */\n --grid-empty-text-color: #999999;\n --grid-empty-icon-color: #cccccc;\n\n display: block;\n height: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;\n}\n\n/* ========================================\n Grid Container\n ======================================== */\n\n.mj-grid-container {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--grid-border-color);\n border-radius: var(--grid-border-radius);\n background: var(--grid-background);\n overflow: hidden;\n}\n\n/* ========================================\n Toolbar\n ======================================== */\n\n.mj-grid-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: var(--grid-toolbar-height);\n padding: 0 12px;\n background: var(--grid-toolbar-bg);\n border-bottom: 1px solid var(--grid-toolbar-border-color);\n gap: 12px;\n}\n\n.toolbar-left,\n.toolbar-right {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.toolbar-center {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #666;\n font-size: 13px;\n}\n\n.toolbar-search {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.search-icon {\n position: absolute;\n left: 10px;\n color: #999;\n font-size: 13px;\n}\n\n.search-input {\n padding: 6px 30px 6px 32px;\n border: 1px solid #ddd;\n border-radius: 4px;\n font-size: 13px;\n width: 200px;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n\n.search-input:focus {\n outline: none;\n border-color: var(--grid-selection-indicator-color);\n box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.1);\n}\n\n.search-clear {\n position: absolute;\n right: 6px;\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #999;\n font-size: 12px;\n}\n\n.search-clear:hover {\n color: #666;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: #f5f5f5;\n border: 1px solid #ddd;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n color: #333;\n transition: background-color 0.2s, border-color 0.2s;\n}\n\n.toolbar-button:hover:not(:disabled) {\n background: #eee;\n border-color: #ccc;\n}\n\n.toolbar-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.toolbar-button i {\n font-size: 14px;\n}\n\n.toolbar-button-danger {\n color: #d32f2f;\n}\n\n.toolbar-button-danger:hover:not(:disabled) {\n background: #ffebee;\n border-color: #ffcdd2;\n}\n\n.row-count,\n.selection-count {\n font-weight: 500;\n}\n\n/* ========================================\n Grid Content\n ======================================== */\n\n.mj-grid-content {\n flex: 1;\n position: relative;\n overflow: hidden;\n}\n\n.mj-grid-scroll-container {\n height: 100%;\n overflow: auto;\n}\n\n/* ========================================\n Loading Overlay\n ======================================== */\n\n.mj-grid-loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--grid-loading-overlay-bg);\n z-index: 10;\n}\n\n/* ========================================\n Error State\n ======================================== */\n\n.mj-grid-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 40px 20px;\n color: #d32f2f;\n gap: 12px;\n}\n\n.mj-grid-error i {\n font-size: 32px;\n}\n\n.error-retry {\n padding: 8px 16px;\n background: #d32f2f;\n color: white;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n}\n\n.error-retry:hover {\n background: #c62828;\n}\n\n/* ========================================\n Empty State\n ======================================== */\n\n.mj-grid-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--grid-empty-text-color);\n gap: 12px;\n}\n\n.mj-grid-empty i {\n font-size: 48px;\n color: var(--grid-empty-icon-color);\n}\n\n/* ========================================\n Header Row\n ======================================== */\n\n.mj-grid-header {\n display: flex;\n min-height: var(--grid-header-height);\n background: var(--grid-header-bg);\n border-bottom: 2px solid var(--grid-header-border-color);\n position: sticky;\n top: 0;\n z-index: 5;\n}\n\n.mj-grid-header-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n font-weight: var(--grid-header-font-weight);\n color: var(--grid-header-text);\n font-size: 13px;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n border-right: 1px solid var(--grid-cell-border-color);\n flex-shrink: 0;\n}\n\n.mj-grid-header-cell:last-child {\n border-right: none;\n}\n\n.mj-grid-header-cell.sortable {\n cursor: pointer;\n}\n\n.mj-grid-header-cell.sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n.header-text {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sort-indicator {\n display: flex;\n align-items: center;\n margin-left: 6px;\n color: var(--grid-sort-indicator-color);\n}\n\n.sort-indicator i {\n font-size: 12px;\n}\n\n.sort-index {\n font-size: 10px;\n margin-left: 2px;\n font-weight: normal;\n}\n\n/* ========================================\n Data Rows\n ======================================== */\n\n.mj-grid-row {\n display: flex;\n align-items: stretch;\n background: var(--grid-row-bg);\n transition: background-color 0.15s;\n cursor: default;\n}\n\n.mj-grid-row:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-alt {\n background: var(--grid-row-bg-alt);\n}\n\n.mj-grid-row.grid-row-alt:hover {\n background: var(--grid-row-hover-bg);\n}\n\n.mj-grid-row.grid-row-selected {\n background: var(--grid-row-selected-bg);\n}\n\n.mj-grid-row.grid-row-selected:hover {\n background: var(--grid-row-selected-hover-bg);\n}\n\n.mj-grid-row.grid-row-editing {\n background: #fffde7;\n}\n\n.mj-grid-row.grid-row-dirty {\n border-left: 3px solid #ff9800;\n}\n\n/* ========================================\n Data Cells\n ======================================== */\n\n.mj-grid-cell {\n display: flex;\n align-items: center;\n padding: var(--grid-cell-padding);\n color: var(--grid-cell-text);\n font-size: 13px;\n overflow: hidden;\n border-right: 1px solid transparent;\n flex-shrink: 0;\n}\n\n.mj-grid-cell:last-child {\n border-right: none;\n}\n\n/* Grid lines modes */\n.grid-lines-horizontal .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-vertical .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-row {\n border-bottom: 1px solid var(--grid-cell-border-color);\n}\n\n.grid-lines-both .mj-grid-cell {\n border-right: 1px solid var(--grid-cell-border-color);\n}\n\n/* Cell alignment */\n.mj-grid-cell.align-left {\n justify-content: flex-start;\n}\n\n.mj-grid-cell.align-center {\n justify-content: center;\n}\n\n.mj-grid-cell.align-right {\n justify-content: flex-end;\n}\n\n.cell-content {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Special cells */\n.row-number-cell {\n width: 50px;\n min-width: 50px;\n max-width: 50px;\n justify-content: center;\n color: #999;\n font-size: 12px;\n background: var(--grid-header-bg);\n}\n\n.checkbox-cell {\n width: 40px;\n min-width: 40px;\n max-width: 40px;\n justify-content: center;\n}\n\n.checkbox-cell input[type=\"checkbox\"] {\n width: 16px;\n height: 16px;\n cursor: pointer;\n accent-color: var(--grid-checkbox-color);\n}\n\n/* ========================================\n Virtual Scrolling\n ======================================== */\n\n.mj-grid-virtual-spacer {\n flex-shrink: 0;\n}\n\n/* ========================================\n Responsive Adjustments\n ======================================== */\n\n@media (max-width: 768px) {\n .mj-grid-toolbar {\n flex-wrap: wrap;\n padding: 8px;\n }\n\n .toolbar-search {\n order: 3;\n width: 100%;\n margin-top: 8px;\n }\n\n .search-input {\n width: 100%;\n }\n\n .toolbar-center {\n order: 2;\n }\n\n /* Hide button text on mobile */\n .toolbar-button .button-text {\n display: none;\n }\n}\n\n/* ========================================\n Toolbar Button Text\n ======================================== */\n\n.toolbar-button .button-text {\n font-size: 13px;\n}\n\n/* ========================================\n Overflow Menu\n ======================================== */\n\n.toolbar-overflow {\n position: relative;\n}\n\n.overflow-trigger {\n padding: 6px 8px !important;\n}\n\n.overflow-trigger i {\n font-size: 16px;\n}\n\n.overflow-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: 4px;\n min-width: 220px;\n background: #ffffff;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.08);\n z-index: 1000;\n overflow: hidden;\n}\n\n.overflow-item {\n display: flex;\n align-items: center;\n width: 100%;\n padding: 10px 16px;\n border: none;\n background: none;\n cursor: pointer;\n font-size: 14px;\n color: #333;\n text-align: left;\n gap: 12px;\n transition: background-color 0.15s;\n}\n\n.overflow-item:hover:not(:disabled) {\n background: #f5f5f5;\n}\n\n.overflow-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.overflow-item i {\n width: 18px;\n font-size: 14px;\n color: #666;\n text-align: center;\n}\n\n.overflow-item span {\n flex: 1;\n}\n\n.overflow-divider {\n height: 1px;\n background: #e0e0e0;\n margin: 4px 0;\n}\n\n.overflow-section-label {\n padding: 8px 16px 4px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n color: #999;\n letter-spacing: 0.5px;\n}\n\n/* Entity Actions submenu styling */\n.overflow-item.action-item i {\n color: #2196F3;\n}\n\n/* ========================================\n Highlight Matches\n ======================================== */\n\n::ng-deep .highlight-match {\n background-color: #fff176;\n border-radius: 2px;\n padding: 0 1px;\n}\n\n/* ========================================\n AG Grid Customizations\n ======================================== */\n\n.mj-ag-grid {\n width: 100%;\n height: 100%;\n}\n\n::ng-deep .ag-theme-alpine {\n /* Row colors */\n --ag-row-hover-color: var(--grid-row-hover-bg);\n --ag-selected-row-background-color: var(--grid-row-selected-bg);\n --ag-header-background-color: var(--grid-header-bg);\n\n /* Selection accent colors - mellow yellow */\n --ag-range-selection-background-color: rgba(249, 168, 37, 0.15);\n --ag-range-selection-border-color: #f9a825;\n\n /* Ensure borders are visible */\n --ag-borders: none;\n --ag-row-border-color: var(--grid-cell-border-color);\n}\n\n/* Selected row styling - left indicator bar only, background handled by AG Grid theme */\n::ng-deep .ag-row-selected {\n box-shadow: inset 4px 0 0 0 #f9a825;\n}\n\n/* Selection checkbox styling */\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper {\n width: 18px;\n height: 18px;\n}\n\n::ng-deep .ag-theme-alpine .ag-checkbox-input-wrapper.ag-checked::after {\n color: var(--grid-checkbox-color, #2196F3);\n}\n\n/* Row hover effect */\n::ng-deep .ag-theme-alpine .ag-row:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f0f7ff);\n}\n\n/* ========================================\n Visual Config: Header Styles\n ======================================== */\n\n/* Flat header (minimal) */\n.header-style-flat ::ng-deep .ag-header {\n background: var(--grid-header-bg, #fafafa);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n/* Elevated header (default - subtle shadow) */\n.header-style-elevated ::ng-deep .ag-header {\n background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);\n border-bottom: 1px solid var(--grid-header-border-color, #e0e0e0);\n}\n\n.header-style-elevated.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n/* Gradient header (more prominent) */\n.header-style-gradient ::ng-deep .ag-header {\n background: linear-gradient(180deg, #f8f9fa 0%, #e9ecef 100%);\n border-bottom: none;\n}\n\n.header-style-gradient.header-shadow ::ng-deep .ag-header {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n}\n\n/* Bold header (high contrast) */\n.header-style-bold ::ng-deep .ag-header {\n background: linear-gradient(180deg, #37474f 0%, #263238 100%);\n border-bottom: none;\n}\n\n.header-style-bold ::ng-deep .ag-header-cell-text {\n color: #ffffff;\n font-weight: 600;\n}\n\n.header-style-bold ::ng-deep .ag-header-icon {\n color: rgba(255, 255, 255, 0.7);\n}\n\n.header-style-bold ::ng-deep .ag-header-cell:hover {\n background: rgba(255, 255, 255, 0.1);\n}\n\n/* Header sort icons enhancement */\n::ng-deep .ag-header-cell-sorted-asc .ag-icon-asc,\n::ng-deep .ag-header-cell-sorted-desc .ag-icon-desc {\n color: var(--grid-accent-color, var(--grid-sort-indicator-color, #2196F3));\n}\n\n/* ========================================\n Visual Config: Zebra Striping\n ======================================== */\n\n/* Subtle contrast */\n.alternate-rows-subtle ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.015);\n}\n\n.alternate-rows-subtle ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Medium contrast (default) */\n.alternate-rows-medium ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.025);\n}\n\n.alternate-rows-medium ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* Strong contrast */\n.alternate-rows-strong ::ng-deep .ag-row-odd {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n.alternate-rows-strong ::ng-deep .ag-row-odd:hover:not(.ag-row-selected) {\n background-color: var(--grid-row-hover-bg, #f5f5f5);\n}\n\n/* ========================================\n Visual Config: Hover Transitions\n ======================================== */\n\n.hover-transitions ::ng-deep .ag-row {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n.hover-transitions ::ng-deep .ag-cell {\n transition: background-color var(--grid-hover-transition, 150ms) ease;\n}\n\n/* ========================================\n Visual Config: Cell Padding\n ======================================== */\n\n.cell-padding-compact ::ng-deep .ag-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-compact ::ng-deep .ag-header-cell {\n padding-left: 8px;\n padding-right: 8px;\n}\n\n.cell-padding-normal ::ng-deep .ag-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-normal ::ng-deep .ag-header-cell {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n.cell-padding-comfortable ::ng-deep .ag-header-cell {\n padding-left: 16px;\n padding-right: 16px;\n}\n\n/* ========================================\n Visual Config: Checkbox Styles\n ======================================== */\n\n/* Rounded checkbox */\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper {\n border-radius: 4px;\n}\n\n.checkbox-style-rounded ::ng-deep .ag-checkbox-input-wrapper::after {\n border-radius: 3px;\n}\n\n/* Filled checkbox */\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked {\n background-color: var(--grid-checkbox-color, #2196F3);\n border-color: var(--grid-checkbox-color, #2196F3);\n}\n\n.checkbox-style-filled ::ng-deep .ag-checkbox-input-wrapper.ag-checked::after {\n color: #ffffff;\n}\n\n/* ========================================\n Cell Content Formatting\n ======================================== */\n\n/* Right-aligned cells (numbers) */\n::ng-deep .cell-align-right {\n text-align: right;\n justify-content: flex-end;\n}\n\n::ng-deep .header-align-right .ag-header-cell-label {\n justify-content: flex-end;\n}\n\n/* Empty cell placeholder */\n::ng-deep .cell-empty {\n color: #bdbdbd;\n font-style: normal;\n}\n\n/* Boolean icons */\n::ng-deep .cell-boolean-true {\n color: #43a047;\n font-size: 14px;\n}\n\n::ng-deep .cell-boolean-false {\n color: #bdbdbd;\n font-size: 14px;\n}\n\n/* Clickable links */\n::ng-deep .cell-link {\n color: var(--grid-accent-color, #2196F3);\n text-decoration: none;\n transition: color 0.15s;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n\n::ng-deep .cell-link:hover {\n color: #1976D2;\n text-decoration: underline;\n}\n\n/* Email cells */\n::ng-deep .cell-email {\n font-family: inherit;\n font-size: 13px;\n}\n\n/* Foreign key link cells */\n::ng-deep .cell-fk-link {\n color: var(--grid-accent-color, #1976D2);\n text-decoration: none;\n cursor: pointer;\n transition: color 0.15s, text-decoration 0.15s;\n}\n\n::ng-deep .cell-fk-link:hover {\n color: #1565C0;\n text-decoration: underline;\n}\n\n::ng-deep .cell-fk-link:active {\n color: #0D47A1;\n}\n\n/* URL cells */\n::ng-deep .cell-url {\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n font-size: 13px;\n}\n\n/* Phone cells */\n::ng-deep .cell-phone {\n font-variant-numeric: tabular-nums;\n letter-spacing: 0.3px;\n}\n\n/* ========================================\n Skeleton Loading Animation\n ======================================== */\n\n@keyframes skeleton-shimmer {\n 0% {\n background-position: -200px 0;\n }\n 100% {\n background-position: calc(200px + 100%) 0;\n }\n}\n\n.skeleton-row {\n display: flex;\n height: 40px;\n align-items: center;\n padding: 0 12px;\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n.skeleton-cell {\n height: 16px;\n border-radius: 4px;\n background: linear-gradient(\n 90deg,\n #f0f0f0 0px,\n #e8e8e8 40px,\n #f0f0f0 80px\n );\n background-size: 200px 100%;\n animation: skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-cell-short {\n width: 60px;\n}\n\n.skeleton-cell-medium {\n width: 120px;\n}\n\n.skeleton-cell-long {\n width: 180px;\n}\n\n/* Selection checkbox column header */\n::ng-deep .ag-header-select-all {\n margin-right: 0;\n}\n\n/* ========================================\n Row Border Enhancement\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-row {\n border-bottom: 1px solid var(--grid-cell-border-color, #f0f0f0);\n}\n\n::ng-deep .ag-theme-alpine .ag-row:last-child {\n border-bottom: none;\n}\n\n/* ========================================\n Focus States\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-cell-focus {\n border: none !important;\n outline: none !important;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:focus {\n outline: 2px solid var(--grid-accent-color, #2196F3);\n outline-offset: -2px;\n}\n\n/* ========================================\n Scrollbar Styling\n ======================================== */\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-track {\n background: #f5f5f5;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb {\n background: #c0c0c0;\n border-radius: 4px;\n}\n\n::ng-deep .ag-body-viewport::-webkit-scrollbar-thumb:hover {\n background: #a0a0a0;\n}\n\n/* ========================================\n Pinned Column Styling\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-pinned-left-cols-container {\n border-right: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n::ng-deep .ag-theme-alpine .ag-pinned-right-cols-container {\n border-left: 2px solid var(--grid-border-color, #e0e0e0);\n}\n\n/* ========================================\n Header Cell Enhancements\n ======================================== */\n\n::ng-deep .ag-theme-alpine .ag-header-cell {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n color: #546e7a;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell-sortable:hover .ag-header-cell-label {\n color: var(--grid-accent-color, #2196F3);\n}\n\n/* Sort icon animation */\n::ng-deep .ag-theme-alpine .ag-sort-indicator-icon {\n transition: transform 0.2s ease;\n}\n\n::ng-deep .ag-theme-alpine .ag-header-cell:hover .ag-sort-indicator-icon {\n transform: scale(1.1);\n}\n\n/* ========================================\n Enhanced Multi-Sort Indicators\n These styles use :host to ensure they're scoped to this component\n and !important to override AG Grid's built-in styles\n ======================================== */\n\n/* Highlight sorted column headers with eye-catching background */\n/* Ascending = blue tint */\n:host ::ng-deep .ag-header-cell-sorted-asc {\n background: linear-gradient(180deg, rgba(25, 118, 210, 0.15) 0%, rgba(25, 118, 210, 0.08) 100%) !important;\n position: relative;\n}\n\n/* Descending = pink tint */\n:host ::ng-deep .ag-header-cell-sorted-desc {\n background: linear-gradient(180deg, rgba(216, 27, 96, 0.15) 0%, rgba(216, 27, 96, 0.08) 100%) !important;\n position: relative;\n}\n\n/* Bottom border accent for sorted columns - ascending = blue */\n:host ::ng-deep .ag-header-cell-sorted-asc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #1976d2;\n}\n\n/* Bottom border accent for sorted columns - descending = pink */\n:host ::ng-deep .ag-header-cell-sorted-desc::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background: #d81b60;\n}\n\n/* Sorted column header text - ascending = blue, bold */\n:host ::ng-deep .ag-header-cell-sorted-asc .ag-header-cell-text {\n color: #1976d2 !important;\n font-weight: 700 !important;\n}\n\n/* Sorted column header text - descending = pink, bold */\n:host ::ng-deep .ag-header-cell-sorted-desc .ag-header-cell-text {\n color: #d81b60 !important;\n font-weight: 700 !important;\n}\n\n/* Sort icons - larger and more prominent */\n/* Ascending = blue */\n:host ::ng-deep .ag-sort-ascending-icon {\n color: #1976d2 !important;\n}\n\n/* Descending = pink/magenta */\n:host ::ng-deep .ag-sort-descending-icon {\n color: #d81b60 !important;\n}\n\n:host ::ng-deep .ag-sort-ascending-icon .ag-icon,\n:host ::ng-deep .ag-sort-descending-icon .ag-icon {\n font-size: 14px !important;\n}\n\n/* Sort order number (1, 2, 3) - show as plain number, no bubble */\n/* This avoids AG Grid bug where .ag-sort-order is always present but empty when unsorted */\n/* The number is only visible when AG Grid populates it (i.e., when column is sorted) */\n/* Default blue for ascending */\n:host ::ng-deep .ag-sort-order {\n margin-left: 4px;\n font-size: 11px !important;\n font-weight: 700 !important;\n color: #1976d2 !important;\n}\n\n/* Sort order number - pink for descending */\n:host ::ng-deep .ag-header-cell-sorted-desc .ag-sort-order {\n color: #d81b60 !important;\n}\n\n/* Hover state for sortable headers */\n:host ::ng-deep .ag-header-cell-sortable:hover {\n background: rgba(0, 0, 0, 0.04);\n}\n\n:host ::ng-deep .ag-header-cell-sortable:hover .ag-header-cell-text {\n color: #1976d2;\n}\n\n/* ========================================\n Aggregate Summary Row\n ======================================== */\n\n.mj-aggregate-summary {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 16px;\n background: linear-gradient(to bottom, #f8fafc, #f1f5f9);\n border-top: 1px solid #e2e8f0;\n font-size: 13px;\n min-height: 44px;\n}\n\n.aggregate-summary-content {\n display: flex;\n flex-wrap: wrap;\n gap: 20px;\n align-items: center;\n}\n\n.aggregate-summary-item {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 6px;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n}\n\n.aggregate-summary-item i {\n font-size: 12px;\n color: #64748b;\n}\n\n.agg-summary-label {\n color: #64748b;\n font-weight: 500;\n}\n\n.agg-summary-value {\n color: #1e293b;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n}\n\n.aggregate-loading {\n display: flex;\n align-items: center;\n color: #94a3b8;\n}\n\n.aggregate-loading i {\n font-size: 14px;\n}\n\n/* ========================================\n AGGREGATE CARDS (displayed above grid)\n ======================================== */\n\n.mj-aggregate-cards {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding: 12px 16px;\n background: linear-gradient(to bottom, #f8fafc, #f1f5f9);\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.aggregate-card {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 10px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);\n min-width: 140px;\n transition: all 0.15s ease;\n}\n\n.aggregate-card:hover {\n border-color: #cbd5e1;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);\n}\n\n.aggregate-card-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: linear-gradient(135deg, #e0f2fe 0%, #bae6fd 100%);\n border-radius: 10px;\n color: #0284c7;\n font-size: 16px;\n flex-shrink: 0;\n}\n\n.aggregate-card-content {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.aggregate-card-label {\n font-size: 12px;\n font-weight: 500;\n color: #64748b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.aggregate-card-value {\n font-size: 18px;\n font-weight: 700;\n color: #0f172a;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n.aggregate-card-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n color: #94a3b8;\n}\n\n.aggregate-card-loading i {\n font-size: 16px;\n}\n\n/* ========================================\n Text Wrapping Styles\n ======================================== */\n\n/* Cell class for wrapped text */\n::ng-deep .cell-wrap-text {\n white-space: normal !important;\n word-wrap: break-word;\n line-height: 1.4;\n padding-top: 8px !important;\n padding-bottom: 8px !important;\n}\n\n/* Ensure AG Grid cells allow wrapping */\n::ng-deep .ag-cell.cell-wrap-text {\n overflow: visible;\n text-overflow: clip;\n}\n\n/* Maintain minimum row height when wrapping */\n::ng-deep .ag-row[style*=\"auto-height\"] {\n min-height: 40px;\n}\n"] }]
3609
4220
  }], () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1.ExportService }], { Params: [{
3610
4221
  type: Input
3611
4222
  }], AllowLoad: [{
@@ -3660,6 +4271,8 @@ export class EntityDataGridComponent {
3660
4271
  type: Input
3661
4272
  }], RowHeight: [{
3662
4273
  type: Input
4274
+ }], WrapText: [{
4275
+ type: Input
3663
4276
  }], VirtualScroll: [{
3664
4277
  type: Input
3665
4278
  }], ShowRowNumbers: [{
@@ -3714,6 +4327,10 @@ export class EntityDataGridComponent {
3714
4327
  type: Input
3715
4328
  }], EntityActions: [{
3716
4329
  type: Input
4330
+ }], AggregatesConfig: [{
4331
+ type: Input
4332
+ }], AggregatesLoaded: [{
4333
+ type: Output
3717
4334
  }], BeforeRowSelect: [{
3718
4335
  type: Output
3719
4336
  }], AfterRowSelect: [{
@@ -3732,6 +4349,8 @@ export class EntityDataGridComponent {
3732
4349
  type: Output
3733
4350
  }], AfterRowDoubleClick: [{
3734
4351
  type: Output
4352
+ }], ForeignKeyClick: [{
4353
+ type: Output
3735
4354
  }], BeforeCellEdit: [{
3736
4355
  type: Output
3737
4356
  }], AfterCellEditBegin: [{
@@ -3826,5 +4445,5 @@ export class EntityDataGridComponent {
3826
4445
  type: ViewChild,
3827
4446
  args: ['gridContainer']
3828
4447
  }] }); })();
3829
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityDataGridComponent, { className: "EntityDataGridComponent", filePath: "src/lib/entity-data-grid/entity-data-grid.component.ts", lineNumber: 150 }); })();
4448
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityDataGridComponent, { className: "EntityDataGridComponent", filePath: "src/lib/entity-data-grid/entity-data-grid.component.ts", lineNumber: 151 }); })();
3830
4449
  //# sourceMappingURL=entity-data-grid.component.js.map