@memberjunction/ng-entity-viewer 2.131.0 → 2.133.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 (37) hide show
  1. package/README.md +317 -124
  2. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +792 -0
  3. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -0
  4. package/dist/lib/entity-data-grid/entity-data-grid.component.js +3778 -0
  5. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -0
  6. package/dist/lib/entity-data-grid/events/grid-events.d.ts +398 -0
  7. package/dist/lib/entity-data-grid/events/grid-events.d.ts.map +1 -0
  8. package/dist/lib/entity-data-grid/events/grid-events.js +556 -0
  9. package/dist/lib/entity-data-grid/events/grid-events.js.map +1 -0
  10. package/dist/lib/entity-data-grid/models/grid-types.d.ts +437 -0
  11. package/dist/lib/entity-data-grid/models/grid-types.d.ts.map +1 -0
  12. package/dist/lib/entity-data-grid/models/grid-types.js +37 -0
  13. package/dist/lib/entity-data-grid/models/grid-types.js.map +1 -0
  14. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +92 -2
  15. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  16. package/dist/lib/entity-viewer/entity-viewer.component.js +255 -92
  17. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  18. package/dist/lib/types.d.ts +14 -31
  19. package/dist/lib/types.d.ts.map +1 -1
  20. package/dist/lib/types.js.map +1 -1
  21. package/dist/lib/view-config-panel/view-config-panel.component.d.ts +363 -0
  22. package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -0
  23. package/dist/lib/view-config-panel/view-config-panel.component.js +2006 -0
  24. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -0
  25. package/dist/module.d.ts +16 -13
  26. package/dist/module.d.ts.map +1 -1
  27. package/dist/module.js +24 -14
  28. package/dist/module.js.map +1 -1
  29. package/dist/public-api.d.ts +4 -1
  30. package/dist/public-api.d.ts.map +1 -1
  31. package/dist/public-api.js +6 -1
  32. package/dist/public-api.js.map +1 -1
  33. package/package.json +10 -6
  34. package/dist/lib/entity-grid/entity-grid.component.d.ts +0 -216
  35. package/dist/lib/entity-grid/entity-grid.component.d.ts.map +0 -1
  36. package/dist/lib/entity-grid/entity-grid.component.js +0 -676
  37. package/dist/lib/entity-grid/entity-grid.component.js.map +0 -1
@@ -8,26 +8,26 @@ import * as i0 from "@angular/core";
8
8
  import * as i1 from "@angular/forms";
9
9
  import * as i2 from "@memberjunction/ng-shared-generic";
10
10
  import * as i3 from "@memberjunction/ng-timeline";
11
- import * as i4 from "../entity-grid/entity-grid.component";
12
- import * as i5 from "../entity-cards/entity-cards.component";
13
- import * as i6 from "../pagination/pagination.component";
11
+ import * as i4 from "../entity-cards/entity-cards.component";
12
+ import * as i5 from "../pagination/pagination.component";
13
+ import * as i6 from "../entity-data-grid/entity-data-grid.component";
14
14
  import * as i7 from "@angular/common";
15
15
  const _forTrack0 = ($index, $item) => $item.Name;
16
16
  function EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
17
17
  const _r3 = i0.ɵɵgetCurrentView();
18
- i0.ɵɵelementStart(0, "button", 12);
18
+ i0.ɵɵelementStart(0, "button", 20);
19
19
  i0.ɵɵlistener("click", function EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.clearFilter()); });
20
- i0.ɵɵelement(1, "i", 13);
20
+ i0.ɵɵelement(1, "i", 21);
21
21
  i0.ɵɵelementEnd();
22
22
  } }
23
23
  function EntityViewerComponent_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
24
24
  const _r1 = i0.ɵɵgetCurrentView();
25
- i0.ɵɵelementStart(0, "div", 6);
26
- i0.ɵɵelement(1, "i", 9);
27
- i0.ɵɵelementStart(2, "input", 10);
25
+ i0.ɵɵelementStart(0, "div", 14);
26
+ i0.ɵɵelement(1, "i", 17);
27
+ i0.ɵɵelementStart(2, "input", 18);
28
28
  i0.ɵɵlistener("input", function EntityViewerComponent_Conditional_1_Conditional_1_Template_input_input_2_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onFilterChange($event.target.value)); });
29
29
  i0.ɵɵelementEnd();
30
- i0.ɵɵtemplate(3, EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template, 2, 0, "button", 11);
30
+ i0.ɵɵtemplate(3, EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template, 2, 0, "button", 19);
31
31
  i0.ɵɵelementEnd();
32
32
  } if (rf & 2) {
33
33
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -58,7 +58,7 @@ function EntityViewerComponent_Conditional_1_Conditional_2_Conditional_2_Templat
58
58
  i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind1(2, 1, ctx_r1.totalRecordCount), " records");
59
59
  } }
60
60
  function EntityViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
61
- i0.ɵɵelementStart(0, "div", 7);
61
+ i0.ɵɵelementStart(0, "div", 15);
62
62
  i0.ɵɵtemplate(1, EntityViewerComponent_Conditional_1_Conditional_2_Conditional_1_Template, 4, 6, "span")(2, EntityViewerComponent_Conditional_1_Conditional_2_Conditional_2_Template, 3, 3, "span");
63
63
  i0.ɵɵelementEnd();
64
64
  } if (rf & 2) {
@@ -68,9 +68,9 @@ function EntityViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { i
68
68
  } }
69
69
  function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
70
70
  const _r5 = i0.ɵɵgetCurrentView();
71
- i0.ɵɵelementStart(0, "button", 19);
71
+ i0.ɵɵelementStart(0, "button", 27);
72
72
  i0.ɵɵlistener("click", function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.setViewMode("timeline")); });
73
- i0.ɵɵelement(1, "i", 20);
73
+ i0.ɵɵelement(1, "i", 28);
74
74
  i0.ɵɵelementEnd();
75
75
  } if (rf & 2) {
76
76
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -78,15 +78,15 @@ function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Templat
78
78
  } }
79
79
  function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
80
80
  const _r4 = i0.ɵɵgetCurrentView();
81
- i0.ɵɵelementStart(0, "div", 8)(1, "button", 14);
81
+ i0.ɵɵelementStart(0, "div", 16)(1, "button", 22);
82
82
  i0.ɵɵlistener("click", function EntityViewerComponent_Conditional_1_Conditional_3_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setViewMode("grid")); });
83
- i0.ɵɵelement(2, "i", 15);
83
+ i0.ɵɵelement(2, "i", 23);
84
84
  i0.ɵɵelementEnd();
85
- i0.ɵɵelementStart(3, "button", 16);
85
+ i0.ɵɵelementStart(3, "button", 24);
86
86
  i0.ɵɵlistener("click", function EntityViewerComponent_Conditional_1_Conditional_3_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setViewMode("cards")); });
87
- i0.ɵɵelement(4, "i", 17);
87
+ i0.ɵɵelement(4, "i", 25);
88
88
  i0.ɵɵelementEnd();
89
- i0.ɵɵtemplate(5, EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template, 2, 2, "button", 18);
89
+ i0.ɵɵtemplate(5, EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template, 2, 2, "button", 26);
90
90
  i0.ɵɵelementEnd();
91
91
  } if (rf & 2) {
92
92
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -98,7 +98,7 @@ function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { i
98
98
  i0.ɵɵconditional(ctx_r1.hasDateFields ? 5 : -1);
99
99
  } }
100
100
  function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template(rf, ctx) { if (rf & 1) {
101
- i0.ɵɵelementStart(0, "span", 23);
101
+ i0.ɵɵelementStart(0, "span", 31);
102
102
  i0.ɵɵtext(1);
103
103
  i0.ɵɵelementEnd();
104
104
  } if (rf & 2) {
@@ -107,7 +107,7 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Templat
107
107
  i0.ɵɵtextInterpolate(ctx_r1.selectedDateFieldDisplayName);
108
108
  } }
109
109
  function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
110
- i0.ɵɵelementStart(0, "option", 29);
110
+ i0.ɵɵelementStart(0, "option", 37);
111
111
  i0.ɵɵtext(1);
112
112
  i0.ɵɵelementEnd();
113
113
  } if (rf & 2) {
@@ -118,9 +118,9 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_T
118
118
  } }
119
119
  function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
120
120
  const _r7 = i0.ɵɵgetCurrentView();
121
- i0.ɵɵelementStart(0, "select", 28);
121
+ i0.ɵɵelementStart(0, "select", 36);
122
122
  i0.ɵɵlistener("change", function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template_select_change_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.setTimelineDateField($event.target.value)); });
123
- i0.ɵɵrepeaterCreate(1, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template, 2, 2, "option", 29, _forTrack0);
123
+ i0.ɵɵrepeaterCreate(1, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template, 2, 2, "option", 37, _forTrack0);
124
124
  i0.ɵɵelementEnd();
125
125
  } if (rf & 2) {
126
126
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -130,15 +130,15 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Templat
130
130
  } }
131
131
  function EntityViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
132
132
  const _r6 = i0.ɵɵgetCurrentView();
133
- i0.ɵɵelementStart(0, "div", 21);
134
- i0.ɵɵelement(1, "i", 22);
135
- i0.ɵɵtemplate(2, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template, 2, 1, "span", 23)(3, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template, 3, 1, "select", 24);
133
+ i0.ɵɵelementStart(0, "div", 29);
134
+ i0.ɵɵelement(1, "i", 30);
135
+ i0.ɵɵtemplate(2, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template, 2, 1, "span", 31)(3, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template, 3, 1, "select", 32);
136
136
  i0.ɵɵelementEnd();
137
- i0.ɵɵelementStart(4, "div", 25)(5, "button", 26);
137
+ i0.ɵɵelementStart(4, "div", 33)(5, "button", 34);
138
138
  i0.ɵɵlistener("click", function EntityViewerComponent_Conditional_1_Conditional_4_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleTimelineOrientation()); });
139
139
  i0.ɵɵelement(6, "i");
140
140
  i0.ɵɵelementEnd()();
141
- i0.ɵɵelementStart(7, "div", 27)(8, "button", 26);
141
+ i0.ɵɵelementStart(7, "div", 35)(8, "button", 34);
142
142
  i0.ɵɵlistener("click", function EntityViewerComponent_Conditional_1_Conditional_4_Template_button_click_8_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleTimelineSortOrder()); });
143
143
  i0.ɵɵelement(9, "i");
144
144
  i0.ɵɵelementEnd()();
@@ -157,7 +157,7 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { i
157
157
  } }
158
158
  function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
159
159
  i0.ɵɵelementStart(0, "div", 1);
160
- i0.ɵɵtemplate(1, EntityViewerComponent_Conditional_1_Conditional_1_Template, 4, 3, "div", 6)(2, EntityViewerComponent_Conditional_1_Conditional_2_Template, 3, 1, "div", 7)(3, EntityViewerComponent_Conditional_1_Conditional_3_Template, 6, 5, "div", 8)(4, EntityViewerComponent_Conditional_1_Conditional_4_Template, 10, 7);
160
+ i0.ɵɵtemplate(1, EntityViewerComponent_Conditional_1_Conditional_1_Template, 4, 3, "div", 14)(2, EntityViewerComponent_Conditional_1_Conditional_2_Template, 3, 1, "div", 15)(3, EntityViewerComponent_Conditional_1_Conditional_3_Template, 6, 5, "div", 16)(4, EntityViewerComponent_Conditional_1_Conditional_4_Template, 10, 7);
161
161
  i0.ɵɵelementEnd();
162
162
  } if (rf & 2) {
163
163
  const ctx_r1 = i0.ɵɵnextContext();
@@ -170,63 +170,10 @@ function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
170
170
  i0.ɵɵadvance();
171
171
  i0.ɵɵconditional(ctx_r1.effectiveViewMode === "timeline" && ctx_r1.hasDateFields ? 4 : -1);
172
172
  } }
173
- function EntityViewerComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
174
- i0.ɵɵelementStart(0, "div", 3);
175
- i0.ɵɵelement(1, "mj-loading", 30);
176
- i0.ɵɵelementEnd();
177
- } if (rf & 2) {
178
- const ctx_r1 = i0.ɵɵnextContext();
179
- i0.ɵɵadvance();
180
- i0.ɵɵproperty("text", ctx_r1.loadingMessage);
181
- } }
182
- function EntityViewerComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
183
- i0.ɵɵelementStart(0, "div", 4);
184
- i0.ɵɵelement(1, "i", 31);
185
- i0.ɵɵelementStart(2, "p");
186
- i0.ɵɵtext(3, "Select an entity to view records");
187
- i0.ɵɵelementEnd()();
188
- } }
189
- function EntityViewerComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
190
- i0.ɵɵelementStart(0, "div", 4);
191
- i0.ɵɵelement(1, "i", 32);
192
- i0.ɵɵelementStart(2, "p");
193
- i0.ɵɵtext(3);
194
- i0.ɵɵelementEnd()();
195
- } if (rf & 2) {
196
- const ctx_r1 = i0.ɵɵnextContext();
197
- i0.ɵɵadvance(3);
198
- i0.ɵɵtextInterpolate(ctx_r1.debouncedFilterText ? "No matching records" : "No records found");
199
- } }
200
- function EntityViewerComponent_Conditional_6_Conditional_2_Template(rf, ctx) { if (rf & 1) {
201
- const _r10 = i0.ɵɵgetCurrentView();
202
- i0.ɵɵelementStart(0, "mj-timeline", 36);
203
- i0.ɵɵlistener("afterEventClick", function EntityViewerComponent_Conditional_6_Conditional_2_Template_mj_timeline_afterEventClick_0_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onTimelineEventClick($event)); });
204
- i0.ɵɵelementEnd();
205
- } if (rf & 2) {
206
- const ctx_r1 = i0.ɵɵnextContext(2);
207
- i0.ɵɵproperty("groups", ctx_r1.timelineGroups)("orientation", ctx_r1.timelineOrientation)("layout", ctx_r1.timelineOrientation === "vertical" ? "alternating" : "single")("sortOrder", ctx_r1.timelineSortOrder)("segmentGrouping", ctx_r1.timelineSegmentGrouping)("segmentsCollapsible", true)("segmentsDefaultExpanded", true)("selectedEventId", ctx_r1.timelineSelectedEventId);
208
- } }
209
- function EntityViewerComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
173
+ function EntityViewerComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
210
174
  const _r9 = i0.ɵɵgetCurrentView();
211
- i0.ɵɵelementStart(0, "mj-entity-grid", 33);
212
- i0.ɵɵlistener("recordSelected", function EntityViewerComponent_Conditional_6_Template_mj_entity_grid_recordSelected_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRecordSelected($event)); })("recordOpened", function EntityViewerComponent_Conditional_6_Template_mj_entity_grid_recordOpened_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRecordOpened($event)); })("sortChanged", function EntityViewerComponent_Conditional_6_Template_mj_entity_grid_sortChanged_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSortChanged($event)); })("gridStateChanged", function EntityViewerComponent_Conditional_6_Template_mj_entity_grid_gridStateChanged_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onGridStateChanged($event)); });
213
- i0.ɵɵelementEnd();
214
- i0.ɵɵelementStart(1, "mj-entity-cards", 34);
215
- i0.ɵɵlistener("recordSelected", function EntityViewerComponent_Conditional_6_Template_mj_entity_cards_recordSelected_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRecordSelected($event)); })("recordOpened", function EntityViewerComponent_Conditional_6_Template_mj_entity_cards_recordOpened_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRecordOpened($event)); });
216
- i0.ɵɵelementEnd();
217
- i0.ɵɵtemplate(2, EntityViewerComponent_Conditional_6_Conditional_2_Template, 1, 8, "mj-timeline", 35);
218
- } if (rf & 2) {
219
- const ctx_r1 = i0.ɵɵnextContext();
220
- i0.ɵɵproperty("hidden", ctx_r1.effectiveViewMode !== "grid")("entity", ctx_r1.entity)("records", ctx_r1.filteredRecords)("selectedRecordId", ctx_r1.selectedRecordId)("columns", ctx_r1.gridColumns)("height", "100%")("filterText", ctx_r1.debouncedFilterText)("sortState", ctx_r1.effectiveSortState)("serverSideSorting", ctx_r1.effectiveConfig.serverSideSorting)("gridState", ctx_r1.gridState);
221
- i0.ɵɵadvance();
222
- i0.ɵɵproperty("hidden", ctx_r1.effectiveViewMode !== "cards")("entity", ctx_r1.entity)("records", ctx_r1.filteredRecords)("selectedRecordId", ctx_r1.selectedRecordId)("cardTemplate", ctx_r1.cardTemplate)("hiddenFieldMatches", ctx_r1.hiddenFieldMatches)("filterText", ctx_r1.debouncedFilterText);
223
- i0.ɵɵadvance();
224
- i0.ɵɵconditional(ctx_r1.hasDateFields && ctx_r1.effectiveViewMode === "timeline" ? 2 : -1);
225
- } }
226
- function EntityViewerComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
227
- const _r11 = i0.ɵɵgetCurrentView();
228
- i0.ɵɵelementStart(0, "mj-pagination", 37);
229
- i0.ɵɵlistener("loadMore", function EntityViewerComponent_Conditional_7_Template_mj_pagination_loadMore_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onLoadMore()); });
175
+ i0.ɵɵelementStart(0, "mj-pagination", 38);
176
+ i0.ɵɵlistener("loadMore", function EntityViewerComponent_Conditional_18_Template_mj_pagination_loadMore_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onLoadMore()); });
230
177
  i0.ɵɵelementEnd();
231
178
  } if (rf & 2) {
232
179
  const ctx_r1 = i0.ɵɵnextContext();
@@ -344,6 +291,23 @@ export class EntityViewerComponent {
344
291
  }
345
292
  }
346
293
  _timelineConfig = null;
294
+ /**
295
+ * Whether to show the grid toolbar.
296
+ * When false, the grid is displayed without its own toolbar - useful when
297
+ * entity-viewer provides its own filter/actions in the header.
298
+ * @default false
299
+ */
300
+ showGridToolbar = false;
301
+ /**
302
+ * Grid toolbar configuration - controls which buttons are shown and their behavior
303
+ * When not provided, uses sensible defaults
304
+ */
305
+ gridToolbarConfig = null;
306
+ /**
307
+ * Grid selection mode
308
+ * @default 'single'
309
+ */
310
+ gridSelectionMode = 'single';
347
311
  // ========================================
348
312
  // OUTPUTS
349
313
  // ========================================
@@ -383,6 +347,23 @@ export class EntityViewerComponent {
383
347
  * Emitted when timeline configuration changes (date field, grouping, etc.)
384
348
  */
385
349
  timelineConfigChange = new EventEmitter();
350
+ /**
351
+ * Emitted when the Add/New button is clicked in the grid toolbar
352
+ */
353
+ addRequested = new EventEmitter();
354
+ /**
355
+ * Emitted when the Delete button is clicked in the grid toolbar
356
+ * Includes the selected records to be deleted
357
+ */
358
+ deleteRequested = new EventEmitter();
359
+ /**
360
+ * Emitted when the Refresh button is clicked in the grid toolbar
361
+ */
362
+ refreshRequested = new EventEmitter();
363
+ /**
364
+ * Emitted when the Export button is clicked in the grid toolbar
365
+ */
366
+ exportRequested = new EventEmitter();
386
367
  // ========================================
387
368
  // INTERNAL STATE
388
369
  // ========================================
@@ -398,6 +379,10 @@ export class EntityViewerComponent {
398
379
  hiddenFieldMatches = new Map();
399
380
  /** Current sort state */
400
381
  internalSortState = null;
382
+ /** Cached grid params to avoid recreating object on every change detection */
383
+ _cachedGridParams = null;
384
+ _lastGridParamsEntity = null;
385
+ _lastGridParamsViewEntity = null;
401
386
  /** Pagination state */
402
387
  pagination = {
403
388
  currentPage: 0,
@@ -488,12 +473,61 @@ export class EntityViewerComponent {
488
473
  get effectiveSortState() {
489
474
  return this.sortState ?? this.internalSortState;
490
475
  }
476
+ /**
477
+ * Get the OrderBy string for mj-entity-data-grid from the effective sort state
478
+ */
479
+ get effectiveSortOrderBy() {
480
+ const sortState = this.effectiveSortState;
481
+ if (!sortState?.field || !sortState.direction) {
482
+ return '';
483
+ }
484
+ return `${sortState.field} ${sortState.direction.toUpperCase()}`;
485
+ }
491
486
  /**
492
487
  * Get merged configuration with defaults
493
488
  */
494
489
  get effectiveConfig() {
495
490
  return { ...DEFAULT_VIEWER_CONFIG, ...this.config };
496
491
  }
492
+ /**
493
+ * Get cached grid params - only recreates object when entity or viewEntity changes
494
+ * This prevents Angular from seeing a new object reference on every change detection
495
+ * which would cause the grid to reinitialize
496
+ */
497
+ get gridParams() {
498
+ if (!this.entity) {
499
+ return null;
500
+ }
501
+ // Check if we need to recreate the params object
502
+ const entityChanged = this._lastGridParamsEntity !== this.entity.Name;
503
+ const viewEntityChanged = this._lastGridParamsViewEntity !== this.viewEntity;
504
+ if (entityChanged || viewEntityChanged || !this._cachedGridParams) {
505
+ this._lastGridParamsEntity = this.entity.Name;
506
+ this._lastGridParamsViewEntity = this.viewEntity ?? null;
507
+ this._cachedGridParams = {
508
+ EntityName: this.entity.Name,
509
+ ViewEntity: this.viewEntity || undefined
510
+ };
511
+ }
512
+ return this._cachedGridParams;
513
+ }
514
+ /**
515
+ * Get the effective grid toolbar configuration
516
+ * Merges user-provided config with defaults appropriate for entity-viewer context
517
+ */
518
+ get effectiveGridToolbarConfig() {
519
+ const defaults = {
520
+ showSearch: false, // Entity-viewer has its own filter
521
+ showRefresh: true,
522
+ showAdd: true,
523
+ showDelete: true,
524
+ showExport: true,
525
+ showColumnChooser: true,
526
+ showRowCount: true,
527
+ showSelectionCount: true
528
+ };
529
+ return { ...defaults, ...this.gridToolbarConfig };
530
+ }
497
531
  /**
498
532
  * Get the records to display (external or internal)
499
533
  */
@@ -987,6 +1021,81 @@ export class EntityViewerComponent {
987
1021
  this.loadMore();
988
1022
  }
989
1023
  // ========================================
1024
+ // DATA GRID EVENT HANDLERS
1025
+ // ========================================
1026
+ /**
1027
+ * Handle row click from mj-entity-data-grid
1028
+ * Maps to recordSelected event for parent components
1029
+ */
1030
+ onDataGridRowClick(event) {
1031
+ if (!this.entity || !event.row)
1032
+ return;
1033
+ this.recordSelected.emit({
1034
+ record: event.row,
1035
+ entity: this.entity,
1036
+ compositeKey: event.row.PrimaryKey
1037
+ });
1038
+ }
1039
+ /**
1040
+ * Handle row double-click from mj-entity-data-grid
1041
+ * Maps to recordOpened event for parent components
1042
+ */
1043
+ onDataGridRowDoubleClick(event) {
1044
+ if (!this.entity || !event.row)
1045
+ return;
1046
+ this.recordOpened.emit({
1047
+ record: event.row,
1048
+ entity: this.entity,
1049
+ compositeKey: event.row.PrimaryKey
1050
+ });
1051
+ }
1052
+ /**
1053
+ * Handle sort changed from mj-entity-data-grid
1054
+ * Maps to sortChanged event for parent components
1055
+ */
1056
+ onDataGridSortChanged(event) {
1057
+ // Convert the data grid's sort state to our SortState format
1058
+ const newSort = event.newSortState && event.newSortState.length > 0
1059
+ ? {
1060
+ field: event.newSortState[0].field,
1061
+ direction: event.newSortState[0].direction
1062
+ }
1063
+ : null;
1064
+ this.internalSortState = newSort;
1065
+ this.sortChanged.emit({ sort: newSort });
1066
+ // If server-side sorting, reload from page 1
1067
+ if (this.effectiveConfig.serverSideSorting && !this.records) {
1068
+ this.resetPaginationState();
1069
+ this.loadData();
1070
+ }
1071
+ }
1072
+ /**
1073
+ * Handle Add/New button click from data grid toolbar
1074
+ */
1075
+ onGridAddRequested() {
1076
+ this.addRequested.emit();
1077
+ }
1078
+ /**
1079
+ * Handle Refresh button click from data grid toolbar
1080
+ */
1081
+ onGridRefreshRequested() {
1082
+ this.refreshRequested.emit();
1083
+ // Also trigger an internal refresh
1084
+ this.refresh();
1085
+ }
1086
+ /**
1087
+ * Handle Delete button click from data grid toolbar
1088
+ */
1089
+ onGridDeleteRequested(records) {
1090
+ this.deleteRequested.emit({ records });
1091
+ }
1092
+ /**
1093
+ * Handle Export button click from data grid toolbar
1094
+ */
1095
+ onGridExportRequested() {
1096
+ this.exportRequested.emit({ format: 'excel' });
1097
+ }
1098
+ // ========================================
990
1099
  // TIMELINE METHODS
991
1100
  // ========================================
992
1101
  /**
@@ -1231,29 +1340,69 @@ export class EntityViewerComponent {
1231
1340
  return firstOther?.Name || null;
1232
1341
  }
1233
1342
  static ɵfac = function EntityViewerComponent_Factory(t) { return new (t || EntityViewerComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
1234
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityViewerComponent, selectors: [["mj-entity-viewer"]], hostAttrs: [2, "display", "block", "height", "100%"], inputs: { entity: "entity", records: "records", config: "config", selectedRecordId: "selectedRecordId", viewMode: "viewMode", filterText: "filterText", sortState: "sortState", gridColumns: "gridColumns", cardTemplate: "cardTemplate", viewEntity: "viewEntity", gridState: "gridState", timelineConfig: "timelineConfig" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened", dataLoaded: "dataLoaded", viewModeChange: "viewModeChange", filterTextChange: "filterTextChange", filteredCountChanged: "filteredCountChanged", sortChanged: "sortChanged", gridStateChanged: "gridStateChanged", timelineConfigChange: "timelineConfigChange" }, features: [i0.ɵɵNgOnChangesFeature], decls: 8, vars: 5, consts: [[1, "entity-viewer-container"], [1, "viewer-header"], [1, "viewer-content"], [1, "loading-container"], [1, "empty-state"], [3, "pagination", "loadedRecordCount"], [1, "filter-container"], [1, "record-count"], [1, "view-mode-toggle"], [1, "fa-solid", "fa-search", "filter-icon"], ["type", "text", 1, "filter-input", 3, "input", "placeholder", "value"], ["title", "Clear filter", 1, "clear-filter-btn"], ["title", "Clear filter", 1, "clear-filter-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Grid View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-list"], ["title", "Cards View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-grip"], ["title", "Timeline View", 1, "toggle-btn", 3, "active"], ["title", "Timeline View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-timeline"], [1, "timeline-date-selector"], [1, "fa-solid", "fa-calendar-days"], [1, "date-field-label"], [1, "date-field-select", 3, "value"], [1, "timeline-orientation-toggle"], [1, "toggle-btn", 3, "click", "title"], [1, "timeline-sort-toggle"], [1, "date-field-select", 3, "change", "value"], [3, "value"], ["size", "medium", 3, "text"], [1, "fa-solid", "fa-database"], [1, "fa-solid", "fa-inbox"], [3, "recordSelected", "recordOpened", "sortChanged", "gridStateChanged", "hidden", "entity", "records", "selectedRecordId", "columns", "height", "filterText", "sortState", "serverSideSorting", "gridState"], [3, "recordSelected", "recordOpened", "hidden", "entity", "records", "selectedRecordId", "cardTemplate", "hiddenFieldMatches", "filterText"], [3, "groups", "orientation", "layout", "sortOrder", "segmentGrouping", "segmentsCollapsible", "segmentsDefaultExpanded", "selectedEventId"], [3, "afterEventClick", "groups", "orientation", "layout", "sortOrder", "segmentGrouping", "segmentsCollapsible", "segmentsDefaultExpanded", "selectedEventId"], [3, "loadMore", "pagination", "loadedRecordCount"]], template: function EntityViewerComponent_Template(rf, ctx) { if (rf & 1) {
1343
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityViewerComponent, selectors: [["mj-entity-viewer"]], hostAttrs: [2, "display", "block", "height", "100%"], inputs: { entity: "entity", records: "records", config: "config", selectedRecordId: "selectedRecordId", viewMode: "viewMode", filterText: "filterText", sortState: "sortState", gridColumns: "gridColumns", cardTemplate: "cardTemplate", viewEntity: "viewEntity", gridState: "gridState", timelineConfig: "timelineConfig", showGridToolbar: "showGridToolbar", gridToolbarConfig: "gridToolbarConfig", gridSelectionMode: "gridSelectionMode" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened", dataLoaded: "dataLoaded", viewModeChange: "viewModeChange", filterTextChange: "filterTextChange", filteredCountChanged: "filteredCountChanged", sortChanged: "sortChanged", gridStateChanged: "gridStateChanged", timelineConfigChange: "timelineConfigChange", addRequested: "addRequested", deleteRequested: "deleteRequested", refreshRequested: "refreshRequested", exportRequested: "exportRequested" }, features: [i0.ɵɵNgOnChangesFeature], decls: 19, vars: 37, consts: [[1, "entity-viewer-container"], [1, "viewer-header"], [1, "viewer-content"], [1, "loading-container", 3, "hidden"], ["size", "medium", 3, "text"], [1, "loading-overlay", 3, "hidden"], ["size", "small", 3, "text"], [1, "empty-state", 3, "hidden"], [1, "fa-solid", "fa-database"], [1, "fa-solid", "fa-inbox"], [3, "AfterRowClick", "AfterRowDoubleClick", "AfterSort", "GridStateChanged", "NewButtonClick", "RefreshButtonClick", "DeleteButtonClick", "ExportButtonClick", "hidden", "Data", "Params", "FilterText", "GridState", "Height", "ShowToolbar", "ToolbarConfig", "SelectionMode", "AllowLoad"], [3, "recordSelected", "recordOpened", "hidden", "entity", "records", "selectedRecordId", "cardTemplate", "hiddenFieldMatches", "filterText"], [3, "afterEventClick", "hidden", "groups", "orientation", "layout", "sortOrder", "segmentGrouping", "segmentsCollapsible", "segmentsDefaultExpanded", "selectedEventId"], [3, "pagination", "loadedRecordCount"], [1, "filter-container"], [1, "record-count"], [1, "view-mode-toggle"], [1, "fa-solid", "fa-search", "filter-icon"], ["type", "text", 1, "filter-input", 3, "input", "placeholder", "value"], ["title", "Clear filter", 1, "clear-filter-btn"], ["title", "Clear filter", 1, "clear-filter-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Grid View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-list"], ["title", "Cards View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-grip"], ["title", "Timeline View", 1, "toggle-btn", 3, "active"], ["title", "Timeline View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-timeline"], [1, "timeline-date-selector"], [1, "fa-solid", "fa-calendar-days"], [1, "date-field-label"], [1, "date-field-select", 3, "value"], [1, "timeline-orientation-toggle"], [1, "toggle-btn", 3, "click", "title"], [1, "timeline-sort-toggle"], [1, "date-field-select", 3, "change", "value"], [3, "value"], [3, "loadMore", "pagination", "loadedRecordCount"]], template: function EntityViewerComponent_Template(rf, ctx) { if (rf & 1) {
1235
1344
  i0.ɵɵelementStart(0, "div", 0);
1236
1345
  i0.ɵɵtemplate(1, EntityViewerComponent_Conditional_1_Template, 5, 4, "div", 1);
1237
- i0.ɵɵelementStart(2, "div", 2);
1238
- i0.ɵɵtemplate(3, EntityViewerComponent_Conditional_3_Template, 2, 1, "div", 3)(4, EntityViewerComponent_Conditional_4_Template, 4, 0, "div", 4)(5, EntityViewerComponent_Conditional_5_Template, 4, 1, "div", 4)(6, EntityViewerComponent_Conditional_6_Template, 3, 18);
1346
+ i0.ɵɵelementStart(2, "div", 2)(3, "div", 3);
1347
+ i0.ɵɵelement(4, "mj-loading", 4);
1348
+ i0.ɵɵelementEnd();
1349
+ i0.ɵɵelementStart(5, "div", 5);
1350
+ i0.ɵɵelement(6, "mj-loading", 6);
1351
+ i0.ɵɵelementEnd();
1352
+ i0.ɵɵelementStart(7, "div", 7);
1353
+ i0.ɵɵelement(8, "i", 8);
1354
+ i0.ɵɵelementStart(9, "p");
1355
+ i0.ɵɵtext(10, "Select an entity to view records");
1356
+ i0.ɵɵelementEnd()();
1357
+ i0.ɵɵelementStart(11, "div", 7);
1358
+ i0.ɵɵelement(12, "i", 9);
1359
+ i0.ɵɵelementStart(13, "p");
1360
+ i0.ɵɵtext(14);
1361
+ i0.ɵɵelementEnd()();
1362
+ i0.ɵɵelementStart(15, "mj-entity-data-grid", 10);
1363
+ i0.ɵɵlistener("AfterRowClick", function EntityViewerComponent_Template_mj_entity_data_grid_AfterRowClick_15_listener($event) { return ctx.onDataGridRowClick($event); })("AfterRowDoubleClick", function EntityViewerComponent_Template_mj_entity_data_grid_AfterRowDoubleClick_15_listener($event) { return ctx.onDataGridRowDoubleClick($event); })("AfterSort", function EntityViewerComponent_Template_mj_entity_data_grid_AfterSort_15_listener($event) { return ctx.onDataGridSortChanged($event); })("GridStateChanged", function EntityViewerComponent_Template_mj_entity_data_grid_GridStateChanged_15_listener($event) { return ctx.onGridStateChanged($event); })("NewButtonClick", function EntityViewerComponent_Template_mj_entity_data_grid_NewButtonClick_15_listener() { return ctx.onGridAddRequested(); })("RefreshButtonClick", function EntityViewerComponent_Template_mj_entity_data_grid_RefreshButtonClick_15_listener() { return ctx.onGridRefreshRequested(); })("DeleteButtonClick", function EntityViewerComponent_Template_mj_entity_data_grid_DeleteButtonClick_15_listener($event) { return ctx.onGridDeleteRequested($event); })("ExportButtonClick", function EntityViewerComponent_Template_mj_entity_data_grid_ExportButtonClick_15_listener() { return ctx.onGridExportRequested(); });
1239
1364
  i0.ɵɵelementEnd();
1240
- i0.ɵɵtemplate(7, EntityViewerComponent_Conditional_7_Template, 1, 2, "mj-pagination", 5);
1365
+ i0.ɵɵelementStart(16, "mj-entity-cards", 11);
1366
+ i0.ɵɵlistener("recordSelected", function EntityViewerComponent_Template_mj_entity_cards_recordSelected_16_listener($event) { return ctx.onRecordSelected($event); })("recordOpened", function EntityViewerComponent_Template_mj_entity_cards_recordOpened_16_listener($event) { return ctx.onRecordOpened($event); });
1367
+ i0.ɵɵelementEnd();
1368
+ i0.ɵɵelementStart(17, "mj-timeline", 12);
1369
+ i0.ɵɵlistener("afterEventClick", function EntityViewerComponent_Template_mj_timeline_afterEventClick_17_listener($event) { return ctx.onTimelineEventClick($event); });
1370
+ i0.ɵɵelementEnd()();
1371
+ i0.ɵɵtemplate(18, EntityViewerComponent_Conditional_18_Template, 1, 2, "mj-pagination", 13);
1241
1372
  i0.ɵɵelementEnd();
1242
1373
  } if (rf & 2) {
1243
1374
  i0.ɵɵstyleProp("height", ctx.effectiveConfig.height);
1244
1375
  i0.ɵɵadvance();
1245
1376
  i0.ɵɵconditional(ctx.effectiveConfig.showFilter || ctx.effectiveConfig.showViewModeToggle || ctx.effectiveConfig.showRecordCount ? 1 : -1);
1246
1377
  i0.ɵɵadvance(2);
1247
- i0.ɵɵconditional(ctx.isLoading && ctx.filteredRecords.length === 0 ? 3 : !ctx.entity ? 4 : ctx.filteredRecords.length === 0 && !ctx.isLoading ? 5 : 6);
1378
+ i0.ɵɵproperty("hidden", !(ctx.isLoading && ctx.filteredRecords.length === 0));
1379
+ i0.ɵɵadvance();
1380
+ i0.ɵɵproperty("text", ctx.loadingMessage);
1381
+ i0.ɵɵadvance();
1382
+ i0.ɵɵproperty("hidden", !(ctx.isLoading && ctx.filteredRecords.length > 0));
1383
+ i0.ɵɵadvance();
1384
+ i0.ɵɵproperty("text", ctx.loadingMessage);
1385
+ i0.ɵɵadvance();
1386
+ i0.ɵɵproperty("hidden", !!ctx.entity);
1248
1387
  i0.ɵɵadvance(4);
1249
- i0.ɵɵconditional(ctx.effectiveConfig.showPagination && ctx.entity && (ctx.pagination.hasMore || ctx.pagination.totalRecords > ctx.effectiveConfig.pageSize) ? 7 : -1);
1250
- } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i2.LoadingComponent, i3.TimelineComponent, i4.EntityGridComponent, i5.EntityCardsComponent, i6.PaginationComponent, i7.DecimalPipe], styles: [".entity-viewer-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n background: #fafafa;\n}\n\n\n\n.viewer-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 12px 16px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n flex-shrink: 0;\n}\n\n\n\n.filter-container[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 400px;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n color: #9e9e9e;\n font-size: 14px;\n pointer-events: none;\n}\n\n.filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 36px 8px 36px;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n font-size: 14px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.filter-input[_ngcontent-%COMP%]:focus {\n border-color: #1976d2;\n}\n\n.filter-input[_ngcontent-%COMP%]::placeholder {\n color: #9e9e9e;\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n width: 20px;\n height: 20px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #9e9e9e;\n transition: all 0.15s ease;\n}\n\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n color: #616161;\n}\n\n\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #757575;\n white-space: nowrap;\n}\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n transition: all 0.15s ease;\n}\n\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: #424242;\n}\n\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: white;\n color: #1976d2;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n\n.timeline-date-selector[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: #616161;\n}\n\n.timeline-date-selector[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #9e9e9e;\n}\n\n.date-field-label[_ngcontent-%COMP%] {\n color: #424242;\n font-weight: 500;\n}\n\n.date-field-select[_ngcontent-%COMP%] {\n padding: 4px 8px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 13px;\n background: white;\n color: #424242;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.date-field-select[_ngcontent-%COMP%]:hover {\n border-color: #bdbdbd;\n}\n\n.date-field-select[_ngcontent-%COMP%]:focus {\n border-color: #1976d2;\n}\n\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n\n\n.viewer-content[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n position: relative;\n background: white;\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #9e9e9e;\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\nmj-entity-grid[hidden][_ngcontent-%COMP%], \nmj-entity-cards[hidden][_ngcontent-%COMP%], \nmj-timeline[hidden][_ngcontent-%COMP%] {\n display: none !important;\n}\n\n\n\nmj-entity-grid[_ngcontent-%COMP%]:not([hidden]), \nmj-entity-cards[_ngcontent-%COMP%]:not([hidden]), \nmj-timeline[_ngcontent-%COMP%]:not([hidden]) {\n display: block;\n height: 100%;\n width: 100%;\n}"] });
1388
+ i0.ɵɵproperty("hidden", !ctx.entity || ctx.filteredRecords.length > 0 || ctx.isLoading);
1389
+ i0.ɵɵadvance(3);
1390
+ i0.ɵɵtextInterpolate(ctx.debouncedFilterText ? "No matching records" : "No records found");
1391
+ i0.ɵɵadvance();
1392
+ i0.ɵɵproperty("hidden", ctx.effectiveViewMode !== "grid" || !ctx.entity)("Data", ctx.filteredRecords)("Params", ctx.gridParams)("FilterText", ctx.debouncedFilterText)("GridState", ctx.gridState)("Height", "auto")("ShowToolbar", ctx.showGridToolbar)("ToolbarConfig", ctx.effectiveGridToolbarConfig)("SelectionMode", ctx.gridSelectionMode)("AllowLoad", false);
1393
+ i0.ɵɵadvance();
1394
+ i0.ɵɵproperty("hidden", ctx.effectiveViewMode !== "cards" || !ctx.entity)("entity", ctx.entity)("records", ctx.filteredRecords)("selectedRecordId", ctx.selectedRecordId)("cardTemplate", ctx.cardTemplate)("hiddenFieldMatches", ctx.hiddenFieldMatches)("filterText", ctx.debouncedFilterText);
1395
+ i0.ɵɵadvance();
1396
+ i0.ɵɵproperty("hidden", ctx.effectiveViewMode !== "timeline" || !ctx.hasDateFields)("groups", ctx.timelineGroups)("orientation", ctx.timelineOrientation)("layout", ctx.timelineOrientation === "vertical" ? "alternating" : "single")("sortOrder", ctx.timelineSortOrder)("segmentGrouping", ctx.timelineSegmentGrouping)("segmentsCollapsible", true)("segmentsDefaultExpanded", true)("selectedEventId", ctx.timelineSelectedEventId);
1397
+ i0.ɵɵadvance();
1398
+ i0.ɵɵconditional(ctx.effectiveConfig.showPagination && ctx.entity && (ctx.pagination.hasMore || ctx.pagination.totalRecords > ctx.effectiveConfig.pageSize) ? 18 : -1);
1399
+ } }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i2.LoadingComponent, i3.TimelineComponent, i4.EntityCardsComponent, i5.PaginationComponent, i6.EntityDataGridComponent, i7.DecimalPipe], styles: [".entity-viewer-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: #fafafa;\n}\n\n\n\nmj-pagination[_ngcontent-%COMP%] {\n flex-shrink: 0;\n}\n\n\n\n.viewer-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 12px 16px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n flex-shrink: 0;\n}\n\n\n\n.filter-container[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 400px;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 12px;\n color: #9e9e9e;\n font-size: 14px;\n pointer-events: none;\n}\n\n.filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 8px 36px 8px 36px;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n font-size: 14px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.filter-input[_ngcontent-%COMP%]:focus {\n border-color: #1976d2;\n}\n\n.filter-input[_ngcontent-%COMP%]::placeholder {\n color: #9e9e9e;\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n width: 20px;\n height: 20px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #9e9e9e;\n transition: all 0.15s ease;\n}\n\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: #f5f5f5;\n color: #616161;\n}\n\n\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: #757575;\n white-space: nowrap;\n}\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n transition: all 0.15s ease;\n}\n\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: #424242;\n}\n\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: white;\n color: #1976d2;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n\n\n.timeline-date-selector[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: #616161;\n}\n\n.timeline-date-selector[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #9e9e9e;\n}\n\n.date-field-label[_ngcontent-%COMP%] {\n color: #424242;\n font-weight: 500;\n}\n\n.date-field-select[_ngcontent-%COMP%] {\n padding: 4px 8px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 13px;\n background: white;\n color: #424242;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.date-field-select[_ngcontent-%COMP%]:hover {\n border-color: #bdbdbd;\n}\n\n.date-field-select[_ngcontent-%COMP%]:focus {\n border-color: #1976d2;\n}\n\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n\n\n.viewer-content[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n position: relative;\n background: white;\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n\n\n.loading-overlay[_ngcontent-%COMP%] {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.8);\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n\n.empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #9e9e9e;\n text-align: center;\n}\n\n.empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n}\n\n\n\nmj-entity-cards[hidden][_ngcontent-%COMP%], \nmj-timeline[hidden][_ngcontent-%COMP%] {\n display: none !important;\n}\n\n\n\nmj-entity-cards[_ngcontent-%COMP%]:not([hidden]), \nmj-timeline[_ngcontent-%COMP%]:not([hidden]) {\n display: block;\n height: 100%;\n width: 100%;\n}"] });
1251
1400
  }
1252
1401
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityViewerComponent, [{
1253
1402
  type: Component,
1254
1403
  args: [{ selector: 'mj-entity-viewer', host: {
1255
1404
  'style': 'display: block; height: 100%;'
1256
- }, template: "<div class=\"entity-viewer-container\" [style.height]=\"effectiveConfig.height\">\n <!-- Header -->\n @if (effectiveConfig.showFilter || effectiveConfig.showViewModeToggle || effectiveConfig.showRecordCount) {\n <div class=\"viewer-header\">\n <!-- Filter Input -->\n @if (effectiveConfig.showFilter) {\n <div class=\"filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n type=\"text\"\n class=\"filter-input\"\n [placeholder]=\"effectiveConfig.filterPlaceholder\"\n [value]=\"effectiveFilterText\"\n (input)=\"onFilterChange($any($event.target).value)\"\n />\n @if (effectiveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearFilter()\" title=\"Clear filter\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Record Count -->\n @if (effectiveConfig.showRecordCount && entity) {\n <div class=\"record-count\">\n @if (filteredRecordCount !== totalRecordCount) {\n <span>{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span>{{ totalRecordCount | number }} records</span>\n }\n </div>\n }\n\n <!-- View Mode Toggle -->\n @if (effectiveConfig.showViewModeToggle) {\n <div class=\"view-mode-toggle\">\n <button\n class=\"toggle-btn\"\n [class.active]=\"effectiveViewMode === 'grid'\"\n (click)=\"setViewMode('grid')\"\n title=\"Grid View\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n <button\n class=\"toggle-btn\"\n [class.active]=\"effectiveViewMode === 'cards'\"\n (click)=\"setViewMode('cards')\"\n title=\"Cards View\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n @if (hasDateFields) {\n <button\n class=\"toggle-btn\"\n [class.active]=\"effectiveViewMode === 'timeline'\"\n (click)=\"setViewMode('timeline')\"\n title=\"Timeline View\">\n <i class=\"fa-solid fa-timeline\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Timeline Controls (only shown when timeline is active) -->\n @if (effectiveViewMode === 'timeline' && hasDateFields) {\n <!-- Date Field Selector -->\n <div class=\"timeline-date-selector\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n @if (availableDateFields.length === 1) {\n <span class=\"date-field-label\">{{ selectedDateFieldDisplayName }}</span>\n } @else {\n <select\n class=\"date-field-select\"\n [value]=\"selectedTimelineDateField\"\n (change)=\"setTimelineDateField($any($event.target).value)\">\n @for (field of availableDateFields; track field.Name) {\n <option [value]=\"field.Name\">{{ field.DisplayNameOrName }}</option>\n }\n </select>\n }\n </div>\n\n <!-- Orientation Toggle -->\n <div class=\"timeline-orientation-toggle\">\n <button\n class=\"toggle-btn\"\n (click)=\"toggleTimelineOrientation()\"\n [title]=\"timelineOrientation === 'vertical' ? 'Switch to Horizontal' : 'Switch to Vertical'\">\n <i [class]=\"timelineOrientation === 'vertical' ? 'fa-solid fa-ellipsis-vertical' : 'fa-solid fa-ellipsis'\"></i>\n </button>\n </div>\n\n <!-- Sort Order Toggle -->\n <div class=\"timeline-sort-toggle\">\n <button\n class=\"toggle-btn\"\n (click)=\"toggleTimelineSortOrder()\"\n [title]=\"timelineSortOrder === 'desc' ? 'Showing Newest First (click for Oldest First)' : 'Showing Oldest First (click for Newest First)'\">\n <i [class]=\"timelineSortOrder === 'desc' ? 'fa-solid fa-arrow-down-wide-short' : 'fa-solid fa-arrow-up-wide-short'\"></i>\n </button>\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"viewer-content\">\n @if (isLoading && filteredRecords.length === 0) {\n <!-- Initial loading state -->\n <div class=\"loading-container\">\n <mj-loading [text]=\"loadingMessage\" size=\"medium\"></mj-loading>\n </div>\n } @else if (!entity) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database\"></i>\n <p>Select an entity to view records</p>\n </div>\n } @else if (filteredRecords.length === 0 && !isLoading) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>{{ debouncedFilterText ? 'No matching records' : 'No records found' }}</p>\n </div>\n } @else {\n <!-- Grid View - always rendered but hidden when not active to preserve state -->\n <mj-entity-grid\n [hidden]=\"effectiveViewMode !== 'grid'\"\n [entity]=\"entity\"\n [records]=\"filteredRecords\"\n [selectedRecordId]=\"selectedRecordId\"\n [columns]=\"gridColumns\"\n [height]=\"'100%'\"\n [filterText]=\"debouncedFilterText\"\n [sortState]=\"effectiveSortState\"\n [serverSideSorting]=\"effectiveConfig.serverSideSorting\"\n [gridState]=\"gridState\"\n (recordSelected)=\"onRecordSelected($event)\"\n (recordOpened)=\"onRecordOpened($event)\"\n (sortChanged)=\"onSortChanged($event)\"\n (gridStateChanged)=\"onGridStateChanged($event)\">\n </mj-entity-grid>\n\n <!-- Cards View - always rendered but hidden when not active to preserve state -->\n <mj-entity-cards\n [hidden]=\"effectiveViewMode !== 'cards'\"\n [entity]=\"entity\"\n [records]=\"filteredRecords\"\n [selectedRecordId]=\"selectedRecordId\"\n [cardTemplate]=\"cardTemplate\"\n [hiddenFieldMatches]=\"hiddenFieldMatches\"\n [filterText]=\"debouncedFilterText\"\n (recordSelected)=\"onRecordSelected($event)\"\n (recordOpened)=\"onRecordOpened($event)\">\n </mj-entity-cards>\n\n <!-- Timeline View - only created when timeline mode is active -->\n @if (hasDateFields && effectiveViewMode === 'timeline') {\n <mj-timeline\n [groups]=\"timelineGroups\"\n [orientation]=\"timelineOrientation\"\n [layout]=\"timelineOrientation === 'vertical' ? 'alternating' : 'single'\"\n [sortOrder]=\"timelineSortOrder\"\n [segmentGrouping]=\"timelineSegmentGrouping\"\n [segmentsCollapsible]=\"true\"\n [segmentsDefaultExpanded]=\"true\"\n [selectedEventId]=\"timelineSelectedEventId\"\n (afterEventClick)=\"onTimelineEventClick($event)\">\n </mj-timeline>\n }\n }\n </div>\n\n <!-- Pagination - only show when there's more data to load OR we've loaded more than one page -->\n @if (effectiveConfig.showPagination && entity && (pagination.hasMore || pagination.totalRecords > effectiveConfig.pageSize)) {\n <mj-pagination\n [pagination]=\"pagination\"\n [loadedRecordCount]=\"filteredRecords.length\"\n (loadMore)=\"onLoadMore()\">\n </mj-pagination>\n }\n</div>\n", styles: [".entity-viewer-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n background: #fafafa;\n}\n\n/* Header */\n.viewer-header {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 12px 16px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n flex-shrink: 0;\n}\n\n/* Filter */\n.filter-container {\n flex: 1;\n max-width: 400px;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.filter-icon {\n position: absolute;\n left: 12px;\n color: #9e9e9e;\n font-size: 14px;\n pointer-events: none;\n}\n\n.filter-input {\n width: 100%;\n padding: 8px 36px 8px 36px;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n font-size: 14px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.filter-input:focus {\n border-color: #1976d2;\n}\n\n.filter-input::placeholder {\n color: #9e9e9e;\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n width: 20px;\n height: 20px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #9e9e9e;\n transition: all 0.15s ease;\n}\n\n.clear-filter-btn:hover {\n background: #f5f5f5;\n color: #616161;\n}\n\n/* Record Count */\n.record-count {\n font-size: 13px;\n color: #757575;\n white-space: nowrap;\n}\n\n/* View Mode Toggle */\n.view-mode-toggle {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n.toggle-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n transition: all 0.15s ease;\n}\n\n.toggle-btn:hover {\n color: #424242;\n}\n\n.toggle-btn.active {\n background: white;\n color: #1976d2;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n/* Timeline Date Field Selector */\n.timeline-date-selector {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: #616161;\n}\n\n.timeline-date-selector i {\n color: #9e9e9e;\n}\n\n.date-field-label {\n color: #424242;\n font-weight: 500;\n}\n\n.date-field-select {\n padding: 4px 8px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 13px;\n background: white;\n color: #424242;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.date-field-select:hover {\n border-color: #bdbdbd;\n}\n\n.date-field-select:focus {\n border-color: #1976d2;\n}\n\n/* Timeline Orientation Toggle */\n.timeline-orientation-toggle {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n/* Content */\n.viewer-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n position: relative;\n background: white;\n}\n\n/* Loading State */\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #9e9e9e;\n text-align: center;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n}\n\n/* Hidden components should not display - ensure [hidden] attribute works properly */\nmj-entity-grid[hidden],\nmj-entity-cards[hidden],\nmj-timeline[hidden] {\n display: none !important;\n}\n\n/* Visible view components should fill available space */\nmj-entity-grid:not([hidden]),\nmj-entity-cards:not([hidden]),\nmj-timeline:not([hidden]) {\n display: block;\n height: 100%;\n width: 100%;\n}\n"] }]
1405
+ }, template: "<div class=\"entity-viewer-container\" [style.height]=\"effectiveConfig.height\">\n <!-- Header -->\n @if (effectiveConfig.showFilter || effectiveConfig.showViewModeToggle || effectiveConfig.showRecordCount) {\n <div class=\"viewer-header\">\n <!-- Filter Input -->\n @if (effectiveConfig.showFilter) {\n <div class=\"filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n type=\"text\"\n class=\"filter-input\"\n [placeholder]=\"effectiveConfig.filterPlaceholder\"\n [value]=\"effectiveFilterText\"\n (input)=\"onFilterChange($any($event.target).value)\"\n />\n @if (effectiveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearFilter()\" title=\"Clear filter\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Record Count -->\n @if (effectiveConfig.showRecordCount && entity) {\n <div class=\"record-count\">\n @if (filteredRecordCount !== totalRecordCount) {\n <span>{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span>{{ totalRecordCount | number }} records</span>\n }\n </div>\n }\n\n <!-- View Mode Toggle -->\n @if (effectiveConfig.showViewModeToggle) {\n <div class=\"view-mode-toggle\">\n <button\n class=\"toggle-btn\"\n [class.active]=\"effectiveViewMode === 'grid'\"\n (click)=\"setViewMode('grid')\"\n title=\"Grid View\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n <button\n class=\"toggle-btn\"\n [class.active]=\"effectiveViewMode === 'cards'\"\n (click)=\"setViewMode('cards')\"\n title=\"Cards View\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n @if (hasDateFields) {\n <button\n class=\"toggle-btn\"\n [class.active]=\"effectiveViewMode === 'timeline'\"\n (click)=\"setViewMode('timeline')\"\n title=\"Timeline View\">\n <i class=\"fa-solid fa-timeline\"></i>\n </button>\n }\n </div>\n }\n\n <!-- Timeline Controls (only shown when timeline is active) -->\n @if (effectiveViewMode === 'timeline' && hasDateFields) {\n <!-- Date Field Selector -->\n <div class=\"timeline-date-selector\">\n <i class=\"fa-solid fa-calendar-days\"></i>\n @if (availableDateFields.length === 1) {\n <span class=\"date-field-label\">{{ selectedDateFieldDisplayName }}</span>\n } @else {\n <select\n class=\"date-field-select\"\n [value]=\"selectedTimelineDateField\"\n (change)=\"setTimelineDateField($any($event.target).value)\">\n @for (field of availableDateFields; track field.Name) {\n <option [value]=\"field.Name\">{{ field.DisplayNameOrName }}</option>\n }\n </select>\n }\n </div>\n\n <!-- Orientation Toggle -->\n <div class=\"timeline-orientation-toggle\">\n <button\n class=\"toggle-btn\"\n (click)=\"toggleTimelineOrientation()\"\n [title]=\"timelineOrientation === 'vertical' ? 'Switch to Horizontal' : 'Switch to Vertical'\">\n <i [class]=\"timelineOrientation === 'vertical' ? 'fa-solid fa-ellipsis-vertical' : 'fa-solid fa-ellipsis'\"></i>\n </button>\n </div>\n\n <!-- Sort Order Toggle -->\n <div class=\"timeline-sort-toggle\">\n <button\n class=\"toggle-btn\"\n (click)=\"toggleTimelineSortOrder()\"\n [title]=\"timelineSortOrder === 'desc' ? 'Showing Newest First (click for Oldest First)' : 'Showing Oldest First (click for Newest First)'\">\n <i [class]=\"timelineSortOrder === 'desc' ? 'fa-solid fa-arrow-down-wide-short' : 'fa-solid fa-arrow-up-wide-short'\"></i>\n </button>\n </div>\n }\n </div>\n }\n\n <!-- Content -->\n <div class=\"viewer-content\">\n <!-- Loading container - full page when no data exists -->\n <div class=\"loading-container\" [hidden]=\"!(isLoading && filteredRecords.length === 0)\">\n <mj-loading [text]=\"loadingMessage\" size=\"medium\"></mj-loading>\n </div>\n\n <!-- Loading overlay - shown on top of content when loading with existing data -->\n <div class=\"loading-overlay\" [hidden]=\"!(isLoading && filteredRecords.length > 0)\">\n <mj-loading [text]=\"loadingMessage\" size=\"small\"></mj-loading>\n </div>\n\n <!-- Empty state: no entity selected -->\n <div class=\"empty-state\" [hidden]=\"!!entity\">\n <i class=\"fa-solid fa-database\"></i>\n <p>Select an entity to view records</p>\n </div>\n\n <!-- Empty state: no records found -->\n <div class=\"empty-state\" [hidden]=\"!entity || filteredRecords.length > 0 || isLoading\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>{{ debouncedFilterText ? 'No matching records' : 'No records found' }}</p>\n </div>\n\n <!-- Grid View - always rendered, visibility controlled by hidden -->\n <mj-entity-data-grid\n [hidden]=\"effectiveViewMode !== 'grid' || !entity\"\n [Data]=\"filteredRecords\"\n [Params]=\"gridParams\"\n [FilterText]=\"debouncedFilterText\"\n [GridState]=\"gridState\"\n [Height]=\"'auto'\"\n [ShowToolbar]=\"showGridToolbar\"\n [ToolbarConfig]=\"effectiveGridToolbarConfig\"\n [SelectionMode]=\"gridSelectionMode\"\n [AllowLoad]=\"false\"\n (AfterRowClick)=\"onDataGridRowClick($event)\"\n (AfterRowDoubleClick)=\"onDataGridRowDoubleClick($event)\"\n (AfterSort)=\"onDataGridSortChanged($event)\"\n (GridStateChanged)=\"onGridStateChanged($event)\"\n (NewButtonClick)=\"onGridAddRequested()\"\n (RefreshButtonClick)=\"onGridRefreshRequested()\"\n (DeleteButtonClick)=\"onGridDeleteRequested($event)\"\n (ExportButtonClick)=\"onGridExportRequested()\">\n </mj-entity-data-grid>\n\n <!-- Cards View - always rendered, visibility controlled by hidden -->\n <mj-entity-cards\n [hidden]=\"effectiveViewMode !== 'cards' || !entity\"\n [entity]=\"entity\"\n [records]=\"filteredRecords\"\n [selectedRecordId]=\"selectedRecordId\"\n [cardTemplate]=\"cardTemplate\"\n [hiddenFieldMatches]=\"hiddenFieldMatches\"\n [filterText]=\"debouncedFilterText\"\n (recordSelected)=\"onRecordSelected($event)\"\n (recordOpened)=\"onRecordOpened($event)\">\n </mj-entity-cards>\n\n <!-- Timeline View - always rendered when date fields exist, visibility controlled by hidden -->\n <mj-timeline\n [hidden]=\"effectiveViewMode !== 'timeline' || !hasDateFields\"\n [groups]=\"timelineGroups\"\n [orientation]=\"timelineOrientation\"\n [layout]=\"timelineOrientation === 'vertical' ? 'alternating' : 'single'\"\n [sortOrder]=\"timelineSortOrder\"\n [segmentGrouping]=\"timelineSegmentGrouping\"\n [segmentsCollapsible]=\"true\"\n [segmentsDefaultExpanded]=\"true\"\n [selectedEventId]=\"timelineSelectedEventId\"\n (afterEventClick)=\"onTimelineEventClick($event)\">\n </mj-timeline>\n </div>\n\n <!-- Pagination - only show when there's more data to load OR we've loaded more than one page -->\n @if (effectiveConfig.showPagination && entity && (pagination.hasMore || pagination.totalRecords > effectiveConfig.pageSize)) {\n <mj-pagination\n [pagination]=\"pagination\"\n [loadedRecordCount]=\"filteredRecords.length\"\n (loadMore)=\"onLoadMore()\">\n </mj-pagination>\n }\n</div>\n", styles: [".entity-viewer-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: #fafafa;\n}\n\n/* Pagination footer - always visible at bottom */\nmj-pagination {\n flex-shrink: 0;\n}\n\n/* Header */\n.viewer-header {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 12px 16px;\n background: white;\n border-bottom: 1px solid #e0e0e0;\n flex-shrink: 0;\n}\n\n/* Filter */\n.filter-container {\n flex: 1;\n max-width: 400px;\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.filter-icon {\n position: absolute;\n left: 12px;\n color: #9e9e9e;\n font-size: 14px;\n pointer-events: none;\n}\n\n.filter-input {\n width: 100%;\n padding: 8px 36px 8px 36px;\n border: 1px solid #e0e0e0;\n border-radius: 6px;\n font-size: 14px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.filter-input:focus {\n border-color: #1976d2;\n}\n\n.filter-input::placeholder {\n color: #9e9e9e;\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n width: 20px;\n height: 20px;\n border: none;\n background: transparent;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #9e9e9e;\n transition: all 0.15s ease;\n}\n\n.clear-filter-btn:hover {\n background: #f5f5f5;\n color: #616161;\n}\n\n/* Record Count */\n.record-count {\n font-size: 13px;\n color: #757575;\n white-space: nowrap;\n}\n\n/* View Mode Toggle */\n.view-mode-toggle {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n.toggle-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #757575;\n transition: all 0.15s ease;\n}\n\n.toggle-btn:hover {\n color: #424242;\n}\n\n.toggle-btn.active {\n background: white;\n color: #1976d2;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n/* Timeline Date Field Selector */\n.timeline-date-selector {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 13px;\n color: #616161;\n}\n\n.timeline-date-selector i {\n color: #9e9e9e;\n}\n\n.date-field-label {\n color: #424242;\n font-weight: 500;\n}\n\n.date-field-select {\n padding: 4px 8px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 13px;\n background: white;\n color: #424242;\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.date-field-select:hover {\n border-color: #bdbdbd;\n}\n\n.date-field-select:focus {\n border-color: #1976d2;\n}\n\n/* Timeline Orientation Toggle */\n.timeline-orientation-toggle {\n display: flex;\n background: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n/* Content */\n.viewer-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n position: relative;\n background: white;\n}\n\n/* Loading State - positioned as overlay when data exists */\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n/* Loading overlay when shown on top of content */\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.8);\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Empty State */\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: #9e9e9e;\n text-align: center;\n}\n\n.empty-state i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n}\n\n/* Hidden components should not display - ensure [hidden] attribute works properly */\nmj-entity-cards[hidden],\nmj-timeline[hidden] {\n display: none !important;\n}\n\n/* Visible view components should fill available space */\nmj-entity-cards:not([hidden]),\nmj-timeline:not([hidden]) {\n display: block;\n height: 100%;\n width: 100%;\n}\n"] }]
1257
1406
  }], () => [{ type: i0.ChangeDetectorRef }], { entity: [{
1258
1407
  type: Input
1259
1408
  }], records: [{
@@ -1278,6 +1427,12 @@ export class EntityViewerComponent {
1278
1427
  type: Input
1279
1428
  }], timelineConfig: [{
1280
1429
  type: Input
1430
+ }], showGridToolbar: [{
1431
+ type: Input
1432
+ }], gridToolbarConfig: [{
1433
+ type: Input
1434
+ }], gridSelectionMode: [{
1435
+ type: Input
1281
1436
  }], recordSelected: [{
1282
1437
  type: Output
1283
1438
  }], recordOpened: [{
@@ -1296,6 +1451,14 @@ export class EntityViewerComponent {
1296
1451
  type: Output
1297
1452
  }], timelineConfigChange: [{
1298
1453
  type: Output
1454
+ }], addRequested: [{
1455
+ type: Output
1456
+ }], deleteRequested: [{
1457
+ type: Output
1458
+ }], refreshRequested: [{
1459
+ type: Output
1460
+ }], exportRequested: [{
1461
+ type: Output
1299
1462
  }] }); })();
1300
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent", filePath: "src/lib/entity-viewer/entity-viewer.component.ts", lineNumber: 69 }); })();
1463
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent", filePath: "src/lib/entity-viewer/entity-viewer.component.ts", lineNumber: 75 }); })();
1301
1464
  //# sourceMappingURL=entity-viewer.component.js.map