@memberjunction/ng-entity-viewer 2.122.2 → 2.123.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/entity-cards/entity-cards.component.d.ts.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.js +4 -4
- package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts +103 -3
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.js +454 -36
- package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
- package/dist/lib/types.d.ts +64 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/module.d.ts +2 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +7 -3
- package/dist/module.js.map +1 -1
- package/package.json +6 -5
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
2
|
import { Subject } from 'rxjs';
|
|
3
3
|
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
|
|
4
|
-
import { RunView } from '@memberjunction/core';
|
|
4
|
+
import { EntityFieldTSType, RunView } from '@memberjunction/core';
|
|
5
|
+
import { TimelineGroup } from '@memberjunction/ng-timeline';
|
|
5
6
|
import { DEFAULT_VIEWER_CONFIG } from '../types';
|
|
6
7
|
import * as i0 from "@angular/core";
|
|
7
|
-
import * as i1 from "@
|
|
8
|
-
import * as i2 from "
|
|
9
|
-
import * as i3 from "
|
|
10
|
-
import * as i4 from "../
|
|
11
|
-
import * as i5 from "
|
|
8
|
+
import * as i1 from "@angular/forms";
|
|
9
|
+
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
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";
|
|
14
|
+
import * as i7 from "@angular/common";
|
|
15
|
+
const _forTrack0 = ($index, $item) => $item.Name;
|
|
12
16
|
function EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
13
17
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
14
18
|
i0.ɵɵelementStart(0, "button", 12);
|
|
@@ -62,6 +66,16 @@ function EntityViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { i
|
|
|
62
66
|
i0.ɵɵadvance();
|
|
63
67
|
i0.ɵɵconditional(ctx_r1.filteredRecordCount !== ctx_r1.totalRecordCount ? 1 : 2);
|
|
64
68
|
} }
|
|
69
|
+
function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
70
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
71
|
+
i0.ɵɵelementStart(0, "button", 19);
|
|
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);
|
|
74
|
+
i0.ɵɵelementEnd();
|
|
75
|
+
} if (rf & 2) {
|
|
76
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
77
|
+
i0.ɵɵclassProp("active", ctx_r1.effectiveViewMode === "timeline");
|
|
78
|
+
} }
|
|
65
79
|
function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
66
80
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
67
81
|
i0.ɵɵelementStart(0, "div", 8)(1, "button", 14);
|
|
@@ -71,17 +85,79 @@ function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { i
|
|
|
71
85
|
i0.ɵɵelementStart(3, "button", 16);
|
|
72
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")); });
|
|
73
87
|
i0.ɵɵelement(4, "i", 17);
|
|
74
|
-
i0.ɵɵelementEnd()
|
|
88
|
+
i0.ɵɵelementEnd();
|
|
89
|
+
i0.ɵɵtemplate(5, EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template, 2, 2, "button", 18);
|
|
90
|
+
i0.ɵɵelementEnd();
|
|
75
91
|
} if (rf & 2) {
|
|
76
92
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
77
93
|
i0.ɵɵadvance();
|
|
78
94
|
i0.ɵɵclassProp("active", ctx_r1.effectiveViewMode === "grid");
|
|
79
95
|
i0.ɵɵadvance(2);
|
|
80
96
|
i0.ɵɵclassProp("active", ctx_r1.effectiveViewMode === "cards");
|
|
97
|
+
i0.ɵɵadvance(2);
|
|
98
|
+
i0.ɵɵconditional(ctx_r1.hasDateFields ? 5 : -1);
|
|
99
|
+
} }
|
|
100
|
+
function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
101
|
+
i0.ɵɵelementStart(0, "span", 23);
|
|
102
|
+
i0.ɵɵtext(1);
|
|
103
|
+
i0.ɵɵelementEnd();
|
|
104
|
+
} if (rf & 2) {
|
|
105
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
106
|
+
i0.ɵɵadvance();
|
|
107
|
+
i0.ɵɵtextInterpolate(ctx_r1.selectedDateFieldDisplayName);
|
|
108
|
+
} }
|
|
109
|
+
function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
110
|
+
i0.ɵɵelementStart(0, "option", 29);
|
|
111
|
+
i0.ɵɵtext(1);
|
|
112
|
+
i0.ɵɵelementEnd();
|
|
113
|
+
} if (rf & 2) {
|
|
114
|
+
const field_r8 = ctx.$implicit;
|
|
115
|
+
i0.ɵɵproperty("value", field_r8.Name);
|
|
116
|
+
i0.ɵɵadvance();
|
|
117
|
+
i0.ɵɵtextInterpolate(field_r8.DisplayNameOrName);
|
|
118
|
+
} }
|
|
119
|
+
function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
120
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
121
|
+
i0.ɵɵelementStart(0, "select", 28);
|
|
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);
|
|
124
|
+
i0.ɵɵelementEnd();
|
|
125
|
+
} if (rf & 2) {
|
|
126
|
+
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
127
|
+
i0.ɵɵproperty("value", ctx_r1.selectedTimelineDateField);
|
|
128
|
+
i0.ɵɵadvance();
|
|
129
|
+
i0.ɵɵrepeater(ctx_r1.availableDateFields);
|
|
130
|
+
} }
|
|
131
|
+
function EntityViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
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);
|
|
136
|
+
i0.ɵɵelementEnd();
|
|
137
|
+
i0.ɵɵelementStart(4, "div", 25)(5, "button", 26);
|
|
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
|
+
i0.ɵɵelement(6, "i");
|
|
140
|
+
i0.ɵɵelementEnd()();
|
|
141
|
+
i0.ɵɵelementStart(7, "div", 27)(8, "button", 26);
|
|
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
|
+
i0.ɵɵelement(9, "i");
|
|
144
|
+
i0.ɵɵelementEnd()();
|
|
145
|
+
} if (rf & 2) {
|
|
146
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
147
|
+
i0.ɵɵadvance(2);
|
|
148
|
+
i0.ɵɵconditional(ctx_r1.availableDateFields.length === 1 ? 2 : 3);
|
|
149
|
+
i0.ɵɵadvance(3);
|
|
150
|
+
i0.ɵɵproperty("title", ctx_r1.timelineOrientation === "vertical" ? "Switch to Horizontal" : "Switch to Vertical");
|
|
151
|
+
i0.ɵɵadvance();
|
|
152
|
+
i0.ɵɵclassMap(ctx_r1.timelineOrientation === "vertical" ? "fa-solid fa-ellipsis-vertical" : "fa-solid fa-ellipsis");
|
|
153
|
+
i0.ɵɵadvance(2);
|
|
154
|
+
i0.ɵɵproperty("title", ctx_r1.timelineSortOrder === "desc" ? "Showing Newest First (click for Oldest First)" : "Showing Oldest First (click for Newest First)");
|
|
155
|
+
i0.ɵɵadvance();
|
|
156
|
+
i0.ɵɵclassMap(ctx_r1.timelineSortOrder === "desc" ? "fa-solid fa-arrow-down-wide-short" : "fa-solid fa-arrow-up-wide-short");
|
|
81
157
|
} }
|
|
82
158
|
function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
83
159
|
i0.ɵɵelementStart(0, "div", 1);
|
|
84
|
-
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,
|
|
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);
|
|
85
161
|
i0.ɵɵelementEnd();
|
|
86
162
|
} if (rf & 2) {
|
|
87
163
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -91,10 +167,12 @@ function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
|
91
167
|
i0.ɵɵconditional(ctx_r1.effectiveConfig.showRecordCount && ctx_r1.entity ? 2 : -1);
|
|
92
168
|
i0.ɵɵadvance();
|
|
93
169
|
i0.ɵɵconditional(ctx_r1.effectiveConfig.showViewModeToggle ? 3 : -1);
|
|
170
|
+
i0.ɵɵadvance();
|
|
171
|
+
i0.ɵɵconditional(ctx_r1.effectiveViewMode === "timeline" && ctx_r1.hasDateFields ? 4 : -1);
|
|
94
172
|
} }
|
|
95
173
|
function EntityViewerComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
96
174
|
i0.ɵɵelementStart(0, "div", 3);
|
|
97
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
175
|
+
i0.ɵɵelement(1, "mj-loading", 30);
|
|
98
176
|
i0.ɵɵelementEnd();
|
|
99
177
|
} if (rf & 2) {
|
|
100
178
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -103,14 +181,14 @@ function EntityViewerComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
|
103
181
|
} }
|
|
104
182
|
function EntityViewerComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
105
183
|
i0.ɵɵelementStart(0, "div", 4);
|
|
106
|
-
i0.ɵɵelement(1, "i",
|
|
184
|
+
i0.ɵɵelement(1, "i", 31);
|
|
107
185
|
i0.ɵɵelementStart(2, "p");
|
|
108
186
|
i0.ɵɵtext(3, "Select an entity to view records");
|
|
109
187
|
i0.ɵɵelementEnd()();
|
|
110
188
|
} }
|
|
111
189
|
function EntityViewerComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
112
190
|
i0.ɵɵelementStart(0, "div", 4);
|
|
113
|
-
i0.ɵɵelement(1, "i",
|
|
191
|
+
i0.ɵɵelement(1, "i", 32);
|
|
114
192
|
i0.ɵɵelementStart(2, "p");
|
|
115
193
|
i0.ɵɵtext(3);
|
|
116
194
|
i0.ɵɵelementEnd()();
|
|
@@ -119,34 +197,36 @@ function EntityViewerComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
|
119
197
|
i0.ɵɵadvance(3);
|
|
120
198
|
i0.ɵɵtextInterpolate(ctx_r1.debouncedFilterText ? "No matching records" : "No records found");
|
|
121
199
|
} }
|
|
122
|
-
function
|
|
123
|
-
const
|
|
124
|
-
i0.ɵɵelementStart(0, "mj-
|
|
125
|
-
i0.ɵɵlistener("
|
|
126
|
-
i0.ɵɵelementEnd();
|
|
127
|
-
} if (rf & 2) {
|
|
128
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
129
|
-
i0.ɵɵproperty("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);
|
|
130
|
-
} }
|
|
131
|
-
function EntityViewerComponent_Conditional_6_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
132
|
-
const _r6 = i0.ɵɵgetCurrentView();
|
|
133
|
-
i0.ɵɵelementStart(0, "mj-entity-cards", 24);
|
|
134
|
-
i0.ɵɵlistener("recordSelected", function EntityViewerComponent_Conditional_6_Conditional_1_Template_mj_entity_cards_recordSelected_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onRecordSelected($event)); })("recordOpened", function EntityViewerComponent_Conditional_6_Conditional_1_Template_mj_entity_cards_recordOpened_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onRecordOpened($event)); });
|
|
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)); });
|
|
135
204
|
i0.ɵɵelementEnd();
|
|
136
205
|
} if (rf & 2) {
|
|
137
206
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
138
|
-
i0.ɵɵproperty("
|
|
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);
|
|
139
208
|
} }
|
|
140
209
|
function EntityViewerComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
141
|
-
|
|
210
|
+
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);
|
|
142
218
|
} if (rf & 2) {
|
|
143
219
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
144
|
-
i0.ɵɵ
|
|
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);
|
|
145
225
|
} }
|
|
146
226
|
function EntityViewerComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
147
|
-
const
|
|
148
|
-
i0.ɵɵelementStart(0, "mj-pagination",
|
|
149
|
-
i0.ɵɵlistener("loadMore", function EntityViewerComponent_Conditional_7_Template_mj_pagination_loadMore_0_listener() { i0.ɵɵrestoreView(
|
|
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()); });
|
|
150
230
|
i0.ɵɵelementEnd();
|
|
151
231
|
} if (rf & 2) {
|
|
152
232
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -239,6 +319,31 @@ export class EntityViewerComponent {
|
|
|
239
319
|
* Controls column visibility, widths, order, and sort settings
|
|
240
320
|
*/
|
|
241
321
|
gridState = null;
|
|
322
|
+
/**
|
|
323
|
+
* Timeline configuration state
|
|
324
|
+
* Controls which date field is used and segment grouping
|
|
325
|
+
*/
|
|
326
|
+
get timelineConfig() {
|
|
327
|
+
return this._timelineConfig;
|
|
328
|
+
}
|
|
329
|
+
set timelineConfig(value) {
|
|
330
|
+
const prev = this._timelineConfig;
|
|
331
|
+
// Compare by value, not reference
|
|
332
|
+
const isEqual = (prev === null && value === null) ||
|
|
333
|
+
(prev !== null && value !== null &&
|
|
334
|
+
prev.dateFieldName === value.dateFieldName &&
|
|
335
|
+
prev.sortOrder === value.sortOrder &&
|
|
336
|
+
prev.orientation === value.orientation &&
|
|
337
|
+
prev.segmentGrouping === value.segmentGrouping);
|
|
338
|
+
if (!isEqual) {
|
|
339
|
+
this._timelineConfig = value;
|
|
340
|
+
if (value && this.entity) {
|
|
341
|
+
this.configureTimeline();
|
|
342
|
+
this.cdr.markForCheck();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
_timelineConfig = null;
|
|
242
347
|
// ========================================
|
|
243
348
|
// OUTPUTS
|
|
244
349
|
// ========================================
|
|
@@ -274,6 +379,10 @@ export class EntityViewerComponent {
|
|
|
274
379
|
* Emitted when grid state changes (column resize, reorder, etc.)
|
|
275
380
|
*/
|
|
276
381
|
gridStateChanged = new EventEmitter();
|
|
382
|
+
/**
|
|
383
|
+
* Emitted when timeline configuration changes (date field, grouping, etc.)
|
|
384
|
+
*/
|
|
385
|
+
timelineConfigChange = new EventEmitter();
|
|
277
386
|
// ========================================
|
|
278
387
|
// INTERNAL STATE
|
|
279
388
|
// ========================================
|
|
@@ -297,6 +406,39 @@ export class EntityViewerComponent {
|
|
|
297
406
|
hasMore: false,
|
|
298
407
|
isLoading: false
|
|
299
408
|
};
|
|
409
|
+
// ========================================
|
|
410
|
+
// TIMELINE STATE
|
|
411
|
+
// ========================================
|
|
412
|
+
/** Whether the current entity has date fields available for timeline view */
|
|
413
|
+
hasDateFields = false;
|
|
414
|
+
/** Available date fields from the entity (sorted by priority) */
|
|
415
|
+
availableDateFields = [];
|
|
416
|
+
/** Timeline groups configuration for the timeline component */
|
|
417
|
+
get timelineGroups() {
|
|
418
|
+
return this._timelineGroups;
|
|
419
|
+
}
|
|
420
|
+
set timelineGroups(value) {
|
|
421
|
+
const prev = this._timelineGroups;
|
|
422
|
+
this._timelineGroups = value;
|
|
423
|
+
// Detect meaningful changes to trigger refresh in child timeline component
|
|
424
|
+
const hasChanged = prev !== value ||
|
|
425
|
+
(prev.length > 0 && value.length > 0 &&
|
|
426
|
+
(prev[0].EntityObjects !== value[0]?.EntityObjects ||
|
|
427
|
+
prev[0].DateFieldName !== value[0]?.DateFieldName));
|
|
428
|
+
if (hasChanged) {
|
|
429
|
+
// Force change detection to propagate to child timeline component
|
|
430
|
+
this.cdr.markForCheck();
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
_timelineGroups = [];
|
|
434
|
+
/** Timeline sort order */
|
|
435
|
+
timelineSortOrder = 'desc';
|
|
436
|
+
/** Timeline segment grouping */
|
|
437
|
+
timelineSegmentGrouping = 'month';
|
|
438
|
+
/** Timeline orientation (vertical or horizontal) */
|
|
439
|
+
timelineOrientation = 'vertical';
|
|
440
|
+
/** Currently selected date field for timeline */
|
|
441
|
+
selectedTimelineDateField = null;
|
|
300
442
|
destroy$ = new Subject();
|
|
301
443
|
filterInput$ = new Subject();
|
|
302
444
|
/** Track if this is the first load (vs. load more) */
|
|
@@ -319,6 +461,27 @@ export class EntityViewerComponent {
|
|
|
319
461
|
get effectiveFilterText() {
|
|
320
462
|
return this.filterText ?? this.internalFilterText;
|
|
321
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* Get the raw ID value from selectedRecordId for timeline selection.
|
|
466
|
+
* The selectedRecordId is in composite key format (e.g., "ID|abc-123" or "ID=abc-123"),
|
|
467
|
+
* but the timeline stores just the raw ID value.
|
|
468
|
+
*/
|
|
469
|
+
get timelineSelectedEventId() {
|
|
470
|
+
if (!this.selectedRecordId)
|
|
471
|
+
return null;
|
|
472
|
+
// Handle "ID|value" format (pipe separator)
|
|
473
|
+
if (this.selectedRecordId.includes('|')) {
|
|
474
|
+
const parts = this.selectedRecordId.split('|');
|
|
475
|
+
return parts.length > 1 ? parts[1] : this.selectedRecordId;
|
|
476
|
+
}
|
|
477
|
+
// Handle "ID=value" format (equals separator)
|
|
478
|
+
if (this.selectedRecordId.includes('=')) {
|
|
479
|
+
const parts = this.selectedRecordId.split('=');
|
|
480
|
+
return parts.length > 1 ? parts[1] : this.selectedRecordId;
|
|
481
|
+
}
|
|
482
|
+
// Return as-is if no separator found
|
|
483
|
+
return this.selectedRecordId;
|
|
484
|
+
}
|
|
322
485
|
/**
|
|
323
486
|
* Get the effective sort state (external or internal)
|
|
324
487
|
*/
|
|
@@ -484,6 +647,8 @@ export class EntityViewerComponent {
|
|
|
484
647
|
this.applyConfig();
|
|
485
648
|
}
|
|
486
649
|
if (changes['entity']) {
|
|
650
|
+
// Detect date fields for timeline support
|
|
651
|
+
this.detectDateFields();
|
|
487
652
|
if (this.entity && !this.records) {
|
|
488
653
|
// Reset state for new entity - synchronously clear all data and force change detection
|
|
489
654
|
// before starting the async load to prevent stale data display
|
|
@@ -503,7 +668,10 @@ export class EntityViewerComponent {
|
|
|
503
668
|
this.internalRecords = this.records;
|
|
504
669
|
this.totalRecordCount = this.records.length;
|
|
505
670
|
this.filteredRecordCount = this.records.length;
|
|
671
|
+
// Update timeline with new records
|
|
672
|
+
this.updateTimelineGroups();
|
|
506
673
|
}
|
|
674
|
+
// Timeline config is now handled by setter - no ngOnChanges handling needed
|
|
507
675
|
// Handle external filter text changes (from parent component)
|
|
508
676
|
if (changes['filterText']) {
|
|
509
677
|
const newFilter = this.filterText ?? '';
|
|
@@ -693,6 +861,8 @@ export class EntityViewerComponent {
|
|
|
693
861
|
filteredCount: this.internalRecords.length,
|
|
694
862
|
totalCount: result.TotalRowCount
|
|
695
863
|
});
|
|
864
|
+
// Update timeline groups with new data
|
|
865
|
+
this.updateTimelineGroups();
|
|
696
866
|
}
|
|
697
867
|
else {
|
|
698
868
|
console.error('Failed to load records:', result.ErrorMessage);
|
|
@@ -816,12 +986,256 @@ export class EntityViewerComponent {
|
|
|
816
986
|
onLoadMore() {
|
|
817
987
|
this.loadMore();
|
|
818
988
|
}
|
|
989
|
+
// ========================================
|
|
990
|
+
// TIMELINE METHODS
|
|
991
|
+
// ========================================
|
|
992
|
+
/**
|
|
993
|
+
* Handle timeline event click - emit as record selection
|
|
994
|
+
*/
|
|
995
|
+
onTimelineEventClick(event) {
|
|
996
|
+
const record = event.event.entity;
|
|
997
|
+
if (record && this.entity) {
|
|
998
|
+
this.recordSelected.emit({
|
|
999
|
+
record,
|
|
1000
|
+
entity: this.entity,
|
|
1001
|
+
compositeKey: record.PrimaryKey
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Toggle timeline orientation between vertical and horizontal
|
|
1007
|
+
*/
|
|
1008
|
+
toggleTimelineOrientation() {
|
|
1009
|
+
this.timelineOrientation = this.timelineOrientation === 'vertical' ? 'horizontal' : 'vertical';
|
|
1010
|
+
// Emit config change so parent can persist the preference
|
|
1011
|
+
this.emitTimelineConfigChange();
|
|
1012
|
+
this.cdr.detectChanges();
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Toggle timeline sort order between newest first (desc) and oldest first (asc)
|
|
1016
|
+
*/
|
|
1017
|
+
toggleTimelineSortOrder() {
|
|
1018
|
+
this.timelineSortOrder = this.timelineSortOrder === 'desc' ? 'asc' : 'desc';
|
|
1019
|
+
// Emit config change so parent can persist the preference
|
|
1020
|
+
this.emitTimelineConfigChange();
|
|
1021
|
+
this.cdr.detectChanges();
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Change the date field used for the timeline
|
|
1025
|
+
*/
|
|
1026
|
+
setTimelineDateField(fieldName) {
|
|
1027
|
+
if (this.availableDateFields.some(f => f.Name === fieldName)) {
|
|
1028
|
+
this.selectedTimelineDateField = fieldName;
|
|
1029
|
+
this.updateTimelineGroups();
|
|
1030
|
+
this.emitTimelineConfigChange();
|
|
1031
|
+
this.cdr.detectChanges();
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Get the display name of the currently selected timeline date field
|
|
1036
|
+
*/
|
|
1037
|
+
get selectedDateFieldDisplayName() {
|
|
1038
|
+
if (!this.selectedTimelineDateField)
|
|
1039
|
+
return '';
|
|
1040
|
+
const field = this.availableDateFields.find(f => f.Name === this.selectedTimelineDateField);
|
|
1041
|
+
return field?.DisplayNameOrName || this.selectedTimelineDateField;
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Emit the current timeline configuration for persistence
|
|
1045
|
+
*/
|
|
1046
|
+
emitTimelineConfigChange() {
|
|
1047
|
+
if (this.selectedTimelineDateField) {
|
|
1048
|
+
this.timelineConfigChange.emit({
|
|
1049
|
+
dateFieldName: this.selectedTimelineDateField,
|
|
1050
|
+
sortOrder: this.timelineSortOrder,
|
|
1051
|
+
segmentGrouping: this.timelineSegmentGrouping,
|
|
1052
|
+
orientation: this.timelineOrientation
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Detect and configure timeline based on entity's date fields
|
|
1058
|
+
* Called when entity changes
|
|
1059
|
+
*/
|
|
1060
|
+
detectDateFields() {
|
|
1061
|
+
if (!this.entity) {
|
|
1062
|
+
this.hasDateFields = false;
|
|
1063
|
+
this.availableDateFields = [];
|
|
1064
|
+
this.timelineGroups = [];
|
|
1065
|
+
this.fallbackFromTimelineIfNeeded();
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
// Find all date fields - include __mj_CreatedAt and __mj_UpdatedAt as they're useful for timelines
|
|
1069
|
+
const dateFields = this.entity.Fields.filter(f => f.TSType === EntityFieldTSType.Date);
|
|
1070
|
+
if (dateFields.length === 0) {
|
|
1071
|
+
this.hasDateFields = false;
|
|
1072
|
+
this.availableDateFields = [];
|
|
1073
|
+
this.timelineGroups = [];
|
|
1074
|
+
this.fallbackFromTimelineIfNeeded();
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
// Sort by priority: DefaultInView date fields first (by Sequence), then others (by Sequence)
|
|
1078
|
+
this.availableDateFields = this.sortDateFieldsByPriority(dateFields);
|
|
1079
|
+
this.hasDateFields = true;
|
|
1080
|
+
// Configure timeline with the best date field
|
|
1081
|
+
this.configureTimeline();
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* If currently on timeline view but timeline is no longer available,
|
|
1085
|
+
* fall back to grid view
|
|
1086
|
+
*/
|
|
1087
|
+
fallbackFromTimelineIfNeeded() {
|
|
1088
|
+
if (this.effectiveViewMode === 'timeline' && !this.hasDateFields) {
|
|
1089
|
+
this.setViewMode('grid');
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Sort date fields by priority:
|
|
1094
|
+
* 1. DefaultInView=true fields, sorted by Sequence (lowest first)
|
|
1095
|
+
* 2. Other date fields, sorted by Sequence (lowest first)
|
|
1096
|
+
*/
|
|
1097
|
+
sortDateFieldsByPriority(dateFields) {
|
|
1098
|
+
const defaultInView = dateFields.filter(f => f.DefaultInView).sort((a, b) => a.Sequence - b.Sequence);
|
|
1099
|
+
const others = dateFields.filter(f => !f.DefaultInView).sort((a, b) => a.Sequence - b.Sequence);
|
|
1100
|
+
return [...defaultInView, ...others];
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Configure the timeline with the current date field and records
|
|
1104
|
+
*/
|
|
1105
|
+
configureTimeline() {
|
|
1106
|
+
if (!this.entity || !this.hasDateFields || this.availableDateFields.length === 0) {
|
|
1107
|
+
this.timelineGroups = [];
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
// Determine which date field to use
|
|
1111
|
+
const dateFieldName = this.getEffectiveTimelineDateField();
|
|
1112
|
+
this.selectedTimelineDateField = dateFieldName;
|
|
1113
|
+
// Apply timeline config if provided
|
|
1114
|
+
if (this.timelineConfig) {
|
|
1115
|
+
this.timelineSortOrder = (this.timelineConfig.sortOrder || 'desc');
|
|
1116
|
+
this.timelineSegmentGrouping = (this.timelineConfig.segmentGrouping || 'month');
|
|
1117
|
+
this.timelineOrientation = this.timelineConfig.orientation || 'vertical';
|
|
1118
|
+
}
|
|
1119
|
+
// Create a timeline group for the current entity's data
|
|
1120
|
+
this.updateTimelineGroups();
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Get the effective date field to use for timeline
|
|
1124
|
+
* Priority: timelineConfig > first available date field
|
|
1125
|
+
*/
|
|
1126
|
+
getEffectiveTimelineDateField() {
|
|
1127
|
+
// If we have a config with a specific date field, use it if valid
|
|
1128
|
+
if (this.timelineConfig?.dateFieldName) {
|
|
1129
|
+
const configField = this.availableDateFields.find(f => f.Name === this.timelineConfig.dateFieldName);
|
|
1130
|
+
if (configField) {
|
|
1131
|
+
return configField.Name;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
// Otherwise use the first available date field (already sorted by priority)
|
|
1135
|
+
return this.availableDateFields[0].Name;
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Update timeline groups with current records
|
|
1139
|
+
* Called when records change
|
|
1140
|
+
*/
|
|
1141
|
+
updateTimelineGroups() {
|
|
1142
|
+
if (!this.entity || !this.selectedTimelineDateField) {
|
|
1143
|
+
this.timelineGroups = [];
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
// Find title field - prefer NameField, then first string field with DefaultInView
|
|
1147
|
+
const titleField = this.findTitleField();
|
|
1148
|
+
// Create a single group for the current data
|
|
1149
|
+
const group = new TimelineGroup();
|
|
1150
|
+
group.DataSourceType = 'array';
|
|
1151
|
+
group.EntityObjects = this.filteredRecords;
|
|
1152
|
+
group.TitleFieldName = titleField;
|
|
1153
|
+
group.DateFieldName = this.selectedTimelineDateField;
|
|
1154
|
+
group.IdFieldName = 'ID';
|
|
1155
|
+
group.GroupLabel = this.entity.Name;
|
|
1156
|
+
// Find a suitable description field
|
|
1157
|
+
const descField = this.findDescriptionField();
|
|
1158
|
+
if (descField) {
|
|
1159
|
+
group.DescriptionFieldName = descField;
|
|
1160
|
+
}
|
|
1161
|
+
// Find a suitable subtitle field
|
|
1162
|
+
const subtitleField = this.findSubtitleField(titleField);
|
|
1163
|
+
if (subtitleField) {
|
|
1164
|
+
group.SubtitleFieldName = subtitleField;
|
|
1165
|
+
}
|
|
1166
|
+
// Configure card display
|
|
1167
|
+
group.CardConfig = {
|
|
1168
|
+
collapsible: true,
|
|
1169
|
+
defaultExpanded: false,
|
|
1170
|
+
showDate: true,
|
|
1171
|
+
dateFormat: 'MMM d, yyyy h:mm a'
|
|
1172
|
+
};
|
|
1173
|
+
this.timelineGroups = [group];
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Find the best field to use as the title
|
|
1177
|
+
*/
|
|
1178
|
+
findTitleField() {
|
|
1179
|
+
if (!this.entity)
|
|
1180
|
+
return 'ID';
|
|
1181
|
+
// Prefer the entity's NameField
|
|
1182
|
+
if (this.entity.NameField) {
|
|
1183
|
+
return this.entity.NameField.Name;
|
|
1184
|
+
}
|
|
1185
|
+
// Look for common name patterns in DefaultInView string fields
|
|
1186
|
+
const stringFields = this.entity.Fields.filter(f => f.TSType === EntityFieldTSType.String && f.DefaultInView && !f.Name.startsWith('__mj_')).sort((a, b) => a.Sequence - b.Sequence);
|
|
1187
|
+
const namePatterns = ['name', 'title', 'subject', 'label'];
|
|
1188
|
+
for (const pattern of namePatterns) {
|
|
1189
|
+
const match = stringFields.find(f => f.Name.toLowerCase().includes(pattern));
|
|
1190
|
+
if (match)
|
|
1191
|
+
return match.Name;
|
|
1192
|
+
}
|
|
1193
|
+
// Fall back to first string field
|
|
1194
|
+
return stringFields.length > 0 ? stringFields[0].Name : 'ID';
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Find a suitable description field
|
|
1198
|
+
*/
|
|
1199
|
+
findDescriptionField() {
|
|
1200
|
+
if (!this.entity)
|
|
1201
|
+
return null;
|
|
1202
|
+
// Look for common description patterns
|
|
1203
|
+
const descPatterns = ['description', 'notes', 'summary', 'content', 'body', 'details'];
|
|
1204
|
+
const textFields = this.entity.Fields.filter(f => (f.TSType === EntityFieldTSType.String) && !f.Name.startsWith('__mj_'));
|
|
1205
|
+
for (const pattern of descPatterns) {
|
|
1206
|
+
const match = textFields.find(f => f.Name.toLowerCase().includes(pattern));
|
|
1207
|
+
if (match)
|
|
1208
|
+
return match.Name;
|
|
1209
|
+
}
|
|
1210
|
+
return null;
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Find a suitable subtitle field (different from title)
|
|
1214
|
+
*/
|
|
1215
|
+
findSubtitleField(excludeField) {
|
|
1216
|
+
if (!this.entity)
|
|
1217
|
+
return null;
|
|
1218
|
+
// Look for status, type, category, or other short classification fields
|
|
1219
|
+
const patterns = ['status', 'type', 'category', 'state', 'priority'];
|
|
1220
|
+
const fields = this.entity.Fields.filter(f => f.TSType === EntityFieldTSType.String &&
|
|
1221
|
+
f.DefaultInView &&
|
|
1222
|
+
f.Name !== excludeField &&
|
|
1223
|
+
!f.Name.startsWith('__mj_')).sort((a, b) => a.Sequence - b.Sequence);
|
|
1224
|
+
for (const pattern of patterns) {
|
|
1225
|
+
const match = fields.find(f => f.Name.toLowerCase().includes(pattern));
|
|
1226
|
+
if (match)
|
|
1227
|
+
return match.Name;
|
|
1228
|
+
}
|
|
1229
|
+
// Use the first string field that's not the title field
|
|
1230
|
+
const firstOther = fields.find(f => f.Name !== excludeField);
|
|
1231
|
+
return firstOther?.Name || null;
|
|
1232
|
+
}
|
|
819
1233
|
static ɵfac = function EntityViewerComponent_Factory(t) { return new (t || EntityViewerComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
820
|
-
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" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened", dataLoaded: "dataLoaded", viewModeChange: "viewModeChange", filterTextChange: "filterTextChange", filteredCountChanged: "filteredCountChanged", sortChanged: "sortChanged", gridStateChanged: "gridStateChanged" }, 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"], ["
|
|
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) {
|
|
821
1235
|
i0.ɵɵelementStart(0, "div", 0);
|
|
822
|
-
i0.ɵɵtemplate(1, EntityViewerComponent_Conditional_1_Template,
|
|
1236
|
+
i0.ɵɵtemplate(1, EntityViewerComponent_Conditional_1_Template, 5, 4, "div", 1);
|
|
823
1237
|
i0.ɵɵelementStart(2, "div", 2);
|
|
824
|
-
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,
|
|
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);
|
|
825
1239
|
i0.ɵɵelementEnd();
|
|
826
1240
|
i0.ɵɵtemplate(7, EntityViewerComponent_Conditional_7_Template, 1, 2, "mj-pagination", 5);
|
|
827
1241
|
i0.ɵɵelementEnd();
|
|
@@ -833,13 +1247,13 @@ export class EntityViewerComponent {
|
|
|
833
1247
|
i0.ɵɵconditional(ctx.isLoading && ctx.filteredRecords.length === 0 ? 3 : !ctx.entity ? 4 : ctx.filteredRecords.length === 0 && !ctx.isLoading ? 5 : 6);
|
|
834
1248
|
i0.ɵɵadvance(4);
|
|
835
1249
|
i0.ɵɵconditional(ctx.effectiveConfig.showPagination && ctx.entity && (ctx.pagination.hasMore || ctx.pagination.totalRecords > ctx.effectiveConfig.pageSize) ? 7 : -1);
|
|
836
|
-
} }, dependencies: [i1.
|
|
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}"] });
|
|
837
1251
|
}
|
|
838
1252
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityViewerComponent, [{
|
|
839
1253
|
type: Component,
|
|
840
1254
|
args: [{ selector: 'mj-entity-viewer', host: {
|
|
841
1255
|
'style': 'display: block; height: 100%;'
|
|
842
|
-
}, 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 </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 @if (effectiveViewMode === 'grid') {\n <mj-entity-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 } @else {\n <mj-entity-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 }\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/* Content */\n.viewer-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n position: relative;\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"] }]
|
|
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"] }]
|
|
843
1257
|
}], () => [{ type: i0.ChangeDetectorRef }], { entity: [{
|
|
844
1258
|
type: Input
|
|
845
1259
|
}], records: [{
|
|
@@ -862,6 +1276,8 @@ export class EntityViewerComponent {
|
|
|
862
1276
|
type: Input
|
|
863
1277
|
}], gridState: [{
|
|
864
1278
|
type: Input
|
|
1279
|
+
}], timelineConfig: [{
|
|
1280
|
+
type: Input
|
|
865
1281
|
}], recordSelected: [{
|
|
866
1282
|
type: Output
|
|
867
1283
|
}], recordOpened: [{
|
|
@@ -878,6 +1294,8 @@ export class EntityViewerComponent {
|
|
|
878
1294
|
type: Output
|
|
879
1295
|
}], gridStateChanged: [{
|
|
880
1296
|
type: Output
|
|
1297
|
+
}], timelineConfigChange: [{
|
|
1298
|
+
type: Output
|
|
881
1299
|
}] }); })();
|
|
882
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent", filePath: "src/lib/entity-viewer/entity-viewer.component.ts", lineNumber:
|
|
1300
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent", filePath: "src/lib/entity-viewer/entity-viewer.component.ts", lineNumber: 69 }); })();
|
|
883
1301
|
//# sourceMappingURL=entity-viewer.component.js.map
|