@memberjunction/ng-entity-viewer 2.132.0 → 3.0.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 (42) hide show
  1. package/README.md +317 -124
  2. package/dist/lib/entity-cards/entity-cards.component.js +2 -2
  3. package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
  4. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +793 -0
  5. package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -0
  6. package/dist/lib/entity-data-grid/entity-data-grid.component.js +3781 -0
  7. package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -0
  8. package/dist/lib/entity-data-grid/events/grid-events.d.ts +398 -0
  9. package/dist/lib/entity-data-grid/events/grid-events.d.ts.map +1 -0
  10. package/dist/lib/entity-data-grid/events/grid-events.js +556 -0
  11. package/dist/lib/entity-data-grid/events/grid-events.js.map +1 -0
  12. package/dist/lib/entity-data-grid/models/grid-types.d.ts +437 -0
  13. package/dist/lib/entity-data-grid/models/grid-types.d.ts.map +1 -0
  14. package/dist/lib/entity-data-grid/models/grid-types.js +37 -0
  15. package/dist/lib/entity-data-grid/models/grid-types.js.map +1 -0
  16. package/dist/lib/entity-grid/entity-grid.component.js +1 -1
  17. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +2 -2
  18. package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
  19. package/dist/lib/entity-viewer/entity-viewer.component.d.ts +136 -2
  20. package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
  21. package/dist/lib/entity-viewer/entity-viewer.component.js +321 -94
  22. package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
  23. package/dist/lib/pagination/pagination.component.js +2 -2
  24. package/dist/lib/pagination/pagination.component.js.map +1 -1
  25. package/dist/lib/pill/pill.component.js +2 -2
  26. package/dist/lib/pill/pill.component.js.map +1 -1
  27. package/dist/lib/types.d.ts +14 -31
  28. package/dist/lib/types.d.ts.map +1 -1
  29. package/dist/lib/types.js.map +1 -1
  30. package/dist/lib/view-config-panel/view-config-panel.component.d.ts +363 -0
  31. package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -0
  32. package/dist/lib/view-config-panel/view-config-panel.component.js +2006 -0
  33. package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -0
  34. package/dist/module.d.ts +16 -13
  35. package/dist/module.d.ts.map +1 -1
  36. package/dist/module.js +25 -15
  37. package/dist/module.js.map +1 -1
  38. package/dist/public-api.d.ts +4 -1
  39. package/dist/public-api.d.ts.map +1 -1
  40. package/dist/public-api.js +6 -1
  41. package/dist/public-api.js.map +1 -1
  42. package/package.json +15 -11
@@ -1,33 +1,34 @@
1
- import { Component, Input, Output, EventEmitter } from '@angular/core';
1
+ import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
2
2
  import { Subject } from 'rxjs';
3
3
  import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
4
4
  import { EntityFieldTSType, RunView } from '@memberjunction/core';
5
5
  import { TimelineGroup } from '@memberjunction/ng-timeline';
6
6
  import { DEFAULT_VIEWER_CONFIG } from '../types';
7
+ import { EntityDataGridComponent } from '../entity-data-grid/entity-data-grid.component';
7
8
  import * as i0 from "@angular/core";
8
9
  import * as i1 from "@angular/forms";
9
10
  import * as i2 from "@memberjunction/ng-shared-generic";
10
11
  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";
12
+ import * as i4 from "../entity-cards/entity-cards.component";
13
+ import * as i5 from "../pagination/pagination.component";
14
+ import * as i6 from "../entity-data-grid/entity-data-grid.component";
14
15
  import * as i7 from "@angular/common";
15
16
  const _forTrack0 = ($index, $item) => $item.Name;
16
17
  function EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
17
18
  const _r3 = i0.ɵɵgetCurrentView();
18
- i0.ɵɵelementStart(0, "button", 12);
19
+ i0.ɵɵelementStart(0, "button", 20);
19
20
  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);
21
+ i0.ɵɵelement(1, "i", 21);
21
22
  i0.ɵɵelementEnd();
22
23
  } }
23
24
  function EntityViewerComponent_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
24
25
  const _r1 = i0.ɵɵgetCurrentView();
25
- i0.ɵɵelementStart(0, "div", 6);
26
- i0.ɵɵelement(1, "i", 9);
27
- i0.ɵɵelementStart(2, "input", 10);
26
+ i0.ɵɵelementStart(0, "div", 14);
27
+ i0.ɵɵelement(1, "i", 17);
28
+ i0.ɵɵelementStart(2, "input", 18);
28
29
  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
30
  i0.ɵɵelementEnd();
30
- i0.ɵɵtemplate(3, EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template, 2, 0, "button", 11);
31
+ i0.ɵɵtemplate(3, EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template, 2, 0, "button", 19);
31
32
  i0.ɵɵelementEnd();
32
33
  } if (rf & 2) {
33
34
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -58,7 +59,7 @@ function EntityViewerComponent_Conditional_1_Conditional_2_Conditional_2_Templat
58
59
  i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind1(2, 1, ctx_r1.totalRecordCount), " records");
59
60
  } }
60
61
  function EntityViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
61
- i0.ɵɵelementStart(0, "div", 7);
62
+ i0.ɵɵelementStart(0, "div", 15);
62
63
  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
64
  i0.ɵɵelementEnd();
64
65
  } if (rf & 2) {
@@ -68,9 +69,9 @@ function EntityViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { i
68
69
  } }
69
70
  function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
70
71
  const _r5 = i0.ɵɵgetCurrentView();
71
- i0.ɵɵelementStart(0, "button", 19);
72
+ i0.ɵɵelementStart(0, "button", 27);
72
73
  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);
74
+ i0.ɵɵelement(1, "i", 28);
74
75
  i0.ɵɵelementEnd();
75
76
  } if (rf & 2) {
76
77
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -78,15 +79,15 @@ function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Templat
78
79
  } }
79
80
  function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
80
81
  const _r4 = i0.ɵɵgetCurrentView();
81
- i0.ɵɵelementStart(0, "div", 8)(1, "button", 14);
82
+ i0.ɵɵelementStart(0, "div", 16)(1, "button", 22);
82
83
  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);
84
+ i0.ɵɵelement(2, "i", 23);
84
85
  i0.ɵɵelementEnd();
85
- i0.ɵɵelementStart(3, "button", 16);
86
+ i0.ɵɵelementStart(3, "button", 24);
86
87
  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);
88
+ i0.ɵɵelement(4, "i", 25);
88
89
  i0.ɵɵelementEnd();
89
- i0.ɵɵtemplate(5, EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template, 2, 2, "button", 18);
90
+ i0.ɵɵtemplate(5, EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template, 2, 2, "button", 26);
90
91
  i0.ɵɵelementEnd();
91
92
  } if (rf & 2) {
92
93
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -98,7 +99,7 @@ function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { i
98
99
  i0.ɵɵconditional(ctx_r1.hasDateFields ? 5 : -1);
99
100
  } }
100
101
  function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template(rf, ctx) { if (rf & 1) {
101
- i0.ɵɵelementStart(0, "span", 23);
102
+ i0.ɵɵelementStart(0, "span", 31);
102
103
  i0.ɵɵtext(1);
103
104
  i0.ɵɵelementEnd();
104
105
  } if (rf & 2) {
@@ -107,7 +108,7 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Templat
107
108
  i0.ɵɵtextInterpolate(ctx_r1.selectedDateFieldDisplayName);
108
109
  } }
109
110
  function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
110
- i0.ɵɵelementStart(0, "option", 29);
111
+ i0.ɵɵelementStart(0, "option", 37);
111
112
  i0.ɵɵtext(1);
112
113
  i0.ɵɵelementEnd();
113
114
  } if (rf & 2) {
@@ -118,9 +119,9 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_T
118
119
  } }
119
120
  function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
120
121
  const _r7 = i0.ɵɵgetCurrentView();
121
- i0.ɵɵelementStart(0, "select", 28);
122
+ i0.ɵɵelementStart(0, "select", 36);
122
123
  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);
124
+ i0.ɵɵrepeaterCreate(1, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template, 2, 2, "option", 37, _forTrack0);
124
125
  i0.ɵɵelementEnd();
125
126
  } if (rf & 2) {
126
127
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -130,15 +131,15 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Templat
130
131
  } }
131
132
  function EntityViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
132
133
  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);
134
+ i0.ɵɵelementStart(0, "div", 29);
135
+ i0.ɵɵelement(1, "i", 30);
136
+ 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
137
  i0.ɵɵelementEnd();
137
- i0.ɵɵelementStart(4, "div", 25)(5, "button", 26);
138
+ i0.ɵɵelementStart(4, "div", 33)(5, "button", 34);
138
139
  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
140
  i0.ɵɵelement(6, "i");
140
141
  i0.ɵɵelementEnd()();
141
- i0.ɵɵelementStart(7, "div", 27)(8, "button", 26);
142
+ i0.ɵɵelementStart(7, "div", 35)(8, "button", 34);
142
143
  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
144
  i0.ɵɵelement(9, "i");
144
145
  i0.ɵɵelementEnd()();
@@ -157,7 +158,7 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { i
157
158
  } }
158
159
  function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
159
160
  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);
161
+ 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
162
  i0.ɵɵelementEnd();
162
163
  } if (rf & 2) {
163
164
  const ctx_r1 = i0.ɵɵnextContext();
@@ -170,63 +171,10 @@ function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
170
171
  i0.ɵɵadvance();
171
172
  i0.ɵɵconditional(ctx_r1.effectiveViewMode === "timeline" && ctx_r1.hasDateFields ? 4 : -1);
172
173
  } }
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) {
174
+ function EntityViewerComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
210
175
  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()); });
176
+ i0.ɵɵelementStart(0, "mj-pagination", 38);
177
+ 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
178
  i0.ɵɵelementEnd();
231
179
  } if (rf & 2) {
232
180
  const ctx_r1 = i0.ɵɵnextContext();
@@ -344,6 +292,29 @@ export class EntityViewerComponent {
344
292
  }
345
293
  }
346
294
  _timelineConfig = null;
295
+ /**
296
+ * Whether to show the grid toolbar.
297
+ * When false, the grid is displayed without its own toolbar - useful when
298
+ * entity-viewer provides its own filter/actions in the header.
299
+ * @default false
300
+ */
301
+ showGridToolbar = false;
302
+ /**
303
+ * Grid toolbar configuration - controls which buttons are shown and their behavior
304
+ * When not provided, uses sensible defaults
305
+ */
306
+ gridToolbarConfig = null;
307
+ /**
308
+ * Grid selection mode
309
+ * @default 'single'
310
+ */
311
+ gridSelectionMode = 'single';
312
+ /**
313
+ * Show the "Add to List" button in the grid toolbar.
314
+ * Requires gridSelectionMode to be 'multiple' for best UX.
315
+ * @default false
316
+ */
317
+ showAddToListButton = false;
347
318
  // ========================================
348
319
  // OUTPUTS
349
320
  // ========================================
@@ -383,6 +354,33 @@ export class EntityViewerComponent {
383
354
  * Emitted when timeline configuration changes (date field, grouping, etc.)
384
355
  */
385
356
  timelineConfigChange = new EventEmitter();
357
+ /**
358
+ * Emitted when the Add/New button is clicked in the grid toolbar
359
+ */
360
+ addRequested = new EventEmitter();
361
+ /**
362
+ * Emitted when the Delete button is clicked in the grid toolbar
363
+ * Includes the selected records to be deleted
364
+ */
365
+ deleteRequested = new EventEmitter();
366
+ /**
367
+ * Emitted when the Refresh button is clicked in the grid toolbar
368
+ */
369
+ refreshRequested = new EventEmitter();
370
+ /**
371
+ * Emitted when the Export button is clicked in the grid toolbar
372
+ */
373
+ exportRequested = new EventEmitter();
374
+ /**
375
+ * Emitted when the Add to List button is clicked in the grid toolbar.
376
+ * Parent components should handle this to show the list management dialog.
377
+ */
378
+ addToListRequested = new EventEmitter();
379
+ /**
380
+ * Emitted when grid selection changes.
381
+ * Parent components can use this to track selected records for their own toolbar buttons.
382
+ */
383
+ selectionChanged = new EventEmitter();
386
384
  // ========================================
387
385
  // INTERNAL STATE
388
386
  // ========================================
@@ -398,6 +396,10 @@ export class EntityViewerComponent {
398
396
  hiddenFieldMatches = new Map();
399
397
  /** Current sort state */
400
398
  internalSortState = null;
399
+ /** Cached grid params to avoid recreating object on every change detection */
400
+ _cachedGridParams = null;
401
+ _lastGridParamsEntity = null;
402
+ _lastGridParamsViewEntity = null;
401
403
  /** Pagination state */
402
404
  pagination = {
403
405
  currentPage: 0,
@@ -443,10 +445,22 @@ export class EntityViewerComponent {
443
445
  filterInput$ = new Subject();
444
446
  /** Track if this is the first load (vs. load more) */
445
447
  isInitialLoad = true;
448
+ /** Reference to the data grid component for flushing pending changes */
449
+ dataGridRef;
446
450
  constructor(cdr) {
447
451
  this.cdr = cdr;
448
452
  }
449
453
  // ========================================
454
+ // PUBLIC METHODS
455
+ // ========================================
456
+ /**
457
+ * Ensures any pending grid state changes are saved immediately without waiting for debounce.
458
+ * Call this before switching views or entities to ensure changes are saved.
459
+ */
460
+ EnsurePendingChangesSaved() {
461
+ this.dataGridRef?.EnsurePendingChangesSaved();
462
+ }
463
+ // ========================================
450
464
  // COMPUTED PROPERTIES
451
465
  // ========================================
452
466
  /**
@@ -488,12 +502,61 @@ export class EntityViewerComponent {
488
502
  get effectiveSortState() {
489
503
  return this.sortState ?? this.internalSortState;
490
504
  }
505
+ /**
506
+ * Get the OrderBy string for mj-entity-data-grid from the effective sort state
507
+ */
508
+ get effectiveSortOrderBy() {
509
+ const sortState = this.effectiveSortState;
510
+ if (!sortState?.field || !sortState.direction) {
511
+ return '';
512
+ }
513
+ return `${sortState.field} ${sortState.direction.toUpperCase()}`;
514
+ }
491
515
  /**
492
516
  * Get merged configuration with defaults
493
517
  */
494
518
  get effectiveConfig() {
495
519
  return { ...DEFAULT_VIEWER_CONFIG, ...this.config };
496
520
  }
521
+ /**
522
+ * Get cached grid params - only recreates object when entity or viewEntity changes
523
+ * This prevents Angular from seeing a new object reference on every change detection
524
+ * which would cause the grid to reinitialize
525
+ */
526
+ get gridParams() {
527
+ if (!this.entity) {
528
+ return null;
529
+ }
530
+ // Check if we need to recreate the params object
531
+ const entityChanged = this._lastGridParamsEntity !== this.entity.Name;
532
+ const viewEntityChanged = this._lastGridParamsViewEntity !== this.viewEntity;
533
+ if (entityChanged || viewEntityChanged || !this._cachedGridParams) {
534
+ this._lastGridParamsEntity = this.entity.Name;
535
+ this._lastGridParamsViewEntity = this.viewEntity ?? null;
536
+ this._cachedGridParams = {
537
+ EntityName: this.entity.Name,
538
+ ViewEntity: this.viewEntity || undefined
539
+ };
540
+ }
541
+ return this._cachedGridParams;
542
+ }
543
+ /**
544
+ * Get the effective grid toolbar configuration
545
+ * Merges user-provided config with defaults appropriate for entity-viewer context
546
+ */
547
+ get effectiveGridToolbarConfig() {
548
+ const defaults = {
549
+ showSearch: false, // Entity-viewer has its own filter
550
+ showRefresh: true,
551
+ showAdd: true,
552
+ showDelete: true,
553
+ showExport: true,
554
+ showColumnChooser: true,
555
+ showRowCount: true,
556
+ showSelectionCount: true
557
+ };
558
+ return { ...defaults, ...this.gridToolbarConfig };
559
+ }
497
560
  /**
498
561
  * Get the records to display (external or internal)
499
562
  */
@@ -987,6 +1050,102 @@ export class EntityViewerComponent {
987
1050
  this.loadMore();
988
1051
  }
989
1052
  // ========================================
1053
+ // DATA GRID EVENT HANDLERS
1054
+ // ========================================
1055
+ /**
1056
+ * Handle row click from mj-entity-data-grid
1057
+ * Maps to recordSelected event for parent components
1058
+ */
1059
+ onDataGridRowClick(event) {
1060
+ if (!this.entity || !event.row)
1061
+ return;
1062
+ this.recordSelected.emit({
1063
+ record: event.row,
1064
+ entity: this.entity,
1065
+ compositeKey: event.row.PrimaryKey
1066
+ });
1067
+ }
1068
+ /**
1069
+ * Handle row double-click from mj-entity-data-grid
1070
+ * Maps to recordOpened event for parent components
1071
+ */
1072
+ onDataGridRowDoubleClick(event) {
1073
+ if (!this.entity || !event.row)
1074
+ return;
1075
+ this.recordOpened.emit({
1076
+ record: event.row,
1077
+ entity: this.entity,
1078
+ compositeKey: event.row.PrimaryKey
1079
+ });
1080
+ }
1081
+ /**
1082
+ * Handle sort changed from mj-entity-data-grid
1083
+ * Maps to sortChanged event for parent components
1084
+ */
1085
+ onDataGridSortChanged(event) {
1086
+ // Convert the data grid's sort state to our SortState format
1087
+ const newSort = event.newSortState && event.newSortState.length > 0
1088
+ ? {
1089
+ field: event.newSortState[0].field,
1090
+ direction: event.newSortState[0].direction
1091
+ }
1092
+ : null;
1093
+ this.internalSortState = newSort;
1094
+ this.sortChanged.emit({ sort: newSort });
1095
+ // If server-side sorting, reload from page 1
1096
+ if (this.effectiveConfig.serverSideSorting && !this.records) {
1097
+ this.resetPaginationState();
1098
+ this.loadData();
1099
+ }
1100
+ }
1101
+ /**
1102
+ * Handle Add/New button click from data grid toolbar
1103
+ */
1104
+ onGridAddRequested() {
1105
+ this.addRequested.emit();
1106
+ }
1107
+ /**
1108
+ * Handle Refresh button click from data grid toolbar
1109
+ */
1110
+ onGridRefreshRequested() {
1111
+ this.refreshRequested.emit();
1112
+ // Also trigger an internal refresh
1113
+ this.refresh();
1114
+ }
1115
+ /**
1116
+ * Handle Delete button click from data grid toolbar
1117
+ */
1118
+ onGridDeleteRequested(records) {
1119
+ this.deleteRequested.emit({ records });
1120
+ }
1121
+ /**
1122
+ * Handle Export button click from data grid toolbar
1123
+ */
1124
+ onGridExportRequested() {
1125
+ this.exportRequested.emit({ format: 'excel' });
1126
+ }
1127
+ /**
1128
+ * Handle Add to List button click from data grid toolbar.
1129
+ * Forwards the event to parent components for list management.
1130
+ */
1131
+ onGridAddToListRequested(event) {
1132
+ this.addToListRequested.emit(event);
1133
+ }
1134
+ /**
1135
+ * Handle selection change from data grid.
1136
+ * Converts selected keys to records and forwards to parent components.
1137
+ */
1138
+ onGridSelectionChange(selectedKeys) {
1139
+ // Find the actual records from our filtered records
1140
+ const records = this.filteredRecords.filter(record => {
1141
+ const key = record.PrimaryKey?.ToConcatenatedString() || String(record.Get('ID'));
1142
+ return selectedKeys.includes(key);
1143
+ });
1144
+ // Get the raw primary key values for list management
1145
+ const recordIds = records.map(record => String(record.PrimaryKey.KeyValuePairs[0].Value));
1146
+ this.selectionChanged.emit({ records, recordIds });
1147
+ }
1148
+ // ========================================
990
1149
  // TIMELINE METHODS
991
1150
  // ========================================
992
1151
  /**
@@ -1230,30 +1389,75 @@ export class EntityViewerComponent {
1230
1389
  const firstOther = fields.find(f => f.Name !== excludeField);
1231
1390
  return firstOther?.Name || null;
1232
1391
  }
1233
- 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) {
1392
+ static ɵfac = function EntityViewerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EntityViewerComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
1393
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityViewerComponent, selectors: [["mj-entity-viewer"]], viewQuery: function EntityViewerComponent_Query(rf, ctx) { if (rf & 1) {
1394
+ i0.ɵɵviewQuery(EntityDataGridComponent, 5);
1395
+ } if (rf & 2) {
1396
+ let _t;
1397
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.dataGridRef = _t.first);
1398
+ } }, 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", showAddToListButton: "showAddToListButton" }, 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", addToListRequested: "addToListRequested", selectionChanged: "selectionChanged" }, features: [i0.ɵɵNgOnChangesFeature], decls: 19, vars: 38, 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", "SelectionChange", "NewButtonClick", "RefreshButtonClick", "DeleteButtonClick", "ExportButtonClick", "AddToListRequested", "hidden", "Data", "Params", "FilterText", "GridState", "Height", "ShowToolbar", "ToolbarConfig", "SelectionMode", "ShowAddToListButton", "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
1399
  i0.ɵɵelementStart(0, "div", 0);
1236
1400
  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);
1401
+ i0.ɵɵelementStart(2, "div", 2)(3, "div", 3);
1402
+ i0.ɵɵelement(4, "mj-loading", 4);
1403
+ i0.ɵɵelementEnd();
1404
+ i0.ɵɵelementStart(5, "div", 5);
1405
+ i0.ɵɵelement(6, "mj-loading", 6);
1239
1406
  i0.ɵɵelementEnd();
1240
- i0.ɵɵtemplate(7, EntityViewerComponent_Conditional_7_Template, 1, 2, "mj-pagination", 5);
1407
+ i0.ɵɵelementStart(7, "div", 7);
1408
+ i0.ɵɵelement(8, "i", 8);
1409
+ i0.ɵɵelementStart(9, "p");
1410
+ i0.ɵɵtext(10, "Select an entity to view records");
1411
+ i0.ɵɵelementEnd()();
1412
+ i0.ɵɵelementStart(11, "div", 7);
1413
+ i0.ɵɵelement(12, "i", 9);
1414
+ i0.ɵɵelementStart(13, "p");
1415
+ i0.ɵɵtext(14);
1416
+ i0.ɵɵelementEnd()();
1417
+ i0.ɵɵelementStart(15, "mj-entity-data-grid", 10);
1418
+ 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); })("SelectionChange", function EntityViewerComponent_Template_mj_entity_data_grid_SelectionChange_15_listener($event) { return ctx.onGridSelectionChange($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(); })("AddToListRequested", function EntityViewerComponent_Template_mj_entity_data_grid_AddToListRequested_15_listener($event) { return ctx.onGridAddToListRequested($event); });
1419
+ i0.ɵɵelementEnd();
1420
+ i0.ɵɵelementStart(16, "mj-entity-cards", 11);
1421
+ 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); });
1422
+ i0.ɵɵelementEnd();
1423
+ i0.ɵɵelementStart(17, "mj-timeline", 12);
1424
+ i0.ɵɵlistener("afterEventClick", function EntityViewerComponent_Template_mj_timeline_afterEventClick_17_listener($event) { return ctx.onTimelineEventClick($event); });
1425
+ i0.ɵɵelementEnd()();
1426
+ i0.ɵɵtemplate(18, EntityViewerComponent_Conditional_18_Template, 1, 2, "mj-pagination", 13);
1241
1427
  i0.ɵɵelementEnd();
1242
1428
  } if (rf & 2) {
1243
1429
  i0.ɵɵstyleProp("height", ctx.effectiveConfig.height);
1244
1430
  i0.ɵɵadvance();
1245
1431
  i0.ɵɵconditional(ctx.effectiveConfig.showFilter || ctx.effectiveConfig.showViewModeToggle || ctx.effectiveConfig.showRecordCount ? 1 : -1);
1246
1432
  i0.ɵɵadvance(2);
1247
- i0.ɵɵconditional(ctx.isLoading && ctx.filteredRecords.length === 0 ? 3 : !ctx.entity ? 4 : ctx.filteredRecords.length === 0 && !ctx.isLoading ? 5 : 6);
1433
+ i0.ɵɵproperty("hidden", !(ctx.isLoading && ctx.filteredRecords.length === 0));
1434
+ i0.ɵɵadvance();
1435
+ i0.ɵɵproperty("text", ctx.loadingMessage);
1436
+ i0.ɵɵadvance();
1437
+ i0.ɵɵproperty("hidden", !(ctx.isLoading && ctx.filteredRecords.length > 0));
1438
+ i0.ɵɵadvance();
1439
+ i0.ɵɵproperty("text", ctx.loadingMessage);
1440
+ i0.ɵɵadvance();
1441
+ i0.ɵɵproperty("hidden", !!ctx.entity);
1248
1442
  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}"] });
1443
+ i0.ɵɵproperty("hidden", !ctx.entity || ctx.filteredRecords.length > 0 || ctx.isLoading);
1444
+ i0.ɵɵadvance(3);
1445
+ i0.ɵɵtextInterpolate(ctx.debouncedFilterText ? "No matching records" : "No records found");
1446
+ i0.ɵɵadvance();
1447
+ 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)("ShowAddToListButton", ctx.showAddToListButton)("AllowLoad", false);
1448
+ i0.ɵɵadvance();
1449
+ 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);
1450
+ i0.ɵɵadvance();
1451
+ 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);
1452
+ i0.ɵɵadvance();
1453
+ i0.ɵɵconditional(ctx.effectiveConfig.showPagination && ctx.entity && (ctx.pagination.hasMore || ctx.pagination.totalRecords > ctx.effectiveConfig.pageSize) ? 18 : -1);
1454
+ } }, 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
1455
  }
1252
1456
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityViewerComponent, [{
1253
1457
  type: Component,
1254
1458
  args: [{ selector: 'mj-entity-viewer', host: {
1255
1459
  '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"] }]
1460
+ }, 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 [ShowAddToListButton]=\"showAddToListButton\"\n [AllowLoad]=\"false\"\n (AfterRowClick)=\"onDataGridRowClick($event)\"\n (AfterRowDoubleClick)=\"onDataGridRowDoubleClick($event)\"\n (AfterSort)=\"onDataGridSortChanged($event)\"\n (GridStateChanged)=\"onGridStateChanged($event)\"\n (SelectionChange)=\"onGridSelectionChange($event)\"\n (NewButtonClick)=\"onGridAddRequested()\"\n (RefreshButtonClick)=\"onGridRefreshRequested()\"\n (DeleteButtonClick)=\"onGridDeleteRequested($event)\"\n (ExportButtonClick)=\"onGridExportRequested()\"\n (AddToListRequested)=\"onGridAddToListRequested($event)\">\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
1461
  }], () => [{ type: i0.ChangeDetectorRef }], { entity: [{
1258
1462
  type: Input
1259
1463
  }], records: [{
@@ -1278,6 +1482,14 @@ export class EntityViewerComponent {
1278
1482
  type: Input
1279
1483
  }], timelineConfig: [{
1280
1484
  type: Input
1485
+ }], showGridToolbar: [{
1486
+ type: Input
1487
+ }], gridToolbarConfig: [{
1488
+ type: Input
1489
+ }], gridSelectionMode: [{
1490
+ type: Input
1491
+ }], showAddToListButton: [{
1492
+ type: Input
1281
1493
  }], recordSelected: [{
1282
1494
  type: Output
1283
1495
  }], recordOpened: [{
@@ -1296,6 +1508,21 @@ export class EntityViewerComponent {
1296
1508
  type: Output
1297
1509
  }], timelineConfigChange: [{
1298
1510
  type: Output
1511
+ }], addRequested: [{
1512
+ type: Output
1513
+ }], deleteRequested: [{
1514
+ type: Output
1515
+ }], refreshRequested: [{
1516
+ type: Output
1517
+ }], exportRequested: [{
1518
+ type: Output
1519
+ }], addToListRequested: [{
1520
+ type: Output
1521
+ }], selectionChanged: [{
1522
+ type: Output
1523
+ }], dataGridRef: [{
1524
+ type: ViewChild,
1525
+ args: [EntityDataGridComponent]
1299
1526
  }] }); })();
1300
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent", filePath: "src/lib/entity-viewer/entity-viewer.component.ts", lineNumber: 69 }); })();
1527
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent" }); })();
1301
1528
  //# sourceMappingURL=entity-viewer.component.js.map