@memberjunction/ng-dashboards 5.39.0 → 5.40.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/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +128 -4
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +548 -145
- package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts +56 -0
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js +423 -0
- package/dist/AI/components/autotagging/components/classify-item-drilldown.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts +70 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.js +308 -0
- package/dist/AI/components/autotagging/components/classify-item-grid.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts +29 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js +186 -0
- package/dist/AI/components/autotagging/components/classify-org-context-editor.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts +69 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js +278 -0
- package/dist/AI/components/autotagging/components/classify-overview-analytics.component.js.map +1 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts +73 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js +393 -0
- package/dist/AI/components/autotagging/components/classify-seed-taxonomy.component.js.map +1 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts +122 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.d.ts.map +1 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js +908 -0
- package/dist/AI/components/autotagging/dialogs/classify-setup-wizard.component.js.map +1 -0
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts +100 -2
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js +603 -213
- package/dist/AI/components/autotagging/dialogs/source-type-form.dialog.component.js.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.format.d.ts +15 -0
- package/dist/AI/components/autotagging/shared/classify.format.d.ts.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.format.js +51 -0
- package/dist/AI/components/autotagging/shared/classify.format.js.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.types.d.ts +43 -0
- package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -1
- package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts +38 -1
- package/dist/AI/components/autotagging/tabs/history-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/history-tab.component.js +185 -68
- package/dist/AI/components/autotagging/tabs/history-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts +10 -1
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js +249 -188
- package/dist/AI/components/autotagging/tabs/pipeline-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +12 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js +377 -296
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts +8 -0
- package/dist/AI/components/autotagging/tabs/tags-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/tags-tab.component.js +112 -68
- package/dist/AI/components/autotagging/tabs/tags-tab.component.js.map +1 -1
- package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts +9 -0
- package/dist/AI/components/autotagging/tabs/types-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/types-tab.component.js +87 -36
- package/dist/AI/components/autotagging/tabs/types-tab.component.js.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts +3 -0
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.d.ts.map +1 -1
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js +15 -3
- package/dist/AI/components/duplicates/duplicate-detection-resource.component.js.map +1 -1
- package/dist/AI/components/execution-monitoring.component.js +1 -1
- package/dist/AI/components/execution-monitoring.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +1 -0
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +28 -6
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +3 -0
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +330 -302
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/APIKeys/api-applications-panel.component.js +2 -2
- package/dist/APIKeys/api-key-create-dialog.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +31 -340
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +468 -1958
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-resource.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-resource.component.js +10 -0
- package/dist/DataExplorer/data-explorer-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js +12 -9
- package/dist/KnowledgeHub/components/analytics/analytics-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts +27 -2
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js +244 -120
- package/dist/KnowledgeHub/components/clusters/cluster-visualization-resource.component.js.map +1 -1
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts +65 -0
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js +176 -0
- package/dist/KnowledgeHub/components/visualize/record-drilldown/record-drilldown.component.js.map +1 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts +81 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js +308 -0
- package/dist/KnowledgeHub/components/visualize/tag-cloud/tag-cloud.component.js.map +1 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts +85 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.d.ts.map +1 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js +362 -0
- package/dist/KnowledgeHub/components/visualize/visualize-resource.component.js.map +1 -0
- package/dist/KnowledgeHub/index.d.ts +3 -0
- package/dist/KnowledgeHub/index.d.ts.map +1 -1
- package/dist/KnowledgeHub/index.js +3 -0
- package/dist/KnowledgeHub/index.js.map +1 -1
- package/dist/MCP/components/mcp-server-dialog.component.js +2 -2
- package/dist/QueryBrowser/query-browser-resource.component.js +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/ai-dashboards.module.d.ts +48 -38
- package/dist/ai-dashboards.module.d.ts.map +1 -1
- package/dist/ai-dashboards.module.js +41 -1
- package/dist/ai-dashboards.module.js.map +1 -1
- package/dist/data-explorer-dashboards.module.d.ts +12 -14
- package/dist/data-explorer-dashboards.module.d.ts.map +1 -1
- package/dist/data-explorer-dashboards.module.js +5 -14
- package/dist/data-explorer-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +57 -55
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts +0 -79
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.d.ts.map +0 -1
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js +0 -195
- package/dist/DataExplorer/components/filter-dialog/filter-dialog.component.js.map +0 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts +0 -226
- package/dist/DataExplorer/components/view-selector/view-selector.component.d.ts.map +0 -1
- package/dist/DataExplorer/components/view-selector/view-selector.component.js +0 -861
- package/dist/DataExplorer/components/view-selector/view-selector.component.js.map +0 -1
|
@@ -13,32 +13,25 @@ import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
|
|
|
13
13
|
import { RunView, EntityFieldTSType } from '@memberjunction/core';
|
|
14
14
|
// CompositeKey is used via buildCompositeKey from ng-entity-viewer
|
|
15
15
|
import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
16
|
-
import {
|
|
17
|
-
import { ViewSelectorComponent } from './components/view-selector/view-selector.component';
|
|
18
|
-
import { createEmptyFilter } from '@memberjunction/ng-filter-builder';
|
|
16
|
+
import { ViewWorkspaceComponent, buildCompositeKey, buildPkString } from '@memberjunction/ng-entity-viewer';
|
|
19
17
|
import { UserViewEngine } from '@memberjunction/core-entities';
|
|
20
18
|
import { MJEventType, MJGlobal } from '@memberjunction/global';
|
|
21
19
|
import * as i0 from "@angular/core";
|
|
22
20
|
import * as i1 from "./services/explorer-state.service";
|
|
23
21
|
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
24
|
-
import * as i3 from "@
|
|
25
|
-
import * as i4 from "@
|
|
26
|
-
import * as i5 from "
|
|
27
|
-
import * as i6 from "@
|
|
28
|
-
import * as i7 from "./components/navigation-panel/navigation-panel.component";
|
|
29
|
-
import * as i8 from "./components/view-selector/view-selector.component";
|
|
30
|
-
import * as i9 from "./components/filter-dialog/filter-dialog.component";
|
|
31
|
-
import * as i10 from "@angular/common";
|
|
22
|
+
import * as i3 from "@angular/forms";
|
|
23
|
+
import * as i4 from "@memberjunction/ng-entity-viewer";
|
|
24
|
+
import * as i5 from "./components/navigation-panel/navigation-panel.component";
|
|
25
|
+
import * as i6 from "@angular/common";
|
|
32
26
|
const _c0 = ["filterInput"];
|
|
33
27
|
const _forTrack0 = ($index, $item) => $item.label;
|
|
34
|
-
const _forTrack1 = ($index, $item) => $item.
|
|
35
|
-
const _forTrack2 = ($index, $item) => $item.
|
|
36
|
-
const _forTrack3 = ($index, $item) => $item.
|
|
37
|
-
const _forTrack4 = ($index, $item) => $item.
|
|
38
|
-
const _forTrack5 = ($index, $item) => $item.applicationId;
|
|
28
|
+
const _forTrack1 = ($index, $item) => $item.entityId + "|" + $item.recordId;
|
|
29
|
+
const _forTrack2 = ($index, $item) => $item.ID;
|
|
30
|
+
const _forTrack3 = ($index, $item) => $item.userFavoriteId;
|
|
31
|
+
const _forTrack4 = ($index, $item) => $item.applicationId;
|
|
39
32
|
function DataExplorerDashboardComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
40
33
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
41
|
-
i0.ɵɵelementStart(0, "div",
|
|
34
|
+
i0.ɵɵelementStart(0, "div", 15)(1, "mj-explorer-navigation-panel", 16);
|
|
42
35
|
i0.ɵɵlistener("entitySelected", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_entitySelected_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onEntitySelected($event)); })("toggleCollapse", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_toggleCollapse_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleNavigationPanel()); })("sectionToggled", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_sectionToggled_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.stateService.toggleSection($event)); })("openRecord", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_openRecord_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRecordFromNav($event)); })("selectRecord", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_selectRecord_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSelectRecordFromNav($event)); })("expandAndFocus", function DataExplorerDashboardComponent_Conditional_1_Template_mj_explorer_navigation_panel_expandAndFocus_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onExpandAndFocus($event)); });
|
|
43
36
|
i0.ɵɵelementEnd()();
|
|
44
37
|
} if (rf & 2) {
|
|
@@ -50,23 +43,23 @@ function DataExplorerDashboardComponent_Conditional_1_Template(rf, ctx) { if (rf
|
|
|
50
43
|
i0.ɵɵproperty("entities", ctx_r1.entities)("appEntityGroups", ctx_r1.appEntityGroups)("selectedEntityName", ctx_r1.state.selectedEntityName)("favorites", ctx_r1.state.favorites)("recentItems", ctx_r1.state.recentItems)("collapsed", ctx_r1.state.navigationPanelCollapsed)("allowedEntityNames", ctx_r1.allowedEntityNames)("favoritesSectionExpanded", ctx_r1.state.favoritesSectionExpanded)("recentSectionExpanded", ctx_r1.state.recentSectionExpanded)("entitiesSectionExpanded", ctx_r1.state.entitiesSectionExpanded)("viewsSectionExpanded", ctx_r1.state.viewsSectionExpanded);
|
|
51
44
|
} }
|
|
52
45
|
function DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
53
|
-
i0.ɵɵelement(0, "i",
|
|
46
|
+
i0.ɵɵelement(0, "i", 21);
|
|
54
47
|
} if (rf & 2) {
|
|
55
48
|
const crumb_r5 = i0.ɵɵnextContext().$implicit;
|
|
56
49
|
i0.ɵɵclassMap(crumb_r5.icon);
|
|
57
50
|
} }
|
|
58
51
|
function DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
59
|
-
i0.ɵɵelement(0, "i",
|
|
52
|
+
i0.ɵɵelement(0, "i", 20);
|
|
60
53
|
} }
|
|
61
54
|
function DataExplorerDashboardComponent_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
62
55
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
63
|
-
i0.ɵɵelementStart(0, "span",
|
|
56
|
+
i0.ɵɵelementStart(0, "span", 17);
|
|
64
57
|
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_3_For_2_Template_span_click_0_listener() { const ctx_r3 = i0.ɵɵrestoreView(_r3); const crumb_r5 = ctx_r3.$implicit; const ɵ$index_13_r6 = ctx_r3.$index; const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onBreadcrumbClick(crumb_r5, ɵ$index_13_r6)); });
|
|
65
|
-
i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_1_Template, 1, 2, "i",
|
|
66
|
-
i0.ɵɵelementStart(2, "span",
|
|
58
|
+
i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_1_Template, 1, 2, "i", 18);
|
|
59
|
+
i0.ɵɵelementStart(2, "span", 19);
|
|
67
60
|
i0.ɵɵtext(3);
|
|
68
61
|
i0.ɵɵelementEnd()();
|
|
69
|
-
i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_4_Template, 1, 0, "i",
|
|
62
|
+
i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_3_For_2_Conditional_4_Template, 1, 0, "i", 20);
|
|
70
63
|
} if (rf & 2) {
|
|
71
64
|
const crumb_r5 = ctx.$implicit;
|
|
72
65
|
const ɵ$index_13_r6 = ctx.$index;
|
|
@@ -81,7 +74,7 @@ function DataExplorerDashboardComponent_Conditional_3_For_2_Template(rf, ctx) {
|
|
|
81
74
|
i0.ɵɵconditional(!(ɵ$index_13_r6 === ɵ$count_13_r7 - 1) ? 4 : -1);
|
|
82
75
|
} }
|
|
83
76
|
function DataExplorerDashboardComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
84
|
-
i0.ɵɵelementStart(0, "div",
|
|
77
|
+
i0.ɵɵelementStart(0, "div", 4);
|
|
85
78
|
i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_3_For_2_Template, 5, 8, null, null, _forTrack0);
|
|
86
79
|
i0.ɵɵelementEnd();
|
|
87
80
|
} if (rf & 2) {
|
|
@@ -90,7 +83,7 @@ function DataExplorerDashboardComponent_Conditional_3_Template(rf, ctx) { if (rf
|
|
|
90
83
|
i0.ɵɵrepeater(ctx_r1.breadcrumbs);
|
|
91
84
|
} }
|
|
92
85
|
function DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
93
|
-
i0.ɵɵelementStart(0, "span",
|
|
86
|
+
i0.ɵɵelementStart(0, "span", 24);
|
|
94
87
|
i0.ɵɵtext(1);
|
|
95
88
|
i0.ɵɵpipe(2, "number");
|
|
96
89
|
i0.ɵɵpipe(3, "number");
|
|
@@ -101,7 +94,7 @@ function DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template(rf,
|
|
|
101
94
|
i0.ɵɵtextInterpolate2("", i0.ɵɵpipeBind1(2, 2, ctx_r1.filteredRecordCount), " of ", i0.ɵɵpipeBind1(3, 4, ctx_r1.totalRecordCount), " records");
|
|
102
95
|
} }
|
|
103
96
|
function DataExplorerDashboardComponent_Conditional_6_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
104
|
-
i0.ɵɵelementStart(0, "span",
|
|
97
|
+
i0.ɵɵelementStart(0, "span", 24);
|
|
105
98
|
i0.ɵɵtext(1);
|
|
106
99
|
i0.ɵɵpipe(2, "number");
|
|
107
100
|
i0.ɵɵelementEnd();
|
|
@@ -110,30 +103,12 @@ function DataExplorerDashboardComponent_Conditional_6_Conditional_4_Template(rf,
|
|
|
110
103
|
i0.ɵɵadvance();
|
|
111
104
|
i0.ɵɵtextInterpolate1("", i0.ɵɵpipeBind1(2, 1, ctx_r1.totalRecordCount), " records");
|
|
112
105
|
} }
|
|
113
|
-
function DataExplorerDashboardComponent_Conditional_6_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
114
|
-
i0.ɵɵelementStart(0, "span", 36);
|
|
115
|
-
i0.ɵɵtext(1);
|
|
116
|
-
i0.ɵɵelementEnd();
|
|
117
|
-
} if (rf & 2) {
|
|
118
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
119
|
-
i0.ɵɵadvance();
|
|
120
|
-
i0.ɵɵtextInterpolate(ctx_r1.selectedRecords.length);
|
|
121
|
-
} }
|
|
122
106
|
function DataExplorerDashboardComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
123
|
-
|
|
124
|
-
i0.ɵɵ
|
|
125
|
-
i0.ɵɵelementStart(1, "h2", 31);
|
|
107
|
+
i0.ɵɵelement(0, "i", 22);
|
|
108
|
+
i0.ɵɵelementStart(1, "h2", 23);
|
|
126
109
|
i0.ɵɵtext(2);
|
|
127
110
|
i0.ɵɵelementEnd();
|
|
128
|
-
i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template, 4, 6, "span",
|
|
129
|
-
i0.ɵɵelementStart(5, "mj-view-selector", 33);
|
|
130
|
-
i0.ɵɵlistener("viewSelected", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_viewSelected_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewSelected($event)); })("saveViewRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_saveViewRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onSaveViewRequested($event)); })("manageViewsRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_manageViewsRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onManageViewsRequested()); })("openInTabRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_openInTabRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenInTabRequested($event)); })("configureViewRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_configureViewRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onConfigureViewRequested()); })("createNewRecordRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_createNewRecordRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCreateNewRecord()); })("exportRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_exportRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onExport()); })("duplicateViewRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_duplicateViewRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDuplicateView($event)); })("quickSaveRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_quickSaveRequested_5_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onQuickSaveRequested($event)); })("revertRequested", function DataExplorerDashboardComponent_Conditional_6_Template_mj_view_selector_revertRequested_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onRevertView()); });
|
|
131
|
-
i0.ɵɵelementEnd();
|
|
132
|
-
i0.ɵɵelementStart(6, "button", 34);
|
|
133
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_6_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onAddToListClick()); });
|
|
134
|
-
i0.ɵɵelement(7, "i", 35);
|
|
135
|
-
i0.ɵɵconditionalCreate(8, DataExplorerDashboardComponent_Conditional_6_Conditional_8_Template, 2, 1, "span", 36);
|
|
136
|
-
i0.ɵɵelementEnd();
|
|
111
|
+
i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_6_Conditional_3_Template, 4, 6, "span", 24)(4, DataExplorerDashboardComponent_Conditional_6_Conditional_4_Template, 3, 3, "span", 24);
|
|
137
112
|
} if (rf & 2) {
|
|
138
113
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
139
114
|
i0.ɵɵclassMap(ctx_r1.getEntityIcon(ctx_r1.selectedEntity));
|
|
@@ -141,26 +116,19 @@ function DataExplorerDashboardComponent_Conditional_6_Template(rf, ctx) { if (rf
|
|
|
141
116
|
i0.ɵɵtextInterpolate(ctx_r1.selectedEntity.DisplayNameOrName);
|
|
142
117
|
i0.ɵɵadvance();
|
|
143
118
|
i0.ɵɵconditional(ctx_r1.debouncedFilterText && ctx_r1.filteredRecordCount !== ctx_r1.totalRecordCount ? 3 : 4);
|
|
144
|
-
i0.ɵɵadvance(2);
|
|
145
|
-
i0.ɵɵproperty("entity", ctx_r1.selectedEntity)("selectedViewId", ctx_r1.state.selectedViewId)("viewModified", ctx_r1.state.viewModified);
|
|
146
|
-
i0.ɵɵadvance();
|
|
147
|
-
i0.ɵɵclassProp("disabled", !ctx_r1.hasSelectedRecords);
|
|
148
|
-
i0.ɵɵproperty("disabled", !ctx_r1.hasSelectedRecords)("title", ctx_r1.hasSelectedRecords ? "Add " + ctx_r1.selectedRecords.length + " selected record(s) to a list" : "Select records to add to a list");
|
|
149
|
-
i0.ɵɵadvance(2);
|
|
150
|
-
i0.ɵɵconditional(ctx_r1.hasSelectedRecords ? 8 : -1);
|
|
151
119
|
} }
|
|
152
120
|
function DataExplorerDashboardComponent_Conditional_7_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
153
|
-
i0.ɵɵelement(0, "i",
|
|
121
|
+
i0.ɵɵelement(0, "i", 22);
|
|
154
122
|
} if (rf & 2) {
|
|
155
123
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
156
124
|
i0.ɵɵclassMap(ctx_r1.displayIcon);
|
|
157
125
|
} }
|
|
158
126
|
function DataExplorerDashboardComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
159
|
-
i0.ɵɵconditionalCreate(0, DataExplorerDashboardComponent_Conditional_7_Conditional_0_Template, 1, 2, "i",
|
|
160
|
-
i0.ɵɵelementStart(1, "h2",
|
|
127
|
+
i0.ɵɵconditionalCreate(0, DataExplorerDashboardComponent_Conditional_7_Conditional_0_Template, 1, 2, "i", 25);
|
|
128
|
+
i0.ɵɵelementStart(1, "h2", 23);
|
|
161
129
|
i0.ɵɵtext(2);
|
|
162
130
|
i0.ɵɵelementEnd();
|
|
163
|
-
i0.ɵɵelementStart(3, "span",
|
|
131
|
+
i0.ɵɵelementStart(3, "span", 24);
|
|
164
132
|
i0.ɵɵtext(4);
|
|
165
133
|
i0.ɵɵelementEnd();
|
|
166
134
|
} if (rf & 2) {
|
|
@@ -172,20 +140,20 @@ function DataExplorerDashboardComponent_Conditional_7_Template(rf, ctx) { if (rf
|
|
|
172
140
|
i0.ɵɵtextInterpolate1("", ctx_r1.entities.length, " entities available");
|
|
173
141
|
} }
|
|
174
142
|
function DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
175
|
-
const
|
|
176
|
-
i0.ɵɵelementStart(0, "button",
|
|
177
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(
|
|
178
|
-
i0.ɵɵelement(1, "i",
|
|
143
|
+
const _r10 = i0.ɵɵgetCurrentView();
|
|
144
|
+
i0.ɵɵelementStart(0, "button", 29);
|
|
145
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.clearRecordFilter()); });
|
|
146
|
+
i0.ɵɵelement(1, "i", 30);
|
|
179
147
|
i0.ɵɵelementEnd();
|
|
180
148
|
} }
|
|
181
149
|
function DataExplorerDashboardComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
182
|
-
const
|
|
183
|
-
i0.ɵɵelementStart(0, "div",
|
|
184
|
-
i0.ɵɵelement(1, "i",
|
|
185
|
-
i0.ɵɵelementStart(2, "input",
|
|
186
|
-
i0.ɵɵlistener("input", function DataExplorerDashboardComponent_Conditional_9_Template_input_input_2_listener() { i0.ɵɵrestoreView(
|
|
150
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
151
|
+
i0.ɵɵelementStart(0, "div", 8);
|
|
152
|
+
i0.ɵɵelement(1, "i", 26);
|
|
153
|
+
i0.ɵɵelementStart(2, "input", 27, 0);
|
|
154
|
+
i0.ɵɵlistener("input", function DataExplorerDashboardComponent_Conditional_9_Template_input_input_2_listener() { i0.ɵɵrestoreView(_r8); const filterInput_r9 = i0.ɵɵreference(3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterInputChanged(filterInput_r9.value)); });
|
|
187
155
|
i0.ɵɵelementEnd();
|
|
188
|
-
i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template, 2, 0, "button",
|
|
156
|
+
i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_9_Conditional_4_Template, 2, 0, "button", 28);
|
|
189
157
|
i0.ɵɵelementEnd();
|
|
190
158
|
} if (rf & 2) {
|
|
191
159
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -194,141 +162,9 @@ function DataExplorerDashboardComponent_Conditional_9_Template(rf, ctx) { if (rf
|
|
|
194
162
|
i0.ɵɵadvance(2);
|
|
195
163
|
i0.ɵɵconditional(ctx_r1.liveFilterText ? 4 : -1);
|
|
196
164
|
} }
|
|
197
|
-
function
|
|
198
|
-
const _r14 = i0.ɵɵgetCurrentView();
|
|
199
|
-
i0.ɵɵelementStart(0, "div", 60);
|
|
200
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_2_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.closeDateFieldDropdown()); });
|
|
201
|
-
i0.ɵɵelementEnd();
|
|
202
|
-
} }
|
|
203
|
-
function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
204
|
-
i0.ɵɵelement(0, "i", 61);
|
|
205
|
-
} if (rf & 2) {
|
|
206
|
-
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
207
|
-
i0.ɵɵclassProp("rotated", ctx_r1.isDateFieldDropdownOpen);
|
|
208
|
-
} }
|
|
209
|
-
function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
210
|
-
i0.ɵɵelement(0, "i", 66);
|
|
211
|
-
} }
|
|
212
|
-
function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
213
|
-
const _r15 = i0.ɵɵgetCurrentView();
|
|
214
|
-
i0.ɵɵelementStart(0, "div", 63);
|
|
215
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Template_div_click_0_listener() { const field_r16 = i0.ɵɵrestoreView(_r15).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.setTimelineDateField(field_r16.name)); });
|
|
216
|
-
i0.ɵɵelement(1, "i", 64);
|
|
217
|
-
i0.ɵɵelementStart(2, "span", 65);
|
|
218
|
-
i0.ɵɵtext(3);
|
|
219
|
-
i0.ɵɵelementEnd();
|
|
220
|
-
i0.ɵɵconditionalCreate(4, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Conditional_4_Template, 1, 0, "i", 66);
|
|
221
|
-
i0.ɵɵelementEnd();
|
|
222
|
-
} if (rf & 2) {
|
|
223
|
-
const field_r16 = ctx.$implicit;
|
|
224
|
-
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
225
|
-
i0.ɵɵclassProp("selected", field_r16.name === ctx_r1.effectiveTimelineDateField);
|
|
226
|
-
i0.ɵɵadvance(3);
|
|
227
|
-
i0.ɵɵtextInterpolate(field_r16.displayName);
|
|
228
|
-
i0.ɵɵadvance();
|
|
229
|
-
i0.ɵɵconditional(field_r16.name === ctx_r1.effectiveTimelineDateField ? 4 : -1);
|
|
230
|
-
} }
|
|
231
|
-
function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
232
|
-
i0.ɵɵelementStart(0, "div", 58);
|
|
233
|
-
i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_For_2_Template, 5, 4, "div", 62, _forTrack1);
|
|
234
|
-
i0.ɵɵelementEnd();
|
|
235
|
-
} if (rf & 2) {
|
|
236
|
-
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
237
|
-
i0.ɵɵadvance();
|
|
238
|
-
i0.ɵɵrepeater(ctx_r1.availableDateFields);
|
|
239
|
-
} }
|
|
240
|
-
function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
241
|
-
const _r13 = i0.ɵɵgetCurrentView();
|
|
242
|
-
i0.ɵɵelementStart(0, "div", 43)(1, "div", 51);
|
|
243
|
-
i0.ɵɵconditionalCreate(2, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_2_Template, 1, 0, "div", 52);
|
|
244
|
-
i0.ɵɵelementStart(3, "div", 53)(4, "button", 54);
|
|
245
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleDateFieldDropdown()); });
|
|
246
|
-
i0.ɵɵelement(5, "i", 55);
|
|
247
|
-
i0.ɵɵelementStart(6, "span", 56);
|
|
248
|
-
i0.ɵɵtext(7);
|
|
249
|
-
i0.ɵɵelementEnd();
|
|
250
|
-
i0.ɵɵconditionalCreate(8, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_8_Template, 1, 2, "i", 57);
|
|
251
|
-
i0.ɵɵelementEnd();
|
|
252
|
-
i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Conditional_9_Template, 3, 0, "div", 58);
|
|
253
|
-
i0.ɵɵelementEnd()();
|
|
254
|
-
i0.ɵɵelementStart(10, "button", 59);
|
|
255
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleTimelineOrientation()); });
|
|
256
|
-
i0.ɵɵelement(11, "i");
|
|
257
|
-
i0.ɵɵelementEnd();
|
|
258
|
-
i0.ɵɵelementStart(12, "button", 59);
|
|
259
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleTimelineSortOrder()); });
|
|
260
|
-
i0.ɵɵelement(13, "i");
|
|
261
|
-
i0.ɵɵelementEnd()();
|
|
262
|
-
} if (rf & 2) {
|
|
263
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
264
|
-
i0.ɵɵadvance(2);
|
|
265
|
-
i0.ɵɵconditional(ctx_r1.isDateFieldDropdownOpen ? 2 : -1);
|
|
266
|
-
i0.ɵɵadvance(2);
|
|
267
|
-
i0.ɵɵclassProp("open", ctx_r1.isDateFieldDropdownOpen);
|
|
268
|
-
i0.ɵɵproperty("disabled", ctx_r1.availableDateFields.length <= 1);
|
|
269
|
-
i0.ɵɵadvance(3);
|
|
270
|
-
i0.ɵɵtextInterpolate(ctx_r1.effectiveTimelineDateFieldDisplayName);
|
|
271
|
-
i0.ɵɵadvance();
|
|
272
|
-
i0.ɵɵconditional(ctx_r1.availableDateFields.length > 1 ? 8 : -1);
|
|
273
|
-
i0.ɵɵadvance();
|
|
274
|
-
i0.ɵɵconditional(ctx_r1.isDateFieldDropdownOpen && ctx_r1.availableDateFields.length > 1 ? 9 : -1);
|
|
275
|
-
i0.ɵɵadvance();
|
|
276
|
-
i0.ɵɵproperty("title", ctx_r1.state.timelineOrientation === "vertical" ? "Switch to Horizontal" : "Switch to Vertical");
|
|
277
|
-
i0.ɵɵadvance();
|
|
278
|
-
i0.ɵɵclassMap(ctx_r1.state.timelineOrientation === "vertical" ? "fa-solid fa-ellipsis-vertical" : "fa-solid fa-ellipsis");
|
|
279
|
-
i0.ɵɵadvance();
|
|
280
|
-
i0.ɵɵproperty("title", ctx_r1.state.timelineSortOrder === "desc" ? "Showing Newest First (click for Oldest First)" : "Showing Oldest First (click for Newest First)");
|
|
281
|
-
i0.ɵɵadvance();
|
|
282
|
-
i0.ɵɵclassMap(ctx_r1.state.timelineSortOrder === "desc" ? "fa-solid fa-arrow-down-wide-short" : "fa-solid fa-arrow-up-wide-short");
|
|
283
|
-
} }
|
|
284
|
-
function DataExplorerDashboardComponent_Conditional_11_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
285
|
-
const _r17 = i0.ɵɵgetCurrentView();
|
|
286
|
-
i0.ɵɵelementStart(0, "button", 67);
|
|
287
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r17); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("timeline")); });
|
|
288
|
-
i0.ɵɵelement(1, "i", 68);
|
|
289
|
-
i0.ɵɵelementEnd();
|
|
290
|
-
} if (rf & 2) {
|
|
291
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
292
|
-
i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "timeline");
|
|
293
|
-
} }
|
|
294
|
-
function DataExplorerDashboardComponent_Conditional_11_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
295
|
-
const _r18 = i0.ɵɵgetCurrentView();
|
|
296
|
-
i0.ɵɵelementStart(0, "button", 69);
|
|
297
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Conditional_7_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r18); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("map")); });
|
|
298
|
-
i0.ɵɵelement(1, "i", 70);
|
|
299
|
-
i0.ɵɵelementEnd();
|
|
300
|
-
} if (rf & 2) {
|
|
301
|
-
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
302
|
-
i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "map");
|
|
303
|
-
} }
|
|
304
|
-
function DataExplorerDashboardComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
305
|
-
const _r12 = i0.ɵɵgetCurrentView();
|
|
306
|
-
i0.ɵɵconditionalCreate(0, DataExplorerDashboardComponent_Conditional_11_Conditional_0_Template, 14, 13, "div", 43);
|
|
307
|
-
i0.ɵɵelementStart(1, "div", 44)(2, "button", 45);
|
|
308
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("grid")); });
|
|
309
|
-
i0.ɵɵelement(3, "i", 46);
|
|
310
|
-
i0.ɵɵelementEnd();
|
|
311
|
-
i0.ɵɵelementStart(4, "button", 47);
|
|
312
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_11_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewModeChanged("cards")); });
|
|
313
|
-
i0.ɵɵelement(5, "i", 48);
|
|
314
|
-
i0.ɵɵelementEnd();
|
|
315
|
-
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_11_Conditional_6_Template, 2, 2, "button", 49);
|
|
316
|
-
i0.ɵɵconditionalCreate(7, DataExplorerDashboardComponent_Conditional_11_Conditional_7_Template, 2, 2, "button", 50);
|
|
317
|
-
i0.ɵɵelementEnd();
|
|
318
|
-
} if (rf & 2) {
|
|
319
|
-
const ctx_r1 = i0.ɵɵnextContext();
|
|
320
|
-
i0.ɵɵconditional(ctx_r1.state.viewMode === "timeline" && ctx_r1.entityHasDateFields ? 0 : -1);
|
|
321
|
-
i0.ɵɵadvance(2);
|
|
322
|
-
i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "grid");
|
|
323
|
-
i0.ɵɵadvance(2);
|
|
324
|
-
i0.ɵɵclassProp("active", ctx_r1.state.viewMode === "cards");
|
|
325
|
-
i0.ɵɵadvance(2);
|
|
326
|
-
i0.ɵɵconditional(ctx_r1.entityHasDateFields ? 6 : -1);
|
|
327
|
-
i0.ɵɵadvance();
|
|
328
|
-
i0.ɵɵconditional(ctx_r1.selectedEntity.SupportsGeoCoding ? 7 : -1);
|
|
329
|
-
} }
|
|
165
|
+
function DataExplorerDashboardComponent_Conditional_11_Template(rf, ctx) { }
|
|
330
166
|
function DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
331
|
-
i0.ɵɵelementStart(0, "span",
|
|
167
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
332
168
|
i0.ɵɵtext(1);
|
|
333
169
|
i0.ɵɵelementEnd();
|
|
334
170
|
} if (rf & 2) {
|
|
@@ -337,11 +173,11 @@ function DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template(rf
|
|
|
337
173
|
i0.ɵɵtextInterpolate(ctx_r1.recentRecords.length + ctx_r1.favoriteRecords.length);
|
|
338
174
|
} }
|
|
339
175
|
function DataExplorerDashboardComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
340
|
-
const
|
|
341
|
-
i0.ɵɵelementStart(0, "button",
|
|
342
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(
|
|
343
|
-
i0.ɵɵelement(1, "i",
|
|
344
|
-
i0.ɵɵconditionalCreate(2, DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template, 2, 1, "span",
|
|
176
|
+
const _r11 = i0.ɵɵgetCurrentView();
|
|
177
|
+
i0.ɵɵelementStart(0, "button", 31);
|
|
178
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r11); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessPanel()); });
|
|
179
|
+
i0.ɵɵelement(1, "i", 32);
|
|
180
|
+
i0.ɵɵconditionalCreate(2, DataExplorerDashboardComponent_Conditional_12_Conditional_2_Template, 2, 1, "span", 33);
|
|
345
181
|
i0.ɵɵelementEnd();
|
|
346
182
|
} if (rf & 2) {
|
|
347
183
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -350,19 +186,19 @@ function DataExplorerDashboardComponent_Conditional_12_Template(rf, ctx) { if (r
|
|
|
350
186
|
i0.ɵɵconditional(ctx_r1.recentRecords.length + ctx_r1.favoriteRecords.length > 0 ? 2 : -1);
|
|
351
187
|
} }
|
|
352
188
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
353
|
-
i0.ɵɵelementStart(0, "div",
|
|
354
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
189
|
+
i0.ɵɵelementStart(0, "div", 34);
|
|
190
|
+
i0.ɵɵelement(1, "mj-loading", 35);
|
|
355
191
|
i0.ɵɵelementEnd();
|
|
356
192
|
} }
|
|
357
193
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
358
|
-
const
|
|
359
|
-
i0.ɵɵelementStart(0, "button",
|
|
360
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(
|
|
361
|
-
i0.ɵɵelement(1, "i",
|
|
194
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
195
|
+
i0.ɵɵelementStart(0, "button", 67);
|
|
196
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.entityFilterText = ""); });
|
|
197
|
+
i0.ɵɵelement(1, "i", 30);
|
|
362
198
|
i0.ɵɵelementEnd();
|
|
363
199
|
} }
|
|
364
200
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
365
|
-
i0.ɵɵelementStart(0, "span",
|
|
201
|
+
i0.ɵɵelementStart(0, "span", 42);
|
|
366
202
|
i0.ɵɵtext(1, "/");
|
|
367
203
|
i0.ɵɵelementEnd();
|
|
368
204
|
} }
|
|
@@ -373,49 +209,49 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
|
|
|
373
209
|
i0.ɵɵtextInterpolate1(" across ", ctx_r1.applicationCount, " applications ");
|
|
374
210
|
} }
|
|
375
211
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
376
|
-
i0.ɵɵelementStart(0, "span",
|
|
212
|
+
i0.ɵɵelementStart(0, "span", 73);
|
|
377
213
|
i0.ɵɵtext(1);
|
|
378
214
|
i0.ɵɵelementEnd();
|
|
379
215
|
} if (rf & 2) {
|
|
380
|
-
const
|
|
216
|
+
const entity_r15 = i0.ɵɵnextContext().$implicit;
|
|
381
217
|
i0.ɵɵadvance();
|
|
382
|
-
i0.ɵɵtextInterpolate(
|
|
218
|
+
i0.ɵɵtextInterpolate(entity_r15.Description);
|
|
383
219
|
} }
|
|
384
220
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
385
|
-
const
|
|
386
|
-
i0.ɵɵelementStart(0, "div",
|
|
387
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_div_click_0_listener() { const
|
|
388
|
-
i0.ɵɵelementStart(1, "div",
|
|
221
|
+
const _r14 = i0.ɵɵgetCurrentView();
|
|
222
|
+
i0.ɵɵelementStart(0, "div", 69);
|
|
223
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_div_click_0_listener() { const entity_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r15)); });
|
|
224
|
+
i0.ɵɵelementStart(1, "div", 70);
|
|
389
225
|
i0.ɵɵelement(2, "i");
|
|
390
226
|
i0.ɵɵelementEnd();
|
|
391
|
-
i0.ɵɵelementStart(3, "div",
|
|
227
|
+
i0.ɵɵelementStart(3, "div", 71)(4, "span", 72);
|
|
392
228
|
i0.ɵɵtext(5);
|
|
393
229
|
i0.ɵɵelementEnd();
|
|
394
|
-
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Conditional_6_Template, 2, 1, "span",
|
|
230
|
+
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Conditional_6_Template, 2, 1, "span", 73);
|
|
395
231
|
i0.ɵɵelementEnd();
|
|
396
|
-
i0.ɵɵelementStart(7, "button",
|
|
397
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_button_click_7_listener($event) { const
|
|
232
|
+
i0.ɵɵelementStart(7, "button", 74);
|
|
233
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template_button_click_7_listener($event) { const entity_r15 = i0.ɵɵrestoreView(_r14).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.toggleEntityFavorite(entity_r15, $event)); });
|
|
398
234
|
i0.ɵɵelement(8, "i");
|
|
399
235
|
i0.ɵɵelementEnd()();
|
|
400
236
|
} if (rf & 2) {
|
|
401
|
-
const
|
|
237
|
+
const entity_r15 = ctx.$implicit;
|
|
402
238
|
const ctx_r1 = i0.ɵɵnextContext(4);
|
|
403
|
-
i0.ɵɵproperty("title",
|
|
239
|
+
i0.ɵɵproperty("title", entity_r15.Description || entity_r15.DisplayNameOrName);
|
|
404
240
|
i0.ɵɵadvance(2);
|
|
405
|
-
i0.ɵɵclassMap(ctx_r1.getEntityIcon(
|
|
241
|
+
i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r15));
|
|
406
242
|
i0.ɵɵadvance(3);
|
|
407
|
-
i0.ɵɵtextInterpolate(
|
|
243
|
+
i0.ɵɵtextInterpolate(entity_r15.DisplayNameOrName);
|
|
408
244
|
i0.ɵɵadvance();
|
|
409
|
-
i0.ɵɵconditional(
|
|
245
|
+
i0.ɵɵconditional(entity_r15.Description ? 6 : -1);
|
|
410
246
|
i0.ɵɵadvance();
|
|
411
|
-
i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(
|
|
412
|
-
i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(
|
|
247
|
+
i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(entity_r15));
|
|
248
|
+
i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(entity_r15) ? "Remove from favorites" : "Add to favorites");
|
|
413
249
|
i0.ɵɵadvance();
|
|
414
|
-
i0.ɵɵclassMap(ctx_r1.isEntityFavorited(
|
|
250
|
+
i0.ɵɵclassMap(ctx_r1.isEntityFavorited(entity_r15) ? "fa-solid fa-star" : "fa-regular fa-star");
|
|
415
251
|
} }
|
|
416
252
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
417
|
-
i0.ɵɵelementStart(0, "div",
|
|
418
|
-
i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template, 9, 10, "div",
|
|
253
|
+
i0.ɵɵelementStart(0, "div", 49);
|
|
254
|
+
i0.ɵɵrepeaterCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_For_2_Template, 9, 10, "div", 68, _forTrack2);
|
|
419
255
|
i0.ɵɵelementEnd();
|
|
420
256
|
} if (rf & 2) {
|
|
421
257
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
@@ -423,96 +259,96 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
|
|
|
423
259
|
i0.ɵɵrepeater(ctx_r1.flatFilteredEntities);
|
|
424
260
|
} }
|
|
425
261
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
426
|
-
i0.ɵɵelementStart(0, "span",
|
|
262
|
+
i0.ɵɵelementStart(0, "span", 73);
|
|
427
263
|
i0.ɵɵtext(1);
|
|
428
264
|
i0.ɵɵelementEnd();
|
|
429
265
|
} if (rf & 2) {
|
|
430
|
-
const
|
|
266
|
+
const entity_r19 = i0.ɵɵnextContext().$implicit;
|
|
431
267
|
i0.ɵɵadvance();
|
|
432
|
-
i0.ɵɵtextInterpolate(
|
|
268
|
+
i0.ɵɵtextInterpolate(entity_r19.Description);
|
|
433
269
|
} }
|
|
434
270
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
435
|
-
const
|
|
436
|
-
i0.ɵɵelementStart(0, "div",
|
|
437
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_div_click_0_listener() { const
|
|
438
|
-
i0.ɵɵelementStart(1, "div",
|
|
271
|
+
const _r18 = i0.ɵɵgetCurrentView();
|
|
272
|
+
i0.ɵɵelementStart(0, "div", 69);
|
|
273
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_div_click_0_listener() { const entity_r19 = i0.ɵɵrestoreView(_r18).$implicit; const ctx_r1 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r19)); });
|
|
274
|
+
i0.ɵɵelementStart(1, "div", 70);
|
|
439
275
|
i0.ɵɵelement(2, "i");
|
|
440
276
|
i0.ɵɵelementEnd();
|
|
441
|
-
i0.ɵɵelementStart(3, "div",
|
|
277
|
+
i0.ɵɵelementStart(3, "div", 71)(4, "span", 72);
|
|
442
278
|
i0.ɵɵtext(5);
|
|
443
279
|
i0.ɵɵelementEnd();
|
|
444
|
-
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Conditional_6_Template, 2, 1, "span",
|
|
280
|
+
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Conditional_6_Template, 2, 1, "span", 73);
|
|
445
281
|
i0.ɵɵelementEnd();
|
|
446
|
-
i0.ɵɵelementStart(7, "button",
|
|
447
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_button_click_7_listener($event) { const
|
|
282
|
+
i0.ɵɵelementStart(7, "button", 74);
|
|
283
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template_button_click_7_listener($event) { const entity_r19 = i0.ɵɵrestoreView(_r18).$implicit; const ctx_r1 = i0.ɵɵnextContext(6); return i0.ɵɵresetView(ctx_r1.toggleEntityFavorite(entity_r19, $event)); });
|
|
448
284
|
i0.ɵɵelement(8, "i");
|
|
449
285
|
i0.ɵɵelementEnd()();
|
|
450
286
|
} if (rf & 2) {
|
|
451
|
-
const
|
|
287
|
+
const entity_r19 = ctx.$implicit;
|
|
452
288
|
const ctx_r1 = i0.ɵɵnextContext(6);
|
|
453
|
-
i0.ɵɵproperty("title",
|
|
289
|
+
i0.ɵɵproperty("title", entity_r19.Description || entity_r19.DisplayNameOrName);
|
|
454
290
|
i0.ɵɵadvance(2);
|
|
455
|
-
i0.ɵɵclassMap(ctx_r1.getEntityIcon(
|
|
291
|
+
i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r19));
|
|
456
292
|
i0.ɵɵadvance(3);
|
|
457
|
-
i0.ɵɵtextInterpolate(
|
|
293
|
+
i0.ɵɵtextInterpolate(entity_r19.DisplayNameOrName);
|
|
458
294
|
i0.ɵɵadvance();
|
|
459
|
-
i0.ɵɵconditional(
|
|
295
|
+
i0.ɵɵconditional(entity_r19.Description ? 6 : -1);
|
|
460
296
|
i0.ɵɵadvance();
|
|
461
|
-
i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(
|
|
462
|
-
i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(
|
|
297
|
+
i0.ɵɵclassProp("favorited", ctx_r1.isEntityFavorited(entity_r19));
|
|
298
|
+
i0.ɵɵproperty("title", ctx_r1.isEntityFavorited(entity_r19) ? "Remove from favorites" : "Add to favorites");
|
|
463
299
|
i0.ɵɵadvance();
|
|
464
|
-
i0.ɵɵclassMap(ctx_r1.isEntityFavorited(
|
|
300
|
+
i0.ɵɵclassMap(ctx_r1.isEntityFavorited(entity_r19) ? "fa-solid fa-star" : "fa-regular fa-star");
|
|
465
301
|
} }
|
|
466
302
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
467
|
-
i0.ɵɵelementStart(0, "div",
|
|
468
|
-
i0.ɵɵrepeaterCreate(2, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template, 9, 10, "div",
|
|
303
|
+
i0.ɵɵelementStart(0, "div", 81)(1, "div", 49);
|
|
304
|
+
i0.ɵɵrepeaterCreate(2, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_For_3_Template, 9, 10, "div", 68, _forTrack2);
|
|
469
305
|
i0.ɵɵelementEnd()();
|
|
470
306
|
} if (rf & 2) {
|
|
471
|
-
const
|
|
307
|
+
const group_r17 = i0.ɵɵnextContext().$implicit;
|
|
472
308
|
i0.ɵɵadvance(2);
|
|
473
|
-
i0.ɵɵrepeater(
|
|
309
|
+
i0.ɵɵrepeater(group_r17.entities);
|
|
474
310
|
} }
|
|
475
311
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template(rf, ctx) { if (rf & 1) {
|
|
476
|
-
const
|
|
477
|
-
i0.ɵɵelementStart(0, "div",
|
|
478
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template_div_click_1_listener() { const
|
|
479
|
-
i0.ɵɵelementStart(2, "div",
|
|
312
|
+
const _r16 = i0.ɵɵgetCurrentView();
|
|
313
|
+
i0.ɵɵelementStart(0, "div", 75)(1, "div", 76);
|
|
314
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template_div_click_1_listener() { const group_r17 = i0.ɵɵrestoreView(_r16).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.toggleAppGroup(group_r17.applicationId)); });
|
|
315
|
+
i0.ɵɵelementStart(2, "div", 77);
|
|
480
316
|
i0.ɵɵelement(3, "i");
|
|
481
317
|
i0.ɵɵelementEnd();
|
|
482
|
-
i0.ɵɵelementStart(4, "span",
|
|
318
|
+
i0.ɵɵelementStart(4, "span", 78);
|
|
483
319
|
i0.ɵɵtext(5);
|
|
484
320
|
i0.ɵɵelementEnd();
|
|
485
|
-
i0.ɵɵelementStart(6, "span",
|
|
321
|
+
i0.ɵɵelementStart(6, "span", 79);
|
|
486
322
|
i0.ɵɵtext(7);
|
|
487
323
|
i0.ɵɵelementEnd();
|
|
488
|
-
i0.ɵɵelement(8, "i",
|
|
324
|
+
i0.ɵɵelement(8, "i", 80);
|
|
489
325
|
i0.ɵɵelementEnd();
|
|
490
|
-
i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_Template, 4, 0, "div",
|
|
326
|
+
i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Conditional_9_Template, 4, 0, "div", 81);
|
|
491
327
|
i0.ɵɵelementEnd();
|
|
492
328
|
} if (rf & 2) {
|
|
493
|
-
const
|
|
329
|
+
const group_r17 = ctx.$implicit;
|
|
494
330
|
i0.ɵɵadvance(2);
|
|
495
|
-
i0.ɵɵstyleProp("background",
|
|
331
|
+
i0.ɵɵstyleProp("background", group_r17.applicationColor ? group_r17.applicationColor + "15" : null)("color", group_r17.applicationColor || null);
|
|
496
332
|
i0.ɵɵadvance();
|
|
497
|
-
i0.ɵɵclassMap(
|
|
333
|
+
i0.ɵɵclassMap(group_r17.applicationIcon || "fa-solid fa-folder");
|
|
498
334
|
i0.ɵɵadvance(2);
|
|
499
|
-
i0.ɵɵtextInterpolate(
|
|
335
|
+
i0.ɵɵtextInterpolate(group_r17.applicationName);
|
|
500
336
|
i0.ɵɵadvance(2);
|
|
501
|
-
i0.ɵɵtextInterpolate(
|
|
337
|
+
i0.ɵɵtextInterpolate(group_r17.entities.length);
|
|
502
338
|
i0.ɵɵadvance();
|
|
503
|
-
i0.ɵɵclassProp("expanded",
|
|
339
|
+
i0.ɵɵclassProp("expanded", group_r17.isExpanded);
|
|
504
340
|
i0.ɵɵadvance();
|
|
505
|
-
i0.ɵɵconditional(
|
|
341
|
+
i0.ɵɵconditional(group_r17.isExpanded ? 9 : -1);
|
|
506
342
|
} }
|
|
507
343
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
508
|
-
i0.ɵɵrepeaterCreate(0, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template, 10, 11, "div",
|
|
344
|
+
i0.ɵɵrepeaterCreate(0, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_For_1_Template, 10, 11, "div", 75, _forTrack4);
|
|
509
345
|
} if (rf & 2) {
|
|
510
346
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
511
347
|
i0.ɵɵrepeater(ctx_r1.filteredAppEntityGroups);
|
|
512
348
|
} }
|
|
513
349
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
514
|
-
i0.ɵɵelementStart(0, "div",
|
|
515
|
-
i0.ɵɵelement(1, "i",
|
|
350
|
+
i0.ɵɵelementStart(0, "div", 50);
|
|
351
|
+
i0.ɵɵelement(1, "i", 82);
|
|
516
352
|
i0.ɵɵelementStart(2, "p");
|
|
517
353
|
i0.ɵɵtext(3);
|
|
518
354
|
i0.ɵɵelementEnd()();
|
|
@@ -522,8 +358,8 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
|
|
|
522
358
|
i0.ɵɵtextInterpolate1("No entities match \"", ctx_r1.entityFilterText, "\"");
|
|
523
359
|
} }
|
|
524
360
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_22_Template(rf, ctx) { if (rf & 1) {
|
|
525
|
-
i0.ɵɵelementStart(0, "div",
|
|
526
|
-
i0.ɵɵelement(1, "i",
|
|
361
|
+
i0.ɵɵelementStart(0, "div", 51);
|
|
362
|
+
i0.ɵɵelement(1, "i", 83);
|
|
527
363
|
i0.ɵɵelementStart(2, "h3");
|
|
528
364
|
i0.ɵɵtext(3, "No Entities Available");
|
|
529
365
|
i0.ɵɵelementEnd();
|
|
@@ -532,167 +368,167 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional
|
|
|
532
368
|
i0.ɵɵelementEnd()();
|
|
533
369
|
} }
|
|
534
370
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template(rf, ctx) { if (rf & 1) {
|
|
535
|
-
const
|
|
536
|
-
i0.ɵɵelementStart(0, "div",
|
|
537
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template_div_click_0_listener() { const
|
|
538
|
-
i0.ɵɵelementStart(1, "div",
|
|
371
|
+
const _r20 = i0.ɵɵgetCurrentView();
|
|
372
|
+
i0.ɵɵelementStart(0, "div", 84);
|
|
373
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template_div_click_0_listener() { const record_r21 = i0.ɵɵrestoreView(_r20).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onRecentRecordClick(record_r21)); });
|
|
374
|
+
i0.ɵɵelementStart(1, "div", 85);
|
|
539
375
|
i0.ɵɵelement(2, "i");
|
|
540
376
|
i0.ɵɵelementEnd();
|
|
541
|
-
i0.ɵɵelementStart(3, "div",
|
|
377
|
+
i0.ɵɵelementStart(3, "div", 86)(4, "div", 87);
|
|
542
378
|
i0.ɵɵtext(5);
|
|
543
379
|
i0.ɵɵelementEnd();
|
|
544
|
-
i0.ɵɵelementStart(6, "div",
|
|
380
|
+
i0.ɵɵelementStart(6, "div", 88);
|
|
545
381
|
i0.ɵɵtext(7);
|
|
546
382
|
i0.ɵɵelementEnd()();
|
|
547
|
-
i0.ɵɵelementStart(8, "span",
|
|
383
|
+
i0.ɵɵelementStart(8, "span", 89);
|
|
548
384
|
i0.ɵɵtext(9);
|
|
549
385
|
i0.ɵɵelementEnd()();
|
|
550
386
|
} if (rf & 2) {
|
|
551
|
-
const
|
|
387
|
+
const record_r21 = ctx.$implicit;
|
|
552
388
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
553
389
|
i0.ɵɵadvance(2);
|
|
554
|
-
i0.ɵɵclassMap(ctx_r1.getEntityIconById(
|
|
390
|
+
i0.ɵɵclassMap(ctx_r1.getEntityIconById(record_r21.entityId));
|
|
555
391
|
i0.ɵɵadvance(3);
|
|
556
|
-
i0.ɵɵtextInterpolate(
|
|
392
|
+
i0.ɵɵtextInterpolate(record_r21.recordName || record_r21.recordId);
|
|
557
393
|
i0.ɵɵadvance(2);
|
|
558
|
-
i0.ɵɵtextInterpolate(
|
|
394
|
+
i0.ɵɵtextInterpolate(record_r21.entityName);
|
|
559
395
|
i0.ɵɵadvance(2);
|
|
560
|
-
i0.ɵɵtextInterpolate(ctx_r1.formatRelativeTime(
|
|
396
|
+
i0.ɵɵtextInterpolate(ctx_r1.formatRelativeTime(record_r21.latestAt));
|
|
561
397
|
} }
|
|
562
398
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_41_Template(rf, ctx) { if (rf & 1) {
|
|
563
|
-
i0.ɵɵelementStart(0, "div",
|
|
399
|
+
i0.ɵɵelementStart(0, "div", 64);
|
|
564
400
|
i0.ɵɵtext(1, "No recent records");
|
|
565
401
|
i0.ɵɵelementEnd();
|
|
566
402
|
} }
|
|
567
403
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template(rf, ctx) { if (rf & 1) {
|
|
568
|
-
const
|
|
569
|
-
i0.ɵɵelementStart(0, "div",
|
|
570
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template_div_click_0_listener() { const
|
|
571
|
-
i0.ɵɵelementStart(1, "div",
|
|
404
|
+
const _r22 = i0.ɵɵgetCurrentView();
|
|
405
|
+
i0.ɵɵelementStart(0, "div", 84);
|
|
406
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template_div_click_0_listener() { const entity_r23 = i0.ɵɵrestoreView(_r22).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onEntitySelected(entity_r23)); });
|
|
407
|
+
i0.ɵɵelementStart(1, "div", 85);
|
|
572
408
|
i0.ɵɵelement(2, "i");
|
|
573
409
|
i0.ɵɵelementEnd();
|
|
574
|
-
i0.ɵɵelementStart(3, "div",
|
|
410
|
+
i0.ɵɵelementStart(3, "div", 86)(4, "div", 87);
|
|
575
411
|
i0.ɵɵtext(5);
|
|
576
412
|
i0.ɵɵelementEnd()()();
|
|
577
413
|
} if (rf & 2) {
|
|
578
|
-
const
|
|
414
|
+
const entity_r23 = ctx.$implicit;
|
|
579
415
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
580
416
|
i0.ɵɵadvance(2);
|
|
581
|
-
i0.ɵɵclassMap(ctx_r1.getEntityIcon(
|
|
417
|
+
i0.ɵɵclassMap(ctx_r1.getEntityIcon(entity_r23));
|
|
582
418
|
i0.ɵɵadvance(3);
|
|
583
|
-
i0.ɵɵtextInterpolate(
|
|
419
|
+
i0.ɵɵtextInterpolate(entity_r23.DisplayNameOrName);
|
|
584
420
|
} }
|
|
585
421
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_53_Template(rf, ctx) { if (rf & 1) {
|
|
586
|
-
i0.ɵɵelementStart(0, "div",
|
|
422
|
+
i0.ɵɵelementStart(0, "div", 64);
|
|
587
423
|
i0.ɵɵtext(1, "No recent entities");
|
|
588
424
|
i0.ɵɵelementEnd();
|
|
589
425
|
} }
|
|
590
426
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template(rf, ctx) { if (rf & 1) {
|
|
591
|
-
const
|
|
592
|
-
i0.ɵɵelementStart(0, "div",
|
|
593
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template_div_click_0_listener() { const
|
|
594
|
-
i0.ɵɵelementStart(1, "div",
|
|
427
|
+
const _r24 = i0.ɵɵgetCurrentView();
|
|
428
|
+
i0.ɵɵelementStart(0, "div", 84);
|
|
429
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template_div_click_0_listener() { const record_r25 = i0.ɵɵrestoreView(_r24).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onFavoriteRecordClick(record_r25)); });
|
|
430
|
+
i0.ɵɵelementStart(1, "div", 85);
|
|
595
431
|
i0.ɵɵelement(2, "i");
|
|
596
432
|
i0.ɵɵelementEnd();
|
|
597
|
-
i0.ɵɵelementStart(3, "div",
|
|
433
|
+
i0.ɵɵelementStart(3, "div", 86)(4, "div", 87);
|
|
598
434
|
i0.ɵɵtext(5);
|
|
599
435
|
i0.ɵɵelementEnd();
|
|
600
|
-
i0.ɵɵelementStart(6, "div",
|
|
436
|
+
i0.ɵɵelementStart(6, "div", 88);
|
|
601
437
|
i0.ɵɵtext(7);
|
|
602
438
|
i0.ɵɵelementEnd()()();
|
|
603
439
|
} if (rf & 2) {
|
|
604
|
-
const
|
|
440
|
+
const record_r25 = ctx.$implicit;
|
|
605
441
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
606
442
|
i0.ɵɵadvance(2);
|
|
607
|
-
i0.ɵɵclassMap(ctx_r1.getEntityIconById(
|
|
443
|
+
i0.ɵɵclassMap(ctx_r1.getEntityIconById(record_r25.entityId));
|
|
608
444
|
i0.ɵɵadvance(3);
|
|
609
|
-
i0.ɵɵtextInterpolate(
|
|
445
|
+
i0.ɵɵtextInterpolate(record_r25.recordName || record_r25.recordId);
|
|
610
446
|
i0.ɵɵadvance(2);
|
|
611
|
-
i0.ɵɵtextInterpolate(
|
|
447
|
+
i0.ɵɵtextInterpolate(record_r25.entityName);
|
|
612
448
|
} }
|
|
613
449
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_65_Template(rf, ctx) { if (rf & 1) {
|
|
614
|
-
i0.ɵɵelementStart(0, "div",
|
|
450
|
+
i0.ɵɵelementStart(0, "div", 64);
|
|
615
451
|
i0.ɵɵtext(1, "No favorite records");
|
|
616
452
|
i0.ɵɵelementEnd();
|
|
617
453
|
} }
|
|
618
454
|
function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
619
|
-
const
|
|
620
|
-
i0.ɵɵelementStart(0, "div",
|
|
621
|
-
i0.ɵɵelement(3, "i",
|
|
622
|
-
i0.ɵɵelementStart(4, "input",
|
|
623
|
-
i0.ɵɵtwoWayListener("ngModelChange", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(
|
|
455
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
456
|
+
i0.ɵɵelementStart(0, "div", 36)(1, "div", 37)(2, "div", 38);
|
|
457
|
+
i0.ɵɵelement(3, "i", 39);
|
|
458
|
+
i0.ɵɵelementStart(4, "input", 40, 0);
|
|
459
|
+
i0.ɵɵtwoWayListener("ngModelChange", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.entityFilterText, $event) || (ctx_r1.entityFilterText = $event); return i0.ɵɵresetView($event); });
|
|
624
460
|
i0.ɵɵelementEnd();
|
|
625
|
-
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template, 2, 0, "button",
|
|
461
|
+
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_6_Template, 2, 0, "button", 41)(7, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_7_Template, 2, 0, "span", 42);
|
|
626
462
|
i0.ɵɵelementEnd();
|
|
627
|
-
i0.ɵɵelementStart(8, "div",
|
|
463
|
+
i0.ɵɵelementStart(8, "div", 43)(9, "span", 44);
|
|
628
464
|
i0.ɵɵtext(10);
|
|
629
465
|
i0.ɵɵconditionalCreate(11, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_11_Template, 1, 1);
|
|
630
466
|
i0.ɵɵelementEnd();
|
|
631
|
-
i0.ɵɵelementStart(12, "div",
|
|
632
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(
|
|
467
|
+
i0.ɵɵelementStart(12, "div", 45)(13, "button", 46);
|
|
468
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setHomeViewMode("all")); });
|
|
633
469
|
i0.ɵɵtext(14, " All Entities ");
|
|
634
470
|
i0.ɵɵelementEnd();
|
|
635
|
-
i0.ɵɵelementStart(15, "button",
|
|
636
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(
|
|
637
|
-
i0.ɵɵelement(16, "i",
|
|
471
|
+
i0.ɵɵelementStart(15, "button", 46);
|
|
472
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.setHomeViewMode("favorites")); });
|
|
473
|
+
i0.ɵɵelement(16, "i", 47);
|
|
638
474
|
i0.ɵɵtext(17, " My Favorites ");
|
|
639
475
|
i0.ɵɵelementEnd()()()();
|
|
640
|
-
i0.ɵɵelementStart(18, "div",
|
|
641
|
-
i0.ɵɵconditionalCreate(19, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_Template, 3, 0, "div",
|
|
642
|
-
i0.ɵɵconditionalCreate(21, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_21_Template, 4, 1, "div",
|
|
643
|
-
i0.ɵɵconditionalCreate(22, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_22_Template, 6, 0, "div",
|
|
476
|
+
i0.ɵɵelementStart(18, "div", 48);
|
|
477
|
+
i0.ɵɵconditionalCreate(19, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_19_Template, 3, 0, "div", 49)(20, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_20_Template, 2, 0);
|
|
478
|
+
i0.ɵɵconditionalCreate(21, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_21_Template, 4, 1, "div", 50);
|
|
479
|
+
i0.ɵɵconditionalCreate(22, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_22_Template, 6, 0, "div", 51);
|
|
644
480
|
i0.ɵɵelementEnd()();
|
|
645
|
-
i0.ɵɵelementStart(23, "div",
|
|
481
|
+
i0.ɵɵelementStart(23, "div", 52)(24, "div", 53)(25, "h3");
|
|
646
482
|
i0.ɵɵtext(26, "Quick Access");
|
|
647
483
|
i0.ɵɵelementEnd();
|
|
648
|
-
i0.ɵɵelementStart(27, "button",
|
|
649
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_27_listener() { i0.ɵɵrestoreView(
|
|
650
|
-
i0.ɵɵelement(28, "i",
|
|
484
|
+
i0.ɵɵelementStart(27, "button", 54);
|
|
485
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_button_click_27_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessPanel()); });
|
|
486
|
+
i0.ɵɵelement(28, "i", 55);
|
|
651
487
|
i0.ɵɵelementEnd()();
|
|
652
|
-
i0.ɵɵelementStart(29, "div",
|
|
653
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_31_listener() { i0.ɵɵrestoreView(
|
|
654
|
-
i0.ɵɵelement(32, "i",
|
|
488
|
+
i0.ɵɵelementStart(29, "div", 56)(30, "div", 57)(31, "div", 58);
|
|
489
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_31_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("recentRecords")); });
|
|
490
|
+
i0.ɵɵelement(32, "i", 59);
|
|
655
491
|
i0.ɵɵelementStart(33, "span");
|
|
656
492
|
i0.ɵɵtext(34, "Recent Records");
|
|
657
493
|
i0.ɵɵelementEnd();
|
|
658
|
-
i0.ɵɵelementStart(35, "span",
|
|
494
|
+
i0.ɵɵelementStart(35, "span", 60);
|
|
659
495
|
i0.ɵɵtext(36);
|
|
660
496
|
i0.ɵɵelementEnd();
|
|
661
|
-
i0.ɵɵelement(37, "i",
|
|
497
|
+
i0.ɵɵelement(37, "i", 61);
|
|
662
498
|
i0.ɵɵelementEnd();
|
|
663
|
-
i0.ɵɵelementStart(38, "div",
|
|
664
|
-
i0.ɵɵrepeaterCreate(39, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template, 10, 5, "div",
|
|
665
|
-
i0.ɵɵconditionalCreate(41, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_41_Template, 2, 0, "div",
|
|
499
|
+
i0.ɵɵelementStart(38, "div", 62);
|
|
500
|
+
i0.ɵɵrepeaterCreate(39, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_40_Template, 10, 5, "div", 63, _forTrack1);
|
|
501
|
+
i0.ɵɵconditionalCreate(41, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_41_Template, 2, 0, "div", 64);
|
|
666
502
|
i0.ɵɵelementEnd()();
|
|
667
|
-
i0.ɵɵelementStart(42, "div",
|
|
668
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_43_listener() { i0.ɵɵrestoreView(
|
|
669
|
-
i0.ɵɵelement(44, "i",
|
|
503
|
+
i0.ɵɵelementStart(42, "div", 57)(43, "div", 58);
|
|
504
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_43_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("recentEntities")); });
|
|
505
|
+
i0.ɵɵelement(44, "i", 65);
|
|
670
506
|
i0.ɵɵelementStart(45, "span");
|
|
671
507
|
i0.ɵɵtext(46, "Recent Entities");
|
|
672
508
|
i0.ɵɵelementEnd();
|
|
673
|
-
i0.ɵɵelementStart(47, "span",
|
|
509
|
+
i0.ɵɵelementStart(47, "span", 60);
|
|
674
510
|
i0.ɵɵtext(48);
|
|
675
511
|
i0.ɵɵelementEnd();
|
|
676
|
-
i0.ɵɵelement(49, "i",
|
|
512
|
+
i0.ɵɵelement(49, "i", 61);
|
|
677
513
|
i0.ɵɵelementEnd();
|
|
678
|
-
i0.ɵɵelementStart(50, "div",
|
|
679
|
-
i0.ɵɵrepeaterCreate(51, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template, 6, 3, "div",
|
|
680
|
-
i0.ɵɵconditionalCreate(53, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_53_Template, 2, 0, "div",
|
|
514
|
+
i0.ɵɵelementStart(50, "div", 62);
|
|
515
|
+
i0.ɵɵrepeaterCreate(51, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_52_Template, 6, 3, "div", 63, _forTrack2);
|
|
516
|
+
i0.ɵɵconditionalCreate(53, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_53_Template, 2, 0, "div", 64);
|
|
681
517
|
i0.ɵɵelementEnd()();
|
|
682
|
-
i0.ɵɵelementStart(54, "div",
|
|
683
|
-
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_55_listener() { i0.ɵɵrestoreView(
|
|
684
|
-
i0.ɵɵelement(56, "i",
|
|
518
|
+
i0.ɵɵelementStart(54, "div", 57)(55, "div", 58);
|
|
519
|
+
i0.ɵɵlistener("click", function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template_div_click_55_listener() { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.toggleQuickAccessSection("favoriteRecords")); });
|
|
520
|
+
i0.ɵɵelement(56, "i", 66);
|
|
685
521
|
i0.ɵɵelementStart(57, "span");
|
|
686
522
|
i0.ɵɵtext(58, "Favorite Records");
|
|
687
523
|
i0.ɵɵelementEnd();
|
|
688
|
-
i0.ɵɵelementStart(59, "span",
|
|
524
|
+
i0.ɵɵelementStart(59, "span", 60);
|
|
689
525
|
i0.ɵɵtext(60);
|
|
690
526
|
i0.ɵɵelementEnd();
|
|
691
|
-
i0.ɵɵelement(61, "i",
|
|
527
|
+
i0.ɵɵelement(61, "i", 61);
|
|
692
528
|
i0.ɵɵelementEnd();
|
|
693
|
-
i0.ɵɵelementStart(62, "div",
|
|
694
|
-
i0.ɵɵrepeaterCreate(63, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template, 8, 4, "div",
|
|
695
|
-
i0.ɵɵconditionalCreate(65, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_65_Template, 2, 0, "div",
|
|
529
|
+
i0.ɵɵelementStart(62, "div", 62);
|
|
530
|
+
i0.ɵɵrepeaterCreate(63, DataExplorerDashboardComponent_Conditional_14_Conditional_2_For_64_Template, 8, 4, "div", 63, _forTrack3);
|
|
531
|
+
i0.ɵɵconditionalCreate(65, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Conditional_65_Template, 2, 0, "div", 64);
|
|
696
532
|
i0.ɵɵelementEnd()()()();
|
|
697
533
|
} if (rf & 2) {
|
|
698
534
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -743,8 +579,8 @@ function DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template(rf
|
|
|
743
579
|
i0.ɵɵconditional(ctx_r1.quickAccessFavoriteRecords.length === 0 ? 65 : -1);
|
|
744
580
|
} }
|
|
745
581
|
function DataExplorerDashboardComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
746
|
-
i0.ɵɵelementStart(0, "div",
|
|
747
|
-
i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_1_Template, 2, 0, "div",
|
|
582
|
+
i0.ɵɵelementStart(0, "div", 12);
|
|
583
|
+
i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_14_Conditional_1_Template, 2, 0, "div", 34)(2, DataExplorerDashboardComponent_Conditional_14_Conditional_2_Template, 66, 27);
|
|
748
584
|
i0.ɵɵelementEnd();
|
|
749
585
|
} if (rf & 2) {
|
|
750
586
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -752,40 +588,25 @@ function DataExplorerDashboardComponent_Conditional_14_Template(rf, ctx) { if (r
|
|
|
752
588
|
i0.ɵɵconditional(ctx_r1.isLoadingEntities ? 1 : 2);
|
|
753
589
|
} }
|
|
754
590
|
function DataExplorerDashboardComponent_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
755
|
-
const
|
|
756
|
-
i0.ɵɵelementStart(0, "mj-
|
|
757
|
-
i0.ɵɵlistener("
|
|
591
|
+
const _r26 = i0.ɵɵgetCurrentView();
|
|
592
|
+
i0.ɵɵelementStart(0, "mj-view-workspace", 90);
|
|
593
|
+
i0.ɵɵlistener("SelectedViewChange", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_SelectedViewChange_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("ViewSelected", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_ViewSelected_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSelected($event)); })("OpenViewInTabRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_OpenViewInTabRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenInTabRequested($event)); })("OpenRecordRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_OpenRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceOpenRecord($event)); })("OpenRelatedRecordRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_OpenRelatedRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecordRequested($event)); })("CreateNewRecordRequested", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_CreateNewRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onCreateNewRecordRequested($event)); })("RecordSelected", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_RecordSelected_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onViewerRecordSelected($event)); })("AfterViewSave", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_AfterViewSave_0_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("AfterViewDelete", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_AfterViewDelete_0_listener() { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onWorkspaceViewSaved()); })("FilterTextChanged", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_FilterTextChanged_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilterTextChanged($event)); })("DataLoaded", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_DataLoaded_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDataLoaded($event)); })("FilteredCountChanged", function DataExplorerDashboardComponent_Conditional_15_Template_mj_view_workspace_FilteredCountChanged_0_listener($event) { i0.ɵɵrestoreView(_r26); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onFilteredCountChanged($event)); });
|
|
758
594
|
i0.ɵɵelementEnd();
|
|
759
595
|
} if (rf & 2) {
|
|
760
596
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
761
|
-
i0.ɵɵproperty("
|
|
597
|
+
i0.ɵɵproperty("Entity", ctx_r1.selectedEntity)("AutoSaveView", true)("SelectedView", ctx_r1.selectedViewEntity)("FilterText", ctx_r1.debouncedFilterText)("SelectedRecordId", ctx_r1.state.selectedRecordId)("ViewerConfig", ctx_r1.viewerConfig);
|
|
762
598
|
} }
|
|
763
599
|
function DataExplorerDashboardComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
764
|
-
const
|
|
765
|
-
i0.ɵɵelementStart(0, "div",
|
|
766
|
-
i0.ɵɵlistener("
|
|
767
|
-
i0.ɵɵelement(3, "i", 35);
|
|
768
|
-
i0.ɵɵelementStart(4, "span");
|
|
769
|
-
i0.ɵɵtext(5, "Add to List");
|
|
770
|
-
i0.ɵɵelementEnd()()();
|
|
771
|
-
i0.ɵɵelementStart(6, "mj-entity-record-detail-panel", 134);
|
|
772
|
-
i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_close_6_listener() { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDetailPanelClosed()); })("openRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRecord_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRecord($event)); })("navigateToRelated", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_navigateToRelated_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onNavigateToRelated($event)); })("openRelatedRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRelatedRecord_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecord($event)); })("openForeignKeyRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openForeignKeyRecord_6_listener($event) { i0.ɵɵrestoreView(_r35); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenForeignKeyRecord($event)); });
|
|
600
|
+
const _r27 = i0.ɵɵgetCurrentView();
|
|
601
|
+
i0.ɵɵelementStart(0, "div", 91)(1, "mj-entity-record-detail-panel", 92);
|
|
602
|
+
i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_close_1_listener() { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onDetailPanelClosed()); })("openRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRecord_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRecord($event)); })("navigateToRelated", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_navigateToRelated_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onNavigateToRelated($event)); })("openRelatedRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openRelatedRecord_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenRelatedRecord($event)); })("openForeignKeyRecord", function DataExplorerDashboardComponent_Conditional_16_Template_mj_entity_record_detail_panel_openForeignKeyRecord_1_listener($event) { i0.ɵɵrestoreView(_r27); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenForeignKeyRecord($event)); });
|
|
773
603
|
i0.ɵɵelementEnd()();
|
|
774
604
|
} if (rf & 2) {
|
|
775
605
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
776
606
|
i0.ɵɵstyleProp("width", ctx_r1.state.detailPanelWidth, "px");
|
|
777
|
-
i0.ɵɵadvance(
|
|
607
|
+
i0.ɵɵadvance();
|
|
778
608
|
i0.ɵɵproperty("entity", ctx_r1.detailPanelEntity)("record", ctx_r1.selectedRecord);
|
|
779
609
|
} }
|
|
780
|
-
function DataExplorerDashboardComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
781
|
-
const _r36 = i0.ɵɵgetCurrentView();
|
|
782
|
-
i0.ɵɵelementStart(0, "mj-list-management-dialog", 135);
|
|
783
|
-
i0.ɵɵlistener("complete", function DataExplorerDashboardComponent_Conditional_20_Template_mj_list_management_dialog_complete_0_listener($event) { i0.ɵɵrestoreView(_r36); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onListManagementComplete($event)); })("cancel", function DataExplorerDashboardComponent_Conditional_20_Template_mj_list_management_dialog_cancel_0_listener() { i0.ɵɵrestoreView(_r36); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onListManagementCancel()); });
|
|
784
|
-
i0.ɵɵelementEnd();
|
|
785
|
-
} if (rf & 2) {
|
|
786
|
-
const ctx_r1 = i0.ɵɵnextContext();
|
|
787
|
-
i0.ɵɵproperty("config", ctx_r1.listManagementConfig)("visible", ctx_r1.showListManagementDialog);
|
|
788
|
-
} }
|
|
789
610
|
/**
|
|
790
611
|
* Data Explorer Dashboard - Power user interface for exploring data across entities
|
|
791
612
|
* Combines card-based browsing with grid views and relationship visualization
|
|
@@ -797,18 +618,13 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
797
618
|
stateService;
|
|
798
619
|
cdr;
|
|
799
620
|
recentAccessService;
|
|
800
|
-
exportService;
|
|
801
621
|
ngZone;
|
|
802
622
|
destroy$ = new Subject();
|
|
803
623
|
metadata = this.ProviderToUse;
|
|
804
624
|
/** Reference to the filter input for keyboard shortcuts */
|
|
805
625
|
filterInputRef;
|
|
806
|
-
/** Reference to the view
|
|
807
|
-
|
|
808
|
-
/** Reference to the entity viewer for refreshing after view save */
|
|
809
|
-
entityViewerRef;
|
|
810
|
-
/** Reference to the view config panel for passing filter state */
|
|
811
|
-
viewConfigPanelRef;
|
|
626
|
+
/** Reference to the view workspace (owns view CRUD + the inner data renderer) */
|
|
627
|
+
viewWorkspaceRef;
|
|
812
628
|
/**
|
|
813
629
|
* Optional filter to constrain which entities are shown in the explorer.
|
|
814
630
|
* Can filter by applicationId, schemaNames, or explicit entityNames.
|
|
@@ -872,8 +688,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
872
688
|
breadcrumbs = [];
|
|
873
689
|
// Loading state for entities
|
|
874
690
|
isLoadingEntities = true;
|
|
875
|
-
// Date field dropdown state
|
|
876
|
-
isDateFieldDropdownOpen = false;
|
|
877
691
|
// Recent records from User Record Logs
|
|
878
692
|
recentRecords = [];
|
|
879
693
|
// Favorite records from User Favorites (non-entity favorites)
|
|
@@ -882,31 +696,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
882
696
|
isLoadingRecentRecords = true;
|
|
883
697
|
// Entity filter for recent records (null = show all, string = filter by entityId)
|
|
884
698
|
recentRecordsEntityFilter = null;
|
|
885
|
-
// Export functionality
|
|
886
|
-
showExportDialog = false;
|
|
887
|
-
exportDialogConfig = null;
|
|
888
|
-
// List management
|
|
889
|
-
showListManagementDialog = false;
|
|
890
|
-
listManagementConfig = null;
|
|
891
|
-
// Selection tracking for grid - needed to enable Add to List button in header
|
|
892
|
-
selectedRecordIds = [];
|
|
893
|
-
selectedRecords = [];
|
|
894
|
-
// Quick Save Dialog state (F-001)
|
|
895
|
-
showQuickSaveDialog = false;
|
|
896
|
-
quickSaveSummary = null;
|
|
897
|
-
// Pending new-view context: carries name/description/sharing from quick save dialog
|
|
898
|
-
// to the config panel when user clicks "Customize columns, filters & sorting..."
|
|
899
|
-
pendingNewViewName = '';
|
|
900
|
-
pendingNewViewDescription = '';
|
|
901
|
-
pendingNewViewIsShared = false;
|
|
902
|
-
// Duplicate View Dialog state (F-005)
|
|
903
|
-
showDuplicateDialog = false;
|
|
904
|
-
duplicateSourceViewName = '';
|
|
905
|
-
duplicateSummary = null;
|
|
906
|
-
duplicateTargetViewId = null;
|
|
907
|
-
// Shared View Warning Dialog state (Scenario 5)
|
|
908
|
-
showSharedViewWarning = false;
|
|
909
|
-
pendingQuickSaveEvent = null;
|
|
910
699
|
async GetResourceDisplayName(data) {
|
|
911
700
|
return "Data Explorer";
|
|
912
701
|
}
|
|
@@ -1081,114 +870,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
1081
870
|
get displayIcon() {
|
|
1082
871
|
return this.contextIcon;
|
|
1083
872
|
}
|
|
1084
|
-
/**
|
|
1085
|
-
* Check if the currently selected entity has date fields available for timeline view.
|
|
1086
|
-
* Used to conditionally show the timeline toggle button in the header.
|
|
1087
|
-
*/
|
|
1088
|
-
get entityHasDateFields() {
|
|
1089
|
-
if (!this.selectedEntity)
|
|
1090
|
-
return false;
|
|
1091
|
-
return this.selectedEntity.Fields.some(f => f.TSType === EntityFieldTSType.Date);
|
|
1092
|
-
}
|
|
1093
|
-
/**
|
|
1094
|
-
* Get available date fields for the currently selected entity.
|
|
1095
|
-
* Used for the date field selector in timeline view.
|
|
1096
|
-
*/
|
|
1097
|
-
get availableDateFields() {
|
|
1098
|
-
if (!this.selectedEntity)
|
|
1099
|
-
return [];
|
|
1100
|
-
return this.selectedEntity.Fields
|
|
1101
|
-
.filter(f => f.TSType === EntityFieldTSType.Date)
|
|
1102
|
-
.sort((a, b) => {
|
|
1103
|
-
// Prioritize DefaultInView fields, then by Sequence
|
|
1104
|
-
if (a.DefaultInView && !b.DefaultInView)
|
|
1105
|
-
return -1;
|
|
1106
|
-
if (!a.DefaultInView && b.DefaultInView)
|
|
1107
|
-
return 1;
|
|
1108
|
-
return a.Sequence - b.Sequence;
|
|
1109
|
-
})
|
|
1110
|
-
.map(f => ({
|
|
1111
|
-
name: f.Name,
|
|
1112
|
-
displayName: f.DisplayNameOrName
|
|
1113
|
-
}));
|
|
1114
|
-
}
|
|
1115
|
-
/**
|
|
1116
|
-
* Get the effective timeline date field name.
|
|
1117
|
-
* Returns stored value if valid, otherwise first available date field.
|
|
1118
|
-
*/
|
|
1119
|
-
get effectiveTimelineDateField() {
|
|
1120
|
-
const available = this.availableDateFields;
|
|
1121
|
-
if (available.length === 0)
|
|
1122
|
-
return null;
|
|
1123
|
-
// Check if stored value is still valid
|
|
1124
|
-
if (this.state.timelineDateFieldName && available.some(f => f.name === this.state.timelineDateFieldName)) {
|
|
1125
|
-
return this.state.timelineDateFieldName;
|
|
1126
|
-
}
|
|
1127
|
-
// Default to first available
|
|
1128
|
-
return available[0].name;
|
|
1129
|
-
}
|
|
1130
|
-
/**
|
|
1131
|
-
* Get the display name of the effective timeline date field.
|
|
1132
|
-
*/
|
|
1133
|
-
get effectiveTimelineDateFieldDisplayName() {
|
|
1134
|
-
const fieldName = this.effectiveTimelineDateField;
|
|
1135
|
-
if (!fieldName)
|
|
1136
|
-
return '';
|
|
1137
|
-
const field = this.availableDateFields.find(f => f.name === fieldName);
|
|
1138
|
-
return field?.displayName || fieldName;
|
|
1139
|
-
}
|
|
1140
|
-
/**
|
|
1141
|
-
* Set the timeline date field.
|
|
1142
|
-
*/
|
|
1143
|
-
setTimelineDateField(fieldName) {
|
|
1144
|
-
this.state.timelineDateFieldName = fieldName;
|
|
1145
|
-
this.stateService.updateState({ timelineDateFieldName: fieldName });
|
|
1146
|
-
this.isDateFieldDropdownOpen = false;
|
|
1147
|
-
this.cdr.detectChanges();
|
|
1148
|
-
}
|
|
1149
|
-
/**
|
|
1150
|
-
* Toggle the date field dropdown open/closed.
|
|
1151
|
-
*/
|
|
1152
|
-
toggleDateFieldDropdown() {
|
|
1153
|
-
this.isDateFieldDropdownOpen = !this.isDateFieldDropdownOpen;
|
|
1154
|
-
}
|
|
1155
|
-
/**
|
|
1156
|
-
* Close the date field dropdown.
|
|
1157
|
-
*/
|
|
1158
|
-
closeDateFieldDropdown() {
|
|
1159
|
-
this.isDateFieldDropdownOpen = false;
|
|
1160
|
-
}
|
|
1161
|
-
/**
|
|
1162
|
-
* Toggle timeline orientation between vertical and horizontal.
|
|
1163
|
-
*/
|
|
1164
|
-
toggleTimelineOrientation() {
|
|
1165
|
-
const newOrientation = this.state.timelineOrientation === 'vertical' ? 'horizontal' : 'vertical';
|
|
1166
|
-
this.state.timelineOrientation = newOrientation;
|
|
1167
|
-
this.stateService.updateState({ timelineOrientation: newOrientation });
|
|
1168
|
-
this.cdr.detectChanges();
|
|
1169
|
-
}
|
|
1170
|
-
/**
|
|
1171
|
-
* Toggle timeline sort order between newest first (desc) and oldest first (asc).
|
|
1172
|
-
*/
|
|
1173
|
-
toggleTimelineSortOrder() {
|
|
1174
|
-
const newSortOrder = this.state.timelineSortOrder === 'desc' ? 'asc' : 'desc';
|
|
1175
|
-
this.state.timelineSortOrder = newSortOrder;
|
|
1176
|
-
this.stateService.updateState({ timelineSortOrder: newSortOrder });
|
|
1177
|
-
this.cdr.detectChanges();
|
|
1178
|
-
}
|
|
1179
|
-
/**
|
|
1180
|
-
* Get the current timeline configuration for the entity-viewer.
|
|
1181
|
-
*/
|
|
1182
|
-
get currentTimelineConfig() {
|
|
1183
|
-
const dateField = this.effectiveTimelineDateField;
|
|
1184
|
-
if (!dateField)
|
|
1185
|
-
return null;
|
|
1186
|
-
return {
|
|
1187
|
-
dateFieldName: dateField,
|
|
1188
|
-
orientation: this.state.timelineOrientation,
|
|
1189
|
-
sortOrder: this.state.timelineSortOrder
|
|
1190
|
-
};
|
|
1191
|
-
}
|
|
1192
873
|
/**
|
|
1193
874
|
* Configuration for mj-entity-viewer composite component
|
|
1194
875
|
* Hides the built-in header since we have a custom header in the dashboard
|
|
@@ -1196,129 +877,116 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
1196
877
|
*/
|
|
1197
878
|
viewerConfig = {
|
|
1198
879
|
showFilter: false, // We have our own filter in the dashboard header
|
|
1199
|
-
showViewModeToggle:
|
|
880
|
+
showViewModeToggle: true, // Use the viewer's metadata-driven view-type dropdown (no legacy header toggle)
|
|
1200
881
|
showRecordCount: false, // We show count in the dashboard header
|
|
1201
882
|
showPagination: true, // Show the pagination UI with "Load More" button
|
|
1202
883
|
serverSideFiltering: true, // Use RunView's UserSearchString for filtering
|
|
1203
884
|
serverSideSorting: true, // Use RunView's OrderBy for sorting
|
|
1204
885
|
height: '100%'
|
|
1205
886
|
};
|
|
1206
|
-
|
|
1207
|
-
* Current grid state (built from view entity or local state changes)
|
|
1208
|
-
* This is passed to mj-entity-viewer to control column display
|
|
1209
|
-
*/
|
|
1210
|
-
currentGridState = null;
|
|
1211
|
-
// Filter dialog state (rendered at dashboard level for full viewport width)
|
|
1212
|
-
isFilterDialogOpen = false;
|
|
1213
|
-
filterDialogFields = [];
|
|
1214
|
-
filterDialogState = createEmptyFilter();
|
|
1215
|
-
filterDialogDisabled = false;
|
|
1216
|
-
// View save state
|
|
1217
|
-
isSavingView = false;
|
|
1218
|
-
constructor(stateService, cdr, recentAccessService, exportService, ngZone) {
|
|
887
|
+
constructor(stateService, cdr, recentAccessService, ngZone) {
|
|
1219
888
|
super();
|
|
1220
889
|
this.stateService = stateService;
|
|
1221
890
|
this.cdr = cdr;
|
|
1222
891
|
this.recentAccessService = recentAccessService;
|
|
1223
|
-
this.exportService = exportService;
|
|
1224
892
|
this.ngZone = ngZone;
|
|
1225
893
|
this.state = this.stateService.CurrentState;
|
|
1226
894
|
}
|
|
1227
895
|
async ngOnInit() {
|
|
1228
896
|
super.ngOnInit();
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
else if (this.deepLink) {
|
|
1257
|
-
await this.applyDeepLink(this.deepLink);
|
|
1258
|
-
}
|
|
1259
|
-
// Subscribe to state changes
|
|
1260
|
-
this.stateService.State
|
|
1261
|
-
.pipe(takeUntil(this.destroy$))
|
|
1262
|
-
.subscribe(state => {
|
|
1263
|
-
const entityChanged = state.selectedEntityName !== this.state.selectedEntityName;
|
|
1264
|
-
this.state = state;
|
|
1265
|
-
// Self-correct map mode: if a URL-sourced mode is pending and state
|
|
1266
|
-
// has diverged (e.g., reset to 'point' by some init step), re-apply it.
|
|
1267
|
-
// _pendingMapMode stays alive until the map component emits real state
|
|
1268
|
-
// via onMapDisplayStateChange (user interaction), NOT on first state match.
|
|
1269
|
-
if (this._pendingMapMode && state.mapRenderMode !== this._pendingMapMode) {
|
|
1270
|
-
const mode = this._pendingMapMode;
|
|
1271
|
-
this.stateService.updateState({ mapRenderMode: mode });
|
|
1272
|
-
return; // Let the next subscription fire handle the rest
|
|
897
|
+
try {
|
|
898
|
+
// Ensure UserInfoEngine is configured before we try to access user settings
|
|
899
|
+
// This prevents race conditions where we try to load default view settings
|
|
900
|
+
// before the user settings have been loaded from the server
|
|
901
|
+
await UserInfoEngine.Instance.Config(false);
|
|
902
|
+
// Read initial query params — prefer params forwarded from the resource wrapper
|
|
903
|
+
// (which has Data.Configuration.queryParams from the shell), then fall back to
|
|
904
|
+
// this component's own GetQueryParams() for cases where the dashboard is used standalone.
|
|
905
|
+
const wrapperParams = this.initialQueryParams && Object.keys(this.initialQueryParams).length > 0
|
|
906
|
+
? this.initialQueryParams
|
|
907
|
+
: null;
|
|
908
|
+
const ownParams = this.GetQueryParams();
|
|
909
|
+
const rawParams = wrapperParams || (Object.keys(ownParams).length > 0 ? ownParams : {});
|
|
910
|
+
const urlState = this.buildDeepLinkFromParams(rawParams);
|
|
911
|
+
// Set context for state service (enables context-specific settings)
|
|
912
|
+
this.stateService.Provider = this.ProviderToUse;
|
|
913
|
+
await this.stateService.setContext(this.entityFilter);
|
|
914
|
+
this.state = this.stateService.CurrentState;
|
|
915
|
+
// User search text starts empty - it's separate from smart filter
|
|
916
|
+
this.liveFilterText = '';
|
|
917
|
+
this.debouncedFilterText = '';
|
|
918
|
+
// Load available entities (async to support applicationId filter)
|
|
919
|
+
// Pass urlState so we don't restore persisted entity if URL specifies one
|
|
920
|
+
await this.loadEntities(urlState);
|
|
921
|
+
// Apply URL state after entities are loaded
|
|
922
|
+
if (urlState) {
|
|
923
|
+
await this.applyUrlState(urlState);
|
|
1273
924
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
this.liveFilterText = '';
|
|
1277
|
-
this.debouncedFilterText = '';
|
|
1278
|
-
this.emitDisplayName();
|
|
925
|
+
else if (this.deepLink) {
|
|
926
|
+
await this.applyDeepLink(this.deepLink);
|
|
1279
927
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
928
|
+
// Subscribe to state changes
|
|
929
|
+
this.stateService.State
|
|
930
|
+
.pipe(takeUntil(this.destroy$))
|
|
931
|
+
.subscribe(state => {
|
|
932
|
+
const entityChanged = state.selectedEntityName !== this.state.selectedEntityName;
|
|
933
|
+
this.state = state;
|
|
934
|
+
// When entity changes, clear user search text and update title
|
|
935
|
+
if (entityChanged) {
|
|
936
|
+
this.liveFilterText = '';
|
|
937
|
+
this.debouncedFilterText = '';
|
|
938
|
+
this.emitDisplayName();
|
|
939
|
+
}
|
|
940
|
+
this.onStateChanged();
|
|
941
|
+
// Update URL query params to reflect current state (for deep linking)
|
|
942
|
+
this.pushCurrentStateToUrl();
|
|
943
|
+
this.cdr.detectChanges();
|
|
944
|
+
});
|
|
945
|
+
// Subscribe to breadcrumb changes
|
|
946
|
+
this.stateService.Breadcrumbs
|
|
947
|
+
.pipe(takeUntil(this.destroy$))
|
|
948
|
+
.subscribe(breadcrumbs => {
|
|
949
|
+
this.breadcrumbs = breadcrumbs;
|
|
950
|
+
this.cdr.detectChanges();
|
|
951
|
+
});
|
|
952
|
+
// Setup debounced filter - 500ms delay allows comfortable typing before triggering search
|
|
953
|
+
// IMPORTANT: Do NOT call setSmartFilterPrompt here. Updating the state service triggers
|
|
954
|
+
// URL updates (via pushCurrentStateToUrl → UpdateQueryParams), which in turn can trigger
|
|
955
|
+
// OnQueryParamsChanged, which would clear the filter text. The debouncedFilterText flows
|
|
956
|
+
// directly to the entity-viewer via [filterText] binding — no state service involvement needed.
|
|
957
|
+
this.filterInput$
|
|
958
|
+
.pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$))
|
|
959
|
+
.subscribe(filterText => {
|
|
960
|
+
this.debouncedFilterText = filterText;
|
|
961
|
+
this.cdr.detectChanges();
|
|
962
|
+
});
|
|
963
|
+
// Subscribe to recent records changes
|
|
964
|
+
this.stateService.RecentRecords
|
|
965
|
+
.pipe(takeUntil(this.destroy$))
|
|
966
|
+
.subscribe(records => {
|
|
967
|
+
this.recentRecords = records;
|
|
968
|
+
this.isLoadingRecentRecords = false;
|
|
969
|
+
this.cdr.detectChanges();
|
|
970
|
+
});
|
|
971
|
+
// Subscribe to favorite records changes
|
|
972
|
+
this.stateService.FavoriteRecords
|
|
973
|
+
.pipe(takeUntil(this.destroy$))
|
|
974
|
+
.subscribe(records => {
|
|
975
|
+
this.favoriteRecords = records;
|
|
976
|
+
this.cdr.detectChanges();
|
|
977
|
+
});
|
|
978
|
+
// Push initial state to URL (covers deepLink and persisted state)
|
|
1282
979
|
this.pushCurrentStateToUrl();
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
this
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
// IMPORTANT: Do NOT call setSmartFilterPrompt here. Updating the state service triggers
|
|
1294
|
-
// URL updates (via pushCurrentStateToUrl → UpdateQueryParams), which in turn can trigger
|
|
1295
|
-
// OnQueryParamsChanged, which would clear the filter text. The debouncedFilterText flows
|
|
1296
|
-
// directly to the entity-viewer via [filterText] binding — no state service involvement needed.
|
|
1297
|
-
this.filterInput$
|
|
1298
|
-
.pipe(debounceTime(500), distinctUntilChanged(), takeUntil(this.destroy$))
|
|
1299
|
-
.subscribe(filterText => {
|
|
1300
|
-
this.debouncedFilterText = filterText;
|
|
1301
|
-
this.cdr.detectChanges();
|
|
1302
|
-
});
|
|
1303
|
-
// Subscribe to recent records changes
|
|
1304
|
-
this.stateService.RecentRecords
|
|
1305
|
-
.pipe(takeUntil(this.destroy$))
|
|
1306
|
-
.subscribe(records => {
|
|
1307
|
-
this.recentRecords = records;
|
|
1308
|
-
this.isLoadingRecentRecords = false;
|
|
1309
|
-
this.cdr.detectChanges();
|
|
1310
|
-
});
|
|
1311
|
-
// Subscribe to favorite records changes
|
|
1312
|
-
this.stateService.FavoriteRecords
|
|
1313
|
-
.pipe(takeUntil(this.destroy$))
|
|
1314
|
-
.subscribe(records => {
|
|
1315
|
-
this.favoriteRecords = records;
|
|
1316
|
-
this.cdr.detectChanges();
|
|
1317
|
-
});
|
|
1318
|
-
// Push initial state to URL (covers deepLink and persisted state)
|
|
1319
|
-
this.pushCurrentStateToUrl();
|
|
1320
|
-
// Notify that loading is complete (for resource wrapper integration)
|
|
1321
|
-
this.NotifyLoadComplete();
|
|
980
|
+
}
|
|
981
|
+
catch (err) {
|
|
982
|
+
// Never let a setup failure hang the app loading screen — log it and still signal completion.
|
|
983
|
+
console.error('[DataExplorer] ngOnInit setup failed (signaling load complete anyway):', err);
|
|
984
|
+
}
|
|
985
|
+
finally {
|
|
986
|
+
// ALWAYS notify load complete — the loading screen waits on this; a thrown/awaited error before
|
|
987
|
+
// it would otherwise hang the screen forever on a direct-URL (deep-link) refresh.
|
|
988
|
+
this.NotifyLoadComplete();
|
|
989
|
+
}
|
|
1322
990
|
}
|
|
1323
991
|
/**
|
|
1324
992
|
* Handle keyboard shortcuts
|
|
@@ -1346,41 +1014,31 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
1346
1014
|
this.focusFilterInput();
|
|
1347
1015
|
return;
|
|
1348
1016
|
}
|
|
1349
|
-
// View management shortcuts (only when an entity is selected)
|
|
1017
|
+
// View management shortcuts (only when an entity is selected). These delegate to the
|
|
1018
|
+
// view workspace, which now owns the full saved-view lifecycle.
|
|
1350
1019
|
if (this.selectedEntity && (event.metaKey || event.ctrlKey)) {
|
|
1351
1020
|
// Ctrl+S / Cmd+S: Save current view
|
|
1352
1021
|
if (event.key === 's' && !event.shiftKey) {
|
|
1353
1022
|
event.preventDefault();
|
|
1354
|
-
this.onQuickSaveRequested(false);
|
|
1023
|
+
this.viewWorkspaceRef?.onQuickSaveRequested(false);
|
|
1355
1024
|
return;
|
|
1356
1025
|
}
|
|
1357
1026
|
// Ctrl+Shift+S / Cmd+Shift+S: Save as new view
|
|
1358
1027
|
if (event.key === 'S' || (event.key === 's' && event.shiftKey)) {
|
|
1359
1028
|
event.preventDefault();
|
|
1360
|
-
this.onQuickSaveRequested(true);
|
|
1029
|
+
this.viewWorkspaceRef?.onQuickSaveRequested(true);
|
|
1361
1030
|
return;
|
|
1362
1031
|
}
|
|
1363
|
-
// Ctrl
|
|
1364
|
-
if ((event.key === 'V' || (event.key === 'v' && event.shiftKey))) {
|
|
1365
|
-
event.preventDefault();
|
|
1366
|
-
this.viewSelectorRef?.toggleDropdown();
|
|
1367
|
-
return;
|
|
1368
|
-
}
|
|
1369
|
-
// Ctrl+, / Cmd+,: Toggle config panel
|
|
1032
|
+
// Ctrl+, / Cmd+,: Open config panel
|
|
1370
1033
|
if (event.key === ',') {
|
|
1371
1034
|
event.preventDefault();
|
|
1372
|
-
|
|
1373
|
-
this.onCloseViewConfigPanel();
|
|
1374
|
-
}
|
|
1375
|
-
else {
|
|
1376
|
-
this.onConfigureViewRequested();
|
|
1377
|
-
}
|
|
1035
|
+
this.viewWorkspaceRef?.onConfigureViewRequested();
|
|
1378
1036
|
return;
|
|
1379
1037
|
}
|
|
1380
1038
|
// Ctrl+Z / Cmd+Z: Revert unsaved changes (only when modified)
|
|
1381
1039
|
if (event.key === 'z' && !event.shiftKey && this.state.viewModified) {
|
|
1382
1040
|
event.preventDefault();
|
|
1383
|
-
this.onRevertView();
|
|
1041
|
+
void this.viewWorkspaceRef?.onRevertView();
|
|
1384
1042
|
return;
|
|
1385
1043
|
}
|
|
1386
1044
|
}
|
|
@@ -1451,932 +1109,157 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
1451
1109
|
this.isLoadingEntities = false;
|
|
1452
1110
|
this.cdr.detectChanges();
|
|
1453
1111
|
});
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
/**
|
|
1457
|
-
* Load entity IDs associated with a specific application
|
|
1458
|
-
*/
|
|
1459
|
-
async loadApplicationEntityIds(applicationId) {
|
|
1460
|
-
this.applicationEntityIds.clear();
|
|
1461
|
-
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
1462
|
-
const result = await rv.RunView({
|
|
1463
|
-
EntityName: 'MJ: Application Entities',
|
|
1464
|
-
ExtraFilter: `ApplicationID = '${applicationId}'`,
|
|
1465
|
-
ResultType: 'entity_object'
|
|
1466
|
-
});
|
|
1467
|
-
if (result.Success && result.Results) {
|
|
1468
|
-
for (const appEntity of result.Results) {
|
|
1469
|
-
this.applicationEntityIds.add(appEntity.EntityID);
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
/**
|
|
1474
|
-
* Apply the configured filter to the entity list
|
|
1475
|
-
*/
|
|
1476
|
-
applyEntityFilter(entities) {
|
|
1477
|
-
if (!this.entityFilter) {
|
|
1478
|
-
return entities;
|
|
1479
|
-
}
|
|
1480
|
-
return entities.filter(entity => {
|
|
1481
|
-
// Filter by application (via ApplicationEntities)
|
|
1482
|
-
if (this.entityFilter.applicationId) {
|
|
1483
|
-
if (!this.applicationEntityIds.has(entity.ID)) {
|
|
1484
|
-
return false;
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
// Filter by schema names
|
|
1488
|
-
if (this.entityFilter.schemaNames && this.entityFilter.schemaNames.length > 0) {
|
|
1489
|
-
if (!this.entityFilter.schemaNames.includes(entity.SchemaName)) {
|
|
1490
|
-
return false;
|
|
1491
|
-
}
|
|
1492
|
-
}
|
|
1493
|
-
// Filter by explicit entity names
|
|
1494
|
-
if (this.entityFilter.entityNames && this.entityFilter.entityNames.length > 0) {
|
|
1495
|
-
if (!this.entityFilter.entityNames.includes(entity.Name)) {
|
|
1496
|
-
return false;
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
// Filter out system entities unless explicitly included
|
|
1500
|
-
if (!this.entityFilter.includeSystemEntities) {
|
|
1501
|
-
// Skip entities with names starting with __ (MJ system entities)
|
|
1502
|
-
if (entity.Name.startsWith('__')) {
|
|
1503
|
-
return false;
|
|
1504
|
-
}
|
|
1505
|
-
// Could add more system schema checks here if needed
|
|
1506
|
-
}
|
|
1507
|
-
return true;
|
|
1508
|
-
});
|
|
1509
|
-
}
|
|
1510
|
-
/**
|
|
1511
|
-
* Handle entity selection from navigation panel or home screen
|
|
1512
|
-
*/
|
|
1513
|
-
onEntitySelected(entity) {
|
|
1514
|
-
// Ensure any pending grid state changes are saved before switching entities
|
|
1515
|
-
// This ensures column resizes/reorders are saved to the current entity's view before switching
|
|
1516
|
-
this.entityViewerRef?.EnsurePendingChangesSaved();
|
|
1517
|
-
this.resetRecordCounts();
|
|
1518
|
-
// Clear the previous entity's view — it belongs to the old entity and its sort/filter
|
|
1519
|
-
// state would leak into the new entity's query (e.g., ORDER BY FirstName on Groups)
|
|
1520
|
-
this.selectedViewEntity = null;
|
|
1521
|
-
this.selectedEntity = entity;
|
|
1522
|
-
this.reconcileViewModeForEntity(entity);
|
|
1523
|
-
// Load user's saved default grid state for this entity (if any)
|
|
1524
|
-
// This ensures formatting and column settings persist across sessions
|
|
1525
|
-
this.currentGridState = this.loadUserDefaultGridState();
|
|
1526
|
-
this.stateService.selectEntity(entity.Name);
|
|
1527
|
-
// Track entity access for recent entities
|
|
1528
|
-
this.stateService.trackEntityAccess(entity.Name, entity.ID);
|
|
1529
|
-
// mj-entity-viewer will automatically load data when entity changes
|
|
1530
|
-
}
|
|
1531
|
-
/**
|
|
1532
|
-
* Handle state changes from external sources
|
|
1533
|
-
*/
|
|
1534
|
-
onStateChanged() {
|
|
1535
|
-
if (this.state.selectedEntityName !== this.selectedEntity?.Name) {
|
|
1536
|
-
this.resetRecordCounts();
|
|
1537
|
-
this.selectedEntity = this.entities.find(e => e.Name === this.state.selectedEntityName) || null;
|
|
1538
|
-
this.reconcileViewModeForEntity(this.selectedEntity);
|
|
1539
|
-
// Load user's saved default grid state for this entity (if any)
|
|
1540
|
-
this.currentGridState = this.loadUserDefaultGridState();
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
/**
|
|
1544
|
-
* Reset viewMode to 'grid' if the current mode isn't supported by the given entity
|
|
1545
|
-
* (e.g., switching to an entity without geocoding while viewMode is 'map').
|
|
1546
|
-
*/
|
|
1547
|
-
reconcileViewModeForEntity(entity) {
|
|
1548
|
-
if (!entity)
|
|
1549
|
-
return;
|
|
1550
|
-
const mode = this.state.viewMode;
|
|
1551
|
-
const hasDateFields = entity.Fields.some(f => f.TSType === EntityFieldTSType.Date);
|
|
1552
|
-
const modeUnsupported = (mode === 'map' && !entity.SupportsGeoCoding) ||
|
|
1553
|
-
(mode === 'timeline' && !hasDateFields);
|
|
1554
|
-
if (modeUnsupported) {
|
|
1555
|
-
this.stateService.setViewMode('grid');
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
/**
|
|
1559
|
-
* Reset record counts when entity changes.
|
|
1560
|
-
* The actual counts will be updated when mj-entity-viewer emits dataLoaded event.
|
|
1561
|
-
*/
|
|
1562
|
-
resetRecordCounts() {
|
|
1563
|
-
this.totalRecordCount = 0;
|
|
1564
|
-
this.filteredRecordCount = 0;
|
|
1565
|
-
}
|
|
1566
|
-
// ========================================
|
|
1567
|
-
// VIEW MANAGEMENT
|
|
1568
|
-
// ========================================
|
|
1569
|
-
/**
|
|
1570
|
-
* Handle view selection from view selector dropdown
|
|
1571
|
-
*/
|
|
1572
|
-
onViewSelected(event) {
|
|
1573
|
-
// Ensure any pending grid state changes are saved before switching views
|
|
1574
|
-
// This ensures column resizes/reorders are saved to the current view before switching
|
|
1575
|
-
this.entityViewerRef?.EnsurePendingChangesSaved();
|
|
1576
|
-
this.selectedViewEntity = event.view;
|
|
1577
|
-
this.stateService.selectView(event.viewId);
|
|
1578
|
-
// When a view is selected, apply its configuration
|
|
1579
|
-
if (event.view) {
|
|
1580
|
-
// Parse and apply the view's grid state
|
|
1581
|
-
this.currentGridState = this.parseViewGridState(event.view);
|
|
1582
|
-
// Apply the view's filter - for Smart Filter views, use SmartFilterPrompt
|
|
1583
|
-
// For regular filter views, the WhereClause is applied in the entity-viewer
|
|
1584
|
-
if (event.view.SmartFilterEnabled && event.view.SmartFilterPrompt) {
|
|
1585
|
-
this.stateService.setSmartFilterPrompt(event.view.SmartFilterPrompt);
|
|
1586
|
-
}
|
|
1587
|
-
else {
|
|
1588
|
-
// Clear the smart filter when switching to a view with regular filters
|
|
1589
|
-
this.stateService.setSmartFilterPrompt('');
|
|
1590
|
-
}
|
|
1591
|
-
// Always clear user search text when switching views - smart filter is separate
|
|
1592
|
-
this.liveFilterText = '';
|
|
1593
|
-
this.debouncedFilterText = '';
|
|
1594
|
-
}
|
|
1595
|
-
else {
|
|
1596
|
-
// Switching to default view - load user's saved defaults from UserInfoEngine
|
|
1597
|
-
this.currentGridState = this.loadUserDefaultGridState();
|
|
1598
|
-
this.stateService.setSmartFilterPrompt('');
|
|
1599
|
-
this.liveFilterText = '';
|
|
1600
|
-
this.debouncedFilterText = '';
|
|
1601
|
-
}
|
|
1602
|
-
// detectChanges pushes the new bindings to entity-viewer; its viewEntity setter
|
|
1603
|
-
// already calls deferReload() so no explicit refresh() is needed.
|
|
1604
|
-
this.cdr.detectChanges();
|
|
1605
|
-
}
|
|
1606
|
-
/**
|
|
1607
|
-
* Load user's saved default grid state from UserInfoEngine
|
|
1608
|
-
* Returns null if no saved state exists
|
|
1609
|
-
*/
|
|
1610
|
-
loadUserDefaultGridState() {
|
|
1611
|
-
if (!this.selectedEntity)
|
|
1612
|
-
return null;
|
|
1613
|
-
try {
|
|
1614
|
-
const settingKey = `default-view-setting/${this.selectedEntity.Name}`;
|
|
1615
|
-
const savedState = UserInfoEngine.Instance.GetSetting(settingKey);
|
|
1616
|
-
if (savedState) {
|
|
1617
|
-
const gridState = JSON.parse(savedState);
|
|
1618
|
-
if (gridState && Array.isArray(gridState.columnSettings)) {
|
|
1619
|
-
// Validate columns and sorts against current entity to prevent stale
|
|
1620
|
-
// fields from a previously viewed entity leaking into the query
|
|
1621
|
-
const validColumns = gridState.columnSettings.filter((col) => this.selectedEntity.Fields.some(f => f.Name === col.Name));
|
|
1622
|
-
const validSorts = (gridState.sortSettings || []).filter((s) => this.selectedEntity.Fields.some(f => f.Name === s.field));
|
|
1623
|
-
if (validColumns.length > 0) {
|
|
1624
|
-
return {
|
|
1625
|
-
columnSettings: validColumns,
|
|
1626
|
-
sortSettings: validSorts
|
|
1627
|
-
};
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
catch (error) {
|
|
1633
|
-
console.warn('[DataExplorer] Failed to load user default grid state:', error);
|
|
1634
|
-
}
|
|
1635
|
-
return null;
|
|
1636
|
-
}
|
|
1637
|
-
/**
|
|
1638
|
-
* Parse GridState JSON from a UserView entity
|
|
1639
|
-
* Returns null if no valid GridState is present
|
|
1640
|
-
*/
|
|
1641
|
-
parseViewGridState(view) {
|
|
1642
|
-
if (!view.GridState) {
|
|
1643
|
-
return null;
|
|
1644
|
-
}
|
|
1645
|
-
try {
|
|
1646
|
-
const parsed = view.GridStateObject;
|
|
1647
|
-
// Validate structure - expect columnSettings array
|
|
1648
|
-
if (parsed && Array.isArray(parsed.columnSettings)) {
|
|
1649
|
-
// Validate columns and sorts against current entity to prevent stale
|
|
1650
|
-
// fields from a previously viewed entity leaking into the query
|
|
1651
|
-
const validColumns = this.selectedEntity
|
|
1652
|
-
? parsed.columnSettings.filter((col) => this.selectedEntity.Fields.some(f => f.Name === col.Name))
|
|
1653
|
-
: parsed.columnSettings;
|
|
1654
|
-
const validSorts = this.selectedEntity
|
|
1655
|
-
? (parsed.sortSettings || []).filter((s) => this.selectedEntity.Fields.some(f => f.Name === s.field))
|
|
1656
|
-
: parsed.sortSettings || [];
|
|
1657
|
-
if (validColumns.length > 0) {
|
|
1658
|
-
return {
|
|
1659
|
-
columnSettings: validColumns,
|
|
1660
|
-
sortSettings: validSorts,
|
|
1661
|
-
aggregates: parsed.aggregates || undefined
|
|
1662
|
-
};
|
|
1663
|
-
}
|
|
1664
|
-
return null;
|
|
1665
|
-
}
|
|
1666
|
-
return null;
|
|
1667
|
-
}
|
|
1668
|
-
catch (error) {
|
|
1669
|
-
// BUG-010: Warn user about parse failure instead of silently returning null
|
|
1670
|
-
console.warn('[DataExplorer] Failed to parse GridState:', error);
|
|
1671
|
-
this.showNotification('Warning: Could not parse view grid configuration', 'info', 3000);
|
|
1672
|
-
return null;
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
/**
|
|
1676
|
-
* Handle grid state changes from entity-viewer (column resize, reorder, etc.)
|
|
1677
|
-
* Updates the local currentGridState and marks view as modified
|
|
1678
|
-
*/
|
|
1679
|
-
onGridStateChanged(event) {
|
|
1680
|
-
this.currentGridState = event.gridState;
|
|
1681
|
-
// Mark view as modified if we have a selected view
|
|
1682
|
-
if (this.state.selectedViewId) {
|
|
1683
|
-
this.stateService.setViewModified(true);
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
/**
|
|
1687
|
-
* Whether the config panel should default to save-as-new mode (BUG-011)
|
|
1688
|
-
*/
|
|
1689
|
-
defaultSaveAsNew = false;
|
|
1690
|
-
/**
|
|
1691
|
-
* Handle save view request from view selector (BUG-011: forward saveAsNew intent)
|
|
1692
|
-
*/
|
|
1693
|
-
onSaveViewRequested(event) {
|
|
1694
|
-
this.defaultSaveAsNew = event.saveAsNew || false;
|
|
1695
|
-
this.stateService.openViewConfigPanel();
|
|
1696
|
-
}
|
|
1697
|
-
/**
|
|
1698
|
-
* Handle manage views request - opens view browser
|
|
1699
|
-
*/
|
|
1700
|
-
onManageViewsRequested() {
|
|
1701
|
-
// TODO: Implement navigation to view management
|
|
1702
|
-
}
|
|
1703
|
-
/**
|
|
1704
|
-
* Handle open in tab request - opens the view as a ViewResource in a new tab
|
|
1705
|
-
*/
|
|
1706
|
-
onOpenInTabRequested(viewId) {
|
|
1707
|
-
// Get the view name from the component's selectedViewEntity (set when view is selected)
|
|
1708
|
-
const viewName = this.selectedViewEntity?.Name || 'View';
|
|
1709
|
-
// Use NavigationService to open as a proper ViewResource (not entity record)
|
|
1710
|
-
this.navigationService.OpenView(viewId, viewName, { forceNewTab: true });
|
|
1711
|
-
}
|
|
1712
|
-
/**
|
|
1713
|
-
* Handle configure view request - opens the configuration panel
|
|
1714
|
-
*/
|
|
1715
|
-
onConfigureViewRequested() {
|
|
1716
|
-
this.stateService.openViewConfigPanel();
|
|
1717
|
-
}
|
|
1718
|
-
/**
|
|
1719
|
-
* Close the view configuration panel
|
|
1720
|
-
*/
|
|
1721
|
-
onCloseViewConfigPanel() {
|
|
1722
|
-
this.stateService.closeViewConfigPanel();
|
|
1723
|
-
this.clearPendingNewViewState();
|
|
1724
|
-
}
|
|
1725
|
-
clearPendingNewViewState() {
|
|
1726
|
-
this.pendingNewViewName = '';
|
|
1727
|
-
this.pendingNewViewDescription = '';
|
|
1728
|
-
this.pendingNewViewIsShared = false;
|
|
1729
|
-
this.defaultSaveAsNew = false;
|
|
1730
|
-
}
|
|
1731
|
-
// ========================================
|
|
1732
|
-
// FILTER DIALOG (at dashboard level for full width)
|
|
1733
|
-
// ========================================
|
|
1734
|
-
/**
|
|
1735
|
-
* Handle request to open filter dialog from view config panel
|
|
1736
|
-
* The dialog is rendered at dashboard level to allow full viewport width
|
|
1737
|
-
*/
|
|
1738
|
-
onOpenFilterDialogRequest(event) {
|
|
1739
|
-
this.filterDialogState = event.filterState;
|
|
1740
|
-
this.filterDialogFields = event.filterFields;
|
|
1741
|
-
this.filterDialogDisabled = !this.viewConfigPanelRef?.canEdit;
|
|
1742
|
-
this.isFilterDialogOpen = true;
|
|
1743
|
-
this.cdr.detectChanges();
|
|
1744
|
-
}
|
|
1745
|
-
/**
|
|
1746
|
-
* Close the filter dialog
|
|
1747
|
-
*/
|
|
1748
|
-
onCloseFilterDialog() {
|
|
1749
|
-
this.isFilterDialogOpen = false;
|
|
1750
|
-
this.cdr.detectChanges();
|
|
1751
|
-
}
|
|
1752
|
-
/**
|
|
1753
|
-
* Handle filter applied from dialog - pass back to view config panel
|
|
1754
|
-
*/
|
|
1755
|
-
onFilterApplied(filter) {
|
|
1756
|
-
this.filterDialogState = filter;
|
|
1757
|
-
this.isFilterDialogOpen = false;
|
|
1758
|
-
// The view config panel will pick up the new filter state via input binding
|
|
1759
|
-
this.cdr.detectChanges();
|
|
1760
|
-
}
|
|
1761
|
-
/**
|
|
1762
|
-
* Handle save view from config panel
|
|
1763
|
-
* BUG-001: Panel only closes on success (not on failure)
|
|
1764
|
-
* BUG-002: Shows success/error notifications
|
|
1765
|
-
* BUG-008: Consistent filter handling for both create and update paths
|
|
1766
|
-
*/
|
|
1767
|
-
async onSaveView(event) {
|
|
1768
|
-
if (!this.selectedEntity)
|
|
1769
|
-
return;
|
|
1770
|
-
this.isSavingView = true;
|
|
1771
|
-
this.cdr.detectChanges();
|
|
1772
|
-
try {
|
|
1773
|
-
const md = this.ProviderToUse;
|
|
1774
|
-
// Build GridState in Kendo-compatible format
|
|
1775
|
-
const gridState = this.buildGridState(event);
|
|
1776
|
-
// Build SortState in Kendo-compatible format
|
|
1777
|
-
const sortState = this.buildSortState(event);
|
|
1778
|
-
// BUG-008: Consistent filter state for both paths
|
|
1779
|
-
const filterStateJson = event.filterState
|
|
1780
|
-
? JSON.stringify(event.filterState)
|
|
1781
|
-
: JSON.stringify({ logic: 'and', filters: [] });
|
|
1782
|
-
if (event.saveAsNew || !this.selectedViewEntity) {
|
|
1783
|
-
// Create new view
|
|
1784
|
-
const newView = await md.GetEntityObject('MJ: User Views');
|
|
1785
|
-
newView.Name = event.name || 'Custom';
|
|
1786
|
-
newView.Description = event.description;
|
|
1787
|
-
newView.EntityID = this.selectedEntity.ID;
|
|
1788
|
-
newView.UserID = md.CurrentUser.ID;
|
|
1789
|
-
newView.IsShared = event.isShared;
|
|
1790
|
-
newView.IsDefault = false;
|
|
1791
|
-
// Set state via typed object setters
|
|
1792
|
-
if (gridState) {
|
|
1793
|
-
newView.GridStateObject = gridState;
|
|
1794
|
-
}
|
|
1795
|
-
if (sortState) {
|
|
1796
|
-
newView.SortStateObject = sortState;
|
|
1797
|
-
}
|
|
1798
|
-
// Set Smart Filter settings
|
|
1799
|
-
newView.SmartFilterEnabled = event.smartFilterEnabled;
|
|
1800
|
-
newView.SmartFilterPrompt = event.smartFilterPrompt;
|
|
1801
|
-
// BUG-008: Always set FilterState consistently (raw string — Kendo CompositeFilterDescriptor shape)
|
|
1802
|
-
newView.FilterState = filterStateJson;
|
|
1803
|
-
const saved = await newView.Save();
|
|
1804
|
-
if (saved) {
|
|
1805
|
-
this.selectedViewEntity = newView;
|
|
1806
|
-
this.stateService.selectView(newView.ID);
|
|
1807
|
-
this.stateService.setViewModified(false);
|
|
1808
|
-
this.currentGridState = this.parseViewGridState(newView);
|
|
1809
|
-
this.cdr.detectChanges();
|
|
1810
|
-
await this.viewSelectorRef?.loadViews();
|
|
1811
|
-
// BUG-007: Await the refresh
|
|
1812
|
-
await this.entityViewerRef?.loadData();
|
|
1813
|
-
// BUG-001: Only close panel on success
|
|
1814
|
-
this.stateService.closeViewConfigPanel();
|
|
1815
|
-
// BUG-002: Show success notification
|
|
1816
|
-
this.showNotification(`View "${newView.Name}" created successfully`, 'success', 2500);
|
|
1817
|
-
this.clearPendingNewViewState();
|
|
1818
|
-
}
|
|
1819
|
-
else {
|
|
1820
|
-
// BUG-001: Panel stays open on failure
|
|
1821
|
-
// BUG-002: Show error notification
|
|
1822
|
-
this.showNotification('Failed to create view', 'error', 3500);
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
else {
|
|
1826
|
-
// Update existing view
|
|
1827
|
-
this.selectedViewEntity.Name = event.name;
|
|
1828
|
-
this.selectedViewEntity.Description = event.description;
|
|
1829
|
-
this.selectedViewEntity.IsShared = event.isShared;
|
|
1830
|
-
// Update state via typed object setters
|
|
1831
|
-
if (gridState) {
|
|
1832
|
-
this.selectedViewEntity.GridStateObject = gridState;
|
|
1833
|
-
}
|
|
1834
|
-
if (sortState) {
|
|
1835
|
-
this.selectedViewEntity.SortStateObject = sortState;
|
|
1836
|
-
}
|
|
1837
|
-
// Update Smart Filter settings
|
|
1838
|
-
this.selectedViewEntity.SmartFilterEnabled = event.smartFilterEnabled;
|
|
1839
|
-
this.selectedViewEntity.SmartFilterPrompt = event.smartFilterPrompt;
|
|
1840
|
-
// BUG-008: Always set FilterState consistently (raw string — Kendo CompositeFilterDescriptor shape)
|
|
1841
|
-
this.selectedViewEntity.FilterState = filterStateJson;
|
|
1842
|
-
const saved = await this.selectedViewEntity.Save();
|
|
1843
|
-
if (saved) {
|
|
1844
|
-
this.stateService.setViewModified(false);
|
|
1845
|
-
this.currentGridState = this.parseViewGridState(this.selectedViewEntity);
|
|
1846
|
-
this.cdr.detectChanges();
|
|
1847
|
-
await this.viewSelectorRef?.loadViews();
|
|
1848
|
-
// BUG-007: Await the refresh
|
|
1849
|
-
await this.entityViewerRef?.loadData();
|
|
1850
|
-
// BUG-001: Only close panel on success
|
|
1851
|
-
this.stateService.closeViewConfigPanel();
|
|
1852
|
-
// BUG-002: Show success notification
|
|
1853
|
-
this.showNotification(`View "${event.name}" updated successfully`, 'success', 2500);
|
|
1854
|
-
}
|
|
1855
|
-
else {
|
|
1856
|
-
// BUG-001: Panel stays open on failure
|
|
1857
|
-
// BUG-002: Show error notification
|
|
1858
|
-
this.showNotification('Failed to update view', 'error', 3500);
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
this.cdr.detectChanges();
|
|
1862
|
-
}
|
|
1863
|
-
catch (error) {
|
|
1864
|
-
console.error('[DataExplorer] Error saving view:', error);
|
|
1865
|
-
// BUG-002: Show error notification with details
|
|
1866
|
-
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
1867
|
-
this.showNotification(`Failed to save view: ${errorMsg}`, 'error', 4000);
|
|
1868
|
-
}
|
|
1869
|
-
finally {
|
|
1870
|
-
this.ngZone.run(() => {
|
|
1871
|
-
this.isSavingView = false;
|
|
1872
|
-
this.cdr.detectChanges();
|
|
1873
|
-
});
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
/**
|
|
1877
|
-
* Handle saving default view settings to user settings
|
|
1878
|
-
* Used for dynamic/default views that persist to MJ: User Settings
|
|
1879
|
-
*/
|
|
1880
|
-
async onSaveDefaultViewSettings(event) {
|
|
1881
|
-
if (!this.selectedEntity)
|
|
1882
|
-
return;
|
|
1883
|
-
this.isSavingView = true;
|
|
1884
|
-
this.cdr.detectChanges();
|
|
1885
|
-
try {
|
|
1886
|
-
// Build GridState from the event
|
|
1887
|
-
const gridState = this.buildGridState(event);
|
|
1888
|
-
if (gridState) {
|
|
1889
|
-
// Build sort settings if present - prefer sortItems (multi-sort)
|
|
1890
|
-
if (event.sortItems && event.sortItems.length > 0) {
|
|
1891
|
-
gridState.sortSettings = event.sortItems.map(item => ({
|
|
1892
|
-
field: item.field,
|
|
1893
|
-
dir: item.direction
|
|
1894
|
-
}));
|
|
1895
|
-
}
|
|
1896
|
-
else if (event.sortField) {
|
|
1897
|
-
// Fallback to deprecated sortField for backward compatibility
|
|
1898
|
-
gridState.sortSettings = [{
|
|
1899
|
-
field: event.sortField,
|
|
1900
|
-
dir: event.sortDirection
|
|
1901
|
-
}];
|
|
1902
|
-
}
|
|
1903
|
-
// Save to user settings using the same key pattern as entity-data-grid
|
|
1904
|
-
const settingKey = `default-view-setting/${this.selectedEntity.Name}`;
|
|
1905
|
-
await UserInfoEngine.Instance.SetSetting(settingKey, JSON.stringify(gridState));
|
|
1906
|
-
// Update currentGridState to reflect saved state
|
|
1907
|
-
this.currentGridState = {
|
|
1908
|
-
columnSettings: gridState.columnSettings,
|
|
1909
|
-
sortSettings: gridState.sortSettings,
|
|
1910
|
-
aggregates: gridState.aggregates
|
|
1911
|
-
};
|
|
1912
|
-
// Force change detection to ensure grid picks up the new gridState
|
|
1913
|
-
this.cdr.detectChanges();
|
|
1914
|
-
// Refresh the entity viewer data to apply saved aggregates and fetch their values
|
|
1915
|
-
this.entityViewerRef?.refresh();
|
|
1916
|
-
// Show success notification
|
|
1917
|
-
this.showNotification('Default view settings saved', 'success', 2500);
|
|
1918
|
-
}
|
|
1919
|
-
this.stateService.closeViewConfigPanel();
|
|
1920
|
-
this.cdr.detectChanges();
|
|
1921
|
-
}
|
|
1922
|
-
catch (error) {
|
|
1923
|
-
console.error('[DataExplorer] Error saving default view settings:', error);
|
|
1924
|
-
// Show error notification
|
|
1925
|
-
this.showNotification('Failed to save default view settings', 'error', 3500);
|
|
1926
|
-
}
|
|
1927
|
-
finally {
|
|
1928
|
-
this.ngZone.run(() => {
|
|
1929
|
-
this.isSavingView = false;
|
|
1930
|
-
this.cdr.detectChanges();
|
|
1931
|
-
});
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
/**
|
|
1935
|
-
* Build GridState in Kendo-compatible format
|
|
1936
|
-
* Format: { columnSettings: [...], sortSettings: [...], aggregates: {...} }
|
|
1937
|
-
*
|
|
1938
|
-
* Priority for column settings:
|
|
1939
|
-
* 1. If event.columns provided (from config panel) - use those
|
|
1940
|
-
* 2. If currentGridState exists (from grid interactions) - use that
|
|
1941
|
-
* 3. Otherwise return null
|
|
1942
|
-
*/
|
|
1943
|
-
buildGridState(event) {
|
|
1944
|
-
let columnSettings;
|
|
1945
|
-
// First check if the event has columns configured (from config panel)
|
|
1946
|
-
if (event.columns.length > 0) {
|
|
1947
|
-
columnSettings = event.columns.map((col, idx) => ({
|
|
1948
|
-
ID: col.fieldId,
|
|
1949
|
-
Name: col.fieldName,
|
|
1950
|
-
DisplayName: col.displayName,
|
|
1951
|
-
userDisplayName: col.userDisplayName, // Include user-defined column alias
|
|
1952
|
-
hidden: false, // Visible columns only
|
|
1953
|
-
width: col.width || undefined,
|
|
1954
|
-
orderIndex: idx,
|
|
1955
|
-
format: col.format // Include column format settings
|
|
1956
|
-
}));
|
|
1957
|
-
}
|
|
1958
|
-
// Otherwise, use the current grid state if available (from grid interactions)
|
|
1959
|
-
else if (this.currentGridState?.columnSettings && this.currentGridState.columnSettings.length > 0) {
|
|
1960
|
-
columnSettings = this.currentGridState.columnSettings;
|
|
1961
|
-
}
|
|
1962
|
-
// BUG-005: Third fallback - use entity DefaultInView fields so we never return null
|
|
1963
|
-
else if (this.selectedEntity) {
|
|
1964
|
-
columnSettings = this.selectedEntity.Fields
|
|
1965
|
-
.filter(f => f.DefaultInView)
|
|
1966
|
-
.map((f, idx) => ({
|
|
1967
|
-
ID: f.ID,
|
|
1968
|
-
Name: f.Name,
|
|
1969
|
-
DisplayName: f.DisplayNameOrName,
|
|
1970
|
-
hidden: false,
|
|
1971
|
-
width: f.DefaultColumnWidth || undefined,
|
|
1972
|
-
orderIndex: idx
|
|
1973
|
-
}));
|
|
1974
|
-
if (columnSettings.length === 0) {
|
|
1975
|
-
return null;
|
|
1976
|
-
}
|
|
1977
|
-
}
|
|
1978
|
-
// No columns to save
|
|
1979
|
-
else {
|
|
1980
|
-
return null;
|
|
1981
|
-
}
|
|
1982
|
-
// Build sort settings - prefer event.sortItems (multi-sort), fall back to currentGridState
|
|
1983
|
-
let sortSettings;
|
|
1984
|
-
if (event.sortItems && event.sortItems.length > 0) {
|
|
1985
|
-
sortSettings = event.sortItems.map(item => ({
|
|
1986
|
-
field: item.field,
|
|
1987
|
-
dir: item.direction // 'asc' or 'desc'
|
|
1988
|
-
}));
|
|
1989
|
-
}
|
|
1990
|
-
else if (event.sortField) {
|
|
1991
|
-
// Fallback to deprecated sortField for backward compatibility
|
|
1992
|
-
sortSettings = [{
|
|
1993
|
-
field: event.sortField,
|
|
1994
|
-
dir: event.sortDirection
|
|
1995
|
-
}];
|
|
1996
|
-
}
|
|
1997
|
-
else if (this.currentGridState?.sortSettings && this.currentGridState.sortSettings.length > 0) {
|
|
1998
|
-
sortSettings = this.currentGridState.sortSettings;
|
|
1999
|
-
}
|
|
2000
|
-
// Build aggregate settings from event or current state
|
|
2001
|
-
let aggregates;
|
|
2002
|
-
if (event.aggregatesConfig) {
|
|
2003
|
-
aggregates = event.aggregatesConfig;
|
|
2004
|
-
}
|
|
2005
|
-
else if (this.currentGridState?.aggregates) {
|
|
2006
|
-
aggregates = this.currentGridState.aggregates;
|
|
2007
|
-
}
|
|
2008
|
-
return { columnSettings, sortSettings, aggregates };
|
|
2009
|
-
}
|
|
2010
|
-
/**
|
|
2011
|
-
* Build SortState in Kendo-compatible format
|
|
2012
|
-
* Format: [{field, direction}] where direction is 'asc' or 'desc'
|
|
2013
|
-
* Supports multi-column sorting via sortItems array
|
|
2014
|
-
*/
|
|
2015
|
-
buildSortState(event) {
|
|
2016
|
-
// Prefer sortItems array (multi-sort) over deprecated sortField
|
|
2017
|
-
if (event.sortItems && event.sortItems.length > 0) {
|
|
2018
|
-
return event.sortItems.map(item => ({
|
|
2019
|
-
field: item.field,
|
|
2020
|
-
direction: item.direction
|
|
2021
|
-
}));
|
|
2022
|
-
}
|
|
2023
|
-
// Fallback to deprecated sortField for backward compatibility
|
|
2024
|
-
if (event.sortField) {
|
|
2025
|
-
return [{
|
|
2026
|
-
field: event.sortField,
|
|
2027
|
-
direction: event.sortDirection
|
|
2028
|
-
}];
|
|
2029
|
-
}
|
|
2030
|
-
return null;
|
|
2031
|
-
}
|
|
2032
|
-
/**
|
|
2033
|
-
* Handle delete view from config panel
|
|
2034
|
-
*/
|
|
2035
|
-
async onDeleteView() {
|
|
2036
|
-
if (!this.selectedViewEntity)
|
|
2037
|
-
return;
|
|
2038
|
-
const viewName = this.selectedViewEntity.Name;
|
|
2039
|
-
try {
|
|
2040
|
-
const deleted = await this.selectedViewEntity.Delete();
|
|
2041
|
-
if (deleted) {
|
|
2042
|
-
this.selectedViewEntity = null;
|
|
2043
|
-
this.stateService.selectView(null);
|
|
2044
|
-
this.stateService.closeViewConfigPanel();
|
|
2045
|
-
await this.viewSelectorRef?.loadViews();
|
|
2046
|
-
this.showNotification(`View "${viewName}" deleted`, 'success', 2500);
|
|
2047
|
-
}
|
|
2048
|
-
else {
|
|
2049
|
-
this.showNotification('Failed to delete view', 'error', 3500);
|
|
2050
|
-
}
|
|
2051
|
-
}
|
|
2052
|
-
catch (error) {
|
|
2053
|
-
console.error('[DataExplorer] Error deleting view:', error);
|
|
2054
|
-
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
2055
|
-
this.showNotification(`Failed to delete view: ${errorMsg}`, 'error', 4000);
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
// ========================================
|
|
2059
|
-
// QUICK SAVE, DUPLICATE, REVERT (F-001, F-005, F-007)
|
|
2060
|
-
// ========================================
|
|
2061
|
-
/**
|
|
2062
|
-
* Handle quick save request from view selector (F-001)
|
|
2063
|
-
* Builds a summary from the current config panel state and opens the Quick Save dialog
|
|
2064
|
-
* @param saveAsNew - true when user explicitly clicked "Save As New"
|
|
2065
|
-
*/
|
|
2066
|
-
onQuickSaveRequested(saveAsNew) {
|
|
2067
|
-
this.defaultSaveAsNew = saveAsNew;
|
|
2068
|
-
// Build summary from config panel if available
|
|
2069
|
-
this.quickSaveSummary = this.viewConfigPanelRef?.BuildSummary() ?? null;
|
|
2070
|
-
this.showQuickSaveDialog = true;
|
|
2071
|
-
this.cdr.detectChanges();
|
|
2072
|
-
}
|
|
2073
|
-
/**
|
|
2074
|
-
* Handle quick save event from Quick Save dialog (F-001)
|
|
2075
|
-
* If updating a shared view, intercepts to show the shared view warning first.
|
|
2076
|
-
* Otherwise constructs a ViewSaveEvent and delegates to onSaveView.
|
|
2077
|
-
*/
|
|
2078
|
-
async onQuickSave(event) {
|
|
2079
|
-
this.showQuickSaveDialog = false;
|
|
2080
|
-
// If updating (not save-as-new) a shared view, show the warning dialog
|
|
2081
|
-
if (!event.SaveAsNew && this.selectedViewEntity?.IsShared) {
|
|
2082
|
-
this.pendingQuickSaveEvent = event;
|
|
2083
|
-
this.showSharedViewWarning = true;
|
|
2084
|
-
this.cdr.detectChanges();
|
|
2085
|
-
return;
|
|
2086
|
-
}
|
|
2087
|
-
await this.executeQuickSave(event);
|
|
2088
|
-
}
|
|
2089
|
-
/**
|
|
2090
|
-
* Execute the actual quick save (called directly or after shared view warning confirmation)
|
|
2091
|
-
*/
|
|
2092
|
-
async executeQuickSave(event) {
|
|
2093
|
-
const viewSaveEvent = {
|
|
2094
|
-
name: event.Name,
|
|
2095
|
-
description: event.Description,
|
|
2096
|
-
isShared: event.IsShared,
|
|
2097
|
-
saveAsNew: event.SaveAsNew,
|
|
2098
|
-
columns: [],
|
|
2099
|
-
sortField: null,
|
|
2100
|
-
sortDirection: 'asc',
|
|
2101
|
-
sortItems: [],
|
|
2102
|
-
smartFilterEnabled: false,
|
|
2103
|
-
smartFilterPrompt: '',
|
|
2104
|
-
filterState: this.filterDialogState ?? null,
|
|
2105
|
-
aggregatesConfig: null
|
|
2106
|
-
};
|
|
2107
|
-
await this.onSaveView(viewSaveEvent);
|
|
2108
|
-
}
|
|
2109
|
-
/**
|
|
2110
|
-
* Handle shared view warning dialog action
|
|
2111
|
-
*/
|
|
2112
|
-
async onSharedViewAction(action) {
|
|
2113
|
-
this.showSharedViewWarning = false;
|
|
2114
|
-
const event = this.pendingQuickSaveEvent;
|
|
2115
|
-
this.pendingQuickSaveEvent = null;
|
|
2116
|
-
if (!event)
|
|
2117
|
-
return;
|
|
2118
|
-
if (action === 'update-shared') {
|
|
2119
|
-
// Proceed with the update
|
|
2120
|
-
await this.executeQuickSave(event);
|
|
2121
|
-
}
|
|
2122
|
-
else if (action === 'save-as-copy') {
|
|
2123
|
-
// Save as a new personal copy instead
|
|
2124
|
-
await this.executeQuickSave({
|
|
2125
|
-
...event,
|
|
2126
|
-
SaveAsNew: true,
|
|
2127
|
-
IsShared: false
|
|
2128
|
-
});
|
|
2129
|
-
}
|
|
2130
|
-
// 'cancel' - do nothing
|
|
2131
|
-
this.cdr.detectChanges();
|
|
2132
|
-
}
|
|
2133
|
-
/**
|
|
2134
|
-
* Handle shared view warning cancel
|
|
2135
|
-
*/
|
|
2136
|
-
onSharedViewWarningCancel() {
|
|
2137
|
-
this.showSharedViewWarning = false;
|
|
2138
|
-
this.pendingQuickSaveEvent = null;
|
|
2139
|
-
this.cdr.detectChanges();
|
|
2140
|
-
}
|
|
2141
|
-
/**
|
|
2142
|
-
* Handle quick save dialog close
|
|
2143
|
-
*/
|
|
2144
|
-
onQuickSaveClose() {
|
|
2145
|
-
this.showQuickSaveDialog = false;
|
|
2146
|
-
this.cdr.detectChanges();
|
|
2147
|
-
}
|
|
2148
|
-
/**
|
|
2149
|
-
* Handle quick save "Open Advanced" - close dialog and open full config panel
|
|
2150
|
-
*/
|
|
2151
|
-
onQuickSaveOpenAdvanced(event) {
|
|
2152
|
-
// Carry form data from quick save dialog to the config panel
|
|
2153
|
-
this.pendingNewViewName = event.Name;
|
|
2154
|
-
this.pendingNewViewDescription = event.Description;
|
|
2155
|
-
this.pendingNewViewIsShared = event.IsShared;
|
|
2156
|
-
this.defaultSaveAsNew = true;
|
|
2157
|
-
this.showQuickSaveDialog = false;
|
|
2158
|
-
this.stateService.openViewConfigPanel();
|
|
2159
|
-
this.cdr.detectChanges();
|
|
2160
|
-
}
|
|
2161
|
-
/**
|
|
2162
|
-
* Handle duplicate view request (F-005)
|
|
2163
|
-
* Opens the Duplicate View Dialog so user can choose a name for the copy
|
|
2164
|
-
*/
|
|
2165
|
-
async onDuplicateView(viewId) {
|
|
2166
|
-
const targetId = viewId || this.selectedViewEntity?.ID;
|
|
2167
|
-
if (!targetId || !this.selectedEntity)
|
|
2168
|
-
return;
|
|
2169
|
-
// Find the view to get its name for the dialog
|
|
2170
|
-
const allViews = [...(this.viewSelectorRef?.myViews ?? []), ...(this.viewSelectorRef?.sharedViews ?? [])];
|
|
2171
|
-
const viewItem = allViews.find(v => v.id === targetId);
|
|
2172
|
-
this.duplicateTargetViewId = targetId;
|
|
2173
|
-
this.duplicateSourceViewName = viewItem?.name || this.selectedViewEntity?.Name || 'View';
|
|
2174
|
-
this.duplicateSummary = this.buildDuplicateSummary(viewItem?.entity ?? this.selectedViewEntity);
|
|
2175
|
-
this.showDuplicateDialog = true;
|
|
2176
|
-
this.cdr.detectChanges();
|
|
1112
|
+
}
|
|
2177
1113
|
}
|
|
2178
1114
|
/**
|
|
2179
|
-
*
|
|
1115
|
+
* Load entity IDs associated with a specific application
|
|
2180
1116
|
*/
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
1117
|
+
async loadApplicationEntityIds(applicationId) {
|
|
1118
|
+
this.applicationEntityIds.clear();
|
|
1119
|
+
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
1120
|
+
const result = await rv.RunView({
|
|
1121
|
+
EntityName: 'MJ: Application Entities',
|
|
1122
|
+
ExtraFilter: `ApplicationID = '${applicationId}'`,
|
|
1123
|
+
ResultType: 'entity_object'
|
|
1124
|
+
});
|
|
1125
|
+
if (result.Success && result.Results) {
|
|
1126
|
+
for (const appEntity of result.Results) {
|
|
1127
|
+
this.applicationEntityIds.add(appEntity.EntityID);
|
|
2192
1128
|
}
|
|
2193
1129
|
}
|
|
2194
|
-
catch { /* ignore */ }
|
|
2195
|
-
try {
|
|
2196
|
-
const filterState = view.FilterStateObject;
|
|
2197
|
-
if (filterState?.filters?.length)
|
|
2198
|
-
filterCount = filterState.filters.length;
|
|
2199
|
-
}
|
|
2200
|
-
catch { /* ignore */ }
|
|
2201
|
-
try {
|
|
2202
|
-
const sortState = view.SortStateObject;
|
|
2203
|
-
if (Array.isArray(sortState))
|
|
2204
|
-
sortCount = sortState.length;
|
|
2205
|
-
}
|
|
2206
|
-
catch { /* ignore */ }
|
|
2207
|
-
return {
|
|
2208
|
-
ColumnCount: columnCount,
|
|
2209
|
-
FilterCount: filterCount,
|
|
2210
|
-
SortCount: sortCount,
|
|
2211
|
-
SmartFilterActive: view.SmartFilterEnabled || false,
|
|
2212
|
-
SmartFilterPrompt: view.SmartFilterPrompt || '',
|
|
2213
|
-
AggregateCount: aggregateCount
|
|
2214
|
-
};
|
|
2215
1130
|
}
|
|
2216
1131
|
/**
|
|
2217
|
-
*
|
|
1132
|
+
* Apply the configured filter to the entity list
|
|
2218
1133
|
*/
|
|
2219
|
-
|
|
2220
|
-
this.
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
EntityName: 'MJ: User Views',
|
|
2230
|
-
ExtraFilter: `ID = '${targetId}'`,
|
|
2231
|
-
ResultType: 'entity_object'
|
|
2232
|
-
});
|
|
2233
|
-
if (!result.Success || !result.Results || result.Results.length === 0) {
|
|
2234
|
-
this.showNotification('Could not find view to duplicate', 'error', 3500);
|
|
2235
|
-
return;
|
|
1134
|
+
applyEntityFilter(entities) {
|
|
1135
|
+
if (!this.entityFilter) {
|
|
1136
|
+
return entities;
|
|
1137
|
+
}
|
|
1138
|
+
return entities.filter(entity => {
|
|
1139
|
+
// Filter by application (via ApplicationEntities)
|
|
1140
|
+
if (this.entityFilter.applicationId) {
|
|
1141
|
+
if (!this.applicationEntityIds.has(entity.ID)) {
|
|
1142
|
+
return false;
|
|
1143
|
+
}
|
|
2236
1144
|
}
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
newView.IsShared = false;
|
|
2243
|
-
newView.IsDefault = false;
|
|
2244
|
-
newView.GridState = sourceView.GridState;
|
|
2245
|
-
newView.FilterState = sourceView.FilterState;
|
|
2246
|
-
newView.SortState = sourceView.SortState;
|
|
2247
|
-
newView.SmartFilterEnabled = sourceView.SmartFilterEnabled || false;
|
|
2248
|
-
newView.SmartFilterPrompt = sourceView.SmartFilterPrompt || '';
|
|
2249
|
-
const saved = await newView.Save();
|
|
2250
|
-
if (saved) {
|
|
2251
|
-
this.showNotification(`View duplicated as "${newView.Name}"`, 'success', 2500);
|
|
2252
|
-
await this.viewSelectorRef?.loadViews();
|
|
1145
|
+
// Filter by schema names
|
|
1146
|
+
if (this.entityFilter.schemaNames && this.entityFilter.schemaNames.length > 0) {
|
|
1147
|
+
if (!this.entityFilter.schemaNames.includes(entity.SchemaName)) {
|
|
1148
|
+
return false;
|
|
1149
|
+
}
|
|
2253
1150
|
}
|
|
2254
|
-
|
|
2255
|
-
|
|
1151
|
+
// Filter by explicit entity names
|
|
1152
|
+
if (this.entityFilter.entityNames && this.entityFilter.entityNames.length > 0) {
|
|
1153
|
+
if (!this.entityFilter.entityNames.includes(entity.Name)) {
|
|
1154
|
+
return false;
|
|
1155
|
+
}
|
|
2256
1156
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
1157
|
+
// Filter out system entities unless explicitly included
|
|
1158
|
+
if (!this.entityFilter.includeSystemEntities) {
|
|
1159
|
+
// Skip entities with names starting with __ (MJ system entities)
|
|
1160
|
+
if (entity.Name.startsWith('__')) {
|
|
1161
|
+
return false;
|
|
1162
|
+
}
|
|
1163
|
+
// Could add more system schema checks here if needed
|
|
1164
|
+
}
|
|
1165
|
+
return true;
|
|
1166
|
+
});
|
|
2263
1167
|
}
|
|
2264
1168
|
/**
|
|
2265
|
-
* Handle
|
|
1169
|
+
* Handle entity selection from navigation panel or home screen
|
|
2266
1170
|
*/
|
|
2267
|
-
|
|
2268
|
-
this.
|
|
2269
|
-
|
|
2270
|
-
|
|
1171
|
+
onEntitySelected(entity) {
|
|
1172
|
+
this.resetRecordCounts();
|
|
1173
|
+
// Clear the previous entity's view — it belongs to the old entity and its sort/filter
|
|
1174
|
+
// state would leak into the new entity's query (e.g., ORDER BY FirstName on Groups).
|
|
1175
|
+
// The workspace resets its own view/grid state when its [Entity] input changes.
|
|
1176
|
+
this.selectedViewEntity = null;
|
|
1177
|
+
this.selectedEntity = entity;
|
|
1178
|
+
this.reconcileViewModeForEntity(entity);
|
|
1179
|
+
this.stateService.selectEntity(entity.Name);
|
|
1180
|
+
// Track entity access for recent entities
|
|
1181
|
+
this.stateService.trackEntityAccess(entity.Name, entity.ID);
|
|
1182
|
+
// mj-entity-viewer will automatically load data when entity changes
|
|
2271
1183
|
}
|
|
2272
1184
|
/**
|
|
2273
|
-
* Handle
|
|
2274
|
-
* Duplicates the currently selected view
|
|
1185
|
+
* Handle state changes from external sources
|
|
2275
1186
|
*/
|
|
2276
|
-
|
|
2277
|
-
if (this.
|
|
2278
|
-
this.
|
|
2279
|
-
this.
|
|
1187
|
+
onStateChanged() {
|
|
1188
|
+
if (this.state.selectedEntityName !== this.selectedEntity?.Name) {
|
|
1189
|
+
this.resetRecordCounts();
|
|
1190
|
+
this.selectedEntity = this.entities.find(e => e.Name === this.state.selectedEntityName) || null;
|
|
1191
|
+
this.reconcileViewModeForEntity(this.selectedEntity);
|
|
2280
1192
|
}
|
|
2281
1193
|
}
|
|
2282
1194
|
/**
|
|
2283
|
-
*
|
|
2284
|
-
*
|
|
1195
|
+
* Reset viewMode to 'grid' if the current mode isn't supported by the given entity
|
|
1196
|
+
* (e.g., switching to an entity without geocoding while viewMode is 'map').
|
|
2285
1197
|
*/
|
|
2286
|
-
|
|
2287
|
-
if (!
|
|
1198
|
+
reconcileViewModeForEntity(entity) {
|
|
1199
|
+
if (!entity)
|
|
2288
1200
|
return;
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
// Reset modified flag
|
|
2296
|
-
this.stateService.setViewModified(false);
|
|
2297
|
-
// Refresh the viewer to apply the reverted state
|
|
2298
|
-
await this.entityViewerRef?.loadData();
|
|
2299
|
-
this.showNotification('View reverted to last saved state', 'info', 2500);
|
|
2300
|
-
this.cdr.detectChanges();
|
|
2301
|
-
}
|
|
2302
|
-
catch (error) {
|
|
2303
|
-
console.error('[DataExplorer] Error reverting view:', error);
|
|
2304
|
-
this.showNotification('Failed to revert view', 'error', 3500);
|
|
1201
|
+
const mode = this.state.viewMode;
|
|
1202
|
+
const hasDateFields = entity.Fields.some(f => f.TSType === EntityFieldTSType.Date);
|
|
1203
|
+
const modeUnsupported = (mode === 'map' && !entity.SupportsGeoCoding) ||
|
|
1204
|
+
(mode === 'timeline' && !hasDateFields);
|
|
1205
|
+
if (modeUnsupported) {
|
|
1206
|
+
this.stateService.setViewMode('grid');
|
|
2305
1207
|
}
|
|
2306
1208
|
}
|
|
2307
1209
|
/**
|
|
2308
|
-
*
|
|
2309
|
-
*
|
|
1210
|
+
* Reset record counts when entity changes.
|
|
1211
|
+
* The actual counts will be updated when mj-entity-viewer emits dataLoaded event.
|
|
2310
1212
|
*/
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
try {
|
|
2315
|
-
this.selectedViewEntity.Name = newName.trim();
|
|
2316
|
-
const saved = await this.selectedViewEntity.Save();
|
|
2317
|
-
if (saved) {
|
|
2318
|
-
this.showNotification(`View renamed to "${newName.trim()}"`, 'success', 2500);
|
|
2319
|
-
// Refresh the view selector to show the updated name
|
|
2320
|
-
this.viewSelectorRef?.loadViews();
|
|
2321
|
-
}
|
|
2322
|
-
else {
|
|
2323
|
-
this.showNotification('Failed to rename view', 'error', 3500);
|
|
2324
|
-
}
|
|
2325
|
-
this.cdr.detectChanges();
|
|
2326
|
-
}
|
|
2327
|
-
catch (error) {
|
|
2328
|
-
console.error('[DataExplorer] Error renaming view:', error);
|
|
2329
|
-
this.showNotification('Failed to rename view', 'error', 3500);
|
|
2330
|
-
}
|
|
1213
|
+
resetRecordCounts() {
|
|
1214
|
+
this.totalRecordCount = 0;
|
|
1215
|
+
this.filteredRecordCount = 0;
|
|
2331
1216
|
}
|
|
2332
1217
|
// ========================================
|
|
2333
|
-
// VIEW
|
|
1218
|
+
// VIEW WORKSPACE EVENT HANDLERS
|
|
1219
|
+
// (View CRUD now lives in mj-view-workspace; these thin handlers only drive
|
|
1220
|
+
// Explorer routing + URL/state sync.)
|
|
2334
1221
|
// ========================================
|
|
2335
1222
|
/**
|
|
2336
|
-
* Handle view
|
|
1223
|
+
* Handle a view selection emitted by the workspace. Tracks the selected view for routing/export
|
|
1224
|
+
* and syncs the selected-view-id + smart-filter into the Explorer state service for URL sync.
|
|
1225
|
+
* Grid-state application is owned by the workspace.
|
|
2337
1226
|
*/
|
|
2338
|
-
|
|
2339
|
-
this.
|
|
2340
|
-
|
|
2341
|
-
if (
|
|
2342
|
-
this.stateService.
|
|
1227
|
+
onWorkspaceViewSelected(view) {
|
|
1228
|
+
this.selectedViewEntity = view;
|
|
1229
|
+
this.stateService.selectView(view?.ID ?? null);
|
|
1230
|
+
if (view && view.SmartFilterEnabled && view.SmartFilterPrompt) {
|
|
1231
|
+
this.stateService.setSmartFilterPrompt(view.SmartFilterPrompt);
|
|
2343
1232
|
}
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
* Get the current map display state for passing to the EntityViewer/MapView.
|
|
2347
|
-
*/
|
|
2348
|
-
get mapDisplayState() {
|
|
2349
|
-
if (this.state.mapZoom == null) {
|
|
2350
|
-
return null;
|
|
1233
|
+
else {
|
|
1234
|
+
this.stateService.setSmartFilterPrompt('');
|
|
2351
1235
|
}
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
};
|
|
1236
|
+
// User search text is separate from a saved view's filter — always clear on view switch.
|
|
1237
|
+
this.liveFilterText = '';
|
|
1238
|
+
this.debouncedFilterText = '';
|
|
1239
|
+
this.cdr.detectChanges();
|
|
2357
1240
|
}
|
|
2358
1241
|
/**
|
|
2359
|
-
* Handle
|
|
2360
|
-
* Persists zoom, center, and render mode across page reloads.
|
|
1242
|
+
* Handle the workspace's "open view in tab" request — route via NavigationService.
|
|
2361
1243
|
*/
|
|
1244
|
+
onOpenInTabRequested(viewId) {
|
|
1245
|
+
const viewName = this.selectedViewEntity?.Name || 'View';
|
|
1246
|
+
this.navigationService.OpenView(viewId, viewName, { forceNewTab: true });
|
|
1247
|
+
}
|
|
2362
1248
|
/**
|
|
2363
|
-
* Handle
|
|
1249
|
+
* Handle the workspace's "create new record" request — route via NavigationService.
|
|
2364
1250
|
*/
|
|
2365
|
-
|
|
2366
|
-
this.
|
|
2367
|
-
this.stateService.updateState({ mapRenderMode: mode });
|
|
1251
|
+
onCreateNewRecordRequested(entity) {
|
|
1252
|
+
this.navigationService.OpenNewEntityRecord(entity.Name);
|
|
2368
1253
|
}
|
|
2369
1254
|
/**
|
|
2370
|
-
*
|
|
1255
|
+
* Clear the Explorer "view modified" flag after the workspace persists/reverts a view.
|
|
2371
1256
|
*/
|
|
2372
|
-
|
|
2373
|
-
this.
|
|
2374
|
-
this.stateService.updateState({
|
|
2375
|
-
mapZoom: state.ZoomLevel ?? null,
|
|
2376
|
-
mapCenterLat: state.CenterLat ?? null,
|
|
2377
|
-
mapCenterLng: state.CenterLng ?? null
|
|
2378
|
-
});
|
|
1257
|
+
onWorkspaceViewSaved() {
|
|
1258
|
+
this.stateService.setViewModified(false);
|
|
2379
1259
|
}
|
|
1260
|
+
// ========================================
|
|
1261
|
+
// VIEW MODE & FILTERING (Dashboard Header)
|
|
1262
|
+
// ========================================
|
|
2380
1263
|
/**
|
|
2381
1264
|
* Handle smart filter change from dashboard header
|
|
2382
1265
|
*/
|
|
@@ -2448,6 +1331,16 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
2448
1331
|
RecordPKey: event.compositeKey
|
|
2449
1332
|
});
|
|
2450
1333
|
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Handle the workspace's OpenRecordRequested (record open from the inner viewer). Builds the
|
|
1336
|
+
* composite key from the record and routes to the full record view via the OpenEntityRecord output.
|
|
1337
|
+
*/
|
|
1338
|
+
onWorkspaceOpenRecord(event) {
|
|
1339
|
+
this.OpenEntityRecord.emit({
|
|
1340
|
+
EntityName: event.entity.Name,
|
|
1341
|
+
RecordPKey: buildCompositeKey(event.record, event.entity)
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
2451
1344
|
/**
|
|
2452
1345
|
* Handle data loaded from mj-entity-viewer
|
|
2453
1346
|
*/
|
|
@@ -2528,174 +1421,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
2528
1421
|
// Use NavigationService to open a new record form
|
|
2529
1422
|
this.navigationService.OpenNewEntityRecord(this.selectedEntity.Name);
|
|
2530
1423
|
}
|
|
2531
|
-
/**
|
|
2532
|
-
* Handle export request - opens the export dialog
|
|
2533
|
-
*/
|
|
2534
|
-
async onExport() {
|
|
2535
|
-
if (!this.selectedEntity) {
|
|
2536
|
-
console.error('Cannot export: No entity selected');
|
|
2537
|
-
return;
|
|
2538
|
-
}
|
|
2539
|
-
try {
|
|
2540
|
-
this.showNotification('Preparing export...', 'info', 2000);
|
|
2541
|
-
// Load the export data
|
|
2542
|
-
const data = await this.getExportData();
|
|
2543
|
-
// Get visible columns for export
|
|
2544
|
-
const columns = this.getExportColumns();
|
|
2545
|
-
// Generate file name
|
|
2546
|
-
const viewName = this.selectedViewEntity?.Name || 'Data';
|
|
2547
|
-
const fileName = `${this.selectedEntity.Name}_${viewName}_${new Date().toISOString().split('T')[0]}`;
|
|
2548
|
-
// Configure and show the export dialog
|
|
2549
|
-
this.exportDialogConfig = {
|
|
2550
|
-
data,
|
|
2551
|
-
columns,
|
|
2552
|
-
defaultFileName: fileName,
|
|
2553
|
-
availableFormats: ['excel', 'csv', 'json'],
|
|
2554
|
-
defaultFormat: 'excel',
|
|
2555
|
-
showSamplingOptions: true,
|
|
2556
|
-
defaultSamplingMode: 'all',
|
|
2557
|
-
dialogTitle: `Export ${this.selectedEntity.Name}`
|
|
2558
|
-
};
|
|
2559
|
-
this.showExportDialog = true;
|
|
2560
|
-
this.cdr.detectChanges();
|
|
2561
|
-
}
|
|
2562
|
-
catch (e) {
|
|
2563
|
-
this.showNotification('Error preparing export', 'error', 5000);
|
|
2564
|
-
console.error('Export error:', e);
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
/**
|
|
2568
|
-
* Handle export dialog close
|
|
2569
|
-
*/
|
|
2570
|
-
onExportDialogClosed(result) {
|
|
2571
|
-
this.showExportDialog = false;
|
|
2572
|
-
this.exportDialogConfig = null;
|
|
2573
|
-
this.cdr.detectChanges();
|
|
2574
|
-
if (result.exported) {
|
|
2575
|
-
this.showNotification('Export complete', 'success', 2000);
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
/**
|
|
2579
|
-
* Get visible columns for export based on current grid/view state
|
|
2580
|
-
*/
|
|
2581
|
-
getExportColumns() {
|
|
2582
|
-
if (!this.selectedEntity)
|
|
2583
|
-
return [];
|
|
2584
|
-
// Priority 1: Current grid state (reflects actual displayed columns)
|
|
2585
|
-
if (this.currentGridState?.columnSettings && this.currentGridState.columnSettings.length > 0) {
|
|
2586
|
-
const visibleColumns = this.currentGridState.columnSettings.filter(col => col.hidden !== true);
|
|
2587
|
-
return visibleColumns.map(col => {
|
|
2588
|
-
const field = this.selectedEntity?.Fields.find(f => f.Name === col.Name);
|
|
2589
|
-
return {
|
|
2590
|
-
name: col.Name,
|
|
2591
|
-
displayName: col.DisplayName || col.Name,
|
|
2592
|
-
dataType: this.mapFieldTypeToExportType(field?.Type)
|
|
2593
|
-
};
|
|
2594
|
-
});
|
|
2595
|
-
}
|
|
2596
|
-
// Priority 2: View's column configuration
|
|
2597
|
-
if (this.selectedViewEntity?.Columns) {
|
|
2598
|
-
const visibleColumns = this.selectedViewEntity.Columns.filter(col => !col.hidden);
|
|
2599
|
-
return visibleColumns.map(col => {
|
|
2600
|
-
const field = this.selectedEntity?.Fields.find(f => f.Name === col.Name);
|
|
2601
|
-
return {
|
|
2602
|
-
name: col.Name,
|
|
2603
|
-
displayName: col.DisplayName || col.Name,
|
|
2604
|
-
dataType: this.mapFieldTypeToExportType(field?.Type)
|
|
2605
|
-
};
|
|
2606
|
-
});
|
|
2607
|
-
}
|
|
2608
|
-
// Priority 3: All non-virtual fields
|
|
2609
|
-
const visibleFields = this.selectedEntity.Fields.filter(f => !f.IsVirtual);
|
|
2610
|
-
return visibleFields.map(f => ({
|
|
2611
|
-
name: f.Name,
|
|
2612
|
-
displayName: f.DisplayNameOrName,
|
|
2613
|
-
dataType: this.mapFieldTypeToExportType(f.Type)
|
|
2614
|
-
}));
|
|
2615
|
-
}
|
|
2616
|
-
/**
|
|
2617
|
-
* Map MemberJunction field types to export column types
|
|
2618
|
-
*/
|
|
2619
|
-
mapFieldTypeToExportType(fieldType) {
|
|
2620
|
-
if (!fieldType)
|
|
2621
|
-
return 'string';
|
|
2622
|
-
const type = fieldType.toLowerCase();
|
|
2623
|
-
if (type.includes('int') || type.includes('decimal') || type.includes('float') || type.includes('numeric')) {
|
|
2624
|
-
return 'number';
|
|
2625
|
-
}
|
|
2626
|
-
if (type.includes('date') || type.includes('time')) {
|
|
2627
|
-
return 'date';
|
|
2628
|
-
}
|
|
2629
|
-
if (type.includes('bit') || type.includes('bool')) {
|
|
2630
|
-
return 'boolean';
|
|
2631
|
-
}
|
|
2632
|
-
if (type.includes('money') || type.includes('currency')) {
|
|
2633
|
-
return 'currency';
|
|
2634
|
-
}
|
|
2635
|
-
return 'string';
|
|
2636
|
-
}
|
|
2637
|
-
/**
|
|
2638
|
-
* Get the data for export - loads all records for the current view/entity
|
|
2639
|
-
*/
|
|
2640
|
-
async getExportData() {
|
|
2641
|
-
if (!this.selectedEntity) {
|
|
2642
|
-
throw new Error('No entity selected for export');
|
|
2643
|
-
}
|
|
2644
|
-
const md = this.ProviderToUse;
|
|
2645
|
-
const rv = RunView.FromMetadataProvider(this.ProviderToUse);
|
|
2646
|
-
// Build the run view params based on current state
|
|
2647
|
-
const baseParams = {
|
|
2648
|
-
EntityName: this.selectedEntity.Name,
|
|
2649
|
-
ExtraFilter: this.buildExtraFilter(),
|
|
2650
|
-
OrderBy: this.buildOrderBy(),
|
|
2651
|
-
IgnoreMaxRows: true,
|
|
2652
|
-
ForceAuditLog: true,
|
|
2653
|
-
AuditLogDescription: `Export of Data From ${this.selectedViewEntity ? '"' + this.selectedViewEntity.Name + '"' : this.selectedEntity.Name} View for User ${md.CurrentUser.Email}`
|
|
2654
|
-
};
|
|
2655
|
-
// Add smart filter if present
|
|
2656
|
-
const params = this.debouncedFilterText
|
|
2657
|
-
? { ...baseParams, UserSearchString: this.debouncedFilterText }
|
|
2658
|
-
: baseParams;
|
|
2659
|
-
const result = await rv.RunView(params);
|
|
2660
|
-
if (result && result.Success) {
|
|
2661
|
-
return result.Results;
|
|
2662
|
-
}
|
|
2663
|
-
else {
|
|
2664
|
-
throw new Error('Unable to get export data: ' + (result?.ErrorMessage || 'Unknown error'));
|
|
2665
|
-
}
|
|
2666
|
-
}
|
|
2667
|
-
/**
|
|
2668
|
-
* Build the ExtraFilter string based on current view and filter state
|
|
2669
|
-
*/
|
|
2670
|
-
buildExtraFilter() {
|
|
2671
|
-
const filters = [];
|
|
2672
|
-
// Add view filter if a view is selected
|
|
2673
|
-
if (this.selectedViewEntity?.WhereClause) {
|
|
2674
|
-
filters.push(`(${this.selectedViewEntity.WhereClause})`);
|
|
2675
|
-
}
|
|
2676
|
-
// Add smart filter if present
|
|
2677
|
-
if (this.debouncedFilterText) {
|
|
2678
|
-
// Smart filter is applied via UserSearchString in RunView, not ExtraFilter
|
|
2679
|
-
// So we don't need to add it here
|
|
2680
|
-
}
|
|
2681
|
-
return filters.join(' AND ');
|
|
2682
|
-
}
|
|
2683
|
-
/**
|
|
2684
|
-
* Build the OrderBy string based on current view state
|
|
2685
|
-
*/
|
|
2686
|
-
buildOrderBy() {
|
|
2687
|
-
// Use view's OrderByClause if available
|
|
2688
|
-
if (this.selectedViewEntity?.OrderByClause) {
|
|
2689
|
-
return this.selectedViewEntity.OrderByClause;
|
|
2690
|
-
}
|
|
2691
|
-
// Use grid state sort if available
|
|
2692
|
-
if (this.currentGridState?.sortSettings && this.currentGridState.sortSettings.length > 0) {
|
|
2693
|
-
const sorts = this.currentGridState.sortSettings.map(s => `${s.field} ${s.dir.toUpperCase()}`);
|
|
2694
|
-
return sorts.join(', ');
|
|
2695
|
-
}
|
|
2696
|
-
// Default sort by primary key
|
|
2697
|
-
return this.selectedEntity.FirstPrimaryKey.Name;
|
|
2698
|
-
}
|
|
2699
1424
|
/**
|
|
2700
1425
|
* Show a notification to the user
|
|
2701
1426
|
*/
|
|
@@ -2847,10 +1572,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
2847
1572
|
* Apply a deep link to navigate to a specific entity/record
|
|
2848
1573
|
*/
|
|
2849
1574
|
async applyDeepLink(deepLink) {
|
|
2850
|
-
//
|
|
2851
|
-
if (deepLink.viewMode) {
|
|
2852
|
-
this.stateService.setViewMode(deepLink.viewMode);
|
|
2853
|
-
}
|
|
1575
|
+
// ViewTypeID-only: view type is no longer deep-linked — the inner viewer persists it.
|
|
2854
1576
|
// Navigate to entity if specified
|
|
2855
1577
|
if (deepLink.entity) {
|
|
2856
1578
|
const entity = this.entities.find(e => e.Name.toLowerCase() === deepLink.entity.toLowerCase());
|
|
@@ -2876,12 +1598,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
2876
1598
|
}
|
|
2877
1599
|
/** Record ID to select once data loads (from deep link) */
|
|
2878
1600
|
pendingRecordSelection = null;
|
|
2879
|
-
/**
|
|
2880
|
-
* Pending map mode from URL that must survive initialization state resets.
|
|
2881
|
-
* Set during applyUrlState, cleared once state matches or after first successful re-apply.
|
|
2882
|
-
* The state subscription self-corrects: any time state diverges from this value, it re-applies.
|
|
2883
|
-
*/
|
|
2884
|
-
_pendingMapMode = null;
|
|
2885
1601
|
// ========================================
|
|
2886
1602
|
// BREADCRUMB NAVIGATION
|
|
2887
1603
|
// ========================================
|
|
@@ -2965,19 +1681,17 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
2965
1681
|
const entity = params['entity'] || null;
|
|
2966
1682
|
const record = params['record'] || null;
|
|
2967
1683
|
const filterParam = params['filter'] || null;
|
|
2968
|
-
const view = params['view'] || null;
|
|
2969
1684
|
const viewId = params['viewId'] || null;
|
|
2970
|
-
|
|
2971
|
-
if (!entity && !record && !filterParam && !view && !viewId && !mapMode) {
|
|
1685
|
+
if (!entity && !record && !filterParam && !viewId) {
|
|
2972
1686
|
return null;
|
|
2973
1687
|
}
|
|
1688
|
+
// ViewTypeID-only: the active view type is persisted via UserView.ViewTypeID / per-user settings
|
|
1689
|
+
// by the inner viewer, NOT via URL query params. So we no longer read/write view/mapMode here.
|
|
2974
1690
|
return {
|
|
2975
1691
|
entity: entity || undefined,
|
|
2976
1692
|
record: record || undefined,
|
|
2977
1693
|
filter: filterParam || undefined,
|
|
2978
|
-
|
|
2979
|
-
viewId: viewId || undefined,
|
|
2980
|
-
mapMode: mapMode || undefined
|
|
1694
|
+
viewId: viewId || undefined
|
|
2981
1695
|
};
|
|
2982
1696
|
}
|
|
2983
1697
|
/**
|
|
@@ -3019,13 +1733,13 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3019
1733
|
pushCurrentStateToUrl() {
|
|
3020
1734
|
const hasEntity = !!this.state.selectedEntityName;
|
|
3021
1735
|
const hasViewId = !!(this.state.selectedViewId && hasEntity);
|
|
1736
|
+
// ViewTypeID-only: the active view type is persisted by the inner viewer (UserView.ViewTypeID /
|
|
1737
|
+
// per-user settings), not via URL. We only round-trip entity / record / saved-view selection.
|
|
3022
1738
|
const queryParams = {
|
|
3023
1739
|
entity: this.state.selectedEntityName || null,
|
|
3024
1740
|
record: (this.state.selectedRecordId && hasEntity) ? this.state.selectedRecordId : null,
|
|
3025
1741
|
filter: null, // Never in URL — filters live in saved views (DB), not query strings
|
|
3026
|
-
|
|
3027
|
-
viewId: hasViewId ? this.state.selectedViewId : null,
|
|
3028
|
-
mapMode: this.state.viewMode === 'map' ? (this.state.mapRenderMode || 'point') : null
|
|
1742
|
+
viewId: hasViewId ? this.state.selectedViewId : null
|
|
3029
1743
|
};
|
|
3030
1744
|
this.UpdateQueryParams(queryParams);
|
|
3031
1745
|
}
|
|
@@ -3034,19 +1748,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3034
1748
|
* Used both during init and for popstate handling.
|
|
3035
1749
|
*/
|
|
3036
1750
|
async applyUrlState(urlState) {
|
|
3037
|
-
//
|
|
3038
|
-
// can reset mapRenderMode to 'point'. The state subscription self-corrects using this.
|
|
3039
|
-
if (urlState.mapMode && ['point', 'choropleth', 'heatmap'].includes(urlState.mapMode)) {
|
|
3040
|
-
this._pendingMapMode = urlState.mapMode;
|
|
3041
|
-
}
|
|
3042
|
-
// Apply view mode (may trigger map component creation if switching to 'map')
|
|
3043
|
-
if (urlState.viewMode) {
|
|
3044
|
-
this.stateService.setViewMode(urlState.viewMode);
|
|
3045
|
-
}
|
|
3046
|
-
// Apply map render mode to state
|
|
3047
|
-
if (this._pendingMapMode) {
|
|
3048
|
-
this.stateService.updateState({ mapRenderMode: this._pendingMapMode });
|
|
3049
|
-
}
|
|
1751
|
+
// ViewTypeID-only: view type / map mode are no longer URL-driven — the inner viewer persists them.
|
|
3050
1752
|
// Navigate to entity if specified
|
|
3051
1753
|
if (urlState.entity) {
|
|
3052
1754
|
const entity = this.entities.find(e => e.Name.toLowerCase() === urlState.entity.toLowerCase());
|
|
@@ -3058,7 +1760,8 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3058
1760
|
this.selectedEntity = entity;
|
|
3059
1761
|
this.stateService.selectEntity(entity.Name);
|
|
3060
1762
|
}
|
|
3061
|
-
// Restore saved view by ID if specified
|
|
1763
|
+
// Restore saved view by ID if specified. The workspace applies the view's grid state
|
|
1764
|
+
// itself once selectedViewEntity flows into its [SelectedView] input.
|
|
3062
1765
|
if (urlState.viewId) {
|
|
3063
1766
|
await this.restoreViewFromUrl(urlState.viewId, entity);
|
|
3064
1767
|
}
|
|
@@ -3066,7 +1769,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3066
1769
|
// No specific view — clear view selection to use default
|
|
3067
1770
|
this.selectedViewEntity = null;
|
|
3068
1771
|
this.stateService.selectView(null);
|
|
3069
|
-
this.currentGridState = this.loadUserDefaultGridState();
|
|
3070
1772
|
}
|
|
3071
1773
|
// Filters live in saved views (DB), never in URL query strings.
|
|
3072
1774
|
// Clear smart filter on entity change when no specific view is selected.
|
|
@@ -3122,8 +1824,9 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3122
1824
|
}
|
|
3123
1825
|
/**
|
|
3124
1826
|
* Restore a saved view from the URL's viewId parameter.
|
|
3125
|
-
* Looks up the view by ID
|
|
3126
|
-
* Must be async because UserViewEngine's
|
|
1827
|
+
* Looks up the view by ID and sets it as selected; the workspace applies its grid state once
|
|
1828
|
+
* selectedViewEntity flows into its [SelectedView] input. Must be async because UserViewEngine's
|
|
1829
|
+
* cache may not be populated yet on cold page loads.
|
|
3127
1830
|
*/
|
|
3128
1831
|
async restoreViewFromUrl(viewId, entity) {
|
|
3129
1832
|
// Ensure the view engine cache is populated before querying —
|
|
@@ -3134,7 +1837,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3134
1837
|
if (view) {
|
|
3135
1838
|
this.selectedViewEntity = view;
|
|
3136
1839
|
this.stateService.selectView(viewId);
|
|
3137
|
-
this.currentGridState = this.parseViewGridState(view);
|
|
3138
1840
|
// Apply the view's smart filter if it has one
|
|
3139
1841
|
if (view.SmartFilterEnabled && view.SmartFilterPrompt) {
|
|
3140
1842
|
this.stateService.setSmartFilterPrompt(view.SmartFilterPrompt);
|
|
@@ -3144,7 +1846,6 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3144
1846
|
console.warn('[DataExplorer] restoreViewFromUrl: view NOT FOUND, falling back to default. viewId=', viewId);
|
|
3145
1847
|
this.selectedViewEntity = null;
|
|
3146
1848
|
this.stateService.selectView(null);
|
|
3147
|
-
this.currentGridState = this.loadUserDefaultGridState();
|
|
3148
1849
|
}
|
|
3149
1850
|
this.cdr.detectChanges();
|
|
3150
1851
|
}
|
|
@@ -3382,219 +2083,48 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3382
2083
|
get isAtHomeLevel() {
|
|
3383
2084
|
return !this.selectedEntity;
|
|
3384
2085
|
}
|
|
3385
|
-
// ========================================
|
|
3386
|
-
// SELECTION TRACKING
|
|
3387
|
-
// ========================================
|
|
3388
|
-
/**
|
|
3389
|
-
* Handle selection changes from entity-viewer grid.
|
|
3390
|
-
* Tracks selected records to enable the Add to List button in the header toolbar.
|
|
3391
|
-
*/
|
|
3392
|
-
onSelectionChanged(event) {
|
|
3393
|
-
this.selectedRecords = event.records || [];
|
|
3394
|
-
this.selectedRecordIds = event.recordIds || [];
|
|
3395
|
-
this.cdr.detectChanges();
|
|
3396
|
-
}
|
|
3397
|
-
/**
|
|
3398
|
-
* Check if there are selected records (for enabling Add to List button)
|
|
3399
|
-
*/
|
|
3400
|
-
get hasSelectedRecords() {
|
|
3401
|
-
return this.selectedRecords.length > 0;
|
|
3402
|
-
}
|
|
3403
|
-
// ========================================
|
|
3404
|
-
// LIST MANAGEMENT
|
|
3405
|
-
// ========================================
|
|
3406
|
-
/**
|
|
3407
|
-
* Handle Add to List button click from header toolbar.
|
|
3408
|
-
* Opens the list management dialog for selected records.
|
|
3409
|
-
*/
|
|
3410
|
-
onAddToListClick() {
|
|
3411
|
-
if (!this.selectedEntity || this.selectedRecords.length === 0) {
|
|
3412
|
-
console.warn('Add to List: No entity selected or no records selected');
|
|
3413
|
-
return;
|
|
3414
|
-
}
|
|
3415
|
-
// Build the event object and delegate to existing handler
|
|
3416
|
-
const event = {
|
|
3417
|
-
entityInfo: this.selectedEntity,
|
|
3418
|
-
records: this.selectedRecords,
|
|
3419
|
-
recordIds: this.selectedRecordIds
|
|
3420
|
-
};
|
|
3421
|
-
this.onAddToListRequested(event);
|
|
3422
|
-
}
|
|
3423
|
-
/**
|
|
3424
|
-
* Handle Add to List request from entity-viewer grid toolbar.
|
|
3425
|
-
* Opens the list management dialog for multiple selected records.
|
|
3426
|
-
*/
|
|
3427
|
-
onAddToListRequested(event) {
|
|
3428
|
-
// Validate input
|
|
3429
|
-
if (!event.entityInfo) {
|
|
3430
|
-
console.error('Add to List: entityInfo is missing from event');
|
|
3431
|
-
return;
|
|
3432
|
-
}
|
|
3433
|
-
if (!event.records || event.records.length === 0) {
|
|
3434
|
-
console.error('Add to List: No records in event. Event:', event);
|
|
3435
|
-
return;
|
|
3436
|
-
}
|
|
3437
|
-
console.log(`Add to List: Processing ${event.records.length} record(s) for entity "${event.entityInfo.Name}"`);
|
|
3438
|
-
// Get display names for the records
|
|
3439
|
-
const recordDisplayNames = event.records.map(record => {
|
|
3440
|
-
try {
|
|
3441
|
-
if (event.entityInfo.NameField) {
|
|
3442
|
-
const nameValue = record[event.entityInfo.NameField.Name];
|
|
3443
|
-
if (nameValue)
|
|
3444
|
-
return String(nameValue);
|
|
3445
|
-
}
|
|
3446
|
-
return buildPkString(record, event.entityInfo) || 'Unknown';
|
|
3447
|
-
}
|
|
3448
|
-
catch (err) {
|
|
3449
|
-
console.error('Add to List: Error getting record display name:', err);
|
|
3450
|
-
return 'Unknown';
|
|
3451
|
-
}
|
|
3452
|
-
});
|
|
3453
|
-
// Get raw primary key values (not concatenated strings) for list membership
|
|
3454
|
-
const pkFieldName = event.entityInfo.PrimaryKeys[0]?.Name;
|
|
3455
|
-
const recordIds = event.records.map(record => {
|
|
3456
|
-
try {
|
|
3457
|
-
if (!pkFieldName || record[pkFieldName] === null || record[pkFieldName] === undefined) {
|
|
3458
|
-
console.error('Add to List: Record has no primary key:', record);
|
|
3459
|
-
return '';
|
|
3460
|
-
}
|
|
3461
|
-
return String(record[pkFieldName]);
|
|
3462
|
-
}
|
|
3463
|
-
catch (err) {
|
|
3464
|
-
console.error('Add to List: Error getting record ID:', err);
|
|
3465
|
-
return '';
|
|
3466
|
-
}
|
|
3467
|
-
}).filter(id => id !== '');
|
|
3468
|
-
if (recordIds.length === 0) {
|
|
3469
|
-
console.error('Add to List: No valid record IDs found');
|
|
3470
|
-
return;
|
|
3471
|
-
}
|
|
3472
|
-
const recordCount = event.records.length;
|
|
3473
|
-
const dialogTitle = recordCount === 1
|
|
3474
|
-
? `Manage Lists for "${recordDisplayNames[0]}"`
|
|
3475
|
-
: `Add ${recordCount} Records to List`;
|
|
3476
|
-
console.log(`Add to List: Opening dialog for ${recordIds.length} record(s)`);
|
|
3477
|
-
this.listManagementConfig = {
|
|
3478
|
-
mode: 'manage',
|
|
3479
|
-
entityId: event.entityInfo.ID,
|
|
3480
|
-
entityName: event.entityInfo.Name,
|
|
3481
|
-
recordIds: recordIds,
|
|
3482
|
-
recordDisplayNames: recordDisplayNames,
|
|
3483
|
-
allowCreate: true,
|
|
3484
|
-
allowRemove: recordCount === 1, // Only allow remove for single record
|
|
3485
|
-
showMembership: recordCount === 1, // Only show membership for single record
|
|
3486
|
-
dialogTitle: dialogTitle
|
|
3487
|
-
};
|
|
3488
|
-
this.showListManagementDialog = true;
|
|
3489
|
-
this.cdr.detectChanges();
|
|
3490
|
-
}
|
|
3491
|
-
/**
|
|
3492
|
-
* Open the list management dialog for the currently selected record
|
|
3493
|
-
*/
|
|
3494
|
-
openListManagementDialog() {
|
|
3495
|
-
if (!this.selectedEntity || !this.selectedRecord) {
|
|
3496
|
-
return;
|
|
3497
|
-
}
|
|
3498
|
-
// Use the raw primary key value (not concatenated string) for list membership
|
|
3499
|
-
// This matches how records are stored in List Details and enables proper subquery filtering
|
|
3500
|
-
const pkFieldName = this.selectedEntity.PrimaryKeys[0]?.Name;
|
|
3501
|
-
const recordId = pkFieldName ? String(this.selectedRecord[pkFieldName] ?? '') : '';
|
|
3502
|
-
const recordName = this.getRecordDisplayName(this.selectedRecord);
|
|
3503
|
-
this.listManagementConfig = {
|
|
3504
|
-
mode: 'manage',
|
|
3505
|
-
entityId: this.selectedEntity.ID,
|
|
3506
|
-
entityName: this.selectedEntity.Name,
|
|
3507
|
-
recordIds: [recordId],
|
|
3508
|
-
recordDisplayNames: [recordName],
|
|
3509
|
-
allowCreate: true,
|
|
3510
|
-
allowRemove: true,
|
|
3511
|
-
showMembership: true,
|
|
3512
|
-
dialogTitle: `Manage Lists for "${recordName}"`
|
|
3513
|
-
};
|
|
3514
|
-
this.showListManagementDialog = true;
|
|
3515
|
-
this.cdr.detectChanges();
|
|
3516
|
-
}
|
|
3517
2086
|
/**
|
|
3518
|
-
*
|
|
2087
|
+
* NAVIGATION handler: open a *related* record on a (possibly different) entity, bubbled up from a
|
|
2088
|
+
* plug-in renderer through the workspace (e.g. a grid foreign-key drill-through). Resolves the
|
|
2089
|
+
* target entity and shows the record in the detail panel, mirroring the FK navigation path used
|
|
2090
|
+
* by {@link onOpenForeignKeyRecord}.
|
|
2091
|
+
*
|
|
2092
|
+
* @param nav the related-record navigation payload: the target entity name and the record's key.
|
|
3519
2093
|
*/
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
if (result.action === 'apply') {
|
|
3524
|
-
const addedCount = result.added.length;
|
|
3525
|
-
const removedCount = result.removed.length;
|
|
3526
|
-
if (addedCount > 0 || removedCount > 0) {
|
|
3527
|
-
let message = '';
|
|
3528
|
-
if (addedCount > 0) {
|
|
3529
|
-
message += `Added to ${addedCount} list(s)`;
|
|
3530
|
-
}
|
|
3531
|
-
if (removedCount > 0) {
|
|
3532
|
-
if (message)
|
|
3533
|
-
message += ', ';
|
|
3534
|
-
message += `Removed from ${removedCount} list(s)`;
|
|
3535
|
-
}
|
|
3536
|
-
this.showNotification(message, 'success', 2500);
|
|
3537
|
-
}
|
|
2094
|
+
onOpenRelatedRecordRequested(nav) {
|
|
2095
|
+
if (nav?.entityName && nav.recordKey != null) {
|
|
2096
|
+
void this.loadAndShowRecordInDetailPanel(nav.entityName, String(nav.recordKey));
|
|
3538
2097
|
}
|
|
3539
|
-
this.cdr.detectChanges();
|
|
3540
|
-
}
|
|
3541
|
-
/**
|
|
3542
|
-
* Handle cancellation of the list management dialog
|
|
3543
|
-
*/
|
|
3544
|
-
onListManagementCancel() {
|
|
3545
|
-
this.showListManagementDialog = false;
|
|
3546
|
-
this.listManagementConfig = null;
|
|
3547
|
-
this.cdr.detectChanges();
|
|
3548
2098
|
}
|
|
3549
|
-
static ɵfac = function DataExplorerDashboardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DataExplorerDashboardComponent)(i0.ɵɵdirectiveInject(i1.ExplorerStateService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i2.RecentAccessService), i0.ɵɵdirectiveInject(
|
|
2099
|
+
static ɵfac = function DataExplorerDashboardComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DataExplorerDashboardComponent)(i0.ɵɵdirectiveInject(i1.ExplorerStateService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i2.RecentAccessService), i0.ɵɵdirectiveInject(i0.NgZone)); };
|
|
3550
2100
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DataExplorerDashboardComponent, selectors: [["mj-data-explorer-dashboard"]], viewQuery: function DataExplorerDashboardComponent_Query(rf, ctx) { if (rf & 1) {
|
|
3551
|
-
i0.ɵɵviewQuery(_c0, 5)(
|
|
2101
|
+
i0.ɵɵviewQuery(_c0, 5)(ViewWorkspaceComponent, 5);
|
|
3552
2102
|
} if (rf & 2) {
|
|
3553
2103
|
let _t;
|
|
3554
2104
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.filterInputRef = _t.first);
|
|
3555
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.
|
|
3556
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.entityViewerRef = _t.first);
|
|
3557
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.viewConfigPanelRef = _t.first);
|
|
2105
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.viewWorkspaceRef = _t.first);
|
|
3558
2106
|
} }, hostBindings: function DataExplorerDashboardComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
3559
2107
|
i0.ɵɵlistener("keydown", function DataExplorerDashboardComponent_keydown_HostBindingHandler($event) { return ctx.handleKeyboardShortcut($event); }, i0.ɵɵresolveDocument);
|
|
3560
|
-
} }, inputs: { entityFilter: "entityFilter", deepLink: "deepLink", contextName: "contextName", contextIcon: "contextIcon", initialQueryParams: "initialQueryParams" }, outputs: { DisplayNameChanged: "DisplayNameChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls:
|
|
3561
|
-
i0.ɵɵelementStart(0, "div",
|
|
3562
|
-
i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_1_Template, 2, 16, "div",
|
|
3563
|
-
i0.ɵɵelementStart(2, "div",
|
|
3564
|
-
i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_3_Template, 3, 0, "div",
|
|
3565
|
-
i0.ɵɵelementStart(4, "div",
|
|
3566
|
-
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_6_Template,
|
|
2108
|
+
} }, inputs: { entityFilter: "entityFilter", deepLink: "deepLink", contextName: "contextName", contextIcon: "contextIcon", initialQueryParams: "initialQueryParams" }, outputs: { DisplayNameChanged: "DisplayNameChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 17, vars: 12, consts: [["filterInput", ""], [1, "data-explorer-container"], [1, "navigation-panel", 3, "collapsed", "width"], [1, "content-area"], [1, "breadcrumb-bar"], [1, "content-header"], [1, "header-left"], [1, "header-center"], [1, "smart-filter-container"], [1, "header-right"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "active"], [1, "content-body"], [1, "home-view-concept-d"], [3, "Entity", "AutoSaveView", "SelectedView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel", 3, "width"], [1, "navigation-panel"], [3, "entitySelected", "toggleCollapse", "sectionToggled", "openRecord", "selectRecord", "expandAndFocus", "entities", "appEntityGroups", "selectedEntityName", "favorites", "recentItems", "collapsed", "allowedEntityNames", "favoritesSectionExpanded", "recentSectionExpanded", "entitiesSectionExpanded", "viewsSectionExpanded"], [1, "breadcrumb-item", 3, "click", "title"], [1, "breadcrumb-icon", 3, "class"], [1, "breadcrumb-label"], [1, "fa-solid", "fa-chevron-right", "breadcrumb-separator"], [1, "breadcrumb-icon"], [1, "entity-icon"], [1, "entity-title"], [1, "record-count"], [1, "entity-icon", 3, "class"], [1, "fa-solid", "fa-search", "filter-icon"], ["type", "text", "placeholder", "Filter records... (press / to focus)", 1, "smart-filter-input", 3, "input", "value"], [1, "clear-filter-btn"], [1, "clear-filter-btn", 3, "click"], [1, "fa-solid", "fa-times"], ["title", "Recents & Favorites", 1, "header-action-btn", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left"], [1, "qa-badge"], [1, "loading-state"], ["text", "Loading entities...", "size", "medium"], [1, "home-main-area"], [1, "search-hero"], [1, "search-hero-container"], [1, "fa-solid", "fa-magnifying-glass", "search-hero-icon"], ["type", "text", "placeholder", "Search entities...", 1, "search-hero-input", 3, "ngModelChange", "ngModel"], [1, "search-hero-clear"], [1, "search-hero-shortcut"], [1, "search-meta-row"], [1, "search-entity-count"], [1, "pill-toggle"], [1, "pill-btn", 3, "click"], [1, "fa-solid", "fa-star"], [1, "entity-groups-area"], [1, "entity-item-grid"], [1, "home-no-results"], [1, "empty-state"], [1, "quick-access-panel"], [1, "qa-header"], [1, "qa-close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "qa-body"], [1, "qa-section"], [1, "qa-section-header", 3, "click"], [1, "fa-solid", "fa-clock-rotate-left", "qa-section-icon"], [1, "qa-section-count"], [1, "fa-solid", "fa-chevron-down", "qa-section-chevron"], [1, "qa-section-body"], [1, "qa-item"], [1, "qa-empty"], [1, "fa-solid", "fa-table", "qa-section-icon"], [1, "fa-solid", "fa-star", "qa-section-icon", 2, "color", "var(--mj-status-warning)"], [1, "search-hero-clear", 3, "click"], [1, "entity-item", 3, "title"], [1, "entity-item", 3, "click", "title"], [1, "entity-item-icon"], [1, "entity-item-text"], [1, "entity-item-name"], [1, "entity-item-desc"], [1, "entity-item-fav", 3, "click", "title"], [1, "app-group"], [1, "app-group-header", 3, "click"], [1, "app-group-icon"], [1, "app-group-name"], [1, "app-group-count"], [1, "fa-solid", "fa-chevron-right", "app-group-chevron"], [1, "app-group-entities"], [1, "fa-solid", "fa-magnifying-glass"], [1, "fa-solid", "fa-database", "empty-icon"], [1, "qa-item", 3, "click"], [1, "qa-item-icon"], [1, "qa-item-info"], [1, "qa-item-name"], [1, "qa-item-meta"], [1, "qa-item-time"], [3, "SelectedViewChange", "ViewSelected", "OpenViewInTabRequested", "OpenRecordRequested", "OpenRelatedRecordRequested", "CreateNewRecordRequested", "RecordSelected", "AfterViewSave", "AfterViewDelete", "FilterTextChanged", "DataLoaded", "FilteredCountChanged", "Entity", "AutoSaveView", "SelectedView", "FilterText", "SelectedRecordId", "ViewerConfig"], [1, "detail-panel"], [3, "close", "openRecord", "navigateToRelated", "openRelatedRecord", "openForeignKeyRecord", "entity", "record"]], template: function DataExplorerDashboardComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2109
|
+
i0.ɵɵelementStart(0, "div", 1);
|
|
2110
|
+
i0.ɵɵconditionalCreate(1, DataExplorerDashboardComponent_Conditional_1_Template, 2, 16, "div", 2);
|
|
2111
|
+
i0.ɵɵelementStart(2, "div", 3);
|
|
2112
|
+
i0.ɵɵconditionalCreate(3, DataExplorerDashboardComponent_Conditional_3_Template, 3, 0, "div", 4);
|
|
2113
|
+
i0.ɵɵelementStart(4, "div", 5)(5, "div", 6);
|
|
2114
|
+
i0.ɵɵconditionalCreate(6, DataExplorerDashboardComponent_Conditional_6_Template, 5, 4)(7, DataExplorerDashboardComponent_Conditional_7_Template, 5, 3);
|
|
3567
2115
|
i0.ɵɵelementEnd();
|
|
3568
|
-
i0.ɵɵelementStart(8, "div",
|
|
3569
|
-
i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_9_Template, 5, 2, "div",
|
|
2116
|
+
i0.ɵɵelementStart(8, "div", 7);
|
|
2117
|
+
i0.ɵɵconditionalCreate(9, DataExplorerDashboardComponent_Conditional_9_Template, 5, 2, "div", 8);
|
|
3570
2118
|
i0.ɵɵelementEnd();
|
|
3571
|
-
i0.ɵɵelementStart(10, "div",
|
|
3572
|
-
i0.ɵɵconditionalCreate(11, DataExplorerDashboardComponent_Conditional_11_Template,
|
|
3573
|
-
i0.ɵɵconditionalCreate(12, DataExplorerDashboardComponent_Conditional_12_Template, 3, 3, "button",
|
|
2119
|
+
i0.ɵɵelementStart(10, "div", 9);
|
|
2120
|
+
i0.ɵɵconditionalCreate(11, DataExplorerDashboardComponent_Conditional_11_Template, 0, 0);
|
|
2121
|
+
i0.ɵɵconditionalCreate(12, DataExplorerDashboardComponent_Conditional_12_Template, 3, 3, "button", 10);
|
|
3574
2122
|
i0.ɵɵelementEnd()();
|
|
3575
|
-
i0.ɵɵelementStart(13, "div",
|
|
3576
|
-
i0.ɵɵconditionalCreate(14, DataExplorerDashboardComponent_Conditional_14_Template, 3, 1, "div",
|
|
2123
|
+
i0.ɵɵelementStart(13, "div", 11);
|
|
2124
|
+
i0.ɵɵconditionalCreate(14, DataExplorerDashboardComponent_Conditional_14_Template, 3, 1, "div", 12)(15, DataExplorerDashboardComponent_Conditional_15_Template, 1, 6, "mj-view-workspace", 13);
|
|
3577
2125
|
i0.ɵɵelementEnd()();
|
|
3578
|
-
i0.ɵɵconditionalCreate(16, DataExplorerDashboardComponent_Conditional_16_Template,
|
|
3579
|
-
i0.ɵɵelementStart(17, "mj-view-config-panel", 16);
|
|
3580
|
-
i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Template_mj_view_config_panel_close_17_listener() { return ctx.onCloseViewConfigPanel(); })("save", function DataExplorerDashboardComponent_Template_mj_view_config_panel_save_17_listener($event) { return ctx.onSaveView($event); })("saveDefaults", function DataExplorerDashboardComponent_Template_mj_view_config_panel_saveDefaults_17_listener($event) { return ctx.onSaveDefaultViewSettings($event); })("delete", function DataExplorerDashboardComponent_Template_mj_view_config_panel_delete_17_listener() { return ctx.onDeleteView(); })("duplicate", function DataExplorerDashboardComponent_Template_mj_view_config_panel_duplicate_17_listener() { return ctx.onDuplicateFromPanel(); })("openFilterDialogRequest", function DataExplorerDashboardComponent_Template_mj_view_config_panel_openFilterDialogRequest_17_listener($event) { return ctx.onOpenFilterDialogRequest($event); });
|
|
3581
|
-
i0.ɵɵelementEnd();
|
|
3582
|
-
i0.ɵɵelementStart(18, "mj-filter-dialog", 17);
|
|
3583
|
-
i0.ɵɵlistener("close", function DataExplorerDashboardComponent_Template_mj_filter_dialog_close_18_listener() { return ctx.onCloseFilterDialog(); })("apply", function DataExplorerDashboardComponent_Template_mj_filter_dialog_apply_18_listener($event) { return ctx.onFilterApplied($event); });
|
|
3584
|
-
i0.ɵɵelementEnd();
|
|
3585
|
-
i0.ɵɵelementStart(19, "mj-export-dialog", 18);
|
|
3586
|
-
i0.ɵɵlistener("closed", function DataExplorerDashboardComponent_Template_mj_export_dialog_closed_19_listener($event) { return ctx.onExportDialogClosed($event); });
|
|
2126
|
+
i0.ɵɵconditionalCreate(16, DataExplorerDashboardComponent_Conditional_16_Template, 2, 4, "div", 14);
|
|
3587
2127
|
i0.ɵɵelementEnd();
|
|
3588
|
-
i0.ɵɵconditionalCreate(20, DataExplorerDashboardComponent_Conditional_20_Template, 1, 2, "mj-list-management-dialog", 19);
|
|
3589
|
-
i0.ɵɵelementStart(21, "mj-quick-save-dialog", 20);
|
|
3590
|
-
i0.ɵɵlistener("Save", function DataExplorerDashboardComponent_Template_mj_quick_save_dialog_Save_21_listener($event) { return ctx.onQuickSave($event); })("Close", function DataExplorerDashboardComponent_Template_mj_quick_save_dialog_Close_21_listener() { return ctx.onQuickSaveClose(); })("OpenAdvanced", function DataExplorerDashboardComponent_Template_mj_quick_save_dialog_OpenAdvanced_21_listener($event) { return ctx.onQuickSaveOpenAdvanced($event); });
|
|
3591
|
-
i0.ɵɵelementEnd();
|
|
3592
|
-
i0.ɵɵelementStart(22, "mj-duplicate-view-dialog", 21);
|
|
3593
|
-
i0.ɵɵlistener("Duplicate", function DataExplorerDashboardComponent_Template_mj_duplicate_view_dialog_Duplicate_22_listener($event) { return ctx.onDuplicateConfirmed($event); })("Cancel", function DataExplorerDashboardComponent_Template_mj_duplicate_view_dialog_Cancel_22_listener() { return ctx.onDuplicateCancel(); });
|
|
3594
|
-
i0.ɵɵelementEnd();
|
|
3595
|
-
i0.ɵɵelementStart(23, "mj-shared-view-warning-dialog", 22);
|
|
3596
|
-
i0.ɵɵlistener("Action", function DataExplorerDashboardComponent_Template_mj_shared_view_warning_dialog_Action_23_listener($event) { return ctx.onSharedViewAction($event); })("Cancel", function DataExplorerDashboardComponent_Template_mj_shared_view_warning_dialog_Cancel_23_listener() { return ctx.onSharedViewWarningCancel(); });
|
|
3597
|
-
i0.ɵɵelementEnd()();
|
|
3598
2128
|
} if (rf & 2) {
|
|
3599
2129
|
i0.ɵɵadvance();
|
|
3600
2130
|
i0.ɵɵconditional(!ctx.isAtHomeLevel ? 1 : -1);
|
|
@@ -3616,21 +2146,7 @@ let DataExplorerDashboardComponent = class DataExplorerDashboardComponent extend
|
|
|
3616
2146
|
i0.ɵɵconditional(!ctx.selectedEntity ? 14 : 15);
|
|
3617
2147
|
i0.ɵɵadvance(2);
|
|
3618
2148
|
i0.ɵɵconditional(ctx.state.detailPanelOpen && ctx.selectedRecord ? 16 : -1);
|
|
3619
|
-
i0.ɵɵadvance();
|
|
3620
|
-
i0.ɵɵproperty("entity", ctx.selectedEntity)("viewEntity", ctx.selectedViewEntity)("isOpen", ctx.state.viewConfigPanelOpen)("currentGridState", ctx.currentGridState)("externalFilterState", ctx.filterDialogState)("isSaving", ctx.isSavingView)("DefaultSaveAsNew", ctx.defaultSaveAsNew)("PendingNewViewName", ctx.pendingNewViewName)("PendingNewViewDescription", ctx.pendingNewViewDescription)("PendingNewViewIsShared", ctx.pendingNewViewIsShared);
|
|
3621
|
-
i0.ɵɵadvance();
|
|
3622
|
-
i0.ɵɵproperty("isOpen", ctx.isFilterDialogOpen)("fields", ctx.filterDialogFields)("filter", ctx.filterDialogState)("disabled", ctx.filterDialogDisabled);
|
|
3623
|
-
i0.ɵɵadvance();
|
|
3624
|
-
i0.ɵɵproperty("visible", ctx.showExportDialog)("config", ctx.exportDialogConfig);
|
|
3625
|
-
i0.ɵɵadvance();
|
|
3626
|
-
i0.ɵɵconditional(ctx.showListManagementDialog && ctx.listManagementConfig ? 20 : -1);
|
|
3627
|
-
i0.ɵɵadvance();
|
|
3628
|
-
i0.ɵɵproperty("IsOpen", ctx.showQuickSaveDialog)("ViewEntity", ctx.selectedViewEntity)("EntityName", (ctx.selectedEntity == null ? null : ctx.selectedEntity.DisplayNameOrName) ?? "")("Summary", ctx.quickSaveSummary)("IsSaving", ctx.isSavingView)("DefaultSaveAsNew", ctx.defaultSaveAsNew);
|
|
3629
|
-
i0.ɵɵadvance();
|
|
3630
|
-
i0.ɵɵproperty("IsOpen", ctx.showDuplicateDialog)("SourceViewName", ctx.duplicateSourceViewName)("Summary", ctx.duplicateSummary);
|
|
3631
|
-
i0.ɵɵadvance();
|
|
3632
|
-
i0.ɵɵproperty("IsOpen", ctx.showSharedViewWarning)("ViewName", (ctx.selectedViewEntity == null ? null : ctx.selectedViewEntity.Name) ?? "");
|
|
3633
|
-
} }, dependencies: [i4.DefaultValueAccessor, i4.NgControlStatus, i4.NgModel, i5.EntityViewerComponent, i5.EntityRecordDetailPanelComponent, i5.ViewConfigPanelComponent, i5.QuickSaveDialogComponent, i5.DuplicateViewDialogComponent, i5.SharedViewWarningDialogComponent, i2.LoadingComponent, i3.ExportDialogComponent, i6.ListManagementDialogComponent, i7.NavigationPanelComponent, i8.ViewSelectorComponent, i9.FilterDialogComponent, i10.DecimalPipe], styles: [".data-explorer-container[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed[_ngcontent-%COMP%] {\n width: 48px;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n\n\n.breadcrumb-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; \n\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n\n\n.header-left[_ngcontent-%COMP%] mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\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.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n.selection-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.date-field-selector-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n\n\n\n.view-specific-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\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.view-specific-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n \n\n\n\n\n\n\n\n\n isolation: isolate;\n}\n\n.loading-container[_ngcontent-%COMP%], \n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\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 text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n\n.home-view-concept-d[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 320px;\n}\n\n\n\n\n\n\n.search-hero[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container[_ngcontent-%COMP%] {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n\n\n.search-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%] {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n\n\n\n\n.entity-groups-area[_ngcontent-%COMP%] {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.app-group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name[_ngcontent-%COMP%] {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.app-group-entities[_ngcontent-%COMP%] {\n padding: 4px 14px 10px 60px;\n}\n\n\n\n\n\n\n.entity-item-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-fav[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.entity-item-fav.favorited[_ngcontent-%COMP%] {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n\n.quick-access-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.qa-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-count[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n transform: rotate(-90deg);\n}\n\n.qa-section-body[_ngcontent-%COMP%] {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-body[_ngcontent-%COMP%] {\n display: none;\n}\n\n.qa-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty[_ngcontent-%COMP%] {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n\n\n.qa-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n\n\n.home-no-results[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel[_ngcontent-%COMP%] mj-entity-record-detail-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n\n\n.detail-panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n[_nghost-%COMP%] mj-explorer-grid-view, \n[_nghost-%COMP%] mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n\n\n\n\n\n\n\n.content-header.home-header[_ngcontent-%COMP%] {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] .smart-filter-input[_ngcontent-%COMP%] {\n padding-left: 40px;\n}\n\n\n\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] .toggle-btn[_ngcontent-%COMP%] {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n}\n\n\n\n\n\n\n.empty-state.small[_ngcontent-%COMP%] {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n@media (max-width: 1200px) {\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center[_ngcontent-%COMP%] {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero[_ngcontent-%COMP%] {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area[_ngcontent-%COMP%] {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities[_ngcontent-%COMP%] {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 0;\n }\n\n .quick-access-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .navigation-panel[_ngcontent-%COMP%] {\n display: none;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .content-body[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n\n .app-group-name[_ngcontent-%COMP%] {\n font-size: 17px;\n }\n\n .entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}"], data: { animation: [
|
|
2149
|
+
} }, dependencies: [i3.DefaultValueAccessor, i3.NgControlStatus, i3.NgModel, i4.EntityRecordDetailPanelComponent, i4.ViewWorkspaceComponent, i2.LoadingComponent, i5.NavigationPanelComponent, i6.DecimalPipe], styles: [".data-explorer-container[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed[_ngcontent-%COMP%] {\n width: 48px;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n\n\n.breadcrumb-bar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label[_ngcontent-%COMP%] {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; \n\n}\n\n.header-left[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n\n\n.header-left[_ngcontent-%COMP%] mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon[_ngcontent-%COMP%] {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center[_ngcontent-%COMP%] {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn[_ngcontent-%COMP%] {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-primary);\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.header-action-btn[_ngcontent-%COMP%] {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn[_ngcontent-%COMP%]:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 14px;\n}\n.selection-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n\n\n.date-field-selector-container[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button[_ngcontent-%COMP%]:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated[_ngcontent-%COMP%] {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .item-name[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item[_ngcontent-%COMP%] .selected-check[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n\n\n\n.view-specific-controls[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn[_ngcontent-%COMP%] {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\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.view-specific-btn[_ngcontent-%COMP%]:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.timeline-orientation-toggle[_ngcontent-%COMP%] {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n \n\n\n\n\n\n\n\n\n isolation: isolate;\n}\n\n.loading-container[_ngcontent-%COMP%], \n.loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\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 text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon[_ngcontent-%COMP%] {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n\n\n\n\n\n.home-view-concept-d[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 320px;\n}\n\n\n\n\n\n\n.search-hero[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container[_ngcontent-%COMP%] {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input[_ngcontent-%COMP%]::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear[_ngcontent-%COMP%]:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n\n\n.search-meta-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle[_ngcontent-%COMP%] {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%] {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 11px;\n}\n\n\n\n\n\n\n.entity-groups-area[_ngcontent-%COMP%] {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group[_ngcontent-%COMP%] {\n margin-bottom: 4px;\n}\n\n.app-group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header[_ngcontent-%COMP%]:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon[_ngcontent-%COMP%] {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name[_ngcontent-%COMP%] {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded[_ngcontent-%COMP%] {\n transform: rotate(90deg);\n}\n\n.app-group-entities[_ngcontent-%COMP%] {\n padding: 4px 14px 10px 60px;\n}\n\n\n\n\n\n\n.entity-item-grid[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item[_ngcontent-%COMP%]:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon[_ngcontent-%COMP%] {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item[_ngcontent-%COMP%]:hover .entity-item-fav[_ngcontent-%COMP%] {\n opacity: 1;\n}\n\n.entity-item-fav.favorited[_ngcontent-%COMP%] {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n\n\n\n\n\n.quick-access-panel[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.qa-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-icon[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-count[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-chevron[_ngcontent-%COMP%] {\n transform: rotate(-90deg);\n}\n\n.qa-section-body[_ngcontent-%COMP%] {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed[_ngcontent-%COMP%] .qa-section-body[_ngcontent-%COMP%] {\n display: none;\n}\n\n.qa-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon[_ngcontent-%COMP%] {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty[_ngcontent-%COMP%] {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n\n\n.qa-badge[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n\n\n.home-no-results[_ngcontent-%COMP%] {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel[_ngcontent-%COMP%] {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel[_ngcontent-%COMP%] mj-entity-record-detail-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes _ngcontent-%COMP%_slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n\n\n.detail-panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 12px;\n}\n\n[_nghost-%COMP%] mj-explorer-grid-view, \n[_nghost-%COMP%] mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n\n\n\n\n\n\n\n.content-header.home-header[_ngcontent-%COMP%] {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content[_ngcontent-%COMP%] {\n padding: 0;\n}\n\n\n\n.filter-icon[_ngcontent-%COMP%] {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container[_ngcontent-%COMP%] .smart-filter-input[_ngcontent-%COMP%] {\n padding-left: 40px;\n}\n\n\n\n\n\n\n.view-mode-toggle[_ngcontent-%COMP%] .toggle-btn[_ngcontent-%COMP%] {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 500;\n}\n\n\n\n\n\n\n.empty-state.small[_ngcontent-%COMP%] {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] h3[_ngcontent-%COMP%] {\n font-size: 16px;\n}\n\n.empty-state.small[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n font-size: 13px;\n}\n\n\n\n\n\n\n@media (max-width: 1200px) {\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center[_ngcontent-%COMP%] {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero[_ngcontent-%COMP%] {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area[_ngcontent-%COMP%] {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities[_ngcontent-%COMP%] {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open[_ngcontent-%COMP%] {\n margin-right: 0;\n }\n\n .quick-access-panel[_ngcontent-%COMP%] {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container[_ngcontent-%COMP%] {\n flex-direction: column;\n }\n\n .navigation-panel[_ngcontent-%COMP%] {\n display: none;\n }\n\n .content-header[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .content-body[_ngcontent-%COMP%] {\n padding: 12px 16px;\n }\n\n .entity-item-grid[_ngcontent-%COMP%] {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle[_ngcontent-%COMP%] {\n display: none;\n }\n\n .app-group-name[_ngcontent-%COMP%] {\n font-size: 17px;\n }\n\n .entity-item-name[_ngcontent-%COMP%] {\n font-size: 14px;\n }\n}"], data: { animation: [
|
|
3634
2150
|
trigger('slideInLeft', [
|
|
3635
2151
|
transition(':enter', [
|
|
3636
2152
|
style({ transform: 'translateX(-100%)', opacity: 0 }),
|
|
@@ -3658,19 +2174,13 @@ export { DataExplorerDashboardComponent };
|
|
|
3658
2174
|
animate('200ms ease-in', style({ transform: 'translateX(-100%)', opacity: 0 }))
|
|
3659
2175
|
])
|
|
3660
2176
|
])
|
|
3661
|
-
], template: "<div class=\"data-explorer-container\">\n <!-- Navigation Panel (Left) - Hidden at home level, animated -->\n @if (!isAtHomeLevel) {\n <div\n class=\"navigation-panel\"\n [class.collapsed]=\"state.navigationPanelCollapsed\"\n [style.width.px]=\"state.navigationPanelCollapsed ? 48 : state.navigationPanelWidth\"\n [@slideInLeft]>\n\n <mj-explorer-navigation-panel\n [entities]=\"entities\"\n [appEntityGroups]=\"appEntityGroups\"\n [selectedEntityName]=\"state.selectedEntityName\"\n [favorites]=\"state.favorites\"\n [recentItems]=\"state.recentItems\"\n [collapsed]=\"state.navigationPanelCollapsed\"\n [allowedEntityNames]=\"allowedEntityNames\"\n [favoritesSectionExpanded]=\"state.favoritesSectionExpanded\"\n [recentSectionExpanded]=\"state.recentSectionExpanded\"\n [entitiesSectionExpanded]=\"state.entitiesSectionExpanded\"\n [viewsSectionExpanded]=\"state.viewsSectionExpanded\"\n (entitySelected)=\"onEntitySelected($event)\"\n (toggleCollapse)=\"toggleNavigationPanel()\"\n (sectionToggled)=\"stateService.toggleSection($event)\"\n (openRecord)=\"onOpenRecordFromNav($event)\"\n (selectRecord)=\"onSelectRecordFromNav($event)\"\n (expandAndFocus)=\"onExpandAndFocus($event)\">\n </mj-explorer-navigation-panel>\n </div>\n }\n\n <!-- Main Content Area -->\n <div class=\"content-area\">\n <!-- Breadcrumb Bar - Hidden at home level -->\n @if (!isAtHomeLevel && breadcrumbs.length > 0) {\n <div class=\"breadcrumb-bar\">\n @for (crumb of breadcrumbs; track crumb.label; let i = $index; let last = $last) {\n <span\n class=\"breadcrumb-item\"\n [class.clickable]=\"!last\"\n [class.current]=\"last\"\n (click)=\"onBreadcrumbClick(crumb, i)\"\n [title]=\"crumb.label\">\n @if (crumb.icon) {\n <i [class]=\"crumb.icon\" class=\"breadcrumb-icon\"></i>\n }\n <span class=\"breadcrumb-label\">{{ crumb.label }}</span>\n </span>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n }\n\n <!-- Header -->\n <div class=\"content-header\" [class.home-header]=\"isAtHomeLevel\">\n <div class=\"header-left\">\n @if (selectedEntity) {\n <i [class]=\"getEntityIcon(selectedEntity)\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ selectedEntity.DisplayNameOrName }}</h2>\n @if (debouncedFilterText && filteredRecordCount !== totalRecordCount) {\n <span class=\"record-count\">{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span class=\"record-count\">{{ totalRecordCount | number }} records</span>\n }\n\n <!-- View Selector -->\n <mj-view-selector\n [entity]=\"selectedEntity\"\n [selectedViewId]=\"state.selectedViewId\"\n [viewModified]=\"state.viewModified\"\n (viewSelected)=\"onViewSelected($event)\"\n (saveViewRequested)=\"onSaveViewRequested($event)\"\n (manageViewsRequested)=\"onManageViewsRequested()\"\n (openInTabRequested)=\"onOpenInTabRequested($event)\"\n (configureViewRequested)=\"onConfigureViewRequested()\"\n (createNewRecordRequested)=\"onCreateNewRecord()\"\n (exportRequested)=\"onExport()\"\n (duplicateViewRequested)=\"onDuplicateView($event)\"\n (quickSaveRequested)=\"onQuickSaveRequested($event)\"\n (revertRequested)=\"onRevertView()\">\n </mj-view-selector>\n\n <!-- Add to List Button -->\n <button\n class=\"header-action-btn\"\n [class.disabled]=\"!hasSelectedRecords\"\n [disabled]=\"!hasSelectedRecords\"\n (click)=\"onAddToListClick()\"\n [title]=\"hasSelectedRecords ? 'Add ' + selectedRecords.length + ' selected record(s) to a list' : 'Select records to add to a list'\">\n <i class=\"fa-solid fa-list-check\"></i>\n @if (hasSelectedRecords) {\n <span class=\"selection-badge\">{{ selectedRecords.length }}</span>\n }\n </button>\n } @else {\n @if (displayIcon) {\n <i [class]=\"displayIcon\" class=\"entity-icon\"></i>\n }\n <h2 class=\"entity-title\">{{ displayTitle }}</h2>\n <span class=\"record-count\">{{ entities.length }} entities available</span>\n }\n </div>\n\n <div class=\"header-center\">\n @if (selectedEntity) {\n <div class=\"smart-filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"smart-filter-input\"\n placeholder=\"Filter records... (press / to focus)\"\n [value]=\"liveFilterText\"\n (input)=\"onFilterInputChanged(filterInput.value)\"\n />\n @if (liveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearRecordFilter()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n <!-- Home-level search moved to search hero section -->\n </div>\n\n <div class=\"header-right\">\n @if (selectedEntity) {\n <!-- View-specific controls \u2014 positioned LEFT of the view mode toggle -->\n <!-- These controls are contextual to the active view mode -->\n @if (state.viewMode === 'timeline' && entityHasDateFields) {\n <div class=\"view-specific-controls\">\n <!-- Date Field Selector -->\n <div class=\"date-field-selector-container\">\n @if (isDateFieldDropdownOpen) {\n <div class=\"date-field-backdrop\" (click)=\"closeDateFieldDropdown()\"></div>\n }\n <div class=\"date-field-selector-wrapper\">\n <button\n class=\"date-field-selector-button\"\n [class.open]=\"isDateFieldDropdownOpen\"\n [disabled]=\"availableDateFields.length <= 1\"\n (click)=\"toggleDateFieldDropdown()\">\n <i class=\"fa-solid fa-calendar-days date-field-icon\"></i>\n <span class=\"date-field-name\">{{ effectiveTimelineDateFieldDisplayName }}</span>\n @if (availableDateFields.length > 1) {\n <i class=\"fa-solid fa-chevron-down date-field-arrow\" [class.rotated]=\"isDateFieldDropdownOpen\"></i>\n }\n </button>\n @if (isDateFieldDropdownOpen && availableDateFields.length > 1) {\n <div class=\"date-field-dropdown-panel\">\n @for (field of availableDateFields; track field.name) {\n <div\n class=\"date-field-dropdown-item\"\n [class.selected]=\"field.name === effectiveTimelineDateField\"\n (click)=\"setTimelineDateField(field.name)\">\n <i class=\"fa-regular fa-calendar item-icon\"></i>\n <span class=\"item-name\">{{ field.displayName }}</span>\n @if (field.name === effectiveTimelineDateField) {\n <i class=\"fa-solid fa-check selected-check\"></i>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n <!-- Orientation Toggle -->\n <button\n class=\"view-specific-btn\"\n (click)=\"toggleTimelineOrientation()\"\n [title]=\"state.timelineOrientation === 'vertical' ? 'Switch to Horizontal' : 'Switch to Vertical'\">\n <i [class]=\"state.timelineOrientation === 'vertical' ? 'fa-solid fa-ellipsis-vertical' : 'fa-solid fa-ellipsis'\"></i>\n </button>\n <!-- Sort Order Toggle -->\n <button\n class=\"view-specific-btn\"\n (click)=\"toggleTimelineSortOrder()\"\n [title]=\"state.timelineSortOrder === 'desc' ? 'Showing Newest First (click for Oldest First)' : 'Showing Oldest First (click for Newest First)'\">\n <i [class]=\"state.timelineSortOrder === 'desc' ? 'fa-solid fa-arrow-down-wide-short' : 'fa-solid fa-arrow-up-wide-short'\"></i>\n </button>\n </div>\n }\n\n <!-- View Mode Toggle \u2014 always rightmost in the header -->\n <div class=\"view-mode-toggle\">\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'grid'\"\n (click)=\"onViewModeChanged('grid')\"\n title=\"Grid View\">\n <i class=\"fa-solid fa-list\"></i>\n </button>\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'cards'\"\n (click)=\"onViewModeChanged('cards')\"\n title=\"Cards View\">\n <i class=\"fa-solid fa-grip\"></i>\n </button>\n @if (entityHasDateFields) {\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'timeline'\"\n (click)=\"onViewModeChanged('timeline')\"\n title=\"Timeline View\">\n <i class=\"fa-solid fa-timeline\"></i>\n </button>\n }\n @if (selectedEntity.SupportsGeoCoding) {\n <button\n class=\"toggle-btn\"\n [class.active]=\"state.viewMode === 'map'\"\n (click)=\"onViewModeChanged('map')\"\n title=\"Map View\">\n <i class=\"fa-solid fa-map-location-dot\"></i>\n </button>\n }\n </div>\n }\n @if (!selectedEntity) {\n <!-- Quick Access panel toggle -->\n <button\n class=\"header-action-btn\"\n [class.active]=\"state.quickAccessPanelOpen\"\n (click)=\"toggleQuickAccessPanel()\"\n title=\"Recents & Favorites\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n @if (recentRecords.length + favoriteRecords.length > 0) {\n <span class=\"qa-badge\">{{ recentRecords.length + favoriteRecords.length }}</span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Content Body - Using mj-entity-viewer composite -->\n <div class=\"content-body\" [class.home-content]=\"isAtHomeLevel\">\n @if (!selectedEntity) {\n <!-- Concept D: Application Groups + Search-First Home View -->\n <div class=\"home-view-concept-d\">\n @if (isLoadingEntities) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading entities...\" size=\"medium\"></mj-loading>\n </div>\n } @else {\n <div class=\"home-main-area\" [class.panel-open]=\"state.quickAccessPanelOpen\">\n <!-- Search Hero -->\n <div class=\"search-hero\">\n <div class=\"search-hero-container\">\n <i class=\"fa-solid fa-magnifying-glass search-hero-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"search-hero-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entityFilterText\"\n />\n @if (entityFilterText) {\n <button class=\"search-hero-clear\" (click)=\"entityFilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n } @else {\n <span class=\"search-hero-shortcut\">/</span>\n }\n </div>\n\n <!-- Meta row: entity count + All/Favorites pills -->\n <div class=\"search-meta-row\">\n <span class=\"search-entity-count\">\n {{ filteredEntityCount }} entities\n @if (applicationCount > 0) {\n across {{ applicationCount }} applications\n }\n </span>\n <div class=\"pill-toggle\">\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'all'\"\n (click)=\"setHomeViewMode('all')\">\n All Entities\n </button>\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'favorites'\"\n (click)=\"setHomeViewMode('favorites')\">\n <i class=\"fa-solid fa-star\"></i> My Favorites\n </button>\n </div>\n </div>\n </div>\n\n <!-- Entity Groups Area -->\n <div class=\"entity-groups-area\">\n @if (entityFilter?.applicationId) {\n <!-- Single-app mode: flat entity grid (no grouping) -->\n <div class=\"entity-item-grid\">\n @for (entity of flatFilteredEntities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n } @else {\n <!-- Multi-app mode: grouped by application -->\n @for (group of filteredAppEntityGroups; track group.applicationId) {\n <div class=\"app-group\">\n <div class=\"app-group-header\" (click)=\"toggleAppGroup(group.applicationId)\">\n <div\n class=\"app-group-icon\"\n [style.background]=\"group.applicationColor ? group.applicationColor + '15' : null\"\n [style.color]=\"group.applicationColor || null\">\n <i [class]=\"group.applicationIcon || 'fa-solid fa-folder'\"></i>\n </div>\n <span class=\"app-group-name\">{{ group.applicationName }}</span>\n <span class=\"app-group-count\">{{ group.entities.length }}</span>\n <i class=\"fa-solid fa-chevron-right app-group-chevron\"\n [class.expanded]=\"group.isExpanded\"></i>\n </div>\n @if (group.isExpanded) {\n <div class=\"app-group-entities\">\n <div class=\"entity-item-grid\">\n @for (entity of group.entities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- No results -->\n @if (filteredEntityCount === 0 && entities.length > 0) {\n <div class=\"home-no-results\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <p>No entities match \"{{ entityFilterText }}\"</p>\n </div>\n }\n @if (entities.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-icon\"></i>\n <h3>No Entities Available</h3>\n <p>There are no entities configured for this application.</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Quick Access Panel (right slide-in) -->\n <div class=\"quick-access-panel\" [class.open]=\"state.quickAccessPanelOpen\">\n <div class=\"qa-header\">\n <h3>Quick Access</h3>\n <button class=\"qa-close-btn\" (click)=\"toggleQuickAccessPanel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"qa-body\">\n <!-- Recent Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentRecords')\">\n <i class=\"fa-solid fa-clock-rotate-left qa-section-icon\"></i>\n <span>Recent Records</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessRecentRecords; track record.entityId + '|' + record.recordId) {\n <div class=\"qa-item\" (click)=\"onRecentRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n <span class=\"qa-item-time\">{{ formatRelativeTime(record.latestAt) }}</span>\n </div>\n }\n @if (quickAccessRecentRecords.length === 0) {\n <div class=\"qa-empty\">No recent records</div>\n }\n </div>\n </div>\n\n <!-- Recent Entities (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentEntities')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentEntities')\">\n <i class=\"fa-solid fa-table qa-section-icon\"></i>\n <span>Recent Entities</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentEntities.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (entity of quickAccessRecentEntities; track entity.ID) {\n <div class=\"qa-item\" (click)=\"onEntitySelected(entity)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ entity.DisplayNameOrName }}</div>\n </div>\n </div>\n }\n @if (quickAccessRecentEntities.length === 0) {\n <div class=\"qa-empty\">No recent entities</div>\n }\n </div>\n </div>\n\n <!-- Favorite Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('favoriteRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('favoriteRecords')\">\n <i class=\"fa-solid fa-star qa-section-icon\" style=\"color: var(--mj-status-warning);\"></i>\n <span>Favorite Records</span>\n <span class=\"qa-section-count\">{{ quickAccessFavoriteRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessFavoriteRecords; track record.userFavoriteId) {\n <div class=\"qa-item\" (click)=\"onFavoriteRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n </div>\n }\n @if (quickAccessFavoriteRecords.length === 0) {\n <div class=\"qa-empty\">No favorite records</div>\n }\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else {\n <mj-entity-viewer\n #entityViewer\n [entity]=\"selectedEntity\"\n [viewEntity]=\"selectedViewEntity\"\n [viewMode]=\"state.viewMode\"\n [filterText]=\"debouncedFilterText\"\n [selectedRecordId]=\"state.selectedRecordId\"\n [config]=\"viewerConfig\"\n [gridState]=\"currentGridState\"\n [timelineConfig]=\"currentTimelineConfig\"\n [gridSelectionMode]=\"'checkbox'\"\n [showGridToolbar]=\"false\"\n [showAddToListButton]=\"false\"\n (viewModeChange)=\"onViewModeChanged($event)\"\n (filterTextChange)=\"onFilterTextChanged($event)\"\n (recordSelected)=\"onViewerRecordSelected($event)\"\n (recordOpened)=\"onViewerRecordOpened($event)\"\n (dataLoaded)=\"onDataLoaded($event)\"\n (filteredCountChanged)=\"onFilteredCountChanged($event)\"\n (gridStateChanged)=\"onGridStateChanged($event)\"\n (selectionChanged)=\"onSelectionChanged($event)\"\n (addToListRequested)=\"onAddToListRequested($event)\"\n [mapRenderMode]=\"state.mapRenderMode || 'point'\"\n [mapDisplayState]=\"mapDisplayState\"\n (mapRenderModeChange)=\"onMapRenderModeChange($event)\"\n (mapDisplayStateChange)=\"onMapDisplayStateChange($event)\">\n </mj-entity-viewer>\n }\n </div>\n </div>\n\n <!-- Detail Panel (Right - Slide In) -->\n @if (state.detailPanelOpen && selectedRecord) {\n <div class=\"detail-panel\" [style.width.px]=\"state.detailPanelWidth\">\n <!-- Detail Panel Actions Bar -->\n <div class=\"detail-panel-actions\">\n <button\n class=\"detail-action-btn\"\n (click)=\"openListManagementDialog()\"\n title=\"Add to List\">\n <i class=\"fa-solid fa-list-check\"></i>\n <span>Add to List</span>\n </button>\n </div>\n <mj-entity-record-detail-panel\n [entity]=\"detailPanelEntity\"\n [record]=\"selectedRecord\"\n (close)=\"onDetailPanelClosed()\"\n (openRecord)=\"onOpenRecord($event)\"\n (navigateToRelated)=\"onNavigateToRelated($event)\"\n (openRelatedRecord)=\"onOpenRelatedRecord($event)\"\n (openForeignKeyRecord)=\"onOpenForeignKeyRecord($event)\">\n </mj-entity-record-detail-panel>\n </div>\n }\n\n <!-- View Configuration Panel -->\n <mj-view-config-panel\n [entity]=\"selectedEntity\"\n [viewEntity]=\"selectedViewEntity\"\n [isOpen]=\"state.viewConfigPanelOpen\"\n [currentGridState]=\"currentGridState\"\n [externalFilterState]=\"filterDialogState\"\n [isSaving]=\"isSavingView\"\n [DefaultSaveAsNew]=\"defaultSaveAsNew\"\n [PendingNewViewName]=\"pendingNewViewName\"\n [PendingNewViewDescription]=\"pendingNewViewDescription\"\n [PendingNewViewIsShared]=\"pendingNewViewIsShared\"\n (close)=\"onCloseViewConfigPanel()\"\n (save)=\"onSaveView($event)\"\n (saveDefaults)=\"onSaveDefaultViewSettings($event)\"\n (delete)=\"onDeleteView()\"\n (duplicate)=\"onDuplicateFromPanel()\"\n (openFilterDialogRequest)=\"onOpenFilterDialogRequest($event)\">\n </mj-view-config-panel>\n\n <!-- Filter Dialog (rendered at dashboard level for full viewport width) -->\n <mj-filter-dialog\n [isOpen]=\"isFilterDialogOpen\"\n [fields]=\"filterDialogFields\"\n [filter]=\"filterDialogState\"\n [disabled]=\"filterDialogDisabled\"\n (close)=\"onCloseFilterDialog()\"\n (apply)=\"onFilterApplied($event)\">\n </mj-filter-dialog>\n\n <!-- Export Dialog -->\n <mj-export-dialog\n [visible]=\"showExportDialog\"\n [config]=\"exportDialogConfig\"\n (closed)=\"onExportDialogClosed($event)\">\n </mj-export-dialog>\n\n <!-- List Management Dialog -->\n @if (showListManagementDialog && listManagementConfig) {\n <mj-list-management-dialog\n [config]=\"listManagementConfig\"\n [visible]=\"showListManagementDialog\"\n (complete)=\"onListManagementComplete($event)\"\n (cancel)=\"onListManagementCancel()\">\n </mj-list-management-dialog>\n }\n\n <!-- Quick Save Dialog (F-001) -->\n <mj-quick-save-dialog\n [IsOpen]=\"showQuickSaveDialog\"\n [ViewEntity]=\"selectedViewEntity\"\n [EntityName]=\"selectedEntity?.DisplayNameOrName ?? ''\"\n [Summary]=\"quickSaveSummary\"\n [IsSaving]=\"isSavingView\"\n [DefaultSaveAsNew]=\"defaultSaveAsNew\"\n (Save)=\"onQuickSave($event)\"\n (Close)=\"onQuickSaveClose()\"\n (OpenAdvanced)=\"onQuickSaveOpenAdvanced($event)\">\n </mj-quick-save-dialog>\n\n <!-- Duplicate View Dialog (F-005) -->\n <mj-duplicate-view-dialog\n [IsOpen]=\"showDuplicateDialog\"\n [SourceViewName]=\"duplicateSourceViewName\"\n [Summary]=\"duplicateSummary\"\n (Duplicate)=\"onDuplicateConfirmed($event)\"\n (Cancel)=\"onDuplicateCancel()\">\n </mj-duplicate-view-dialog>\n\n <!-- Shared View Warning Dialog (view-creation-flow Scenario 5) -->\n <mj-shared-view-warning-dialog\n [IsOpen]=\"showSharedViewWarning\"\n [ViewName]=\"selectedViewEntity?.Name ?? ''\"\n (Action)=\"onSharedViewAction($event)\"\n (Cancel)=\"onSharedViewWarningCancel()\">\n </mj-shared-view-warning-dialog>\n</div>\n", styles: [".data-explorer-container {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed {\n width: 48px;\n}\n\n.content-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n/* Breadcrumb Bar */\n.breadcrumb-bar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; /* Above sibling .content-body so header dropdowns render on top of grid/map content */\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n/* View Selector within header */\n.header-left ::ng-deep mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn:hover {\n color: var(--mj-text-primary);\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/* Header Action Button (Add to List, etc.) */\n.header-action-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn i {\n font-size: 14px;\n}\n.selection-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Timeline Date Field Selector - Styled Dropdown */\n.date-field-selector-container {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper {\n position: relative;\n}\n\n.date-field-selector-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item .item-icon {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item .item-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item .selected-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n/* View-specific controls \u2014 contextual controls for the active view mode.\n Positioned LEFT of the view mode toggle with a subtle visual separator. */\n.view-specific-controls {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\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.view-specific-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Legacy \u2014 keep for backward compat but no longer used in template */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n /* Contain the body's stacking context. The view components inside (grid\n option menus, the map's Leaflet panes/toolbar, etc.) use z-index values up\n to ~1000; .content-header sits at z-index 2 (kept below the shell header \u2014\n see #2701). Without this, those body z-indices leak into the shared context\n and paint over the header's own dropdowns (view-selector, date-field).\n `isolation: isolate` flattens all body z-indices into one context beneath\n the header. Safe because modals + the detail panel render at the dashboard\n root (outside .content-body), so they still overlay everything. */\n isolation: isolate;\n}\n\n.loading-container,\n.loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n CONCEPT D: HOME VIEW LAYOUT\n ============================================ */\n\n.home-view-concept-d {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open {\n margin-right: 320px;\n}\n\n/* ============================================\n SEARCH HERO\n ============================================ */\n\n.search-hero {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n/* Meta row: entity count + pills */\n.search-meta-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn i {\n font-size: 11px;\n}\n\n/* ============================================\n APPLICATION GROUPS\n ============================================ */\n\n.entity-groups-area {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group {\n margin-bottom: 4px;\n}\n\n.app-group-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.app-group-entities {\n padding: 4px 14px 10px 60px;\n}\n\n/* ============================================\n ENTITY ITEM GRID (pills)\n ============================================ */\n\n.entity-item-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item:hover .entity-item-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item:hover .entity-item-fav {\n opacity: 1;\n}\n\n.entity-item-fav.favorited {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n/* ============================================\n QUICK ACCESS PANEL (right slide-in)\n ============================================ */\n\n.quick-access-panel {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open {\n transform: translateX(0);\n}\n\n.qa-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header .qa-section-icon {\n font-size: 12px;\n}\n\n.qa-section-header .qa-section-count {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header .qa-section-chevron {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed .qa-section-chevron {\n transform: rotate(-90deg);\n}\n\n.qa-section-body {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed .qa-section-body {\n display: none;\n}\n\n.qa-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n/* Quick Access toggle button badge */\n.qa-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n/* No results state for home view */\n.home-no-results {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results i {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results p {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel mj-entity-record-detail-panel {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n/* Detail Panel Actions Bar */\n.detail-panel-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn i {\n font-size: 12px;\n}\n\n:host ::ng-deep mj-explorer-grid-view,\n:host ::ng-deep mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* ============================================\n HOME SCREEN STYLES\n ============================================ */\n\n/* Home-level header adjustments */\n.content-header.home-header {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content {\n padding: 0;\n}\n\n/* Smart filter with search icon (entity-level filter) */\n.filter-icon {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container .smart-filter-input {\n padding-left: 40px;\n}\n\n/* ============================================\n VIEW MODE TOGGLE OVERRIDES\n ============================================ */\n\n.view-mode-toggle .toggle-btn {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label {\n font-size: 12px;\n font-weight: 500;\n}\n\n/* ============================================\n EMPTY STATE VARIANTS\n ============================================ */\n\n.empty-state.small {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small .empty-icon {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small h3 {\n font-size: 16px;\n}\n\n.empty-state.small p {\n font-size: 13px;\n}\n\n/* ============================================\n RESPONSIVE STYLES\n ============================================ */\n\n@media (max-width: 1200px) {\n .entity-item-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open {\n margin-right: 0;\n }\n\n .quick-access-panel {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container {\n flex-direction: column;\n }\n\n .navigation-panel {\n display: none;\n }\n\n .content-header {\n padding: 12px 16px;\n }\n\n .content-body {\n padding: 12px 16px;\n }\n\n .entity-item-grid {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle {\n display: none;\n }\n\n .app-group-name {\n font-size: 17px;\n }\n\n .entity-item-name {\n font-size: 14px;\n }\n}\n"] }]
|
|
3662
|
-
}], () => [{ type: i1.ExplorerStateService }, { type: i0.ChangeDetectorRef }, { type: i2.RecentAccessService }, { type:
|
|
2177
|
+
], template: "<div class=\"data-explorer-container\">\n <!-- Navigation Panel (Left) - Hidden at home level, animated -->\n @if (!isAtHomeLevel) {\n <div\n class=\"navigation-panel\"\n [class.collapsed]=\"state.navigationPanelCollapsed\"\n [style.width.px]=\"state.navigationPanelCollapsed ? 48 : state.navigationPanelWidth\"\n [@slideInLeft]>\n\n <mj-explorer-navigation-panel\n [entities]=\"entities\"\n [appEntityGroups]=\"appEntityGroups\"\n [selectedEntityName]=\"state.selectedEntityName\"\n [favorites]=\"state.favorites\"\n [recentItems]=\"state.recentItems\"\n [collapsed]=\"state.navigationPanelCollapsed\"\n [allowedEntityNames]=\"allowedEntityNames\"\n [favoritesSectionExpanded]=\"state.favoritesSectionExpanded\"\n [recentSectionExpanded]=\"state.recentSectionExpanded\"\n [entitiesSectionExpanded]=\"state.entitiesSectionExpanded\"\n [viewsSectionExpanded]=\"state.viewsSectionExpanded\"\n (entitySelected)=\"onEntitySelected($event)\"\n (toggleCollapse)=\"toggleNavigationPanel()\"\n (sectionToggled)=\"stateService.toggleSection($event)\"\n (openRecord)=\"onOpenRecordFromNav($event)\"\n (selectRecord)=\"onSelectRecordFromNav($event)\"\n (expandAndFocus)=\"onExpandAndFocus($event)\">\n </mj-explorer-navigation-panel>\n </div>\n }\n\n <!-- Main Content Area -->\n <div class=\"content-area\">\n <!-- Breadcrumb Bar - Hidden at home level -->\n @if (!isAtHomeLevel && breadcrumbs.length > 0) {\n <div class=\"breadcrumb-bar\">\n @for (crumb of breadcrumbs; track crumb.label; let i = $index; let last = $last) {\n <span\n class=\"breadcrumb-item\"\n [class.clickable]=\"!last\"\n [class.current]=\"last\"\n (click)=\"onBreadcrumbClick(crumb, i)\"\n [title]=\"crumb.label\">\n @if (crumb.icon) {\n <i [class]=\"crumb.icon\" class=\"breadcrumb-icon\"></i>\n }\n <span class=\"breadcrumb-label\">{{ crumb.label }}</span>\n </span>\n @if (!last) {\n <i class=\"fa-solid fa-chevron-right breadcrumb-separator\"></i>\n }\n }\n </div>\n }\n\n <!-- Header -->\n <div class=\"content-header\" [class.home-header]=\"isAtHomeLevel\">\n <div class=\"header-left\">\n @if (selectedEntity) {\n <i [class]=\"getEntityIcon(selectedEntity)\" class=\"entity-icon\"></i>\n <h2 class=\"entity-title\">{{ selectedEntity.DisplayNameOrName }}</h2>\n @if (debouncedFilterText && filteredRecordCount !== totalRecordCount) {\n <span class=\"record-count\">{{ filteredRecordCount | number }} of {{ totalRecordCount | number }} records</span>\n } @else {\n <span class=\"record-count\">{{ totalRecordCount | number }} records</span>\n }\n\n <!-- View selector + view header now live inside mj-view-workspace (below). -->\n <!-- Add-to-List is now owned inside the grid plug-in renderer (it hosts its own dialog). -->\n } @else {\n @if (displayIcon) {\n <i [class]=\"displayIcon\" class=\"entity-icon\"></i>\n }\n <h2 class=\"entity-title\">{{ displayTitle }}</h2>\n <span class=\"record-count\">{{ entities.length }} entities available</span>\n }\n </div>\n\n <div class=\"header-center\">\n @if (selectedEntity) {\n <div class=\"smart-filter-container\">\n <i class=\"fa-solid fa-search filter-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"smart-filter-input\"\n placeholder=\"Filter records... (press / to focus)\"\n [value]=\"liveFilterText\"\n (input)=\"onFilterInputChanged(filterInput.value)\"\n />\n @if (liveFilterText) {\n <button class=\"clear-filter-btn\" (click)=\"clearRecordFilter()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n }\n <!-- Home-level search moved to search hero section -->\n </div>\n\n <div class=\"header-right\">\n @if (selectedEntity) {\n <!-- View-type switcher AND all view-specific controls (timeline date/orientation/sort,\n map render mode, etc.) now live inside the plug-in renderers hosted by\n mj-view-workspace. Nothing view-type-specific lives in this header anymore. -->\n }\n @if (!selectedEntity) {\n <!-- Quick Access panel toggle -->\n <button\n class=\"header-action-btn\"\n [class.active]=\"state.quickAccessPanelOpen\"\n (click)=\"toggleQuickAccessPanel()\"\n title=\"Recents & Favorites\">\n <i class=\"fa-solid fa-clock-rotate-left\"></i>\n @if (recentRecords.length + favoriteRecords.length > 0) {\n <span class=\"qa-badge\">{{ recentRecords.length + favoriteRecords.length }}</span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Content Body - Using mj-entity-viewer composite -->\n <div class=\"content-body\" [class.home-content]=\"isAtHomeLevel\">\n @if (!selectedEntity) {\n <!-- Concept D: Application Groups + Search-First Home View -->\n <div class=\"home-view-concept-d\">\n @if (isLoadingEntities) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading entities...\" size=\"medium\"></mj-loading>\n </div>\n } @else {\n <div class=\"home-main-area\" [class.panel-open]=\"state.quickAccessPanelOpen\">\n <!-- Search Hero -->\n <div class=\"search-hero\">\n <div class=\"search-hero-container\">\n <i class=\"fa-solid fa-magnifying-glass search-hero-icon\"></i>\n <input\n #filterInput\n type=\"text\"\n class=\"search-hero-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entityFilterText\"\n />\n @if (entityFilterText) {\n <button class=\"search-hero-clear\" (click)=\"entityFilterText = ''\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n } @else {\n <span class=\"search-hero-shortcut\">/</span>\n }\n </div>\n\n <!-- Meta row: entity count + All/Favorites pills -->\n <div class=\"search-meta-row\">\n <span class=\"search-entity-count\">\n {{ filteredEntityCount }} entities\n @if (applicationCount > 0) {\n across {{ applicationCount }} applications\n }\n </span>\n <div class=\"pill-toggle\">\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'all'\"\n (click)=\"setHomeViewMode('all')\">\n All Entities\n </button>\n <button\n class=\"pill-btn\"\n [class.active]=\"state.homeViewMode === 'favorites'\"\n (click)=\"setHomeViewMode('favorites')\">\n <i class=\"fa-solid fa-star\"></i> My Favorites\n </button>\n </div>\n </div>\n </div>\n\n <!-- Entity Groups Area -->\n <div class=\"entity-groups-area\">\n @if (entityFilter?.applicationId) {\n <!-- Single-app mode: flat entity grid (no grouping) -->\n <div class=\"entity-item-grid\">\n @for (entity of flatFilteredEntities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n } @else {\n <!-- Multi-app mode: grouped by application -->\n @for (group of filteredAppEntityGroups; track group.applicationId) {\n <div class=\"app-group\">\n <div class=\"app-group-header\" (click)=\"toggleAppGroup(group.applicationId)\">\n <div\n class=\"app-group-icon\"\n [style.background]=\"group.applicationColor ? group.applicationColor + '15' : null\"\n [style.color]=\"group.applicationColor || null\">\n <i [class]=\"group.applicationIcon || 'fa-solid fa-folder'\"></i>\n </div>\n <span class=\"app-group-name\">{{ group.applicationName }}</span>\n <span class=\"app-group-count\">{{ group.entities.length }}</span>\n <i class=\"fa-solid fa-chevron-right app-group-chevron\"\n [class.expanded]=\"group.isExpanded\"></i>\n </div>\n @if (group.isExpanded) {\n <div class=\"app-group-entities\">\n <div class=\"entity-item-grid\">\n @for (entity of group.entities; track entity.ID) {\n <div\n class=\"entity-item\"\n (click)=\"onEntitySelected(entity)\"\n [title]=\"entity.Description || entity.DisplayNameOrName\">\n <div class=\"entity-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"entity-item-text\">\n <span class=\"entity-item-name\">{{ entity.DisplayNameOrName }}</span>\n @if (entity.Description) {\n <span class=\"entity-item-desc\">{{ entity.Description }}</span>\n }\n </div>\n <button\n class=\"entity-item-fav\"\n [class.favorited]=\"isEntityFavorited(entity)\"\n (click)=\"toggleEntityFavorite(entity, $event)\"\n [title]=\"isEntityFavorited(entity) ? 'Remove from favorites' : 'Add to favorites'\">\n <i [class]=\"isEntityFavorited(entity) ? 'fa-solid fa-star' : 'fa-regular fa-star'\"></i>\n </button>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n\n <!-- No results -->\n @if (filteredEntityCount === 0 && entities.length > 0) {\n <div class=\"home-no-results\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <p>No entities match \"{{ entityFilterText }}\"</p>\n </div>\n }\n @if (entities.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-database empty-icon\"></i>\n <h3>No Entities Available</h3>\n <p>There are no entities configured for this application.</p>\n </div>\n }\n </div>\n </div>\n\n <!-- Quick Access Panel (right slide-in) -->\n <div class=\"quick-access-panel\" [class.open]=\"state.quickAccessPanelOpen\">\n <div class=\"qa-header\">\n <h3>Quick Access</h3>\n <button class=\"qa-close-btn\" (click)=\"toggleQuickAccessPanel()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n <div class=\"qa-body\">\n <!-- Recent Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentRecords')\">\n <i class=\"fa-solid fa-clock-rotate-left qa-section-icon\"></i>\n <span>Recent Records</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessRecentRecords; track record.entityId + '|' + record.recordId) {\n <div class=\"qa-item\" (click)=\"onRecentRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n <span class=\"qa-item-time\">{{ formatRelativeTime(record.latestAt) }}</span>\n </div>\n }\n @if (quickAccessRecentRecords.length === 0) {\n <div class=\"qa-empty\">No recent records</div>\n }\n </div>\n </div>\n\n <!-- Recent Entities (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('recentEntities')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('recentEntities')\">\n <i class=\"fa-solid fa-table qa-section-icon\"></i>\n <span>Recent Entities</span>\n <span class=\"qa-section-count\">{{ quickAccessRecentEntities.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (entity of quickAccessRecentEntities; track entity.ID) {\n <div class=\"qa-item\" (click)=\"onEntitySelected(entity)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIcon(entity)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ entity.DisplayNameOrName }}</div>\n </div>\n </div>\n }\n @if (quickAccessRecentEntities.length === 0) {\n <div class=\"qa-empty\">No recent entities</div>\n }\n </div>\n </div>\n\n <!-- Favorite Records (max 3) -->\n <div class=\"qa-section\" [class.collapsed]=\"!isQuickAccessSectionExpanded('favoriteRecords')\">\n <div class=\"qa-section-header\" (click)=\"toggleQuickAccessSection('favoriteRecords')\">\n <i class=\"fa-solid fa-star qa-section-icon\" style=\"color: var(--mj-status-warning);\"></i>\n <span>Favorite Records</span>\n <span class=\"qa-section-count\">{{ quickAccessFavoriteRecords.length }}</span>\n <i class=\"fa-solid fa-chevron-down qa-section-chevron\"></i>\n </div>\n <div class=\"qa-section-body\">\n @for (record of quickAccessFavoriteRecords; track record.userFavoriteId) {\n <div class=\"qa-item\" (click)=\"onFavoriteRecordClick(record)\">\n <div class=\"qa-item-icon\">\n <i [class]=\"getEntityIconById(record.entityId)\"></i>\n </div>\n <div class=\"qa-item-info\">\n <div class=\"qa-item-name\">{{ record.recordName || record.recordId }}</div>\n <div class=\"qa-item-meta\">{{ record.entityName }}</div>\n </div>\n </div>\n }\n @if (quickAccessFavoriteRecords.length === 0) {\n <div class=\"qa-empty\">No favorite records</div>\n }\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n } @else {\n <!--\n mj-view-workspace owns the saved-view lifecycle (select / save / duplicate / rename /\n delete / revert / quick-save) and the inner data renderer. Every view type is now a\n self-contained plug-in: view-type-specific features (export / add-to-list / delete /\n grid-state / timeline + map controls) live INSIDE the plug-in renderers and no longer\n bubble through the workspace. The dashboard only handles navigation (open record / open\n related record / create new record) + the generic filter/data-load/count signals + URL\n and view-CRUD state sync. AutoSaveView=true \u2192 the workspace persists view CRUD itself.\n -->\n <mj-view-workspace\n [Entity]=\"selectedEntity\"\n [AutoSaveView]=\"true\"\n [SelectedView]=\"selectedViewEntity\"\n [FilterText]=\"debouncedFilterText\"\n [SelectedRecordId]=\"state.selectedRecordId\"\n [ViewerConfig]=\"viewerConfig\"\n (SelectedViewChange)=\"onWorkspaceViewSelected($event)\"\n (ViewSelected)=\"onWorkspaceViewSelected($event)\"\n (OpenViewInTabRequested)=\"onOpenInTabRequested($event)\"\n (OpenRecordRequested)=\"onWorkspaceOpenRecord($event)\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecordRequested($event)\"\n (CreateNewRecordRequested)=\"onCreateNewRecordRequested($event)\"\n (RecordSelected)=\"onViewerRecordSelected($event)\"\n (AfterViewSave)=\"onWorkspaceViewSaved()\"\n (AfterViewDelete)=\"onWorkspaceViewSaved()\"\n (FilterTextChanged)=\"onFilterTextChanged($event)\"\n (DataLoaded)=\"onDataLoaded($event)\"\n (FilteredCountChanged)=\"onFilteredCountChanged($event)\">\n </mj-view-workspace>\n }\n </div>\n </div>\n\n <!-- Detail Panel (Right - Slide In) -->\n @if (state.detailPanelOpen && selectedRecord) {\n <div class=\"detail-panel\" [style.width.px]=\"state.detailPanelWidth\">\n <mj-entity-record-detail-panel\n [entity]=\"detailPanelEntity\"\n [record]=\"selectedRecord\"\n (close)=\"onDetailPanelClosed()\"\n (openRecord)=\"onOpenRecord($event)\"\n (navigateToRelated)=\"onNavigateToRelated($event)\"\n (openRelatedRecord)=\"onOpenRelatedRecord($event)\"\n (openForeignKeyRecord)=\"onOpenForeignKeyRecord($event)\">\n </mj-entity-record-detail-panel>\n </div>\n }\n\n <!-- View config panel, filter dialog, quick-save/duplicate/shared-view-warning dialogs\n now live inside mj-view-workspace (the saved-view lifecycle moved there).\n Export + Add-to-List dialogs now live inside the grid plug-in renderer (it hosts its own\n Generic dialogs), so they are no longer rendered at the dashboard level. -->\n</div>\n", styles: [".data-explorer-container {\n display: flex;\n height: 100%;\n width: 100%;\n background: var(--mj-bg-surface-card);\n overflow: hidden;\n}\n\n.navigation-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-right: 1px solid var(--mj-border-default);\n transition: width 0.2s ease-in-out;\n overflow: hidden;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);\n}\n.navigation-panel.collapsed {\n width: 48px;\n}\n\n.content-area {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-width: 0;\n overflow: hidden;\n background: var(--mj-bg-surface-card);\n}\n\n/* Breadcrumb Bar */\n.breadcrumb-bar {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n font-size: 13px;\n min-height: 40px;\n}\n\n.breadcrumb-item {\n display: flex;\n align-items: center;\n gap: 6px;\n color: var(--mj-text-secondary);\n padding: 4px 8px;\n border-radius: 4px;\n transition: all 0.15s ease;\n max-width: 200px;\n}\n\n.breadcrumb-item.clickable {\n cursor: pointer;\n}\n\n.breadcrumb-item.clickable:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n\n.breadcrumb-item.current {\n color: var(--mj-text-primary);\n font-weight: 500;\n cursor: default;\n}\n\n.breadcrumb-icon {\n font-size: 12px;\n flex-shrink: 0;\n}\n\n.breadcrumb-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.breadcrumb-separator {\n font-size: 10px;\n color: var(--mj-border-strong);\n flex-shrink: 0;\n}\n\n.content-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 24px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n gap: 24px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);\n position: relative;\n z-index: 2; /* Above sibling .content-body so header dropdowns render on top of grid/map content */\n}\n\n.header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n}\n\n/* View Selector within header */\n.header-left ::ng-deep mj-view-selector {\n margin-left: 8px;\n}\n\n.entity-icon {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.entity-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.record-count {\n font-size: 13px;\n color: var(--mj-text-secondary);\n font-weight: 500;\n}\n\n.header-center {\n flex: 1;\n max-width: 600px;\n}\n\n.smart-filter-container {\n position: relative;\n width: 100%;\n}\n\n.smart-filter-input {\n width: 100%;\n padding: 10px 40px 10px 16px;\n border: 1px solid var(--mj-border-strong);\n border-radius: 8px;\n font-size: 14px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n}\n.smart-filter-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n.smart-filter-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-filter-btn {\n position: absolute;\n right: 8px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n.clear-filter-btn:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n.header-right {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.view-mode-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.toggle-btn {\n width: 36px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n}\n.toggle-btn:hover {\n color: var(--mj-text-primary);\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/* Header Action Button (Add to List, etc.) */\n.header-action-btn {\n position: relative;\n width: 36px;\n height: 36px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n transition: all 0.15s ease;\n margin-left: 8px;\n}\n.header-action-btn:hover:not(.disabled) {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n.header-action-btn.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.header-action-btn i {\n font-size: 14px;\n}\n.selection-badge {\n position: absolute;\n top: -6px;\n right: -6px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: 600;\n border-radius: 9px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n}\n\n/* Timeline Date Field Selector - Styled Dropdown */\n.date-field-selector-container {\n display: flex;\n align-items: center;\n position: relative;\n}\n\n.date-field-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n background: transparent;\n}\n\n.date-field-selector-wrapper {\n position: relative;\n}\n\n.date-field-selector-button {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 12px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: all 0.15s ease;\n min-width: 120px;\n max-width: 200px;\n}\n\n.date-field-selector-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-hover);\n border-color: var(--mj-border-strong);\n}\n\n.date-field-selector-button:disabled {\n cursor: default;\n opacity: 0.8;\n}\n\n.date-field-selector-button.open {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n}\n\n.date-field-icon {\n color: var(--mj-text-secondary);\n font-size: 12px;\n}\n\n.date-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n}\n\n.date-field-arrow {\n color: var(--mj-text-secondary);\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.date-field-arrow.rotated {\n transform: rotate(180deg);\n}\n\n.date-field-dropdown-panel {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n min-width: 180px;\n max-width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n z-index: 1000;\n}\n\n.date-field-dropdown-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 13px;\n}\n\n.date-field-dropdown-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.date-field-dropdown-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item.selected:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n}\n\n.date-field-dropdown-item .item-icon {\n color: var(--mj-text-secondary);\n font-size: 13px;\n width: 16px;\n text-align: center;\n}\n\n.date-field-dropdown-item .item-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.date-field-dropdown-item .selected-check {\n color: var(--mj-brand-primary);\n font-size: 12px;\n}\n\n/* View-specific controls \u2014 contextual controls for the active view mode.\n Positioned LEFT of the view mode toggle with a subtle visual separator. */\n.view-specific-controls {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 3px 8px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n border: 1px solid var(--mj-border-subtle);\n}\n\n.view-specific-btn {\n width: 30px;\n height: 30px;\n border: none;\n background: transparent;\n border-radius: 6px;\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.view-specific-btn:hover {\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-hover);\n}\n\n/* Legacy \u2014 keep for backward compat but no longer used in template */\n.timeline-orientation-toggle {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 3px;\n}\n\n.content-body {\n flex: 1;\n overflow: hidden;\n padding: 20px 24px;\n display: flex;\n flex-direction: column;\n /* Contain the body's stacking context. The view components inside (grid\n option menus, the map's Leaflet panes/toolbar, etc.) use z-index values up\n to ~1000; .content-header sits at z-index 2 (kept below the shell header \u2014\n see #2701). Without this, those body z-indices leak into the shared context\n and paint over the header's own dropdowns (view-selector, date-field).\n `isolation: isolate` flattens all body z-indices into one context beneath\n the header. Safe because modals + the detail panel render at the dashboard\n root (outside .content-body), so they still overlay everything. */\n isolation: isolate;\n}\n\n.loading-container,\n.loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n background: var(--mj-bg-surface);\n border-radius: 8px;\n}\n\n.loading-spinner {\n font-size: 32px;\n color: var(--mj-brand-primary);\n}\n\n.loading-message {\n margin: 0;\n font-size: 14px;\n color: var(--mj-text-secondary);\n}\n\n.empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n text-align: center;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border-radius: 8px;\n padding: 40px;\n}\n\n.empty-icon {\n font-size: 64px;\n color: var(--mj-border-default);\n margin-bottom: 24px;\n}\n\n.empty-state h3 {\n margin: 0 0 8px 0;\n font-size: 20px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.empty-state p {\n margin: 0;\n font-size: 14px;\n max-width: 400px;\n color: var(--mj-text-secondary);\n}\n\n/* ============================================\n CONCEPT D: HOME VIEW LAYOUT\n ============================================ */\n\n.home-view-concept-d {\n flex: 1;\n display: flex;\n overflow: hidden;\n}\n\n.home-main-area {\n flex: 1;\n overflow-y: auto;\n transition: margin-right 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.home-main-area.panel-open {\n margin-right: 320px;\n}\n\n/* ============================================\n SEARCH HERO\n ============================================ */\n\n.search-hero {\n background: var(--mj-bg-surface);\n padding: 36px 40px 24px;\n text-align: center;\n}\n\n.search-hero-container {\n position: relative;\n max-width: 600px;\n margin: 0 auto;\n}\n\n.search-hero-input {\n width: 100%;\n padding: 14px 18px 14px 44px;\n font-size: 15px;\n border: 2px solid var(--mj-border-default);\n border-radius: 12px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n outline: none;\n transition: all 0.2s;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);\n font-family: inherit;\n}\n\n.search-hero-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1), 0 0 0 4px color-mix(in srgb, var(--mj-brand-primary) 8%, transparent);\n}\n\n.search-hero-input::placeholder {\n color: var(--mj-text-primary);\n}\n\n.search-hero-icon {\n position: absolute;\n left: 16px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-primary);\n font-size: 15px;\n pointer-events: none;\n}\n\n.search-hero-shortcut {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n padding: 2px 7px;\n border-radius: 5px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-hero-clear {\n position: absolute;\n right: 14px;\n top: 50%;\n transform: translateY(-50%);\n width: 28px;\n height: 28px;\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-muted);\n transition: all 0.15s ease;\n}\n\n.search-hero-clear:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-primary);\n}\n\n/* Meta row: entity count + pills */\n.search-meta-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n margin-top: 16px;\n}\n\n.search-entity-count {\n font-size: 13px;\n color: var(--mj-text-muted);\n}\n\n.pill-toggle {\n display: flex;\n gap: 6px;\n}\n\n.pill-btn {\n padding: 6px 16px;\n border-radius: 20px;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n font-size: 13px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.pill-btn:hover {\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.pill-btn.active {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary);\n}\n\n.pill-btn i {\n font-size: 11px;\n}\n\n/* ============================================\n APPLICATION GROUPS\n ============================================ */\n\n.entity-groups-area {\n padding: 12px 40px 60px;\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.app-group {\n margin-bottom: 4px;\n}\n\n.app-group-header {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px 14px;\n cursor: pointer;\n border-radius: 8px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.app-group-header:hover {\n background: rgba(0, 0, 0, 0.025);\n}\n\n.app-group-icon {\n width: 38px;\n height: 38px;\n border-radius: 10px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 17px;\n flex-shrink: 0;\n background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.app-group-name {\n font-size: 21px;\n font-weight: 600;\n flex: 1;\n}\n\n.app-group-count {\n font-size: 12px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 2px 9px;\n border-radius: 10px;\n}\n\n.app-group-chevron {\n color: var(--mj-text-muted);\n font-size: 12px;\n transition: transform 0.2s;\n}\n\n.app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.app-group-entities {\n padding: 4px 14px 10px 60px;\n}\n\n/* ============================================\n ENTITY ITEM GRID (pills)\n ============================================ */\n\n.entity-item-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));\n gap: 12px;\n}\n\n.entity-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 10px 14px;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.12s;\n border: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface);\n}\n\n.entity-item:hover {\n border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-bg-surface));\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.entity-item-icon {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 14px;\n color: var(--mj-text-secondary);\n background: var(--mj-bg-surface-card);\n flex-shrink: 0;\n}\n\n.entity-item:hover .entity-item-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.entity-item-text {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.entity-item-name {\n font-size: 14px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.entity-item-desc {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: 1.3;\n}\n\n.entity-item-fav {\n color: var(--mj-text-muted);\n opacity: 0;\n transition: opacity 0.12s;\n font-size: 11px;\n cursor: pointer;\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 4px;\n align-self: center;\n}\n\n.entity-item:hover .entity-item-fav {\n opacity: 1;\n}\n\n.entity-item-fav.favorited {\n opacity: 1;\n color: var(--mj-status-warning);\n}\n\n/* ============================================\n QUICK ACCESS PANEL (right slide-in)\n ============================================ */\n\n.quick-access-panel {\n position: fixed;\n top: 0;\n right: 0;\n width: 320px;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n z-index: 50;\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.quick-access-panel.open {\n transform: translateX(0);\n}\n\n.qa-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-header h3 {\n font-size: 14px;\n font-weight: 600;\n margin: 0;\n}\n\n.qa-close-btn {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 14px;\n padding: 4px;\n border-radius: 4px;\n}\n\n.qa-close-btn:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-body {\n flex: 1;\n overflow-y: auto;\n}\n\n.qa-section {\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.qa-section-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 16px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n cursor: pointer;\n user-select: none;\n}\n\n.qa-section-header .qa-section-icon {\n font-size: 12px;\n}\n\n.qa-section-header .qa-section-count {\n background: var(--mj-bg-surface-card);\n padding: 0 6px;\n border-radius: 8px;\n font-size: 10px;\n margin-left: auto;\n}\n\n.qa-section-header .qa-section-chevron {\n font-size: 10px;\n transition: transform 0.15s;\n}\n\n.qa-section.collapsed .qa-section-chevron {\n transform: rotate(-90deg);\n}\n\n.qa-section-body {\n padding: 0 8px 8px;\n}\n\n.qa-section.collapsed .qa-section-body {\n display: none;\n}\n\n.qa-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px;\n border-radius: 8px;\n cursor: pointer;\n transition: background 0.08s;\n}\n\n.qa-item:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.qa-item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n}\n\n.qa-item-info {\n flex: 1;\n min-width: 0;\n}\n\n.qa-item-name {\n font-size: 13px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.qa-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.qa-item-time {\n font-size: 11px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n.qa-empty {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n/* Quick Access toggle button badge */\n.qa-badge {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: 600;\n padding: 0 5px;\n border-radius: 8px;\n min-width: 16px;\n text-align: center;\n}\n\n/* No results state for home view */\n.home-no-results {\n text-align: center;\n padding: 40px 20px;\n color: var(--mj-text-muted);\n}\n\n.home-no-results i {\n font-size: 28px;\n margin-bottom: 10px;\n display: block;\n}\n\n.home-no-results p {\n font-size: 14px;\n margin: 0;\n}\n\n.detail-panel {\n flex-shrink: 0;\n height: 100%;\n background: var(--mj-bg-surface);\n border-left: 1px solid var(--mj-border-default);\n box-shadow: -4px 0 16px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n animation: slideIn 0.2s ease-out;\n display: flex;\n flex-direction: column;\n}\n\n.detail-panel mj-entity-record-detail-panel {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n@keyframes slideIn {\n from {\n transform: translateX(100%);\n opacity: 0;\n }\n to {\n transform: translateX(0);\n opacity: 1;\n }\n}\n\n/* Detail Panel Actions Bar */\n.detail-panel-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n.detail-action-btn {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n border: none;\n border-radius: 6px;\n background: var(--mj-bg-surface);\n color: var(--mj-text-secondary);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n\n.detail-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n transform: translateY(-1px);\n box-shadow: 0 2px 4px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n}\n\n.detail-action-btn i {\n font-size: 12px;\n}\n\n:host ::ng-deep mj-explorer-grid-view,\n:host ::ng-deep mj-explorer-cards-view {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n/* ============================================\n HOME SCREEN STYLES\n ============================================ */\n\n/* Home-level header adjustments */\n.content-header.home-header {\n border-bottom: none;\n background: transparent;\n box-shadow: none;\n padding: 16px 24px 8px;\n}\n\n.content-body.home-content {\n padding: 0;\n}\n\n/* Smart filter with search icon (entity-level filter) */\n.filter-icon {\n position: absolute;\n left: 14px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-muted);\n font-size: 14px;\n pointer-events: none;\n}\n\n.smart-filter-container .smart-filter-input {\n padding-left: 40px;\n}\n\n/* ============================================\n VIEW MODE TOGGLE OVERRIDES\n ============================================ */\n\n.view-mode-toggle .toggle-btn {\n width: auto;\n padding: 0 12px;\n gap: 6px;\n}\n\n.toggle-label {\n font-size: 12px;\n font-weight: 500;\n}\n\n/* ============================================\n EMPTY STATE VARIANTS\n ============================================ */\n\n.empty-state.small {\n height: auto;\n padding: 32px;\n background: var(--mj-bg-surface-card);\n}\n\n.empty-state.small .empty-icon {\n font-size: 40px;\n margin-bottom: 16px;\n}\n\n.empty-state.small h3 {\n font-size: 16px;\n}\n\n.empty-state.small p {\n font-size: 13px;\n}\n\n/* ============================================\n RESPONSIVE STYLES\n ============================================ */\n\n@media (max-width: 1200px) {\n .entity-item-grid {\n grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));\n }\n}\n\n@media (max-width: 900px) {\n .content-header {\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .header-center {\n order: 3;\n flex-basis: 100%;\n max-width: 100%;\n }\n\n .search-hero {\n padding: 24px 16px 16px;\n }\n\n .entity-groups-area {\n padding: 8px 16px 40px;\n }\n\n .app-group-entities {\n padding-left: 36px;\n }\n\n .home-main-area.panel-open {\n margin-right: 0;\n }\n\n .quick-access-panel {\n width: 100%;\n }\n}\n\n@media (max-width: 600px) {\n .data-explorer-container {\n flex-direction: column;\n }\n\n .navigation-panel {\n display: none;\n }\n\n .content-header {\n padding: 12px 16px;\n }\n\n .content-body {\n padding: 12px 16px;\n }\n\n .entity-item-grid {\n grid-template-columns: 1fr;\n }\n\n .view-mode-toggle {\n display: none;\n }\n\n .app-group-name {\n font-size: 17px;\n }\n\n .entity-item-name {\n font-size: 14px;\n }\n}\n"] }]
|
|
2178
|
+
}], () => [{ type: i1.ExplorerStateService }, { type: i0.ChangeDetectorRef }, { type: i2.RecentAccessService }, { type: i0.NgZone }], { filterInputRef: [{
|
|
3663
2179
|
type: ViewChild,
|
|
3664
2180
|
args: ['filterInput']
|
|
3665
|
-
}],
|
|
3666
|
-
type: ViewChild,
|
|
3667
|
-
args: [ViewSelectorComponent]
|
|
3668
|
-
}], entityViewerRef: [{
|
|
3669
|
-
type: ViewChild,
|
|
3670
|
-
args: [EntityViewerComponent]
|
|
3671
|
-
}], viewConfigPanelRef: [{
|
|
2181
|
+
}], viewWorkspaceRef: [{
|
|
3672
2182
|
type: ViewChild,
|
|
3673
|
-
args: [
|
|
2183
|
+
args: [ViewWorkspaceComponent]
|
|
3674
2184
|
}], entityFilter: [{
|
|
3675
2185
|
type: Input
|
|
3676
2186
|
}], deepLink: [{
|
|
@@ -3687,5 +2197,5 @@ export { DataExplorerDashboardComponent };
|
|
|
3687
2197
|
type: HostListener,
|
|
3688
2198
|
args: ['document:keydown', ['$event']]
|
|
3689
2199
|
}] }); })();
|
|
3690
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DataExplorerDashboardComponent, { className: "DataExplorerDashboardComponent", filePath: "src/DataExplorer/data-explorer-dashboard.component.ts", lineNumber:
|
|
2200
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DataExplorerDashboardComponent, { className: "DataExplorerDashboardComponent", filePath: "src/DataExplorer/data-explorer-dashboard.component.ts", lineNumber: 55 }); })();
|
|
3691
2201
|
//# sourceMappingURL=data-explorer-dashboard.component.js.map
|