@memberjunction/ng-entity-viewer 5.23.0 → 5.25.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/aggregate-panel/aggregate-panel.component.d.ts +1 -1
- package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
- package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts +3 -1
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.d.ts.map +1 -1
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js +1 -1
- package/dist/lib/aggregate-setup-dialog/aggregate-setup-dialog.component.js.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.d.ts +10 -1
- package/dist/lib/entity-cards/entity-cards.component.d.ts.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.js +43 -20
- package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.js +12 -17
- package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
- package/dist/lib/entity-data-grid/models/grid-types.js +3 -0
- package/dist/lib/entity-data-grid/models/grid-types.js.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts +43 -2
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.js +161 -53
- package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
- package/dist/lib/types.d.ts +21 -36
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +3 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils/record.util.d.ts +1 -1
- package/dist/lib/utils/record.util.d.ts.map +1 -1
- package/dist/lib/utils/record.util.js +16 -0
- package/dist/lib/utils/record.util.js.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.d.ts.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.js +2 -2
- package/dist/lib/view-config-panel/view-config-panel.component.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/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +2 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +11 -10
|
@@ -11,25 +11,26 @@ import * as i0 from "@angular/core";
|
|
|
11
11
|
import * as i1 from "@angular/forms";
|
|
12
12
|
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
13
13
|
import * as i3 from "@memberjunction/ng-timeline";
|
|
14
|
-
import * as i4 from "
|
|
15
|
-
import * as i5 from "../entity-
|
|
16
|
-
import * as i6 from "
|
|
14
|
+
import * as i4 from "@memberjunction/ng-map-view";
|
|
15
|
+
import * as i5 from "../entity-cards/entity-cards.component";
|
|
16
|
+
import * as i6 from "../entity-data-grid/entity-data-grid.component";
|
|
17
|
+
import * as i7 from "@angular/common";
|
|
17
18
|
const _forTrack0 = ($index, $item) => $item.Name;
|
|
18
19
|
function EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
19
20
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
20
|
-
i0.ɵɵelementStart(0, "button",
|
|
21
|
+
i0.ɵɵelementStart(0, "button", 20);
|
|
21
22
|
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()); });
|
|
22
|
-
i0.ɵɵelement(1, "i",
|
|
23
|
+
i0.ɵɵelement(1, "i", 21);
|
|
23
24
|
i0.ɵɵelementEnd();
|
|
24
25
|
} }
|
|
25
26
|
function EntityViewerComponent_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
26
27
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
27
|
-
i0.ɵɵelementStart(0, "div",
|
|
28
|
-
i0.ɵɵelement(1, "i",
|
|
29
|
-
i0.ɵɵelementStart(2, "input",
|
|
28
|
+
i0.ɵɵelementStart(0, "div", 14);
|
|
29
|
+
i0.ɵɵelement(1, "i", 17);
|
|
30
|
+
i0.ɵɵelementStart(2, "input", 18);
|
|
30
31
|
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)); });
|
|
31
32
|
i0.ɵɵelementEnd();
|
|
32
|
-
i0.ɵɵconditionalCreate(3, EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template, 2, 0, "button",
|
|
33
|
+
i0.ɵɵconditionalCreate(3, EntityViewerComponent_Conditional_1_Conditional_1_Conditional_3_Template, 2, 0, "button", 19);
|
|
33
34
|
i0.ɵɵelementEnd();
|
|
34
35
|
} if (rf & 2) {
|
|
35
36
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -60,7 +61,7 @@ function EntityViewerComponent_Conditional_1_Conditional_2_Conditional_2_Templat
|
|
|
60
61
|
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind1(2, 1, ctx_r1.totalRecordCount), " records");
|
|
61
62
|
} }
|
|
62
63
|
function EntityViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
63
|
-
i0.ɵɵelementStart(0, "div",
|
|
64
|
+
i0.ɵɵelementStart(0, "div", 15);
|
|
64
65
|
i0.ɵɵconditionalCreate(1, EntityViewerComponent_Conditional_1_Conditional_2_Conditional_1_Template, 4, 6, "span")(2, EntityViewerComponent_Conditional_1_Conditional_2_Conditional_2_Template, 3, 3, "span");
|
|
65
66
|
i0.ɵɵelementEnd();
|
|
66
67
|
} if (rf & 2) {
|
|
@@ -70,9 +71,9 @@ function EntityViewerComponent_Conditional_1_Conditional_2_Template(rf, ctx) { i
|
|
|
70
71
|
} }
|
|
71
72
|
function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
72
73
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
73
|
-
i0.ɵɵelementStart(0, "button",
|
|
74
|
+
i0.ɵɵelementStart(0, "button", 29);
|
|
74
75
|
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")); });
|
|
75
|
-
i0.ɵɵelement(1, "i",
|
|
76
|
+
i0.ɵɵelement(1, "i", 30);
|
|
76
77
|
i0.ɵɵelementEnd();
|
|
77
78
|
} if (rf & 2) {
|
|
78
79
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
@@ -80,16 +81,19 @@ function EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Templat
|
|
|
80
81
|
} }
|
|
81
82
|
function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
82
83
|
const _r4 = i0.ɵɵgetCurrentView();
|
|
83
|
-
i0.ɵɵelementStart(0, "div",
|
|
84
|
+
i0.ɵɵelementStart(0, "div", 16)(1, "button", 22);
|
|
84
85
|
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")); });
|
|
85
|
-
i0.ɵɵelement(2, "i",
|
|
86
|
+
i0.ɵɵelement(2, "i", 23);
|
|
86
87
|
i0.ɵɵelementEnd();
|
|
87
|
-
i0.ɵɵelementStart(3, "button",
|
|
88
|
+
i0.ɵɵelementStart(3, "button", 24);
|
|
88
89
|
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")); });
|
|
89
|
-
i0.ɵɵelement(4, "i",
|
|
90
|
-
i0.ɵɵelementEnd();
|
|
91
|
-
i0.ɵɵconditionalCreate(5, EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template, 2, 2, "button", 25);
|
|
90
|
+
i0.ɵɵelement(4, "i", 25);
|
|
92
91
|
i0.ɵɵelementEnd();
|
|
92
|
+
i0.ɵɵconditionalCreate(5, EntityViewerComponent_Conditional_1_Conditional_3_Conditional_5_Template, 2, 2, "button", 26);
|
|
93
|
+
i0.ɵɵelementStart(6, "button", 27);
|
|
94
|
+
i0.ɵɵlistener("click", function EntityViewerComponent_Conditional_1_Conditional_3_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setViewMode("map")); });
|
|
95
|
+
i0.ɵɵelement(7, "i", 28);
|
|
96
|
+
i0.ɵɵelementEnd()();
|
|
93
97
|
} if (rf & 2) {
|
|
94
98
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
95
99
|
i0.ɵɵadvance();
|
|
@@ -98,9 +102,11 @@ function EntityViewerComponent_Conditional_1_Conditional_3_Template(rf, ctx) { i
|
|
|
98
102
|
i0.ɵɵclassProp("active", ctx_r1.effectiveViewMode === "cards");
|
|
99
103
|
i0.ɵɵadvance(2);
|
|
100
104
|
i0.ɵɵconditional(ctx_r1.hasDateFields ? 5 : -1);
|
|
105
|
+
i0.ɵɵadvance();
|
|
106
|
+
i0.ɵɵclassProp("active", ctx_r1.effectiveViewMode === "map")("geo-hidden", !ctx_r1.HasGeoCoding);
|
|
101
107
|
} }
|
|
102
108
|
function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
103
|
-
i0.ɵɵelementStart(0, "span",
|
|
109
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
104
110
|
i0.ɵɵtext(1);
|
|
105
111
|
i0.ɵɵelementEnd();
|
|
106
112
|
} if (rf & 2) {
|
|
@@ -109,7 +115,7 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Templat
|
|
|
109
115
|
i0.ɵɵtextInterpolate(ctx_r1.selectedDateFieldDisplayName);
|
|
110
116
|
} }
|
|
111
117
|
function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
112
|
-
i0.ɵɵelementStart(0, "option",
|
|
118
|
+
i0.ɵɵelementStart(0, "option", 39);
|
|
113
119
|
i0.ɵɵtext(1);
|
|
114
120
|
i0.ɵɵelementEnd();
|
|
115
121
|
} if (rf & 2) {
|
|
@@ -120,9 +126,9 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_T
|
|
|
120
126
|
} }
|
|
121
127
|
function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
122
128
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
123
|
-
i0.ɵɵelementStart(0, "select",
|
|
129
|
+
i0.ɵɵelementStart(0, "select", 38);
|
|
124
130
|
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)); });
|
|
125
|
-
i0.ɵɵrepeaterCreate(1, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template, 2, 2, "option",
|
|
131
|
+
i0.ɵɵrepeaterCreate(1, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_For_2_Template, 2, 2, "option", 39, _forTrack0);
|
|
126
132
|
i0.ɵɵelementEnd();
|
|
127
133
|
} if (rf & 2) {
|
|
128
134
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
@@ -132,15 +138,15 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Templat
|
|
|
132
138
|
} }
|
|
133
139
|
function EntityViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
134
140
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
135
|
-
i0.ɵɵelementStart(0, "div",
|
|
136
|
-
i0.ɵɵelement(1, "i",
|
|
137
|
-
i0.ɵɵconditionalCreate(2, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template, 2, 1, "span",
|
|
141
|
+
i0.ɵɵelementStart(0, "div", 31);
|
|
142
|
+
i0.ɵɵelement(1, "i", 32);
|
|
143
|
+
i0.ɵɵconditionalCreate(2, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_2_Template, 2, 1, "span", 33)(3, EntityViewerComponent_Conditional_1_Conditional_4_Conditional_3_Template, 3, 1, "select", 34);
|
|
138
144
|
i0.ɵɵelementEnd();
|
|
139
|
-
i0.ɵɵelementStart(4, "div",
|
|
145
|
+
i0.ɵɵelementStart(4, "div", 35)(5, "button", 36);
|
|
140
146
|
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()); });
|
|
141
147
|
i0.ɵɵelement(6, "i");
|
|
142
148
|
i0.ɵɵelementEnd()();
|
|
143
|
-
i0.ɵɵelementStart(7, "div",
|
|
149
|
+
i0.ɵɵelementStart(7, "div", 37)(8, "button", 36);
|
|
144
150
|
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()); });
|
|
145
151
|
i0.ɵɵelement(9, "i");
|
|
146
152
|
i0.ɵɵelementEnd()();
|
|
@@ -159,9 +165,9 @@ function EntityViewerComponent_Conditional_1_Conditional_4_Template(rf, ctx) { i
|
|
|
159
165
|
} }
|
|
160
166
|
function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
161
167
|
i0.ɵɵelementStart(0, "div", 1);
|
|
162
|
-
i0.ɵɵconditionalCreate(1, EntityViewerComponent_Conditional_1_Conditional_1_Template, 4, 3, "div",
|
|
163
|
-
i0.ɵɵconditionalCreate(2, EntityViewerComponent_Conditional_1_Conditional_2_Template, 3, 1, "div",
|
|
164
|
-
i0.ɵɵconditionalCreate(3, EntityViewerComponent_Conditional_1_Conditional_3_Template,
|
|
168
|
+
i0.ɵɵconditionalCreate(1, EntityViewerComponent_Conditional_1_Conditional_1_Template, 4, 3, "div", 14);
|
|
169
|
+
i0.ɵɵconditionalCreate(2, EntityViewerComponent_Conditional_1_Conditional_2_Template, 3, 1, "div", 15);
|
|
170
|
+
i0.ɵɵconditionalCreate(3, EntityViewerComponent_Conditional_1_Conditional_3_Template, 8, 9, "div", 16);
|
|
165
171
|
i0.ɵɵconditionalCreate(4, EntityViewerComponent_Conditional_1_Conditional_4_Template, 10, 7);
|
|
166
172
|
i0.ɵɵelementEnd();
|
|
167
173
|
} if (rf & 2) {
|
|
@@ -175,6 +181,15 @@ function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
|
175
181
|
i0.ɵɵadvance();
|
|
176
182
|
i0.ɵɵconditional(ctx_r1.effectiveViewMode === "timeline" && ctx_r1.hasDateFields ? 4 : -1);
|
|
177
183
|
} }
|
|
184
|
+
function EntityViewerComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
185
|
+
const _r9 = i0.ɵɵgetCurrentView();
|
|
186
|
+
i0.ɵɵelementStart(0, "mj-map-view", 40);
|
|
187
|
+
i0.ɵɵlistener("MarkerClick", function EntityViewerComponent_Conditional_18_Template_mj_map_view_MarkerClick_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onMapMarkerClick($event)); })("RenderModeChange", function EntityViewerComponent_Conditional_18_Template_mj_map_view_RenderModeChange_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onMapRenderModeChange($event)); })("DisplayStateChange", function EntityViewerComponent_Conditional_18_Template_mj_map_view_DisplayStateChange_0_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onMapDisplayStateChange($event)); });
|
|
188
|
+
i0.ɵɵelementEnd();
|
|
189
|
+
} if (rf & 2) {
|
|
190
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
191
|
+
i0.ɵɵproperty("hidden", ctx_r1.effectiveViewMode !== "map")("Entity", ctx_r1.effectiveEntity)("Records", ctx_r1.filteredRecords)("TotalRecordCount", ctx_r1.totalRecordCount)("RenderMode", ctx_r1.mapRenderMode)("DisplayState", ctx_r1.mapDisplayState);
|
|
192
|
+
} }
|
|
178
193
|
/**
|
|
179
194
|
* EntityViewerComponent - Full-featured composite component for viewing entity data
|
|
180
195
|
*
|
|
@@ -211,6 +226,12 @@ function EntityViewerComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
|
211
226
|
export class EntityViewerComponent {
|
|
212
227
|
cdr;
|
|
213
228
|
ngZone;
|
|
229
|
+
/**
|
|
230
|
+
* Maximum records to load in map mode. Map view needs all records for
|
|
231
|
+
* geographic visualization — paging doesn't make sense for maps. This cap
|
|
232
|
+
* prevents unbounded queries on very large entities.
|
|
233
|
+
*/
|
|
234
|
+
static MAP_MAX_RECORDS = 10000;
|
|
214
235
|
// ========================================
|
|
215
236
|
// INPUTS (using getter/setter pattern)
|
|
216
237
|
// ========================================
|
|
@@ -236,6 +257,8 @@ export class EntityViewerComponent {
|
|
|
236
257
|
this._entity = value;
|
|
237
258
|
// Detect date fields for timeline support
|
|
238
259
|
this.detectDateFields();
|
|
260
|
+
// Detect geocoding support for map view
|
|
261
|
+
this.updateGeoCodingSupport();
|
|
239
262
|
if (this._initialized) {
|
|
240
263
|
// If entity changed to a different entity, clear all stale state from the old entity
|
|
241
264
|
if (value && previousEntity && !UUIDsEqual(value.ID, previousEntity.ID)) {
|
|
@@ -539,6 +562,8 @@ export class EntityViewerComponent {
|
|
|
539
562
|
// ========================================
|
|
540
563
|
/** Whether the current entity has date fields available for timeline view */
|
|
541
564
|
hasDateFields = false;
|
|
565
|
+
/** Whether the current entity supports geocoding (has SupportsGeoCoding = 1) */
|
|
566
|
+
HasGeoCoding = false;
|
|
542
567
|
/** Available date fields from the entity (sorted by priority) */
|
|
543
568
|
availableDateFields = [];
|
|
544
569
|
/** Timeline groups configuration for the timeline component */
|
|
@@ -940,19 +965,14 @@ export class EntityViewerComponent {
|
|
|
940
965
|
}
|
|
941
966
|
// Priority 2: GridState.sortSettings (sort may only be stored here)
|
|
942
967
|
if (view.GridState) {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
return;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
catch {
|
|
955
|
-
// Invalid GridState JSON — ignore
|
|
968
|
+
const gridState = view.GridStateObject;
|
|
969
|
+
if (gridState?.sortSettings && gridState.sortSettings.length > 0) {
|
|
970
|
+
const firstSort = gridState.sortSettings[0];
|
|
971
|
+
this.internalSortState = {
|
|
972
|
+
field: firstSort.field,
|
|
973
|
+
direction: firstSort.dir === 'desc' ? 'desc' : 'asc'
|
|
974
|
+
};
|
|
975
|
+
return;
|
|
956
976
|
}
|
|
957
977
|
}
|
|
958
978
|
// No sort defined — reset to prevent stale sort from previous view
|
|
@@ -1068,8 +1088,12 @@ export class EntityViewerComponent {
|
|
|
1068
1088
|
.map(s => `${s.field} ${(s.dir || 'asc').toUpperCase()}`)
|
|
1069
1089
|
.join(', ');
|
|
1070
1090
|
}
|
|
1071
|
-
//
|
|
1072
|
-
|
|
1091
|
+
// Map mode loads all records (up to MAP_MAX_RECORDS) since paging
|
|
1092
|
+
// doesn't make sense for geographic visualization. Other modes use
|
|
1093
|
+
// standard page-based pagination.
|
|
1094
|
+
const isMapMode = this.effectiveViewMode === 'map';
|
|
1095
|
+
const maxRows = isMapMode ? EntityViewerComponent.MAP_MAX_RECORDS : config.pageSize;
|
|
1096
|
+
const startRow = isMapMode ? 0 : this.pagination.currentPage * config.pageSize;
|
|
1073
1097
|
// Build ExtraFilter from view's WhereClause if available
|
|
1074
1098
|
// The view's WhereClause is the "business filter" - UserSearchString is additive
|
|
1075
1099
|
const extraFilter = this.viewEntity?.WhereClause || undefined;
|
|
@@ -1077,7 +1101,7 @@ export class EntityViewerComponent {
|
|
|
1077
1101
|
EntityName: entity.Name,
|
|
1078
1102
|
ResultType: 'simple',
|
|
1079
1103
|
Fields: computeFieldsList(entity, this.gridState),
|
|
1080
|
-
MaxRows:
|
|
1104
|
+
MaxRows: maxRows,
|
|
1081
1105
|
StartRow: startRow,
|
|
1082
1106
|
OrderBy: orderBy,
|
|
1083
1107
|
ExtraFilter: extraFilter,
|
|
@@ -1099,6 +1123,8 @@ export class EntityViewerComponent {
|
|
|
1099
1123
|
// Update pagination state
|
|
1100
1124
|
this.pagination.totalRecords = result.TotalRowCount;
|
|
1101
1125
|
this.pagination.hasMore = false; // No longer used with page-based paging
|
|
1126
|
+
// Re-check geo support after data loads (effectiveEntity may have resolved via viewEntity)
|
|
1127
|
+
this.updateGeoCodingSupport();
|
|
1102
1128
|
this.dataLoaded.emit({
|
|
1103
1129
|
totalRowCount: result.TotalRowCount,
|
|
1104
1130
|
loadedRowCount: this.internalRecords.length,
|
|
@@ -1171,10 +1197,21 @@ export class EntityViewerComponent {
|
|
|
1171
1197
|
* Set the view mode and emit change event
|
|
1172
1198
|
*/
|
|
1173
1199
|
setViewMode(mode) {
|
|
1174
|
-
|
|
1200
|
+
const previousMode = this.effectiveViewMode;
|
|
1201
|
+
if (previousMode !== mode) {
|
|
1175
1202
|
this.internalViewMode = mode;
|
|
1176
1203
|
this.viewModeChange.emit(mode);
|
|
1177
|
-
|
|
1204
|
+
// Reload data when switching to/from map mode because map loads all
|
|
1205
|
+
// records (up to MAP_MAX_RECORDS) while other modes use page-based pagination.
|
|
1206
|
+
const switchingToMap = mode === 'map' && previousMode !== 'map';
|
|
1207
|
+
const switchingFromMap = mode !== 'map' && previousMode === 'map';
|
|
1208
|
+
if (switchingToMap || switchingFromMap) {
|
|
1209
|
+
this.resetPaginationState();
|
|
1210
|
+
this.loadData();
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
this.cdr.detectChanges();
|
|
1214
|
+
}
|
|
1178
1215
|
}
|
|
1179
1216
|
}
|
|
1180
1217
|
// ========================================
|
|
@@ -1393,6 +1430,56 @@ export class EntityViewerComponent {
|
|
|
1393
1430
|
});
|
|
1394
1431
|
}
|
|
1395
1432
|
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Update HasGeoCoding based on the current effectiveEntity.
|
|
1435
|
+
* Called from entity setter and after data loads (when effectiveEntity may resolve via viewEntity).
|
|
1436
|
+
*/
|
|
1437
|
+
updateGeoCodingSupport() {
|
|
1438
|
+
const entity = this.effectiveEntity;
|
|
1439
|
+
const newValue = !!(entity && entity.SupportsGeoCoding);
|
|
1440
|
+
if (newValue !== this.HasGeoCoding) {
|
|
1441
|
+
this.HasGeoCoding = newValue;
|
|
1442
|
+
this.fallbackFromMapIfNeeded();
|
|
1443
|
+
this.cdr.detectChanges();
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Handle map marker click — emit the record for the parent to handle (open record, etc.)
|
|
1448
|
+
*/
|
|
1449
|
+
onMapMarkerClick(event) {
|
|
1450
|
+
const entity = this.effectiveEntity;
|
|
1451
|
+
if (event.Record && entity) {
|
|
1452
|
+
const compositeKey = buildCompositeKey(event.Record, entity);
|
|
1453
|
+
// Emit both recordSelected (for detail panels) and recordOpened (for navigation)
|
|
1454
|
+
this.recordSelected.emit({
|
|
1455
|
+
record: event.Record,
|
|
1456
|
+
entity: entity,
|
|
1457
|
+
compositeKey
|
|
1458
|
+
});
|
|
1459
|
+
this.recordOpened.emit({
|
|
1460
|
+
record: event.Record,
|
|
1461
|
+
entity: entity,
|
|
1462
|
+
compositeKey
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
/** Map display state (zoom, center) — passed from parent for persistence across reloads. */
|
|
1467
|
+
mapDisplayState = null;
|
|
1468
|
+
/** Map render mode — separate from DisplayState for clear single-source-of-truth. */
|
|
1469
|
+
mapRenderMode = 'point';
|
|
1470
|
+
/** Emitted when the map's display state changes (zoom, center). */
|
|
1471
|
+
mapDisplayStateChange = new EventEmitter();
|
|
1472
|
+
/** Emitted when the map's render mode changes (user clicks mode buttons). */
|
|
1473
|
+
mapRenderModeChange = new EventEmitter();
|
|
1474
|
+
/**
|
|
1475
|
+
* Handle map display state changes — bubble up to parent for persistence.
|
|
1476
|
+
*/
|
|
1477
|
+
onMapDisplayStateChange(state) {
|
|
1478
|
+
this.mapDisplayStateChange.emit(state);
|
|
1479
|
+
}
|
|
1480
|
+
onMapRenderModeChange(mode) {
|
|
1481
|
+
this.mapRenderModeChange.emit(mode);
|
|
1482
|
+
}
|
|
1396
1483
|
/**
|
|
1397
1484
|
* Toggle timeline orientation between vertical and horizontal
|
|
1398
1485
|
*/
|
|
@@ -1480,6 +1567,15 @@ export class EntityViewerComponent {
|
|
|
1480
1567
|
this.setViewMode('grid');
|
|
1481
1568
|
}
|
|
1482
1569
|
}
|
|
1570
|
+
/**
|
|
1571
|
+
* If currently on map view but geocoding is no longer available,
|
|
1572
|
+
* fall back to grid view
|
|
1573
|
+
*/
|
|
1574
|
+
fallbackFromMapIfNeeded() {
|
|
1575
|
+
if (this.effectiveViewMode === 'map' && !this.HasGeoCoding) {
|
|
1576
|
+
this.setViewMode('grid');
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1483
1579
|
/**
|
|
1484
1580
|
* Sort date fields by priority:
|
|
1485
1581
|
* 1. DefaultInView=true fields, sorted by Sequence (lowest first)
|
|
@@ -1627,7 +1723,7 @@ export class EntityViewerComponent {
|
|
|
1627
1723
|
} if (rf & 2) {
|
|
1628
1724
|
let _t;
|
|
1629
1725
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.dataGridRef = _t.first);
|
|
1630
|
-
} }, 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" }, standalone: false, decls:
|
|
1726
|
+
} }, 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", mapDisplayState: "mapDisplayState", mapRenderMode: "mapRenderMode" }, 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", mapDisplayStateChange: "mapDisplayStateChange", mapRenderModeChange: "mapRenderModeChange" }, standalone: false, decls: 19, vars: 42, 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", "ForeignKeyClick", "PageChange", "hidden", "Data", "Params", "FilterText", "GridState", "Height", "ShowToolbar", "ToolbarConfig", "SelectionMode", "ShowAddToListButton", "AllowLoad", "ShowPager", "PageSize", "TotalRowCount", "PagerPageNumber"], [3, "recordSelected", "recordOpened", "hidden", "entity", "records", "selectedRecordId", "cardTemplate", "hiddenFieldMatches", "filterText"], [3, "afterEventClick", "hidden", "groups", "orientation", "layout", "sortOrder", "segmentGrouping", "segmentsCollapsible", "segmentsDefaultExpanded", "selectedEventId"], [3, "hidden", "Entity", "Records", "TotalRecordCount", "RenderMode", "DisplayState"], [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", "Map View", 1, "toggle-btn", 3, "click"], [1, "fa-solid", "fa-map-location-dot"], ["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, "MarkerClick", "RenderModeChange", "DisplayStateChange", "hidden", "Entity", "Records", "TotalRecordCount", "RenderMode", "DisplayState"]], template: function EntityViewerComponent_Template(rf, ctx) { if (rf & 1) {
|
|
1631
1727
|
i0.ɵɵelementStart(0, "div", 0);
|
|
1632
1728
|
i0.ɵɵconditionalCreate(1, EntityViewerComponent_Conditional_1_Template, 5, 4, "div", 1);
|
|
1633
1729
|
i0.ɵɵelementStart(2, "div", 2)(3, "div", 3);
|
|
@@ -1654,7 +1750,9 @@ export class EntityViewerComponent {
|
|
|
1654
1750
|
i0.ɵɵelementEnd();
|
|
1655
1751
|
i0.ɵɵelementStart(17, "mj-timeline", 12);
|
|
1656
1752
|
i0.ɵɵlistener("afterEventClick", function EntityViewerComponent_Template_mj_timeline_afterEventClick_17_listener($event) { return ctx.onTimelineEventClick($event); });
|
|
1657
|
-
i0.ɵɵelementEnd()
|
|
1753
|
+
i0.ɵɵelementEnd();
|
|
1754
|
+
i0.ɵɵconditionalCreate(18, EntityViewerComponent_Conditional_18_Template, 1, 6, "mj-map-view", 13);
|
|
1755
|
+
i0.ɵɵelementEnd()();
|
|
1658
1756
|
} if (rf & 2) {
|
|
1659
1757
|
i0.ɵɵstyleProp("height", ctx.effectiveConfig.height);
|
|
1660
1758
|
i0.ɵɵadvance();
|
|
@@ -1679,13 +1777,15 @@ export class EntityViewerComponent {
|
|
|
1679
1777
|
i0.ɵɵproperty("hidden", ctx.effectiveViewMode !== "cards" || !ctx.effectiveEntity)("entity", ctx.effectiveEntity)("records", ctx.filteredRecords)("selectedRecordId", ctx.selectedRecordId)("cardTemplate", ctx.cardTemplate)("hiddenFieldMatches", ctx.hiddenFieldMatches)("filterText", ctx.debouncedFilterText);
|
|
1680
1778
|
i0.ɵɵadvance();
|
|
1681
1779
|
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);
|
|
1682
|
-
|
|
1780
|
+
i0.ɵɵadvance();
|
|
1781
|
+
i0.ɵɵconditional(ctx.HasGeoCoding ? 18 : -1);
|
|
1782
|
+
} }, dependencies: [i1.NgSelectOption, i1.ɵNgSelectMultipleOption, i2.LoadingComponent, i3.TimelineComponent, i4.MapViewComponent, i5.EntityCardsComponent, 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: var(--mj-bg-surface-card);\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: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\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: var(--mj-text-disabled);\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 var(--mj-border-default);\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: var(--mj-brand-primary);\n}\n\n.filter-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-disabled);\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: var(--mj-text-disabled);\n transition: all 0.15s ease;\n}\n\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-card);\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: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\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: var(--mj-text-secondary);\n}\n\n.timeline-date-selector[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n\n.date-field-label[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.date-field-select[_ngcontent-%COMP%] {\n padding: 4px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\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: var(--mj-border-strong);\n}\n\n.date-field-select[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n}\n\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-card);\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: var(--mj-bg-surface);\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: color-mix(in srgb, var(--mj-bg-surface) 80%, transparent);\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n\n.loading-container[hidden][_ngcontent-%COMP%], \n.loading-overlay[hidden][_ngcontent-%COMP%] {\n display: none !important;\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: var(--mj-text-disabled);\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%], \nmj-map-view[hidden][_ngcontent-%COMP%] {\n display: none !important;\n}\n\n\n\nmj-entity-cards[_ngcontent-%COMP%]:not([hidden]), \nmj-timeline[_ngcontent-%COMP%]:not([hidden]), \nmj-map-view[_ngcontent-%COMP%]:not([hidden]) {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n\n\n.toggle-btn.geo-hidden[_ngcontent-%COMP%] {\n display: none !important;\n}"] });
|
|
1683
1783
|
}
|
|
1684
1784
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityViewerComponent, [{
|
|
1685
1785
|
type: Component,
|
|
1686
1786
|
args: [{ standalone: false, selector: 'mj-entity-viewer', host: {
|
|
1687
1787
|
'style': 'display: block; height: 100%;'
|
|
1688
|
-
}, 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 && effectiveEntity) {\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]=\"!!effectiveEntity\">\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]=\"!effectiveEntity || 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' || !effectiveEntity\"\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 [ShowPager]=\"effectiveConfig.showPagination\"\n [PageSize]=\"effectiveConfig.pageSize\"\n [TotalRowCount]=\"pagination.totalRecords\"\n [PagerPageNumber]=\"pagination.currentPage + 1\"\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 (ForeignKeyClick)=\"onForeignKeyClick($event)\"\n (PageChange)=\"onGridPageChange($event)\">\n </mj-entity-data-grid>\n\n <!-- Cards View - always rendered, visibility controlled by hidden -->\n <mj-entity-cards\n [hidden]=\"effectiveViewMode !== 'cards' || !effectiveEntity\"\n [entity]=\"effectiveEntity\"\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</div>\n", styles: [".entity-viewer-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--mj-bg-surface-card);\n}\n\n/* Header */\n.viewer-header {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 12px 16px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\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: var(--mj-text-disabled);\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 var(--mj-border-default);\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: var(--mj-brand-primary);\n}\n\n.filter-input::placeholder {\n color: var(--mj-text-disabled);\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: var(--mj-text-disabled);\n transition: all 0.15s ease;\n}\n\n.clear-filter-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n/* Record Count */\n.record-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n/* View Mode Toggle */\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-card);\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: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.toggle-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\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: var(--mj-text-secondary);\n}\n\n.timeline-date-selector i {\n color: var(--mj-text-disabled);\n}\n\n.date-field-label {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.date-field-select {\n padding: 4px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.date-field-select:hover {\n border-color: var(--mj-border-strong);\n}\n\n.date-field-select:focus {\n border-color: var(--mj-brand-primary);\n}\n\n/* Timeline Orientation Toggle */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-card);\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: var(--mj-bg-surface);\n}\n\n/* Loading State - full-page centered loading for initial load when no data exists */\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n/* Loading overlay - semi-transparent overlay on top of existing content during refresh */\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-bg-surface) 80%, transparent);\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Ensure [hidden] attribute works properly on loading elements */\n.loading-container[hidden],\n.loading-overlay[hidden] {\n display: none !important;\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: var(--mj-text-disabled);\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"] }]
|
|
1788
|
+
}, 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 && effectiveEntity) {\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 <button\n class=\"toggle-btn\"\n [class.active]=\"effectiveViewMode === 'map'\"\n [class.geo-hidden]=\"!HasGeoCoding\"\n (click)=\"setViewMode('map')\"\n title=\"Map View\">\n <i class=\"fa-solid fa-map-location-dot\"></i>\n </button>\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]=\"!!effectiveEntity\">\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]=\"!effectiveEntity || 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' || !effectiveEntity\"\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 [ShowPager]=\"effectiveConfig.showPagination\"\n [PageSize]=\"effectiveConfig.pageSize\"\n [TotalRowCount]=\"pagination.totalRecords\"\n [PagerPageNumber]=\"pagination.currentPage + 1\"\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 (ForeignKeyClick)=\"onForeignKeyClick($event)\"\n (PageChange)=\"onGridPageChange($event)\">\n </mj-entity-data-grid>\n\n <!-- Cards View - always rendered, visibility controlled by hidden -->\n <mj-entity-cards\n [hidden]=\"effectiveViewMode !== 'cards' || !effectiveEntity\"\n [entity]=\"effectiveEntity\"\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\n <!-- Map View - rendered when geocoding supported, visibility controlled by hidden -->\n @if (HasGeoCoding) {\n <mj-map-view\n [hidden]=\"effectiveViewMode !== 'map'\"\n [Entity]=\"effectiveEntity!\"\n [Records]=\"filteredRecords\"\n [TotalRecordCount]=\"totalRecordCount\"\n [RenderMode]=\"mapRenderMode\"\n [DisplayState]=\"mapDisplayState\"\n (MarkerClick)=\"onMapMarkerClick($event)\"\n (RenderModeChange)=\"onMapRenderModeChange($event)\"\n (DisplayStateChange)=\"onMapDisplayStateChange($event)\">\n </mj-map-view>\n }\n </div>\n\n</div>\n", styles: [".entity-viewer-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--mj-bg-surface-card);\n}\n\n/* Header */\n.viewer-header {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 12px 16px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\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: var(--mj-text-disabled);\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 var(--mj-border-default);\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: var(--mj-brand-primary);\n}\n\n.filter-input::placeholder {\n color: var(--mj-text-disabled);\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: var(--mj-text-disabled);\n transition: all 0.15s ease;\n}\n\n.clear-filter-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n/* Record Count */\n.record-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n/* View Mode Toggle */\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-card);\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: var(--mj-text-muted);\n transition: all 0.15s ease;\n}\n\n.toggle-btn:hover {\n color: var(--mj-text-secondary);\n}\n\n.toggle-btn.active {\n background: var(--mj-bg-surface);\n color: var(--mj-brand-primary);\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: var(--mj-text-secondary);\n}\n\n.timeline-date-selector i {\n color: var(--mj-text-disabled);\n}\n\n.date-field-label {\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.date-field-select {\n padding: 4px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n font-size: 13px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n cursor: pointer;\n outline: none;\n transition: border-color 0.15s ease;\n}\n\n.date-field-select:hover {\n border-color: var(--mj-border-strong);\n}\n\n.date-field-select:focus {\n border-color: var(--mj-brand-primary);\n}\n\n/* Timeline Orientation Toggle */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-card);\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: var(--mj-bg-surface);\n}\n\n/* Loading State - full-page centered loading for initial load when no data exists */\n.loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n}\n\n/* Loading overlay - semi-transparent overlay on top of existing content during refresh */\n.loading-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-bg-surface) 80%, transparent);\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n/* Ensure [hidden] attribute works properly on loading elements */\n.loading-container[hidden],\n.loading-overlay[hidden] {\n display: none !important;\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: var(--mj-text-disabled);\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],\nmj-map-view[hidden] {\n display: none !important;\n}\n\n/* Visible view components should fill available space */\nmj-entity-cards:not([hidden]),\nmj-timeline:not([hidden]),\nmj-map-view:not([hidden]) {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n/* Hide map toggle when entity does not support geocoding */\n.toggle-btn.geo-hidden {\n display: none !important;\n}\n"] }]
|
|
1689
1789
|
}], () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }], { entity: [{
|
|
1690
1790
|
type: Input
|
|
1691
1791
|
}], records: [{
|
|
@@ -1751,6 +1851,14 @@ export class EntityViewerComponent {
|
|
|
1751
1851
|
}], dataGridRef: [{
|
|
1752
1852
|
type: ViewChild,
|
|
1753
1853
|
args: [EntityDataGridComponent]
|
|
1854
|
+
}], mapDisplayState: [{
|
|
1855
|
+
type: Input
|
|
1856
|
+
}], mapRenderMode: [{
|
|
1857
|
+
type: Input
|
|
1858
|
+
}], mapDisplayStateChange: [{
|
|
1859
|
+
type: Output
|
|
1860
|
+
}], mapRenderModeChange: [{
|
|
1861
|
+
type: Output
|
|
1754
1862
|
}] }); })();
|
|
1755
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent", filePath: "src/lib/entity-viewer/entity-viewer.component.ts", lineNumber:
|
|
1863
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityViewerComponent, { className: "EntityViewerComponent", filePath: "src/lib/entity-viewer/entity-viewer.component.ts", lineNumber: 80 }); })();
|
|
1756
1864
|
//# sourceMappingURL=entity-viewer.component.js.map
|