@memberjunction/ng-dashboards 5.32.0 → 5.34.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/agents/agent-editor.component.js +2 -2
- package/dist/AI/components/agents/agent-editor.component.js.map +1 -1
- package/dist/Admin/admin-data-schema.component.d.ts +16 -0
- package/dist/Admin/admin-data-schema.component.d.ts.map +1 -0
- package/dist/Admin/admin-data-schema.component.js +136 -0
- package/dist/Admin/admin-data-schema.component.js.map +1 -0
- package/dist/Admin/admin-dev-tools-resource.component.d.ts +14 -0
- package/dist/Admin/admin-dev-tools-resource.component.d.ts.map +1 -0
- package/dist/Admin/admin-dev-tools-resource.component.js +162 -0
- package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -0
- package/dist/Admin/admin-identity-access.component.d.ts +15 -0
- package/dist/Admin/admin-identity-access.component.d.ts.map +1 -0
- package/dist/Admin/admin-identity-access.component.js +156 -0
- package/dist/Admin/admin-identity-access.component.js.map +1 -0
- package/dist/Admin/admin-monitoring.component.d.ts +15 -0
- package/dist/Admin/admin-monitoring.component.d.ts.map +1 -0
- package/dist/Admin/admin-monitoring.component.js +130 -0
- package/dist/Admin/admin-monitoring.component.js.map +1 -0
- package/dist/Admin/base-admin-container.component.d.ts +80 -0
- package/dist/Admin/base-admin-container.component.d.ts.map +1 -0
- package/dist/Admin/base-admin-container.component.js +198 -0
- package/dist/Admin/base-admin-container.component.js.map +1 -0
- package/dist/Admin/index.d.ts +6 -0
- package/dist/Admin/index.d.ts.map +1 -0
- package/dist/Admin/index.js +6 -0
- package/dist/Admin/index.js.map +1 -0
- package/dist/ComponentStudio/components/workspace/component-preview.component.js +1 -1
- package/dist/ComponentStudio/components/workspace/component-preview.component.js.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts +28 -8
- package/dist/ComponentStudio/services/component-studio-state.service.d.ts.map +1 -1
- package/dist/ComponentStudio/services/component-studio-state.service.js +45 -27
- package/dist/ComponentStudio/services/component-studio-state.service.js.map +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +18 -3
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts.map +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +51 -11
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +2 -2
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DevTools/app-state-inspector.component.d.ts +53 -0
- package/dist/DevTools/app-state-inspector.component.d.ts.map +1 -0
- package/dist/DevTools/app-state-inspector.component.js +301 -0
- package/dist/DevTools/app-state-inspector.component.js.map +1 -0
- package/dist/DevTools/class-registry.component.d.ts +64 -0
- package/dist/DevTools/class-registry.component.d.ts.map +1 -0
- package/dist/DevTools/class-registry.component.js +423 -0
- package/dist/DevTools/class-registry.component.js.map +1 -0
- package/dist/DevTools/dev-tools-prefs.d.ts +21 -0
- package/dist/DevTools/dev-tools-prefs.d.ts.map +1 -0
- package/dist/DevTools/dev-tools-prefs.js +48 -0
- package/dist/DevTools/dev-tools-prefs.js.map +1 -0
- package/dist/DevTools/event-monitor.component.d.ts +78 -0
- package/dist/DevTools/event-monitor.component.d.ts.map +1 -0
- package/dist/DevTools/event-monitor.component.js +659 -0
- package/dist/DevTools/event-monitor.component.js.map +1 -0
- package/dist/DevTools/graphql-console.component.d.ts +153 -0
- package/dist/DevTools/graphql-console.component.d.ts.map +1 -0
- package/dist/DevTools/graphql-console.component.js +1463 -0
- package/dist/DevTools/graphql-console.component.js.map +1 -0
- package/dist/DevTools/index.d.ts +8 -0
- package/dist/DevTools/index.d.ts.map +1 -0
- package/dist/DevTools/index.js +8 -0
- package/dist/DevTools/index.js.map +1 -0
- package/dist/DevTools/layout-inspector.component.d.ts +42 -0
- package/dist/DevTools/layout-inspector.component.d.ts.map +1 -0
- package/dist/DevTools/layout-inspector.component.js +208 -0
- package/dist/DevTools/layout-inspector.component.js.map +1 -0
- package/dist/DevTools/lazy-module-status.component.d.ts +65 -0
- package/dist/DevTools/lazy-module-status.component.d.ts.map +1 -0
- package/dist/DevTools/lazy-module-status.component.js +388 -0
- package/dist/DevTools/lazy-module-status.component.js.map +1 -0
- package/dist/DevTools/settings-explorer.component.d.ts +55 -0
- package/dist/DevTools/settings-explorer.component.d.ts.map +1 -0
- package/dist/DevTools/settings-explorer.component.js +394 -0
- package/dist/DevTools/settings-explorer.component.js.map +1 -0
- package/dist/Integration/components/widgets/integration-card.component.js +2 -2
- package/dist/Integration/components/widgets/integration-card.component.js.map +1 -1
- package/dist/Integration/components/widgets/run-history-panel.component.js +2 -2
- package/dist/Integration/components/widgets/run-history-panel.component.js.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts +134 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +1227 -24
- package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
- package/dist/SystemDiagnostics/system-diagnostics.component.js +4 -4
- package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
- package/dist/Testing/components/testing-runs.component.js +3 -3
- package/dist/Testing/components/testing-runs.component.js.map +1 -1
- package/dist/core-dashboards.module.d.ts +45 -34
- package/dist/core-dashboards.module.d.ts.map +1 -1
- package/dist/core-dashboards.module.js +57 -0
- package/dist/core-dashboards.module.js.map +1 -1
- package/dist/public-api.d.ts +2 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +2 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +52 -52
|
@@ -6,8 +6,8 @@ import * as i0 from "@angular/core";
|
|
|
6
6
|
import * as i1 from "@angular/forms";
|
|
7
7
|
import * as i2 from "@memberjunction/ng-trees";
|
|
8
8
|
const _c0 = ["entityTree"];
|
|
9
|
-
const _forTrack0 = ($index, $item) => $item.
|
|
10
|
-
const _forTrack1 = ($index, $item) => $item.compositeKeyString;
|
|
9
|
+
const _forTrack0 = ($index, $item) => $item.entityName;
|
|
10
|
+
const _forTrack1 = ($index, $item) => $item.entityName + "|" + $item.compositeKeyString;
|
|
11
11
|
function NavigationPanelComponent_Conditional_3_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
12
12
|
i0.ɵɵelementStart(0, "span", 10);
|
|
13
13
|
i0.ɵɵtext(1);
|
|
@@ -59,7 +59,7 @@ function NavigationPanelComponent_Conditional_3_Conditional_8_Conditional_2_For_
|
|
|
59
59
|
function NavigationPanelComponent_Conditional_3_Conditional_8_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
60
60
|
i0.ɵɵelementStart(0, "div", 19)(1, "div", 20);
|
|
61
61
|
i0.ɵɵrepeaterCreate(2, NavigationPanelComponent_Conditional_3_Conditional_8_Conditional_2_For_3_Template, 4, 4, "div", 21, _forTrack0);
|
|
62
|
-
i0.ɵɵrepeaterCreate(4, NavigationPanelComponent_Conditional_3_Conditional_8_Conditional_2_For_5_Template, 4, 4, "div", 21,
|
|
62
|
+
i0.ɵɵrepeaterCreate(4, NavigationPanelComponent_Conditional_3_Conditional_8_Conditional_2_For_5_Template, 4, 4, "div", 21, _forTrack1);
|
|
63
63
|
i0.ɵɵelementEnd()();
|
|
64
64
|
} if (rf & 2) {
|
|
65
65
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
@@ -264,6 +264,11 @@ function NavigationPanelComponent_Conditional_4_Template(rf, ctx) { if (rf & 1)
|
|
|
264
264
|
i0.ɵɵtextInterpolate(ctx_r1.entities.length);
|
|
265
265
|
} }
|
|
266
266
|
export class NavigationPanelComponent extends BaseAngularComponent {
|
|
267
|
+
cdr;
|
|
268
|
+
constructor(cdr) {
|
|
269
|
+
super();
|
|
270
|
+
this.cdr = cdr;
|
|
271
|
+
}
|
|
267
272
|
entities = [];
|
|
268
273
|
selectedEntityName = null;
|
|
269
274
|
favorites = [];
|
|
@@ -327,6 +332,23 @@ export class NavigationPanelComponent extends BaseAngularComponent {
|
|
|
327
332
|
if (changes['applicationIdFilter']) {
|
|
328
333
|
this.updateTreeBranchFilter();
|
|
329
334
|
}
|
|
335
|
+
if (changes['recentItems']) {
|
|
336
|
+
this.timestampLabelCache.clear();
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
ngOnInit() {
|
|
340
|
+
this.timestampRefreshHandle = setInterval(() => {
|
|
341
|
+
if (this.timestampLabelCache.size === 0)
|
|
342
|
+
return;
|
|
343
|
+
this.timestampLabelCache.clear();
|
|
344
|
+
this.cdr.markForCheck();
|
|
345
|
+
}, 30000);
|
|
346
|
+
}
|
|
347
|
+
ngOnDestroy() {
|
|
348
|
+
if (this.timestampRefreshHandle !== undefined) {
|
|
349
|
+
clearInterval(this.timestampRefreshHandle);
|
|
350
|
+
this.timestampRefreshHandle = undefined;
|
|
351
|
+
}
|
|
330
352
|
}
|
|
331
353
|
/**
|
|
332
354
|
* Update the selected entity IDs for tree highlighting when selected entity changes
|
|
@@ -511,12 +533,30 @@ export class NavigationPanelComponent extends BaseAngularComponent {
|
|
|
511
533
|
return `fa-solid fa-${icon}`;
|
|
512
534
|
}
|
|
513
535
|
/**
|
|
514
|
-
*
|
|
536
|
+
* Cache of formatted relative-time labels keyed by timestamp epoch ms.
|
|
537
|
+
* Stable within a change-detection cycle (avoids NG0100 from `now`-dependent
|
|
538
|
+
* values shifting between dirty-check and verify passes). Cleared on a coarse
|
|
539
|
+
* interval so the displayed label still updates over time.
|
|
540
|
+
*/
|
|
541
|
+
timestampLabelCache = new Map();
|
|
542
|
+
timestampRefreshHandle;
|
|
543
|
+
/**
|
|
544
|
+
* Format recent item timestamp. Cached per-timestamp so the same value is
|
|
545
|
+
* returned across change-detection passes within a single tick — recomputed
|
|
546
|
+
* on a 30-second interval (see `ngOnInit`).
|
|
515
547
|
*/
|
|
516
548
|
formatTimestamp(timestamp) {
|
|
517
|
-
const
|
|
518
|
-
const
|
|
519
|
-
|
|
549
|
+
const epoch = new Date(timestamp).getTime();
|
|
550
|
+
const cached = this.timestampLabelCache.get(epoch);
|
|
551
|
+
if (cached !== undefined) {
|
|
552
|
+
return cached;
|
|
553
|
+
}
|
|
554
|
+
const label = this.computeRelativeLabel(epoch);
|
|
555
|
+
this.timestampLabelCache.set(epoch, label);
|
|
556
|
+
return label;
|
|
557
|
+
}
|
|
558
|
+
computeRelativeLabel(epoch) {
|
|
559
|
+
const diffMs = Date.now() - epoch;
|
|
520
560
|
const diffMins = Math.floor(diffMs / 60000);
|
|
521
561
|
if (diffMins < 1)
|
|
522
562
|
return 'Just now';
|
|
@@ -528,7 +568,7 @@ export class NavigationPanelComponent extends BaseAngularComponent {
|
|
|
528
568
|
const diffDays = Math.floor(diffHours / 24);
|
|
529
569
|
if (diffDays < 7)
|
|
530
570
|
return `${diffDays}d ago`;
|
|
531
|
-
return
|
|
571
|
+
return new Date(epoch).toLocaleDateString();
|
|
532
572
|
}
|
|
533
573
|
/**
|
|
534
574
|
* Get icon for a recent item based on its entity
|
|
@@ -560,7 +600,7 @@ export class NavigationPanelComponent extends BaseAngularComponent {
|
|
|
560
600
|
}
|
|
561
601
|
return 'fa-solid fa-file-alt';
|
|
562
602
|
}
|
|
563
|
-
static ɵfac =
|
|
603
|
+
static ɵfac = function NavigationPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || NavigationPanelComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
564
604
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NavigationPanelComponent, selectors: [["mj-explorer-navigation-panel"]], viewQuery: function NavigationPanelComponent_Query(rf, ctx) { if (rf & 1) {
|
|
565
605
|
i0.ɵɵviewQuery(_c0, 5);
|
|
566
606
|
} if (rf & 2) {
|
|
@@ -585,8 +625,8 @@ export class NavigationPanelComponent extends BaseAngularComponent {
|
|
|
585
625
|
}
|
|
586
626
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NavigationPanelComponent, [{
|
|
587
627
|
type: Component,
|
|
588
|
-
args: [{ standalone: false, selector: 'mj-explorer-navigation-panel', template: "<div class=\"navigation-panel-container\" [class.collapsed]=\"collapsed\">\n <!-- Collapse Toggle -->\n <button class=\"collapse-toggle\" (click)=\"onToggleCollapse()\" [title]=\"collapsed ? 'Expand' : 'Collapse'\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"collapsed\" [class.fa-chevron-left]=\"!collapsed\"></i>\n </button>\n\n @if (!collapsed) {\n <div class=\"panel-content\">\n <!-- Favorites Section -->\n <div class=\"section favorites-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('favorites')\">\n <i class=\"fa-solid fa-star section-icon\"></i>\n <span class=\"section-title\">Favorites</span>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"section-count\">({{ favoriteRecords.length + favoriteEntities.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"favoritesSectionExpanded\" [class.fa-chevron-right]=\"!favoritesSectionExpanded\"></i>\n </div>\n\n @if (favoritesSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (favoriteRecords.length + favoriteEntities.length === 0) {\n <div class=\"empty-section\">\n <span>No favorites yet</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (favorite of favoriteEntities; track favorite.displayName) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n @for (favorite of favoriteRecords; track favorite.displayName) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Recent Items Section -->\n <div class=\"section recent-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('recent')\">\n <i class=\"fa-solid fa-clock section-icon\"></i>\n <span class=\"section-title\">Recent</span>\n @if (filteredRecentItems.length > 0) {\n <span class=\"section-count\">({{ filteredRecentItems.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"recentSectionExpanded\" [class.fa-chevron-right]=\"!recentSectionExpanded\"></i>\n </div>\n\n @if (recentSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (filteredRecentItems.length === 0) {\n <div class=\"empty-section\">\n <span>No recent items</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (item of filteredRecentItems; track item.compositeKeyString) {\n <div class=\"nav-item\" (click)=\"onRecentClick(item)\" [title]=\"item.entityName + ' - ' + item.displayName\">\n <i [class]=\"getRecentItemIcon(item)\"></i>\n <div class=\"nav-item-content\">\n <span class=\"nav-item-label\">{{ item.displayName }}</span>\n <span class=\"nav-item-meta\">{{ formatTimestamp(item.timestamp) }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Entities Section (ng-tree) -->\n <div class=\"section entities-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('entities')\">\n <i class=\"fa-solid fa-database section-icon\"></i>\n <span class=\"section-title\">Entities</span>\n <span class=\"section-count\">({{ entities.length }})</span>\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"entitiesSectionExpanded\" [class.fa-chevron-right]=\"!entitiesSectionExpanded\"></i>\n </div>\n\n @if (entitiesSectionExpanded) {\n <div class=\"section-content entity-tree-container\">\n <!-- Entity Search -->\n <div class=\"entity-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entitySearchTerm\"\n (ngModelChange)=\"onEntitySearchChanged()\"\n />\n @if (entitySearchTerm) {\n <button class=\"clear-search\" (click)=\"clearEntitySearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n\n <!-- Entity Tree -->\n <mj-tree\n #entityTree\n [BranchConfig]=\"treeBranchConfig\"\n [LeafConfig]=\"treeLeafConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'leaf'\"\n [SelectedIDs]=\"selectedEntityIds\"\n [ShowIcons]=\"true\"\n [ShowExpandCollapseAll]=\"false\"\n [AnimateExpandCollapse]=\"true\"\n [EmptyMessage]=\"entitySearchTerm ? 'No matches for: ' + entitySearchTerm : 'No entities available'\"\n [EmptyIcon]=\"'fa-solid fa-database'\"\n (SelectionChange)=\"onTreeEntitySelected($event)\">\n </mj-tree>\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Collapsed State - Show Icons Only -->\n <div class=\"collapsed-icons\">\n <button class=\"icon-btn\" title=\"Favorites\" (click)=\"onCollapsedIconClick('favorites')\">\n <i class=\"fa-solid fa-star\"></i>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"collapsed-badge\">{{ favoriteRecords.length + favoriteEntities.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Recent\" (click)=\"onCollapsedIconClick('recent')\">\n <i class=\"fa-solid fa-clock\"></i>\n @if (filteredRecentItems.length > 0) {\n <span class=\"collapsed-badge\">{{ filteredRecentItems.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Entities\" (click)=\"onCollapsedIconClick('entities')\">\n <i class=\"fa-solid fa-database\"></i>\n <span class=\"collapsed-badge\">{{ entities.length }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [".navigation-panel-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0; /* Critical for nested flex scrolling */\n position: relative;\n background: var(--mj-bg-surface);\n box-shadow: 1px 0 3px rgba(0, 0, 0, 0.05);\n}\n.navigation-panel-container.collapsed {\n align-items: center;\n padding-top: 48px;\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.panel-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.collapse-toggle {\n position: absolute;\n top: 12px;\n right: 12px;\n width: 28px;\n height: 28px;\n border: none;\n background: var(--mj-bg-surface-card);\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 z-index: 10;\n}\n.collapse-toggle:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.collapsed .collapse-toggle {\n right: auto;\n left: 50%;\n transform: translateX(-50%);\n background: transparent;\n}\n.collapsed .collapse-toggle:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.panel-content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n padding-top: 48px;\n min-height: 0; /* Allow flex children to shrink below content size */\n}\n\n.section {\n flex-shrink: 0;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n/* Scrollable sections (Favorites, Recent) - allow them to shrink and scroll */\n.section.favorites-section,\n.section.recent-section {\n display: flex;\n flex-direction: column;\n min-height: 0;\n max-height: 200px; /* Limit height so entities section has room */\n}\n\n.section.entities-section {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n border-bottom: none;\n}\n\n.section-header {\n display: flex;\n align-items: center;\n padding: 14px 16px;\n cursor: pointer;\n user-select: none;\n transition: background 0.15s ease;\n background: var(--mj-bg-surface-card);\n}\n.section-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.section-icon {\n width: 20px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin-right: 10px;\n}\n\n.section-title {\n flex: 1;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n}\n\n.section-count {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-right: 8px;\n font-weight: 500;\n}\n\n.expand-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n transition: transform 0.15s ease;\n}\n\n.section-content {\n padding: 8px 12px 12px 12px;\n background: var(--mj-bg-surface);\n}\n\n/* Scrollable section content for Favorites and Recent */\n.section-content.scrollable-section {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n}\n\n.scrollable-list {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n padding-right: 4px;\n}\n.scrollable-list::-webkit-scrollbar {\n width: 6px;\n}\n.scrollable-list::-webkit-scrollbar-track {\n background: transparent;\n}\n.scrollable-list::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n.scrollable-list::-webkit-scrollbar-thumb:hover {\n background: var(--mj-border-strong);\n}\n\n.scrollable-list-inner {\n /* Inner container grows naturally based on content */\n}\n\n.entities-section .section-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0; /* Allow content to shrink */\n overflow: hidden;\n}\n\n.entity-tree-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n}\n\n.entity-tree-container mj-tree {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n.empty-section {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 12px;\n font-style: italic;\n}\n\n.nav-item {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n gap: 10px;\n margin-bottom: 2px;\n}\n.nav-item:hover {\n background: var(--mj-bg-surface-card);\n}\n.nav-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n.nav-item.selected i {\n color: var(--mj-brand-primary);\n}\n.nav-item.selected .nav-item-label {\n font-weight: 600;\n}\n.nav-item i {\n width: 18px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n text-align: center;\n}\n\n.nav-item-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.nav-item-label {\n font-size: 13px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.nav-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.entity-search {\n position: relative;\n margin-bottom: 12px;\n flex-shrink: 0;\n}\n\n.search-icon {\n position: absolute;\n left: 12px;\n top: 50%;\n transform: translateY(-50%);\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-input {\n width: 100%;\n padding: 10px 36px 10px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n background: var(--mj-bg-surface-card);\n transition: all 0.15s ease;\n}\n.search-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.search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-search {\n position: absolute;\n right: 6px;\n top: 50%;\n transform: translateY(-50%);\n width: 24px;\n height: 24px;\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}\n.clear-search:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-muted);\n}\n\n.entity-list {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n padding-right: 4px;\n}\n.entity-list::-webkit-scrollbar {\n width: 6px;\n}\n.entity-list::-webkit-scrollbar-track {\n background: transparent;\n}\n.entity-list::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n.entity-list::-webkit-scrollbar-thumb:hover {\n background: var(--mj-border-strong);\n}\n\n.entity-list-inner {\n /* Inner container grows naturally based on content */\n /* Does not scroll - parent .entity-list handles scrolling */\n}\n\n.entity-item .nav-item-label {\n flex: 1;\n}\n\n/* ============================================\n NAV PANEL APPLICATION GROUPS\n ============================================ */\n\n.nav-app-group {\n margin-bottom: 2px;\n}\n\n.nav-app-group-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n cursor: pointer;\n border-radius: 6px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.nav-app-group-header:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.nav-app-group-icon {\n font-size: 12px;\n color: var(--mj-text-secondary);\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.nav-app-group-name {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-secondary);\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.nav-app-group-count {\n font-size: 10px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 1px 6px;\n border-radius: 8px;\n}\n\n.nav-app-group-chevron {\n font-size: 9px;\n color: var(--mj-text-muted);\n transition: transform 0.15s;\n}\n\n.nav-app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.nav-app-group-entities {\n padding-left: 8px;\n}\n\n.nav-app-group-entities .nav-item {\n padding: 8px 10px 8px 16px;\n}\n\n.collapsed-icons {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n\n.icon-btn {\n width: 36px;\n height: 36px;\n border: none;\n background: transparent;\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 position: relative;\n}\n.icon-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n.icon-btn i {\n font-size: 16px;\n}\n\n.collapsed-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n}\n"] }]
|
|
589
|
-
}],
|
|
628
|
+
args: [{ standalone: false, selector: 'mj-explorer-navigation-panel', template: "<div class=\"navigation-panel-container\" [class.collapsed]=\"collapsed\">\n <!-- Collapse Toggle -->\n <button class=\"collapse-toggle\" (click)=\"onToggleCollapse()\" [title]=\"collapsed ? 'Expand' : 'Collapse'\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"collapsed\" [class.fa-chevron-left]=\"!collapsed\"></i>\n </button>\n\n @if (!collapsed) {\n <div class=\"panel-content\">\n <!-- Favorites Section -->\n <div class=\"section favorites-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('favorites')\">\n <i class=\"fa-solid fa-star section-icon\"></i>\n <span class=\"section-title\">Favorites</span>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"section-count\">({{ favoriteRecords.length + favoriteEntities.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"favoritesSectionExpanded\" [class.fa-chevron-right]=\"!favoritesSectionExpanded\"></i>\n </div>\n\n @if (favoritesSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (favoriteRecords.length + favoriteEntities.length === 0) {\n <div class=\"empty-section\">\n <span>No favorites yet</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (favorite of favoriteEntities; track favorite.entityName) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n @for (favorite of favoriteRecords; track favorite.entityName + '|' + favorite.compositeKeyString) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Recent Items Section -->\n <div class=\"section recent-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('recent')\">\n <i class=\"fa-solid fa-clock section-icon\"></i>\n <span class=\"section-title\">Recent</span>\n @if (filteredRecentItems.length > 0) {\n <span class=\"section-count\">({{ filteredRecentItems.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"recentSectionExpanded\" [class.fa-chevron-right]=\"!recentSectionExpanded\"></i>\n </div>\n\n @if (recentSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (filteredRecentItems.length === 0) {\n <div class=\"empty-section\">\n <span>No recent items</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (item of filteredRecentItems; track item.entityName + '|' + item.compositeKeyString) {\n <div class=\"nav-item\" (click)=\"onRecentClick(item)\" [title]=\"item.entityName + ' - ' + item.displayName\">\n <i [class]=\"getRecentItemIcon(item)\"></i>\n <div class=\"nav-item-content\">\n <span class=\"nav-item-label\">{{ item.displayName }}</span>\n <span class=\"nav-item-meta\">{{ formatTimestamp(item.timestamp) }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Entities Section (ng-tree) -->\n <div class=\"section entities-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('entities')\">\n <i class=\"fa-solid fa-database section-icon\"></i>\n <span class=\"section-title\">Entities</span>\n <span class=\"section-count\">({{ entities.length }})</span>\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"entitiesSectionExpanded\" [class.fa-chevron-right]=\"!entitiesSectionExpanded\"></i>\n </div>\n\n @if (entitiesSectionExpanded) {\n <div class=\"section-content entity-tree-container\">\n <!-- Entity Search -->\n <div class=\"entity-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entitySearchTerm\"\n (ngModelChange)=\"onEntitySearchChanged()\"\n />\n @if (entitySearchTerm) {\n <button class=\"clear-search\" (click)=\"clearEntitySearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n\n <!-- Entity Tree -->\n <mj-tree\n #entityTree\n [BranchConfig]=\"treeBranchConfig\"\n [LeafConfig]=\"treeLeafConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'leaf'\"\n [SelectedIDs]=\"selectedEntityIds\"\n [ShowIcons]=\"true\"\n [ShowExpandCollapseAll]=\"false\"\n [AnimateExpandCollapse]=\"true\"\n [EmptyMessage]=\"entitySearchTerm ? 'No matches for: ' + entitySearchTerm : 'No entities available'\"\n [EmptyIcon]=\"'fa-solid fa-database'\"\n (SelectionChange)=\"onTreeEntitySelected($event)\">\n </mj-tree>\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Collapsed State - Show Icons Only -->\n <div class=\"collapsed-icons\">\n <button class=\"icon-btn\" title=\"Favorites\" (click)=\"onCollapsedIconClick('favorites')\">\n <i class=\"fa-solid fa-star\"></i>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"collapsed-badge\">{{ favoriteRecords.length + favoriteEntities.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Recent\" (click)=\"onCollapsedIconClick('recent')\">\n <i class=\"fa-solid fa-clock\"></i>\n @if (filteredRecentItems.length > 0) {\n <span class=\"collapsed-badge\">{{ filteredRecentItems.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Entities\" (click)=\"onCollapsedIconClick('entities')\">\n <i class=\"fa-solid fa-database\"></i>\n <span class=\"collapsed-badge\">{{ entities.length }}</span>\n </button>\n </div>\n }\n</div>\n", styles: [".navigation-panel-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0; /* Critical for nested flex scrolling */\n position: relative;\n background: var(--mj-bg-surface);\n box-shadow: 1px 0 3px rgba(0, 0, 0, 0.05);\n}\n.navigation-panel-container.collapsed {\n align-items: center;\n padding-top: 48px;\n}\n\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.panel-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.collapse-toggle {\n position: absolute;\n top: 12px;\n right: 12px;\n width: 28px;\n height: 28px;\n border: none;\n background: var(--mj-bg-surface-card);\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 z-index: 10;\n}\n.collapse-toggle:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n.collapsed .collapse-toggle {\n right: auto;\n left: 50%;\n transform: translateX(-50%);\n background: transparent;\n}\n.collapsed .collapse-toggle:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.panel-content {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n padding-top: 48px;\n min-height: 0; /* Allow flex children to shrink below content size */\n}\n\n.section {\n flex-shrink: 0;\n border-bottom: 1px solid var(--mj-border-default);\n}\n\n/* Scrollable sections (Favorites, Recent) - allow them to shrink and scroll */\n.section.favorites-section,\n.section.recent-section {\n display: flex;\n flex-direction: column;\n min-height: 0;\n max-height: 200px; /* Limit height so entities section has room */\n}\n\n.section.entities-section {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n border-bottom: none;\n}\n\n.section-header {\n display: flex;\n align-items: center;\n padding: 14px 16px;\n cursor: pointer;\n user-select: none;\n transition: background 0.15s ease;\n background: var(--mj-bg-surface-card);\n}\n.section-header:hover {\n background: var(--mj-bg-surface-sunken);\n}\n\n.section-icon {\n width: 20px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n margin-right: 10px;\n}\n\n.section-title {\n flex: 1;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.8px;\n color: var(--mj-text-muted);\n}\n\n.section-count {\n font-size: 11px;\n color: var(--mj-text-muted);\n margin-right: 8px;\n font-weight: 500;\n}\n\n.expand-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n transition: transform 0.15s ease;\n}\n\n.section-content {\n padding: 8px 12px 12px 12px;\n background: var(--mj-bg-surface);\n}\n\n/* Scrollable section content for Favorites and Recent */\n.section-content.scrollable-section {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n}\n\n.scrollable-list {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n padding-right: 4px;\n}\n.scrollable-list::-webkit-scrollbar {\n width: 6px;\n}\n.scrollable-list::-webkit-scrollbar-track {\n background: transparent;\n}\n.scrollable-list::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n.scrollable-list::-webkit-scrollbar-thumb:hover {\n background: var(--mj-border-strong);\n}\n\n.scrollable-list-inner {\n /* Inner container grows naturally based on content */\n}\n\n.entities-section .section-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0; /* Allow content to shrink */\n overflow: hidden;\n}\n\n.entity-tree-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n}\n\n.entity-tree-container mj-tree {\n flex: 1;\n min-height: 0;\n overflow-y: auto;\n}\n\n.empty-section {\n padding: 20px 16px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 12px;\n font-style: italic;\n}\n\n.nav-item {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n gap: 10px;\n margin-bottom: 2px;\n}\n.nav-item:hover {\n background: var(--mj-bg-surface-card);\n}\n.nav-item.selected {\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n box-shadow: 0 1px 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n.nav-item.selected i {\n color: var(--mj-brand-primary);\n}\n.nav-item.selected .nav-item-label {\n font-weight: 600;\n}\n.nav-item i {\n width: 18px;\n font-size: 14px;\n color: var(--mj-text-secondary);\n flex-shrink: 0;\n text-align: center;\n}\n\n.nav-item-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.nav-item-label {\n font-size: 13px;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.nav-item-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n\n.entity-search {\n position: relative;\n margin-bottom: 12px;\n flex-shrink: 0;\n}\n\n.search-icon {\n position: absolute;\n left: 12px;\n top: 50%;\n transform: translateY(-50%);\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.search-input {\n width: 100%;\n padding: 10px 36px 10px 36px;\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 13px;\n background: var(--mj-bg-surface-card);\n transition: all 0.15s ease;\n}\n.search-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.search-input::placeholder {\n color: var(--mj-text-muted);\n}\n\n.clear-search {\n position: absolute;\n right: 6px;\n top: 50%;\n transform: translateY(-50%);\n width: 24px;\n height: 24px;\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}\n.clear-search:hover {\n background: var(--mj-border-default);\n color: var(--mj-text-muted);\n}\n\n.entity-list {\n flex: 1;\n overflow-y: auto;\n min-height: 0;\n padding-right: 4px;\n}\n.entity-list::-webkit-scrollbar {\n width: 6px;\n}\n.entity-list::-webkit-scrollbar-track {\n background: transparent;\n}\n.entity-list::-webkit-scrollbar-thumb {\n background: var(--mj-border-strong);\n border-radius: 3px;\n}\n.entity-list::-webkit-scrollbar-thumb:hover {\n background: var(--mj-border-strong);\n}\n\n.entity-list-inner {\n /* Inner container grows naturally based on content */\n /* Does not scroll - parent .entity-list handles scrolling */\n}\n\n.entity-item .nav-item-label {\n flex: 1;\n}\n\n/* ============================================\n NAV PANEL APPLICATION GROUPS\n ============================================ */\n\n.nav-app-group {\n margin-bottom: 2px;\n}\n\n.nav-app-group-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n cursor: pointer;\n border-radius: 6px;\n transition: background 0.12s;\n user-select: none;\n}\n\n.nav-app-group-header:hover {\n background: var(--mj-bg-surface-card);\n}\n\n.nav-app-group-icon {\n font-size: 12px;\n color: var(--mj-text-secondary);\n width: 16px;\n text-align: center;\n flex-shrink: 0;\n}\n\n.nav-app-group-name {\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--mj-text-secondary);\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.nav-app-group-count {\n font-size: 10px;\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface-card);\n padding: 1px 6px;\n border-radius: 8px;\n}\n\n.nav-app-group-chevron {\n font-size: 9px;\n color: var(--mj-text-muted);\n transition: transform 0.15s;\n}\n\n.nav-app-group-chevron.expanded {\n transform: rotate(90deg);\n}\n\n.nav-app-group-entities {\n padding-left: 8px;\n}\n\n.nav-app-group-entities .nav-item {\n padding: 8px 10px 8px 16px;\n}\n\n.collapsed-icons {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n\n.icon-btn {\n width: 36px;\n height: 36px;\n border: none;\n background: transparent;\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 position: relative;\n}\n.icon-btn:hover {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-brand-primary);\n}\n.icon-btn i {\n font-size: 16px;\n}\n\n.collapsed-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n font-size: 10px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0 4px;\n}\n"] }]
|
|
629
|
+
}], () => [{ type: i0.ChangeDetectorRef }], { entities: [{
|
|
590
630
|
type: Input
|
|
591
631
|
}], selectedEntityName: [{
|
|
592
632
|
type: Input
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation-panel.component.js","sourceRoot":"","sources":["../../../../src/DataExplorer/components/navigation-panel/navigation-panel.component.ts","../../../../src/DataExplorer/components/navigation-panel/navigation-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ViewChild } from '@angular/core';\nimport { EntityInfo, CompositeKey } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { TreeBranchConfig, TreeLeafConfig, TreeNode, TreeComponent } from '@memberjunction/ng-trees';\nimport { RecentItem, FavoriteItem, AppEntityGroup } from '../../models/explorer-state.interface';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Event emitted when a record should be opened in a full tab\n */\nexport interface OpenRecordEvent {\n entityName: string;\n compositeKey: CompositeKey;\n}\n\n/**\n * Event emitted when a record should be selected within Data Explorer (not full tab)\n */\nexport interface SelectRecordEvent {\n entityName: string;\n recordId: string;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-explorer-navigation-panel',\n templateUrl: './navigation-panel.component.html',\n styleUrls: ['./navigation-panel.component.css']\n})\nexport class NavigationPanelComponent extends BaseAngularComponent implements OnChanges {\n @Input() entities: EntityInfo[] = [];\n @Input() selectedEntityName: string | null = null;\n @Input() favorites: FavoriteItem[] = [];\n @Input() recentItems: RecentItem[] = [];\n @Input() collapsed = false;\n /**\n * Optional set of allowed entity names for filtering favorites/recents.\n * If provided, only items matching these entities will be shown.\n */\n @Input() allowedEntityNames: Set<string> | null = null;\n /** Application-based entity groups from the parent dashboard */\n @Input() appEntityGroups: AppEntityGroup[] = [];\n /** Optional application ID filter for the tree */\n @Input() applicationIdFilter: string | null = null;\n\n // Section expansion states\n @Input() favoritesSectionExpanded = true;\n @Input() recentSectionExpanded = true;\n @Input() entitiesSectionExpanded = true;\n @Input() viewsSectionExpanded = true;\n\n @Output() entitySelected = new EventEmitter<EntityInfo>();\n @Output() toggleCollapse = new EventEmitter<void>();\n @Output() sectionToggled = new EventEmitter<'favorites' | 'recent' | 'entities' | 'views'>();\n @Output() openRecord = new EventEmitter<OpenRecordEvent>();\n /** Emitted when a record should be selected within Data Explorer (navigate to entity + select record) */\n @Output() selectRecord = new EventEmitter<SelectRecordEvent>();\n /** Emitted when a collapsed icon is clicked - expands panel and focuses section */\n @Output() expandAndFocus = new EventEmitter<'favorites' | 'recent' | 'entities'>();\n /** Emitted when a nav panel app group is toggled */\n @Output() appGroupToggled = new EventEmitter<string>();\n\n private get metadata() { return this.ProviderToUse; }\n\n // Tree configuration for entity list\n public treeBranchConfig: TreeBranchConfig = {\n EntityName: 'MJ: Applications',\n DisplayField: 'Name',\n IDField: 'ID',\n IconField: 'Icon',\n OrderBy: 'Name'\n };\n\n public treeLeafConfig: TreeLeafConfig = {\n EntityName: 'MJ: Entities',\n ParentField: '', // Using JunctionConfig for M2M relationship\n DisplayField: 'Name',\n IDField: 'ID',\n IconField: 'Icon',\n JunctionConfig: {\n EntityName: 'MJ: Application Entities',\n BranchForeignKey: 'ApplicationID',\n LeafForeignKey: 'EntityID'\n },\n OrderBy: 'Name'\n };\n\n @ViewChild('entityTree') entityTree?: TreeComponent;\n\n /** Selected entity ID for tree highlighting */\n public selectedEntityIds: string[] = [];\n\n /** Search term for filtering the entity tree */\n public entitySearchTerm = '';\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['selectedEntityName']) {\n this.updateSelectedEntityKey();\n }\n if (changes['applicationIdFilter']) {\n this.updateTreeBranchFilter();\n }\n }\n\n /**\n * Update the selected entity IDs for tree highlighting when selected entity changes\n */\n private updateSelectedEntityKey(): void {\n if (this.selectedEntityName) {\n const entity = this.metadata.Entities.find(e => e.Name === this.selectedEntityName);\n if (entity) {\n this.selectedEntityIds = [entity.ID];\n return;\n }\n }\n this.selectedEntityIds = [];\n }\n\n /**\n * Update the tree's branch filter when application filter changes\n */\n private updateTreeBranchFilter(): void {\n if (this.applicationIdFilter) {\n this.treeBranchConfig = {\n ...this.treeBranchConfig,\n ExtraFilter: `ID='${this.applicationIdFilter}'`\n };\n } else {\n this.treeBranchConfig = {\n ...this.treeBranchConfig,\n ExtraFilter: undefined\n };\n }\n }\n\n /**\n * Filter the entity tree when search term changes\n */\n onEntitySearchChanged(): void {\n if (this.entityTree) {\n this.entityTree.FilterNodes(this.entitySearchTerm, {\n searchBranches: true,\n searchLeaves: true,\n caseSensitive: false\n });\n }\n }\n\n /**\n * Clear the entity search\n */\n clearEntitySearch(): void {\n this.entitySearchTerm = '';\n this.onEntitySearchChanged();\n }\n\n /**\n * Handle tree selection change - map TreeNode to EntityInfo and emit\n */\n onTreeEntitySelected(nodes: TreeNode[]): void {\n if (!nodes || nodes.length === 0) return;\n const node = nodes[0];\n if (node.Type !== 'leaf') return;\n\n // Find the EntityInfo by ID from the node\n const entity = this.metadata.Entities.find(e => UUIDsEqual(e.ID, node.ID));\n if (entity) {\n this.entitySelected.emit(entity);\n }\n }\n\n /**\n * Get recent items filtered by allowed entities (if filter is active)\n */\n get filteredRecentItems(): RecentItem[] {\n if (!this.allowedEntityNames) {\n return this.recentItems;\n }\n return this.recentItems.filter(r => this.allowedEntityNames!.has(r.entityName));\n }\n\n /**\n * Get favorites filtered to records only (respecting entity filter)\n */\n get favoriteRecords(): FavoriteItem[] {\n const records = this.favorites.filter(f => f.type === 'record');\n if (!this.allowedEntityNames) {\n return records;\n }\n return records.filter(f => f.entityName && this.allowedEntityNames!.has(f.entityName));\n }\n\n /**\n * Get favorites filtered to entities only (respecting entity filter)\n */\n get favoriteEntities(): FavoriteItem[] {\n const entities = this.favorites.filter(f => f.type === 'entity');\n if (!this.allowedEntityNames) {\n return entities;\n }\n return entities.filter(f => f.entityName && this.allowedEntityNames!.has(f.entityName));\n }\n\n /**\n * Handle entity click\n */\n onEntityClick(entity: EntityInfo): void {\n this.entitySelected.emit(entity);\n }\n\n /**\n * Handle favorite click - navigates to entity and selects record within Data Explorer\n */\n onFavoriteClick(favorite: FavoriteItem): void {\n if (favorite.type === 'entity' && favorite.entityName) {\n const entity = this.entities.find(e => e.Name === favorite.entityName);\n if (entity) {\n this.entitySelected.emit(entity);\n }\n } else if (favorite.type === 'record' && favorite.entityName && favorite.compositeKeyString) {\n // Extract record ID from the composite key string\n // Format is \"FieldName|Value\" or \"FieldName|Value||FieldName2|Value2\"\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromConcatenatedString(favorite.compositeKeyString);\n const recordId = compositeKey.KeyValuePairs[0]?.Value?.toString() || '';\n\n // Navigate to entity and select record within Data Explorer (not full tab)\n this.selectRecord.emit({\n entityName: favorite.entityName,\n recordId\n });\n }\n }\n\n /**\n * Handle recent item click - navigates to entity and selects record within Data Explorer\n */\n onRecentClick(item: RecentItem): void {\n // Extract record ID from the composite key string\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromConcatenatedString(item.compositeKeyString);\n const recordId = compositeKey.KeyValuePairs[0]?.Value?.toString() || '';\n\n // Navigate to entity and select record within Data Explorer (not full tab)\n this.selectRecord.emit({\n entityName: item.entityName,\n recordId\n });\n }\n\n /**\n * Handle section header click\n */\n onSectionToggle(section: 'favorites' | 'recent' | 'entities' | 'views'): void {\n this.sectionToggled.emit(section);\n }\n\n /**\n * Handle collapse toggle\n */\n onToggleCollapse(): void {\n this.toggleCollapse.emit();\n }\n\n /**\n * Handle collapsed icon click - expands panel and focuses section\n */\n onCollapsedIconClick(section: 'favorites' | 'recent' | 'entities'): void {\n this.expandAndFocus.emit(section);\n }\n\n /**\n * Check if entity is selected\n */\n isEntitySelected(entity: EntityInfo): boolean {\n return entity.Name === this.selectedEntityName;\n }\n\n /**\n * Get icon for entity\n */\n getEntityIcon(entity: EntityInfo): string {\n const icon = entity.Icon;\n if (!icon) {\n return 'fa-solid fa-table';\n }\n // If icon already has fa- prefix, use it as-is\n if (icon.startsWith('fa-') || icon.startsWith('fa ')) {\n // Ensure it has a style prefix (fa-solid, fa-regular, etc.)\n if (icon.startsWith('fa-solid') || icon.startsWith('fa-regular') ||\n icon.startsWith('fa-light') || icon.startsWith('fa-brands') ||\n icon.startsWith('fa ')) {\n return icon;\n }\n // It's just \"fa-something\", add fa-solid prefix\n return `fa-solid ${icon}`;\n }\n // Check if it's just an icon name like \"table\" or \"users\"\n return `fa-solid fa-${icon}`;\n }\n\n /**\n * Format recent item timestamp\n */\n formatTimestamp(timestamp: Date): string {\n const date = new Date(timestamp);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / 60000);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n\n const diffHours = Math.floor(diffMins / 60);\n if (diffHours < 24) return `${diffHours}h ago`;\n\n const diffDays = Math.floor(diffHours / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return date.toLocaleDateString();\n }\n\n /**\n * Get icon for a recent item based on its entity\n */\n getRecentItemIcon(item: RecentItem): string {\n const entityInfo = this.metadata.Entities.find(e => e.Name === item.entityName);\n if (entityInfo) {\n return this.getEntityIcon(entityInfo);\n }\n return 'fa-solid fa-file-alt';\n }\n\n /**\n * Get icon for a favorite item based on its type and entity\n */\n getFavoriteIcon(favorite: FavoriteItem): string {\n if (favorite.type === 'view') {\n return 'fa-solid fa-filter';\n }\n\n // For entity and record types, look up the entity icon\n if (favorite.entityName) {\n const entityInfo = this.metadata.Entities.find(e => e.Name === favorite.entityName);\n if (entityInfo) {\n return this.getEntityIcon(entityInfo);\n }\n }\n\n // Fallback icons\n if (favorite.type === 'entity') {\n return 'fa-solid fa-table';\n }\n return 'fa-solid fa-file-alt';\n }\n}\n","<div class=\"navigation-panel-container\" [class.collapsed]=\"collapsed\">\n <!-- Collapse Toggle -->\n <button class=\"collapse-toggle\" (click)=\"onToggleCollapse()\" [title]=\"collapsed ? 'Expand' : 'Collapse'\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"collapsed\" [class.fa-chevron-left]=\"!collapsed\"></i>\n </button>\n\n @if (!collapsed) {\n <div class=\"panel-content\">\n <!-- Favorites Section -->\n <div class=\"section favorites-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('favorites')\">\n <i class=\"fa-solid fa-star section-icon\"></i>\n <span class=\"section-title\">Favorites</span>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"section-count\">({{ favoriteRecords.length + favoriteEntities.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"favoritesSectionExpanded\" [class.fa-chevron-right]=\"!favoritesSectionExpanded\"></i>\n </div>\n\n @if (favoritesSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (favoriteRecords.length + favoriteEntities.length === 0) {\n <div class=\"empty-section\">\n <span>No favorites yet</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (favorite of favoriteEntities; track favorite.displayName) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n @for (favorite of favoriteRecords; track favorite.displayName) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Recent Items Section -->\n <div class=\"section recent-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('recent')\">\n <i class=\"fa-solid fa-clock section-icon\"></i>\n <span class=\"section-title\">Recent</span>\n @if (filteredRecentItems.length > 0) {\n <span class=\"section-count\">({{ filteredRecentItems.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"recentSectionExpanded\" [class.fa-chevron-right]=\"!recentSectionExpanded\"></i>\n </div>\n\n @if (recentSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (filteredRecentItems.length === 0) {\n <div class=\"empty-section\">\n <span>No recent items</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (item of filteredRecentItems; track item.compositeKeyString) {\n <div class=\"nav-item\" (click)=\"onRecentClick(item)\" [title]=\"item.entityName + ' - ' + item.displayName\">\n <i [class]=\"getRecentItemIcon(item)\"></i>\n <div class=\"nav-item-content\">\n <span class=\"nav-item-label\">{{ item.displayName }}</span>\n <span class=\"nav-item-meta\">{{ formatTimestamp(item.timestamp) }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Entities Section (ng-tree) -->\n <div class=\"section entities-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('entities')\">\n <i class=\"fa-solid fa-database section-icon\"></i>\n <span class=\"section-title\">Entities</span>\n <span class=\"section-count\">({{ entities.length }})</span>\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"entitiesSectionExpanded\" [class.fa-chevron-right]=\"!entitiesSectionExpanded\"></i>\n </div>\n\n @if (entitiesSectionExpanded) {\n <div class=\"section-content entity-tree-container\">\n <!-- Entity Search -->\n <div class=\"entity-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entitySearchTerm\"\n (ngModelChange)=\"onEntitySearchChanged()\"\n />\n @if (entitySearchTerm) {\n <button class=\"clear-search\" (click)=\"clearEntitySearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n\n <!-- Entity Tree -->\n <mj-tree\n #entityTree\n [BranchConfig]=\"treeBranchConfig\"\n [LeafConfig]=\"treeLeafConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'leaf'\"\n [SelectedIDs]=\"selectedEntityIds\"\n [ShowIcons]=\"true\"\n [ShowExpandCollapseAll]=\"false\"\n [AnimateExpandCollapse]=\"true\"\n [EmptyMessage]=\"entitySearchTerm ? 'No matches for: ' + entitySearchTerm : 'No entities available'\"\n [EmptyIcon]=\"'fa-solid fa-database'\"\n (SelectionChange)=\"onTreeEntitySelected($event)\">\n </mj-tree>\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Collapsed State - Show Icons Only -->\n <div class=\"collapsed-icons\">\n <button class=\"icon-btn\" title=\"Favorites\" (click)=\"onCollapsedIconClick('favorites')\">\n <i class=\"fa-solid fa-star\"></i>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"collapsed-badge\">{{ favoriteRecords.length + favoriteEntities.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Recent\" (click)=\"onCollapsedIconClick('recent')\">\n <i class=\"fa-solid fa-clock\"></i>\n @if (filteredRecentItems.length > 0) {\n <span class=\"collapsed-badge\">{{ filteredRecentItems.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Entities\" (click)=\"onCollapsedIconClick('entities')\">\n <i class=\"fa-solid fa-database\"></i>\n <span class=\"collapsed-badge\">{{ entities.length }}</span>\n </button>\n </div>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"navigation-panel.component.js","sourceRoot":"","sources":["../../../../src/DataExplorer/components/navigation-panel/navigation-panel.component.ts","../../../../src/DataExplorer/components/navigation-panel/navigation-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, Input, Output, EventEmitter, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild } from '@angular/core';\nimport { EntityInfo, CompositeKey } from '@memberjunction/core';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { TreeBranchConfig, TreeLeafConfig, TreeNode, TreeComponent } from '@memberjunction/ng-trees';\nimport { RecentItem, FavoriteItem, AppEntityGroup } from '../../models/explorer-state.interface';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Event emitted when a record should be opened in a full tab\n */\nexport interface OpenRecordEvent {\n entityName: string;\n compositeKey: CompositeKey;\n}\n\n/**\n * Event emitted when a record should be selected within Data Explorer (not full tab)\n */\nexport interface SelectRecordEvent {\n entityName: string;\n recordId: string;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-explorer-navigation-panel',\n templateUrl: './navigation-panel.component.html',\n styleUrls: ['./navigation-panel.component.css']\n})\nexport class NavigationPanelComponent extends BaseAngularComponent implements OnChanges, OnInit, OnDestroy {\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n @Input() entities: EntityInfo[] = [];\n @Input() selectedEntityName: string | null = null;\n @Input() favorites: FavoriteItem[] = [];\n @Input() recentItems: RecentItem[] = [];\n @Input() collapsed = false;\n /**\n * Optional set of allowed entity names for filtering favorites/recents.\n * If provided, only items matching these entities will be shown.\n */\n @Input() allowedEntityNames: Set<string> | null = null;\n /** Application-based entity groups from the parent dashboard */\n @Input() appEntityGroups: AppEntityGroup[] = [];\n /** Optional application ID filter for the tree */\n @Input() applicationIdFilter: string | null = null;\n\n // Section expansion states\n @Input() favoritesSectionExpanded = true;\n @Input() recentSectionExpanded = true;\n @Input() entitiesSectionExpanded = true;\n @Input() viewsSectionExpanded = true;\n\n @Output() entitySelected = new EventEmitter<EntityInfo>();\n @Output() toggleCollapse = new EventEmitter<void>();\n @Output() sectionToggled = new EventEmitter<'favorites' | 'recent' | 'entities' | 'views'>();\n @Output() openRecord = new EventEmitter<OpenRecordEvent>();\n /** Emitted when a record should be selected within Data Explorer (navigate to entity + select record) */\n @Output() selectRecord = new EventEmitter<SelectRecordEvent>();\n /** Emitted when a collapsed icon is clicked - expands panel and focuses section */\n @Output() expandAndFocus = new EventEmitter<'favorites' | 'recent' | 'entities'>();\n /** Emitted when a nav panel app group is toggled */\n @Output() appGroupToggled = new EventEmitter<string>();\n\n private get metadata() { return this.ProviderToUse; }\n\n // Tree configuration for entity list\n public treeBranchConfig: TreeBranchConfig = {\n EntityName: 'MJ: Applications',\n DisplayField: 'Name',\n IDField: 'ID',\n IconField: 'Icon',\n OrderBy: 'Name'\n };\n\n public treeLeafConfig: TreeLeafConfig = {\n EntityName: 'MJ: Entities',\n ParentField: '', // Using JunctionConfig for M2M relationship\n DisplayField: 'Name',\n IDField: 'ID',\n IconField: 'Icon',\n JunctionConfig: {\n EntityName: 'MJ: Application Entities',\n BranchForeignKey: 'ApplicationID',\n LeafForeignKey: 'EntityID'\n },\n OrderBy: 'Name'\n };\n\n @ViewChild('entityTree') entityTree?: TreeComponent;\n\n /** Selected entity ID for tree highlighting */\n public selectedEntityIds: string[] = [];\n\n /** Search term for filtering the entity tree */\n public entitySearchTerm = '';\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['selectedEntityName']) {\n this.updateSelectedEntityKey();\n }\n if (changes['applicationIdFilter']) {\n this.updateTreeBranchFilter();\n }\n if (changes['recentItems']) {\n this.timestampLabelCache.clear();\n }\n }\n\n ngOnInit(): void {\n this.timestampRefreshHandle = setInterval(() => {\n if (this.timestampLabelCache.size === 0) return;\n this.timestampLabelCache.clear();\n this.cdr.markForCheck();\n }, 30000);\n }\n\n ngOnDestroy(): void {\n if (this.timestampRefreshHandle !== undefined) {\n clearInterval(this.timestampRefreshHandle);\n this.timestampRefreshHandle = undefined;\n }\n }\n\n /**\n * Update the selected entity IDs for tree highlighting when selected entity changes\n */\n private updateSelectedEntityKey(): void {\n if (this.selectedEntityName) {\n const entity = this.metadata.Entities.find(e => e.Name === this.selectedEntityName);\n if (entity) {\n this.selectedEntityIds = [entity.ID];\n return;\n }\n }\n this.selectedEntityIds = [];\n }\n\n /**\n * Update the tree's branch filter when application filter changes\n */\n private updateTreeBranchFilter(): void {\n if (this.applicationIdFilter) {\n this.treeBranchConfig = {\n ...this.treeBranchConfig,\n ExtraFilter: `ID='${this.applicationIdFilter}'`\n };\n } else {\n this.treeBranchConfig = {\n ...this.treeBranchConfig,\n ExtraFilter: undefined\n };\n }\n }\n\n /**\n * Filter the entity tree when search term changes\n */\n onEntitySearchChanged(): void {\n if (this.entityTree) {\n this.entityTree.FilterNodes(this.entitySearchTerm, {\n searchBranches: true,\n searchLeaves: true,\n caseSensitive: false\n });\n }\n }\n\n /**\n * Clear the entity search\n */\n clearEntitySearch(): void {\n this.entitySearchTerm = '';\n this.onEntitySearchChanged();\n }\n\n /**\n * Handle tree selection change - map TreeNode to EntityInfo and emit\n */\n onTreeEntitySelected(nodes: TreeNode[]): void {\n if (!nodes || nodes.length === 0) return;\n const node = nodes[0];\n if (node.Type !== 'leaf') return;\n\n // Find the EntityInfo by ID from the node\n const entity = this.metadata.Entities.find(e => UUIDsEqual(e.ID, node.ID));\n if (entity) {\n this.entitySelected.emit(entity);\n }\n }\n\n /**\n * Get recent items filtered by allowed entities (if filter is active)\n */\n get filteredRecentItems(): RecentItem[] {\n if (!this.allowedEntityNames) {\n return this.recentItems;\n }\n return this.recentItems.filter(r => this.allowedEntityNames!.has(r.entityName));\n }\n\n /**\n * Get favorites filtered to records only (respecting entity filter)\n */\n get favoriteRecords(): FavoriteItem[] {\n const records = this.favorites.filter(f => f.type === 'record');\n if (!this.allowedEntityNames) {\n return records;\n }\n return records.filter(f => f.entityName && this.allowedEntityNames!.has(f.entityName));\n }\n\n /**\n * Get favorites filtered to entities only (respecting entity filter)\n */\n get favoriteEntities(): FavoriteItem[] {\n const entities = this.favorites.filter(f => f.type === 'entity');\n if (!this.allowedEntityNames) {\n return entities;\n }\n return entities.filter(f => f.entityName && this.allowedEntityNames!.has(f.entityName));\n }\n\n /**\n * Handle entity click\n */\n onEntityClick(entity: EntityInfo): void {\n this.entitySelected.emit(entity);\n }\n\n /**\n * Handle favorite click - navigates to entity and selects record within Data Explorer\n */\n onFavoriteClick(favorite: FavoriteItem): void {\n if (favorite.type === 'entity' && favorite.entityName) {\n const entity = this.entities.find(e => e.Name === favorite.entityName);\n if (entity) {\n this.entitySelected.emit(entity);\n }\n } else if (favorite.type === 'record' && favorite.entityName && favorite.compositeKeyString) {\n // Extract record ID from the composite key string\n // Format is \"FieldName|Value\" or \"FieldName|Value||FieldName2|Value2\"\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromConcatenatedString(favorite.compositeKeyString);\n const recordId = compositeKey.KeyValuePairs[0]?.Value?.toString() || '';\n\n // Navigate to entity and select record within Data Explorer (not full tab)\n this.selectRecord.emit({\n entityName: favorite.entityName,\n recordId\n });\n }\n }\n\n /**\n * Handle recent item click - navigates to entity and selects record within Data Explorer\n */\n onRecentClick(item: RecentItem): void {\n // Extract record ID from the composite key string\n const compositeKey = new CompositeKey();\n compositeKey.LoadFromConcatenatedString(item.compositeKeyString);\n const recordId = compositeKey.KeyValuePairs[0]?.Value?.toString() || '';\n\n // Navigate to entity and select record within Data Explorer (not full tab)\n this.selectRecord.emit({\n entityName: item.entityName,\n recordId\n });\n }\n\n /**\n * Handle section header click\n */\n onSectionToggle(section: 'favorites' | 'recent' | 'entities' | 'views'): void {\n this.sectionToggled.emit(section);\n }\n\n /**\n * Handle collapse toggle\n */\n onToggleCollapse(): void {\n this.toggleCollapse.emit();\n }\n\n /**\n * Handle collapsed icon click - expands panel and focuses section\n */\n onCollapsedIconClick(section: 'favorites' | 'recent' | 'entities'): void {\n this.expandAndFocus.emit(section);\n }\n\n /**\n * Check if entity is selected\n */\n isEntitySelected(entity: EntityInfo): boolean {\n return entity.Name === this.selectedEntityName;\n }\n\n /**\n * Get icon for entity\n */\n getEntityIcon(entity: EntityInfo): string {\n const icon = entity.Icon;\n if (!icon) {\n return 'fa-solid fa-table';\n }\n // If icon already has fa- prefix, use it as-is\n if (icon.startsWith('fa-') || icon.startsWith('fa ')) {\n // Ensure it has a style prefix (fa-solid, fa-regular, etc.)\n if (icon.startsWith('fa-solid') || icon.startsWith('fa-regular') ||\n icon.startsWith('fa-light') || icon.startsWith('fa-brands') ||\n icon.startsWith('fa ')) {\n return icon;\n }\n // It's just \"fa-something\", add fa-solid prefix\n return `fa-solid ${icon}`;\n }\n // Check if it's just an icon name like \"table\" or \"users\"\n return `fa-solid fa-${icon}`;\n }\n\n /**\n * Cache of formatted relative-time labels keyed by timestamp epoch ms.\n * Stable within a change-detection cycle (avoids NG0100 from `now`-dependent\n * values shifting between dirty-check and verify passes). Cleared on a coarse\n * interval so the displayed label still updates over time.\n */\n private timestampLabelCache = new Map<number, string>();\n private timestampRefreshHandle?: ReturnType<typeof setInterval>;\n\n /**\n * Format recent item timestamp. Cached per-timestamp so the same value is\n * returned across change-detection passes within a single tick — recomputed\n * on a 30-second interval (see `ngOnInit`).\n */\n formatTimestamp(timestamp: Date): string {\n const epoch = new Date(timestamp).getTime();\n const cached = this.timestampLabelCache.get(epoch);\n if (cached !== undefined) {\n return cached;\n }\n const label = this.computeRelativeLabel(epoch);\n this.timestampLabelCache.set(epoch, label);\n return label;\n }\n\n private computeRelativeLabel(epoch: number): string {\n const diffMs = Date.now() - epoch;\n const diffMins = Math.floor(diffMs / 60000);\n\n if (diffMins < 1) return 'Just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n\n const diffHours = Math.floor(diffMins / 60);\n if (diffHours < 24) return `${diffHours}h ago`;\n\n const diffDays = Math.floor(diffHours / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n\n return new Date(epoch).toLocaleDateString();\n }\n\n /**\n * Get icon for a recent item based on its entity\n */\n getRecentItemIcon(item: RecentItem): string {\n const entityInfo = this.metadata.Entities.find(e => e.Name === item.entityName);\n if (entityInfo) {\n return this.getEntityIcon(entityInfo);\n }\n return 'fa-solid fa-file-alt';\n }\n\n /**\n * Get icon for a favorite item based on its type and entity\n */\n getFavoriteIcon(favorite: FavoriteItem): string {\n if (favorite.type === 'view') {\n return 'fa-solid fa-filter';\n }\n\n // For entity and record types, look up the entity icon\n if (favorite.entityName) {\n const entityInfo = this.metadata.Entities.find(e => e.Name === favorite.entityName);\n if (entityInfo) {\n return this.getEntityIcon(entityInfo);\n }\n }\n\n // Fallback icons\n if (favorite.type === 'entity') {\n return 'fa-solid fa-table';\n }\n return 'fa-solid fa-file-alt';\n }\n}\n","<div class=\"navigation-panel-container\" [class.collapsed]=\"collapsed\">\n <!-- Collapse Toggle -->\n <button class=\"collapse-toggle\" (click)=\"onToggleCollapse()\" [title]=\"collapsed ? 'Expand' : 'Collapse'\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"collapsed\" [class.fa-chevron-left]=\"!collapsed\"></i>\n </button>\n\n @if (!collapsed) {\n <div class=\"panel-content\">\n <!-- Favorites Section -->\n <div class=\"section favorites-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('favorites')\">\n <i class=\"fa-solid fa-star section-icon\"></i>\n <span class=\"section-title\">Favorites</span>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"section-count\">({{ favoriteRecords.length + favoriteEntities.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"favoritesSectionExpanded\" [class.fa-chevron-right]=\"!favoritesSectionExpanded\"></i>\n </div>\n\n @if (favoritesSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (favoriteRecords.length + favoriteEntities.length === 0) {\n <div class=\"empty-section\">\n <span>No favorites yet</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (favorite of favoriteEntities; track favorite.entityName) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n @for (favorite of favoriteRecords; track favorite.entityName + '|' + favorite.compositeKeyString) {\n <div class=\"nav-item\" (click)=\"onFavoriteClick(favorite)\" [title]=\"favorite.entityName ? favorite.entityName + ' - ' + favorite.displayName : favorite.displayName\">\n <i [class]=\"getFavoriteIcon(favorite)\"></i>\n <span class=\"nav-item-label\">{{ favorite.displayName }}</span>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Recent Items Section -->\n <div class=\"section recent-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('recent')\">\n <i class=\"fa-solid fa-clock section-icon\"></i>\n <span class=\"section-title\">Recent</span>\n @if (filteredRecentItems.length > 0) {\n <span class=\"section-count\">({{ filteredRecentItems.length }})</span>\n }\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"recentSectionExpanded\" [class.fa-chevron-right]=\"!recentSectionExpanded\"></i>\n </div>\n\n @if (recentSectionExpanded) {\n <div class=\"section-content scrollable-section\">\n @if (filteredRecentItems.length === 0) {\n <div class=\"empty-section\">\n <span>No recent items</span>\n </div>\n } @else {\n <div class=\"scrollable-list\">\n <div class=\"scrollable-list-inner\">\n @for (item of filteredRecentItems; track item.entityName + '|' + item.compositeKeyString) {\n <div class=\"nav-item\" (click)=\"onRecentClick(item)\" [title]=\"item.entityName + ' - ' + item.displayName\">\n <i [class]=\"getRecentItemIcon(item)\"></i>\n <div class=\"nav-item-content\">\n <span class=\"nav-item-label\">{{ item.displayName }}</span>\n <span class=\"nav-item-meta\">{{ formatTimestamp(item.timestamp) }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Entities Section (ng-tree) -->\n <div class=\"section entities-section\">\n <div class=\"section-header\" (click)=\"onSectionToggle('entities')\">\n <i class=\"fa-solid fa-database section-icon\"></i>\n <span class=\"section-title\">Entities</span>\n <span class=\"section-count\">({{ entities.length }})</span>\n <i class=\"fa-solid expand-icon\" [class.fa-chevron-down]=\"entitiesSectionExpanded\" [class.fa-chevron-right]=\"!entitiesSectionExpanded\"></i>\n </div>\n\n @if (entitiesSectionExpanded) {\n <div class=\"section-content entity-tree-container\">\n <!-- Entity Search -->\n <div class=\"entity-search\">\n <i class=\"fa-solid fa-search search-icon\"></i>\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Search entities...\"\n [(ngModel)]=\"entitySearchTerm\"\n (ngModelChange)=\"onEntitySearchChanged()\"\n />\n @if (entitySearchTerm) {\n <button class=\"clear-search\" (click)=\"clearEntitySearch()\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n }\n </div>\n\n <!-- Entity Tree -->\n <mj-tree\n #entityTree\n [BranchConfig]=\"treeBranchConfig\"\n [LeafConfig]=\"treeLeafConfig\"\n [SelectionMode]=\"'single'\"\n [SelectableTypes]=\"'leaf'\"\n [SelectedIDs]=\"selectedEntityIds\"\n [ShowIcons]=\"true\"\n [ShowExpandCollapseAll]=\"false\"\n [AnimateExpandCollapse]=\"true\"\n [EmptyMessage]=\"entitySearchTerm ? 'No matches for: ' + entitySearchTerm : 'No entities available'\"\n [EmptyIcon]=\"'fa-solid fa-database'\"\n (SelectionChange)=\"onTreeEntitySelected($event)\">\n </mj-tree>\n </div>\n }\n </div>\n </div>\n } @else {\n <!-- Collapsed State - Show Icons Only -->\n <div class=\"collapsed-icons\">\n <button class=\"icon-btn\" title=\"Favorites\" (click)=\"onCollapsedIconClick('favorites')\">\n <i class=\"fa-solid fa-star\"></i>\n @if (favoriteRecords.length + favoriteEntities.length > 0) {\n <span class=\"collapsed-badge\">{{ favoriteRecords.length + favoriteEntities.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Recent\" (click)=\"onCollapsedIconClick('recent')\">\n <i class=\"fa-solid fa-clock\"></i>\n @if (filteredRecentItems.length > 0) {\n <span class=\"collapsed-badge\">{{ filteredRecentItems.length }}</span>\n }\n </button>\n <button class=\"icon-btn\" title=\"Entities\" (click)=\"onCollapsedIconClick('entities')\">\n <i class=\"fa-solid fa-database\"></i>\n <span class=\"collapsed-badge\">{{ entities.length }}</span>\n </button>\n </div>\n }\n</div>\n"]}
|