@memberjunction/ng-explorer-core 5.21.0 → 5.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/generated/lazy-feature-config.d.ts +19 -0
  2. package/dist/generated/lazy-feature-config.d.ts.map +1 -0
  3. package/dist/generated/lazy-feature-config.js +144 -0
  4. package/dist/generated/lazy-feature-config.js.map +1 -0
  5. package/dist/lib/command-palette/command-palette.component.d.ts +10 -1
  6. package/dist/lib/command-palette/command-palette.component.d.ts.map +1 -1
  7. package/dist/lib/command-palette/command-palette.component.js +68 -16
  8. package/dist/lib/command-palette/command-palette.component.js.map +1 -1
  9. package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js +49 -49
  10. package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js.map +1 -1
  11. package/dist/lib/generic/form-toolbar.js +10 -10
  12. package/dist/lib/generic/form-toolbar.js.map +1 -1
  13. package/dist/lib/generic/resource-container-component.d.ts +0 -1
  14. package/dist/lib/generic/resource-container-component.d.ts.map +1 -1
  15. package/dist/lib/generic/resource-container-component.js +3 -12
  16. package/dist/lib/generic/resource-container-component.js.map +1 -1
  17. package/dist/lib/oauth/oauth-callback.component.js +6 -6
  18. package/dist/lib/oauth/oauth-callback.component.js.map +1 -1
  19. package/dist/lib/oauth/oauth.module.d.ts +2 -3
  20. package/dist/lib/oauth/oauth.module.d.ts.map +1 -1
  21. package/dist/lib/oauth/oauth.module.js +0 -4
  22. package/dist/lib/oauth/oauth.module.js.map +1 -1
  23. package/dist/lib/resource-wrappers/chat-collections-resource.component.d.ts +8 -23
  24. package/dist/lib/resource-wrappers/chat-collections-resource.component.d.ts.map +1 -1
  25. package/dist/lib/resource-wrappers/chat-collections-resource.component.js +68 -117
  26. package/dist/lib/resource-wrappers/chat-collections-resource.component.js.map +1 -1
  27. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +9 -21
  28. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
  29. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +66 -137
  30. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
  31. package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts +3 -19
  32. package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts.map +1 -1
  33. package/dist/lib/resource-wrappers/chat-tasks-resource.component.js +16 -98
  34. package/dist/lib/resource-wrappers/chat-tasks-resource.component.js.map +1 -1
  35. package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts +0 -1
  36. package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts.map +1 -1
  37. package/dist/lib/resource-wrappers/dashboard-resource.component.js +4 -12
  38. package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
  39. package/dist/lib/resource-wrappers/view-resource.component.d.ts +13 -11
  40. package/dist/lib/resource-wrappers/view-resource.component.d.ts.map +1 -1
  41. package/dist/lib/resource-wrappers/view-resource.component.js +80 -89
  42. package/dist/lib/resource-wrappers/view-resource.component.js.map +1 -1
  43. package/dist/lib/services/lazy-module-registry.d.ts +24 -9
  44. package/dist/lib/services/lazy-module-registry.d.ts.map +1 -1
  45. package/dist/lib/services/lazy-module-registry.js +32 -13
  46. package/dist/lib/services/lazy-module-registry.js.map +1 -1
  47. package/dist/lib/shell/components/header/app-nav.component.d.ts.map +1 -1
  48. package/dist/lib/shell/components/header/app-nav.component.js +18 -3
  49. package/dist/lib/shell/components/header/app-nav.component.js.map +1 -1
  50. package/dist/lib/shell/components/tabs/component-cache-manager.d.ts +38 -16
  51. package/dist/lib/shell/components/tabs/component-cache-manager.d.ts.map +1 -1
  52. package/dist/lib/shell/components/tabs/component-cache-manager.js +57 -35
  53. package/dist/lib/shell/components/tabs/component-cache-manager.js.map +1 -1
  54. package/dist/lib/shell/components/tabs/tab-container.component.d.ts +56 -1
  55. package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
  56. package/dist/lib/shell/components/tabs/tab-container.component.js +298 -53
  57. package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
  58. package/dist/lib/shell/services/settings-dialog.service.d.ts +8 -8
  59. package/dist/lib/shell/services/settings-dialog.service.d.ts.map +1 -1
  60. package/dist/lib/shell/services/settings-dialog.service.js +20 -26
  61. package/dist/lib/shell/services/settings-dialog.service.js.map +1 -1
  62. package/dist/lib/shell/shell.component.d.ts +26 -2
  63. package/dist/lib/shell/shell.component.d.ts.map +1 -1
  64. package/dist/lib/shell/shell.component.js +225 -54
  65. package/dist/lib/shell/shell.component.js.map +1 -1
  66. package/dist/lib/shell/shell.module.d.ts +4 -5
  67. package/dist/lib/shell/shell.module.d.ts.map +1 -1
  68. package/dist/lib/shell/shell.module.js +4 -8
  69. package/dist/lib/shell/shell.module.js.map +1 -1
  70. package/dist/lib/single-dashboard/Components/add-item/add-item.component.js +72 -71
  71. package/dist/lib/single-dashboard/Components/add-item/add-item.component.js.map +1 -1
  72. package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.js +11 -11
  73. package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.js.map +1 -1
  74. package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.d.ts +36 -12
  75. package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.d.ts.map +1 -1
  76. package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.js +78 -50
  77. package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.js.map +1 -1
  78. package/dist/lib/single-dashboard/single-dashboard.component.d.ts +12 -5
  79. package/dist/lib/single-dashboard/single-dashboard.component.d.ts.map +1 -1
  80. package/dist/lib/single-dashboard/single-dashboard.component.js +44 -55
  81. package/dist/lib/single-dashboard/single-dashboard.component.js.map +1 -1
  82. package/dist/lib/single-list-detail/single-list-detail.component.d.ts +10 -2
  83. package/dist/lib/single-list-detail/single-list-detail.component.d.ts.map +1 -1
  84. package/dist/lib/single-list-detail/single-list-detail.component.js +313 -243
  85. package/dist/lib/single-list-detail/single-list-detail.component.js.map +1 -1
  86. package/dist/lib/user-menu/base-user-menu.d.ts +4 -0
  87. package/dist/lib/user-menu/base-user-menu.d.ts.map +1 -1
  88. package/dist/lib/user-menu/base-user-menu.js +26 -0
  89. package/dist/lib/user-menu/base-user-menu.js.map +1 -1
  90. package/dist/lib/user-menu/user-menu.types.d.ts +20 -0
  91. package/dist/lib/user-menu/user-menu.types.d.ts.map +1 -1
  92. package/dist/lib/user-menu/user-menu.types.js.map +1 -1
  93. package/dist/module.d.ts +23 -34
  94. package/dist/module.d.ts.map +1 -1
  95. package/dist/module.js +33 -74
  96. package/dist/module.js.map +1 -1
  97. package/dist/public-api.d.ts +1 -1
  98. package/dist/public-api.d.ts.map +1 -1
  99. package/dist/public-api.js +1 -1
  100. package/dist/public-api.js.map +1 -1
  101. package/package.json +38 -47
  102. package/dist/lib/services/lazy-feature-config.d.ts +0 -16
  103. package/dist/lib/services/lazy-feature-config.d.ts.map +0 -1
  104. package/dist/lib/services/lazy-feature-config.js +0 -113
  105. package/dist/lib/services/lazy-feature-config.js.map +0 -1
@@ -4,13 +4,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { Component, ViewChild, inject } from '@angular/core';
7
+ import { Component, ViewChild } from '@angular/core';
8
8
  import { BaseResourceComponent, BaseDashboard } from '@memberjunction/ng-shared';
9
9
  import { DashboardEngine } from '@memberjunction/core-entities';
10
10
  import { RegisterClass, MJGlobal, SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
11
11
  import { Metadata, CompositeKey, LogError } from '@memberjunction/core';
12
12
  import { DashboardViewerComponent } from '@memberjunction/ng-dashboard-viewer';
13
- import { LazyModuleRegistry } from '../services/lazy-module-registry';
14
13
  import * as i0 from "@angular/core";
15
14
  import * as i1 from "@memberjunction/ng-shared";
16
15
  import * as i2 from "@angular/forms";
@@ -136,7 +135,6 @@ let DashboardResource = class DashboardResource extends BaseResourceComponent {
136
135
  viewContainer;
137
136
  navigationService;
138
137
  cdr;
139
- lazyRegistry = inject(LazyModuleRegistry);
140
138
  componentRef = null;
141
139
  dataLoaded = false;
142
140
  containerElement;
@@ -425,14 +423,8 @@ let DashboardResource = class DashboardResource extends BaseResourceComponent {
425
423
  if (!dashboard.DriverClass) {
426
424
  throw new Error(`Dashboard '${dashboard.Name}' is marked as Code type but has no DriverClass specified`);
427
425
  }
428
- // Look up the registered class using the DriverClass name (with lazy loading fallback)
429
- let classReg = MJGlobal.Instance.ClassFactory.GetRegistration(BaseDashboard, dashboard.DriverClass);
430
- if (!classReg?.SubClass) {
431
- const loaded = await this.lazyRegistry.Load(dashboard.DriverClass);
432
- if (loaded) {
433
- classReg = MJGlobal.Instance.ClassFactory.GetRegistration(BaseDashboard, dashboard.DriverClass);
434
- }
435
- }
426
+ // Look up the registered class using the DriverClass name (with lazy loading fallback via ClassFactory)
427
+ const classReg = await MJGlobal.Instance.ClassFactory.GetRegistrationAsync(BaseDashboard, dashboard.DriverClass);
436
428
  if (!classReg?.SubClass) {
437
429
  throw new Error(`Dashboard class '${dashboard.DriverClass}' is not registered. Please check the class registration.`);
438
430
  }
@@ -755,5 +747,5 @@ export { DashboardResource };
755
747
  type: ViewChild,
756
748
  args: ['container', { static: true }]
757
749
  }] }); })();
758
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DashboardResource, { className: "DashboardResource", filePath: "src/lib/resource-wrappers/dashboard-resource.component.ts", lineNumber: 411 }); })();
750
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DashboardResource, { className: "DashboardResource", filePath: "src/lib/resource-wrappers/dashboard-resource.component.ts", lineNumber: 410 }); })();
759
751
  //# sourceMappingURL=dashboard-resource.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/dashboard-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewContainerRef, ComponentRef, ViewChild, ElementRef, ChangeDetectorRef, inject } from '@angular/core';\nimport { BaseResourceComponent, NavigationService, BaseDashboard, DashboardConfig } from '@memberjunction/ng-shared';\nimport { ResourceData, MJDashboardEntity, DashboardEngine, MJDashboardUserStateEntity, MJDashboardCategoryEntity, MJDashboardPartTypeEntity, DashboardUserPermissions } from '@memberjunction/core-entities';\nimport { RegisterClass, MJGlobal, SafeJSONParse , UUIDsEqual } from '@memberjunction/global';\nimport { Metadata, CompositeKey, RunView, LogError } from '@memberjunction/core';\nimport type { DataExplorerFilter } from '@memberjunction/ng-dashboards/data-explorer-dashboards.module';\nimport type { ShareDialogResult } from '@memberjunction/ng-dashboards/core-dashboards.module';\nimport { DashboardViewerComponent, DashboardNavRequestEvent, PanelInteractionEvent, AddPanelResult, DashboardPanel } from '@memberjunction/ng-dashboard-viewer';\nimport { LazyModuleRegistry } from '../services/lazy-module-registry';\n/**\n * Dashboard Resource Wrapper - displays a single dashboard in a tab\n * Extends BaseResourceComponent to work with the resource type system\n * Dynamically routes between code-based and config-based dashboards based on dashboard type\n */\n@RegisterClass(BaseResourceComponent, 'DashboardResource')\n@Component({\n standalone: false,\n selector: 'mj-dashboard-resource',\n template: `\n <div class=\"dashboard-resource-wrapper\">\n <!-- Error State -->\n @if (errorMessage) {\n <div class=\"error-state\">\n <div class=\"error-icon\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n </div>\n <h2 class=\"error-title\">Unable to Load Dashboard</h2>\n <p class=\"error-message\">{{ errorMessage }}</p>\n @if (errorDetails) {\n <details class=\"error-details\">\n <summary>Technical Details</summary>\n <pre>{{ errorDetails }}</pre>\n </details>\n }\n </div>\n }\n\n <!-- View Mode Toolbar -->\n @if (configDashboard && !isEditMode && !errorMessage) {\n <div class=\"viewer-toolbar\">\n <div class=\"toolbar-left\">\n <span class=\"dashboard-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n {{ configDashboard.Name }}\n </span>\n @if (!dashboardPermissions.IsOwner && dashboardPermissions.PermissionSource !== 'none') {\n <span class=\"shared-indicator\" title=\"Shared with you\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n </span>\n }\n </div>\n <div class=\"toolbar-actions\">\n @if (dashboardPermissions.CanShare) {\n <button\n class=\"btn-icon\"\n title=\"Share Dashboard\"\n (click)=\"openShareDialog()\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n </button>\n }\n @if (dashboardPermissions.CanEdit) {\n <button\n class=\"btn-icon\"\n title=\"Edit Dashboard\"\n (click)=\"toggleEditMode()\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Edit Mode Toolbar -->\n @if (configDashboard && isEditMode && !errorMessage) {\n <div class=\"viewer-header editing\">\n <div class=\"header-left\">\n <button class=\"btn-add-part\" (click)=\"openAddPartDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Part\n </button>\n <div class=\"header-separator\"></div>\n <div class=\"dashboard-info-edit\">\n <input\n type=\"text\"\n class=\"dashboard-name-input\"\n [(ngModel)]=\"editingName\"\n placeholder=\"Dashboard name\">\n <input\n type=\"text\"\n class=\"dashboard-description-input\"\n [(ngModel)]=\"editingDescription\"\n placeholder=\"Add a description...\">\n </div>\n </div>\n <div class=\"header-right\">\n <button class=\"btn-primary\" (click)=\"saveDashboard()\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n <button class=\"btn-cancel\" (click)=\"cancelEdit()\">\n Cancel\n </button>\n </div>\n </div>\n }\n\n <!-- Dashboard Content Container -->\n <div #container class=\"dashboard-resource-container\"></div>\n\n <!-- Share Dashboard Dialog -->\n @if (configDashboard) {\n <mj-dashboard-share-dialog\n [Visible]=\"showShareDialog\"\n [Dashboard]=\"configDashboard\"\n (Result)=\"onShareDialogResult($event)\">\n </mj-dashboard-share-dialog>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n }\n .dashboard-resource-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n }\n .dashboard-resource-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n }\n\n /* View Mode Toolbar */\n .viewer-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n gap: 16px;\n }\n .viewer-toolbar .toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .viewer-toolbar .dashboard-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .viewer-toolbar .dashboard-title i {\n color: var(--mj-brand-primary);\n }\n .shared-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 11px;\n }\n .viewer-toolbar .toolbar-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n /* Edit Mode Header */\n .viewer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n transition: background 0.2s, border-color 0.2s;\n }\n .viewer-header.editing {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)) 0%, color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-bg-surface)) 100%);\n border-bottom: 2px solid var(--mj-brand-primary);\n }\n .viewer-header .header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n }\n .viewer-header .header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n /* Add Part button */\n .btn-add-part {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s, transform 0.1s;\n box-shadow: 0 2px 4px rgba(92, 107, 192, 0.3);\n }\n .btn-add-part:hover {\n background: var(--mj-brand-primary-hover);\n transform: translateY(-1px);\n box-shadow: 0 3px 6px rgba(92, 107, 192, 0.4);\n }\n .btn-add-part i { font-size: 12px; }\n\n /* Header separator */\n .header-separator {\n width: 1px;\n height: 28px;\n background: rgba(92, 107, 192, 0.3);\n margin: 0 4px;\n }\n\n /* Buttons */\n .btn-primary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s;\n }\n .btn-primary:hover { background: var(--mj-brand-primary-hover); }\n\n .btn-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n }\n .btn-icon:hover { background: var(--mj-bg-surface-sunken); }\n\n .btn-cancel {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n }\n .btn-cancel:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-default);\n color: var(--mj-text-primary);\n }\n\n /* Dashboard info inputs */\n .dashboard-info-edit {\n display: flex;\n align-items: center;\n gap: 16px;\n flex: 1;\n }\n .dashboard-name-input {\n border: 1px solid transparent;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-primary);\n background: rgba(255, 255, 255, 0.7);\n outline: none;\n min-width: 200px;\n max-width: 300px;\n transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;\n }\n .dashboard-name-input:hover { background: rgba(255, 255, 255, 0.9); }\n .dashboard-name-input:focus {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px rgba(92, 107, 192, 0.2);\n }\n .dashboard-description-input {\n border: 1px solid transparent;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n background: rgba(255, 255, 255, 0.5);\n outline: none;\n flex: 1;\n min-width: 150px;\n max-width: 400px;\n transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;\n }\n .dashboard-description-input:hover { background: rgba(255, 255, 255, 0.8); }\n .dashboard-description-input:focus {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px rgba(92, 107, 192, 0.2);\n }\n .dashboard-description-input::placeholder {\n color: var(--mj-text-muted);\n font-style: normal;\n }\n\n /* Error state */\n .error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 40px;\n text-align: center;\n color: var(--mj-text-secondary);\n }\n .error-icon {\n font-size: 64px;\n color: #f44336;\n margin-bottom: 24px;\n opacity: 0.8;\n }\n .error-title {\n font-size: 24px;\n font-weight: 500;\n margin: 0 0 12px 0;\n color: var(--mj-text-primary);\n }\n .error-message {\n font-size: 16px;\n color: var(--mj-text-muted);\n margin: 0 0 24px 0;\n max-width: 500px;\n line-height: 1.5;\n }\n .error-details {\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 12px 16px;\n max-width: 600px;\n text-align: left;\n font-size: 13px;\n }\n .error-details summary {\n cursor: pointer;\n font-weight: 500;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n }\n .error-details pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n color: #d32f2f;\n font-family: 'Consolas', 'Monaco', monospace;\n font-size: 12px;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .viewer-header {\n flex-direction: column;\n gap: 12px;\n align-items: stretch;\n }\n .viewer-header .header-left { flex-wrap: wrap; }\n .dashboard-info-edit {\n flex-direction: column;\n align-items: stretch;\n }\n .dashboard-name-input,\n .dashboard-description-input { max-width: none; }\n }\n `]\n})\nexport class DashboardResource extends BaseResourceComponent {\n private lazyRegistry = inject(LazyModuleRegistry);\n private componentRef: ComponentRef<unknown> | null = null;\n private dataLoaded = false;\n @ViewChild('container', { static: true }) containerElement!: ElementRef<HTMLDivElement>;\n\n /** Error message to display when dashboard fails to load */\n public errorMessage: string | null = null;\n /** Technical error details (shown in expandable section) */\n public errorDetails: string | null = null;\n\n /** Cached dashboard categories for breadcrumb navigation */\n private categories: MJDashboardCategoryEntity[] = [];\n\n /** Reference to the dashboard viewer component (for config-based dashboards) */\n private viewerInstance: DashboardViewerComponent | null = null;\n\n /** The config-based dashboard entity (null for code-based dashboards) */\n public configDashboard: MJDashboardEntity | null = null;\n\n /** Whether we're in edit mode */\n public isEditMode = false;\n\n /** Editing fields */\n public editingName = '';\n public editingDescription = '';\n\n /** Current user's permissions for this dashboard */\n public dashboardPermissions: DashboardUserPermissions = {\n DashboardID: '',\n CanRead: true,\n CanEdit: true,\n CanDelete: true,\n CanShare: true,\n IsOwner: true,\n PermissionSource: 'owner'\n };\n\n /** Whether the share dialog is visible */\n public showShareDialog = false;\n\n /**\n * Sets the error state with a user-friendly message and optional technical details\n */\n private setError(message: string, error?: unknown): void {\n this.errorMessage = message;\n if (error instanceof Error) {\n this.errorDetails = error.message;\n if (error.stack) {\n this.errorDetails += '\\n\\nStack trace:\\n' + error.stack;\n }\n } else if (error) {\n this.errorDetails = String(error);\n }\n }\n\n /**\n * Clears any previous error state\n */\n private clearError(): void {\n this.errorMessage = null;\n this.errorDetails = null;\n }\n\n constructor(\n private viewContainer: ViewContainerRef,\n private navigationService: NavigationService,\n private cdr: ChangeDetectorRef\n ) {\n super();\n }\n\n override set Data(value: ResourceData) {\n const previousRecordId = super.Data?.ResourceRecordID;\n super.Data = value;\n\n const newRecordId = value?.ResourceRecordID;\n\n // Load on first set, or when the dashboard has changed\n if (!this.dataLoaded || newRecordId !== previousRecordId) {\n this.dataLoaded = true;\n // Destroy previous component before loading new one\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = null;\n }\n this.clearError();\n this.configDashboard = null;\n this.viewerInstance = null;\n this.loadDashboard();\n }\n }\n\n // Need to override the getter too in TS otherwise the override to the setter alone above would break things\n override get Data(): ResourceData {\n return super.Data;\n }\n\n ngOnDestroy(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n }\n }\n\n // ========================================\n // Edit Mode Methods\n // ========================================\n\n /**\n * Toggle between view and edit mode\n */\n public toggleEditMode(): void {\n if (this.isEditMode) {\n this.cancelEdit();\n } else {\n this.enterEditMode();\n }\n }\n\n /**\n * Enter edit mode\n */\n private enterEditMode(): void {\n if (!this.configDashboard) return;\n\n this.isEditMode = true;\n this.editingName = this.configDashboard.Name;\n this.editingDescription = this.configDashboard.Description || '';\n\n // Tell the viewer to enter edit mode\n if (this.viewerInstance) {\n this.viewerInstance.isEditing = true;\n }\n\n this.cdr.detectChanges();\n }\n\n /**\n * Cancel edit mode and discard changes\n */\n public cancelEdit(): void {\n this.isEditMode = false;\n\n // Tell the viewer to exit edit mode\n if (this.viewerInstance) {\n this.viewerInstance.isEditing = false;\n }\n\n this.cdr.detectChanges();\n }\n\n /**\n * Save dashboard changes\n */\n public async saveDashboard(): Promise<void> {\n if (!this.configDashboard || !this.viewerInstance) return;\n\n try {\n // Update dashboard name and description\n this.configDashboard.Name = this.editingName;\n this.configDashboard.Description = this.editingDescription;\n\n // Save via the viewer (which handles layout saving)\n await this.viewerInstance.save();\n\n // Exit edit mode\n this.isEditMode = false;\n this.viewerInstance.isEditing = false;\n\n this.cdr.detectChanges();\n } catch (error) {\n console.error('Error saving dashboard:', error);\n }\n }\n\n /**\n * Open the add panel dialog\n */\n public openAddPartDialog(): void {\n if (this.viewerInstance) {\n // Trigger the viewer's add panel flow\n this.viewerInstance.onAddPanelClick();\n }\n }\n\n /**\n * Open the share dialog for this dashboard\n */\n public openShareDialog(): void {\n this.showShareDialog = true;\n this.cdr.detectChanges();\n }\n\n /**\n * Close the share dialog\n */\n public closeShareDialog(): void {\n this.showShareDialog = false;\n this.cdr.detectChanges();\n }\n\n /**\n * Handle share dialog result\n */\n public onShareDialogResult(result: ShareDialogResult): void {\n this.showShareDialog = false;\n\n if (result.Action === 'save' && this.configDashboard) {\n // Recompute permissions after sharing changes\n const md = new Metadata();\n this.dashboardPermissions = DashboardEngine.Instance.GetDashboardPermissions(\n this.configDashboard.ID,\n md.CurrentUser.ID\n );\n }\n\n this.cdr.detectChanges();\n }\n\n /**\n * Load the appropriate dashboard component based on dashboard type\n * Routes between code-based dashboards (registered classes) and config-based dashboards\n */\n private async loadDashboard(): Promise<void> {\n // Clear any previous error state\n this.clearError();\n\n const data = this.Data;\n\n if (!data?.ResourceRecordID) {\n this.NotifyLoadStarted();\n this.NotifyLoadComplete();\n return;\n }\n\n this.NotifyLoadStarted();\n\n try {\n // Check if this is a special dashboard type (not a database record)\n const config = data.Configuration || {};\n\n if (config['dashboardType'] === 'DataExplorer' || data.ResourceRecordID === 'DataExplorer') {\n // Special case: Data Explorer dashboard with optional entity filter\n await this.loadDataExplorer(\n config['entityFilter'],\n config['appName'] as string | undefined,\n config['appIcon'] as string | undefined\n );\n return;\n }\n\n await DashboardEngine.Instance.Config(false); // make sure it is configured, if already configured does nothing\n const dashboard = DashboardEngine.Instance.Dashboards.find(d => UUIDsEqual(d.ID, data.ResourceRecordID));\n if (!dashboard) {\n throw new Error(`Dashboard with ID ${data.ResourceRecordID} not found.`);\n }\n\n // Determine which dashboard component to load based on dashboard type\n if (dashboard.Type === 'Code') {\n // CODE-BASED DASHBOARD: Use registered class via DriverClass\n await this.loadCodeBasedDashboard(dashboard);\n } else {\n // CONFIG-BASED DASHBOARD: Use the generic metadata-driven renderer\n await this.loadConfigBasedDashboard(dashboard);\n }\n } catch (error) {\n console.error('Error loading dashboard:', error);\n this.setError('The dashboard could not be loaded. This may be due to a missing component or configuration issue.', error);\n this.NotifyLoadComplete();\n }\n }\n\n /**\n * Load the Data Explorer dashboard component with optional entity filter and context info\n * @param entityFilter Optional filter to constrain which entities are shown\n * @param contextName Optional name to display in the header (e.g., \"CRM\", \"Association Demo\")\n * @param contextIcon Optional Font Awesome icon class for the header\n */\n private async loadDataExplorer(\n entityFilter?: DataExplorerFilter,\n contextName?: string,\n contextIcon?: string\n ): Promise<void> {\n try {\n // Lazy-load the Data Explorer component to keep it out of the initial bundle\n const { DataExplorerDashboardComponent } = await import('@memberjunction/ng-dashboards/data-explorer-dashboards.module');\n this.containerElement.nativeElement.innerHTML = '';\n const componentRef = this.viewContainer.createComponent(DataExplorerDashboardComponent);\n this.componentRef = componentRef;\n const instance = componentRef.instance;\n\n // Set the entity filter - ngOnInit will use this when it runs\n if (entityFilter) {\n instance.entityFilter = entityFilter;\n }\n\n // Set context name and icon for customized header display\n if (contextName) {\n instance.contextName = contextName;\n }\n if (contextIcon) {\n instance.contextIcon = contextIcon;\n }\n\n // Manually append the component's native element inside the div\n const nativeElement = (componentRef.hostView as any).rootNodes[0];\n nativeElement.style.width = '100%';\n nativeElement.style.height = '100%';\n this.containerElement.nativeElement.appendChild(nativeElement);\n\n // Handle open entity record events\n instance.OpenEntityRecord.subscribe((eventData: { EntityName: string; RecordPKey: CompositeKey }) => {\n if (eventData && eventData.EntityName && eventData.RecordPKey) {\n this.navigationService.OpenEntityRecord(eventData.EntityName, eventData.RecordPKey);\n }\n });\n\n // Setup LoadCompleteEvent to know when the dashboard is ready\n instance.LoadCompleteEvent = () => {\n this.NotifyLoadComplete();\n };\n\n // Initialize dashboard (no database config needed for DataExplorer)\n const config: DashboardConfig = {\n dashboard: null as unknown as MJDashboardEntity, // No database record\n userState: {}\n };\n instance.Config = config;\n instance.Refresh();\n\n // Trigger change detection to ensure the component updates\n componentRef.changeDetectorRef.detectChanges();\n } catch (error) {\n console.error('Error loading Data Explorer:', error);\n this.setError('The Data Explorer could not be loaded.', error);\n this.NotifyLoadComplete();\n }\n }\n\n /**\n * Load a code-based dashboard by looking up the registered class\n */\n private async loadCodeBasedDashboard(dashboard: MJDashboardEntity): Promise<void> {\n try {\n if (!dashboard.DriverClass) {\n throw new Error(`Dashboard '${dashboard.Name}' is marked as Code type but has no DriverClass specified`);\n }\n\n // Look up the registered class using the DriverClass name (with lazy loading fallback)\n let classReg = MJGlobal.Instance.ClassFactory.GetRegistration(\n BaseDashboard,\n dashboard.DriverClass\n );\n\n if (!classReg?.SubClass) {\n const loaded = await this.lazyRegistry.Load(dashboard.DriverClass);\n if (loaded) {\n classReg = MJGlobal.Instance.ClassFactory.GetRegistration(BaseDashboard, dashboard.DriverClass);\n }\n }\n\n if (!classReg?.SubClass) {\n throw new Error(`Dashboard class '${dashboard.DriverClass}' is not registered. Please check the class registration.`);\n }\n\n // Create the component instance\n this.containerElement.nativeElement.innerHTML = '';\n this.componentRef = this.viewContainer.createComponent<BaseDashboard>(classReg.SubClass);\n const instance = this.componentRef.instance as BaseDashboard;\n\n // Setup LoadCompleteEvent() to know when the dashboard is ready\n instance.LoadCompleteEvent = () => {\n this.NotifyLoadComplete();\n };\n\n // Initialize with dashboard data\n const userStateEntity = await this.loadDashboardUserState(dashboard.ID);\n const config: DashboardConfig = {\n dashboard,\n userState: userStateEntity.UserState ? SafeJSONParse(userStateEntity.UserState) : {}\n };\n\n instance.Config = config;\n\n // Manually append the component's native element inside the div\n const nativeElement = (this.componentRef.hostView as any).rootNodes[0];\n nativeElement.style.width = '100%';\n nativeElement.style.height = '100%';\n this.containerElement.nativeElement.appendChild(nativeElement);\n\n // handle open entity record events in MJ Explorer with routing\n instance.OpenEntityRecord.subscribe((data: { EntityName: string; RecordPKey: CompositeKey }) => {\n // check to see if the data has entityname/pkey\n if (data && data.EntityName && data.RecordPKey) {\n // Use NavigationService to open entity record in new tab\n this.navigationService.OpenEntityRecord(data.EntityName, data.RecordPKey);\n } else {\n console.warn('DashboardResource - invalid data, missing EntityName or RecordPKey:', data);\n }\n });\n\n instance.UserStateChanged.subscribe(async (userState: any) => {\n if (!userState) {\n // if the user state is null, we need to remove it from the user state\n userState = {};\n }\n // save the user state to the dashboard user state entity\n userStateEntity.UserState = JSON.stringify(userState);\n if (!await userStateEntity.Save()) {\n LogError('Error saving user state', null, userStateEntity.LatestResult?.CompleteMessage);\n }\n });\n\n instance.Refresh();\n } catch (error) {\n console.error('Error loading code-based dashboard:', error);\n this.setError(`The dashboard \"${dashboard.Name}\" could not be loaded. The dashboard class may not be registered or may have failed to initialize.`, error);\n this.NotifyLoadComplete();\n }\n }\n\n protected async loadDashboardUserState(dashboardId: string): Promise<MJDashboardUserStateEntity> {\n // handle user state changes for the dashboard\n const md = new Metadata();\n const stateResult = DashboardEngine.Instance.DashboardUserStates.filter(dus => UUIDsEqual(dus.DashboardID, dashboardId) && UUIDsEqual(dus.UserID, md.CurrentUser.ID));\n let stateObject: MJDashboardUserStateEntity;\n if (stateResult && stateResult.length > 0) {\n stateObject = stateResult[0];\n }\n else {\n stateObject = await md.GetEntityObject<MJDashboardUserStateEntity>('MJ: Dashboard User States');\n stateObject.DashboardID = dashboardId;\n stateObject.UserID = md.CurrentUser.ID;\n // don't save becuase we don't care about the state until something changes\n }\n return stateObject;\n }\n\n /**\n * Load a config-based dashboard using the new DashboardViewerComponent (Golden Layout)\n */\n private async loadConfigBasedDashboard(dashboard: MJDashboardEntity): Promise<void> {\n try {\n this.containerElement.nativeElement.innerHTML = '';\n const componentRef = this.viewContainer.createComponent(DashboardViewerComponent);\n this.componentRef = componentRef;\n const instance = componentRef.instance;\n\n // Store references for external toolbar control\n this.viewerInstance = instance;\n this.configDashboard = dashboard;\n\n // Compute user permissions for this dashboard\n const md = new Metadata();\n this.dashboardPermissions = DashboardEngine.Instance.GetDashboardPermissions(\n dashboard.ID,\n md.CurrentUser.ID\n );\n\n // Manually append the component's native element inside the div\n const nativeElement = (this.componentRef.hostView as any).rootNodes[0];\n nativeElement.style.width = '100%';\n nativeElement.style.height = '100%';\n this.containerElement.nativeElement.appendChild(nativeElement);\n\n // Load categories for breadcrumb navigation (if not already loaded)\n if (this.categories.length === 0) {\n this.categories = DashboardEngine.Instance.DashboardCategories;\n }\n\n // Set the dashboard entity directly on the viewer\n // We provide our own external toolbar, so disable the viewer's internal toolbar\n instance.dashboard = dashboard;\n instance.showToolbar = false; // We provide external toolbar\n instance.showBreadcrumb = false; // Already in its own tab, no breadcrumb needed\n instance.showOpenInTabButton = false; // Already in its own tab\n instance.showEditButton = false; // External toolbar handles edit\n instance.Categories = this.categories;\n\n // Wire up navigation events - handle navigation requests from the dashboard\n instance.navigationRequested.subscribe((event: DashboardNavRequestEvent) => {\n this.handleNavigationRequest(event);\n });\n\n // Wire up \"Open in Tab\" button click\n instance.openInTab.subscribe((event: { dashboardId: string; dashboardName: string }) => {\n this.navigationService.OpenDashboard(event.dashboardId, event.dashboardName);\n });\n\n // Wire up dashboard saved event\n instance.dashboardSaved.subscribe((savedDashboard: MJDashboardEntity) => {\n this.ResourceRecordSaved(savedDashboard);\n });\n\n // Wire up error events\n instance.error.subscribe((errorEvent: { message: string; error?: Error }) => {\n console.error('Dashboard error:', errorEvent.message, errorEvent.error);\n });\n\n // Notify load complete after a brief delay to let Golden Layout initialize\n setTimeout(() => {\n this.NotifyLoadComplete();\n this.cdr.detectChanges();\n }, 150);\n\n } catch (error) {\n console.error('Error loading config-based dashboard:', error);\n this.setError(`The dashboard \"${dashboard.Name}\" could not be loaded. There may be an issue with the dashboard configuration.`, error);\n this.NotifyLoadComplete();\n }\n }\n\n /**\n * Handle navigation requests from the dashboard viewer\n */\n private handleNavigationRequest(event: DashboardNavRequestEvent): void {\n const request = event.request;\n\n switch (request.type) {\n case 'OpenEntityRecord': {\n const entityRequest = request as { type: 'OpenEntityRecord'; entityName: string; recordId: string };\n const pkey = new CompositeKey([{ FieldName: 'ID', Value: entityRequest.recordId }]);\n this.navigationService.OpenEntityRecord(entityRequest.entityName, pkey);\n break;\n }\n case 'OpenDashboard': {\n const dashRequest = request as { type: 'OpenDashboard'; dashboardId: string };\n // Load dashboard name from engine cache\n const targetDashboard = DashboardEngine.Instance.Dashboards.find(d => UUIDsEqual(d.ID, dashRequest.dashboardId));\n const name = targetDashboard?.Name || 'Dashboard';\n this.navigationService.OpenDashboard(dashRequest.dashboardId, name);\n break;\n }\n case 'OpenQuery': {\n const queryRequest = request as { type: 'OpenQuery'; queryId: string };\n this.navigationService.OpenQuery(queryRequest.queryId, 'Query');\n break;\n }\n default:\n console.warn('Unhandled navigation request type:', request.type);\n }\n }\n\n /**\n * Get the display name for a dashboard resource\n * Loads the actual dashboard name from the database if available\n */\n override async GetResourceDisplayName(data: ResourceData): Promise<string> {\n try {\n // Try to load dashboard metadata if we have the record ID\n if (data.ResourceRecordID && data.ResourceRecordID.length > 0) {\n const md = new Metadata();\n const compositeKey = new CompositeKey([{ FieldName: 'ID', Value: data.ResourceRecordID }]);\n const name = await md.GetEntityRecordName('Dashboards', compositeKey);\n if (name) {\n return name;\n }\n }\n } catch (error) {\n // Silently fail and use fallback\n }\n\n // Fallback: use provided name or generic label\n return data.Name || 'Dashboard';\n }\n\n /**\n * Get the icon class for dashboard resources\n */\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-table-columns';\n }\n}\n"]}
1
+ {"version":3,"file":"dashboard-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/dashboard-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewContainerRef, ComponentRef, ViewChild, ElementRef, ChangeDetectorRef, inject } from '@angular/core';\nimport { BaseResourceComponent, NavigationService, BaseDashboard, DashboardConfig } from '@memberjunction/ng-shared';\nimport { ResourceData, MJDashboardEntity, DashboardEngine, MJDashboardUserStateEntity, MJDashboardCategoryEntity, MJDashboardPartTypeEntity, DashboardUserPermissions } from '@memberjunction/core-entities';\nimport { RegisterClass, MJGlobal, SafeJSONParse , UUIDsEqual } from '@memberjunction/global';\nimport { Metadata, CompositeKey, RunView, LogError } from '@memberjunction/core';\nimport type { DataExplorerFilter } from '@memberjunction/ng-dashboards/data-explorer-dashboards.module';\nimport type { ShareDialogResult } from '@memberjunction/ng-dashboards/core-dashboards.module';\nimport { DashboardViewerComponent, DashboardNavRequestEvent, PanelInteractionEvent, AddPanelResult, DashboardPanel } from '@memberjunction/ng-dashboard-viewer';\n/**\n * Dashboard Resource Wrapper - displays a single dashboard in a tab\n * Extends BaseResourceComponent to work with the resource type system\n * Dynamically routes between code-based and config-based dashboards based on dashboard type\n */\n@RegisterClass(BaseResourceComponent, 'DashboardResource')\n@Component({\n standalone: false,\n selector: 'mj-dashboard-resource',\n template: `\n <div class=\"dashboard-resource-wrapper\">\n <!-- Error State -->\n @if (errorMessage) {\n <div class=\"error-state\">\n <div class=\"error-icon\">\n <i class=\"fa-solid fa-triangle-exclamation\"></i>\n </div>\n <h2 class=\"error-title\">Unable to Load Dashboard</h2>\n <p class=\"error-message\">{{ errorMessage }}</p>\n @if (errorDetails) {\n <details class=\"error-details\">\n <summary>Technical Details</summary>\n <pre>{{ errorDetails }}</pre>\n </details>\n }\n </div>\n }\n\n <!-- View Mode Toolbar -->\n @if (configDashboard && !isEditMode && !errorMessage) {\n <div class=\"viewer-toolbar\">\n <div class=\"toolbar-left\">\n <span class=\"dashboard-title\">\n <i class=\"fa-solid fa-chart-line\"></i>\n {{ configDashboard.Name }}\n </span>\n @if (!dashboardPermissions.IsOwner && dashboardPermissions.PermissionSource !== 'none') {\n <span class=\"shared-indicator\" title=\"Shared with you\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n </span>\n }\n </div>\n <div class=\"toolbar-actions\">\n @if (dashboardPermissions.CanShare) {\n <button\n class=\"btn-icon\"\n title=\"Share Dashboard\"\n (click)=\"openShareDialog()\">\n <i class=\"fa-solid fa-share-nodes\"></i>\n </button>\n }\n @if (dashboardPermissions.CanEdit) {\n <button\n class=\"btn-icon\"\n title=\"Edit Dashboard\"\n (click)=\"toggleEditMode()\">\n <i class=\"fa-solid fa-edit\"></i>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Edit Mode Toolbar -->\n @if (configDashboard && isEditMode && !errorMessage) {\n <div class=\"viewer-header editing\">\n <div class=\"header-left\">\n <button class=\"btn-add-part\" (click)=\"openAddPartDialog()\">\n <i class=\"fa-solid fa-plus\"></i>\n Add Part\n </button>\n <div class=\"header-separator\"></div>\n <div class=\"dashboard-info-edit\">\n <input\n type=\"text\"\n class=\"dashboard-name-input\"\n [(ngModel)]=\"editingName\"\n placeholder=\"Dashboard name\">\n <input\n type=\"text\"\n class=\"dashboard-description-input\"\n [(ngModel)]=\"editingDescription\"\n placeholder=\"Add a description...\">\n </div>\n </div>\n <div class=\"header-right\">\n <button class=\"btn-primary\" (click)=\"saveDashboard()\">\n <i class=\"fa-solid fa-save\"></i>\n Save\n </button>\n <button class=\"btn-cancel\" (click)=\"cancelEdit()\">\n Cancel\n </button>\n </div>\n </div>\n }\n\n <!-- Dashboard Content Container -->\n <div #container class=\"dashboard-resource-container\"></div>\n\n <!-- Share Dashboard Dialog -->\n @if (configDashboard) {\n <mj-dashboard-share-dialog\n [Visible]=\"showShareDialog\"\n [Dashboard]=\"configDashboard\"\n (Result)=\"onShareDialogResult($event)\">\n </mj-dashboard-share-dialog>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n }\n .dashboard-resource-wrapper {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n }\n .dashboard-resource-container {\n flex: 1;\n overflow: hidden;\n min-height: 0;\n }\n\n /* View Mode Toolbar */\n .viewer-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n gap: 16px;\n }\n .viewer-toolbar .toolbar-left {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n .viewer-toolbar .dashboard-title {\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .viewer-toolbar .dashboard-title i {\n color: var(--mj-brand-primary);\n }\n .shared-indicator {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 11px;\n }\n .viewer-toolbar .toolbar-actions {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n /* Edit Mode Header */\n .viewer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 24px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n transition: background 0.2s, border-color 0.2s;\n }\n .viewer-header.editing {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)) 0%, color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-bg-surface)) 100%);\n border-bottom: 2px solid var(--mj-brand-primary);\n }\n .viewer-header .header-left {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n }\n .viewer-header .header-right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n /* Add Part button */\n .btn-add-part {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 16px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s, transform 0.1s;\n box-shadow: 0 2px 4px rgba(92, 107, 192, 0.3);\n }\n .btn-add-part:hover {\n background: var(--mj-brand-primary-hover);\n transform: translateY(-1px);\n box-shadow: 0 3px 6px rgba(92, 107, 192, 0.4);\n }\n .btn-add-part i { font-size: 12px; }\n\n /* Header separator */\n .header-separator {\n width: 1px;\n height: 28px;\n background: rgba(92, 107, 192, 0.3);\n margin: 0 4px;\n }\n\n /* Buttons */\n .btn-primary {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: none;\n border-radius: 6px;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.2s;\n }\n .btn-primary:hover { background: var(--mj-brand-primary-hover); }\n\n .btn-icon {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n }\n .btn-icon:hover { background: var(--mj-bg-surface-sunken); }\n\n .btn-cancel {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n font-size: 14px;\n cursor: pointer;\n transition: all 0.2s;\n }\n .btn-cancel:hover {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-default);\n color: var(--mj-text-primary);\n }\n\n /* Dashboard info inputs */\n .dashboard-info-edit {\n display: flex;\n align-items: center;\n gap: 16px;\n flex: 1;\n }\n .dashboard-name-input {\n border: 1px solid transparent;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 16px;\n font-weight: 500;\n color: var(--mj-text-primary);\n background: rgba(255, 255, 255, 0.7);\n outline: none;\n min-width: 200px;\n max-width: 300px;\n transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;\n }\n .dashboard-name-input:hover { background: rgba(255, 255, 255, 0.9); }\n .dashboard-name-input:focus {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px rgba(92, 107, 192, 0.2);\n }\n .dashboard-description-input {\n border: 1px solid transparent;\n border-radius: 4px;\n padding: 6px 12px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n background: rgba(255, 255, 255, 0.5);\n outline: none;\n flex: 1;\n min-width: 150px;\n max-width: 400px;\n transition: border-color 0.2s, background 0.2s, box-shadow 0.2s;\n }\n .dashboard-description-input:hover { background: rgba(255, 255, 255, 0.8); }\n .dashboard-description-input:focus {\n background: var(--mj-bg-surface-card);\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px rgba(92, 107, 192, 0.2);\n }\n .dashboard-description-input::placeholder {\n color: var(--mj-text-muted);\n font-style: normal;\n }\n\n /* Error state */\n .error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 40px;\n text-align: center;\n color: var(--mj-text-secondary);\n }\n .error-icon {\n font-size: 64px;\n color: #f44336;\n margin-bottom: 24px;\n opacity: 0.8;\n }\n .error-title {\n font-size: 24px;\n font-weight: 500;\n margin: 0 0 12px 0;\n color: var(--mj-text-primary);\n }\n .error-message {\n font-size: 16px;\n color: var(--mj-text-muted);\n margin: 0 0 24px 0;\n max-width: 500px;\n line-height: 1.5;\n }\n .error-details {\n background: var(--mj-bg-surface-sunken);\n border-radius: 8px;\n padding: 12px 16px;\n max-width: 600px;\n text-align: left;\n font-size: 13px;\n }\n .error-details summary {\n cursor: pointer;\n font-weight: 500;\n color: var(--mj-text-muted);\n margin-bottom: 8px;\n }\n .error-details pre {\n margin: 0;\n white-space: pre-wrap;\n word-break: break-word;\n color: #d32f2f;\n font-family: 'Consolas', 'Monaco', monospace;\n font-size: 12px;\n }\n\n /* Responsive */\n @media (max-width: 768px) {\n .viewer-header {\n flex-direction: column;\n gap: 12px;\n align-items: stretch;\n }\n .viewer-header .header-left { flex-wrap: wrap; }\n .dashboard-info-edit {\n flex-direction: column;\n align-items: stretch;\n }\n .dashboard-name-input,\n .dashboard-description-input { max-width: none; }\n }\n `]\n})\nexport class DashboardResource extends BaseResourceComponent {\n private componentRef: ComponentRef<unknown> | null = null;\n private dataLoaded = false;\n @ViewChild('container', { static: true }) containerElement!: ElementRef<HTMLDivElement>;\n\n /** Error message to display when dashboard fails to load */\n public errorMessage: string | null = null;\n /** Technical error details (shown in expandable section) */\n public errorDetails: string | null = null;\n\n /** Cached dashboard categories for breadcrumb navigation */\n private categories: MJDashboardCategoryEntity[] = [];\n\n /** Reference to the dashboard viewer component (for config-based dashboards) */\n private viewerInstance: DashboardViewerComponent | null = null;\n\n /** The config-based dashboard entity (null for code-based dashboards) */\n public configDashboard: MJDashboardEntity | null = null;\n\n /** Whether we're in edit mode */\n public isEditMode = false;\n\n /** Editing fields */\n public editingName = '';\n public editingDescription = '';\n\n /** Current user's permissions for this dashboard */\n public dashboardPermissions: DashboardUserPermissions = {\n DashboardID: '',\n CanRead: true,\n CanEdit: true,\n CanDelete: true,\n CanShare: true,\n IsOwner: true,\n PermissionSource: 'owner'\n };\n\n /** Whether the share dialog is visible */\n public showShareDialog = false;\n\n /**\n * Sets the error state with a user-friendly message and optional technical details\n */\n private setError(message: string, error?: unknown): void {\n this.errorMessage = message;\n if (error instanceof Error) {\n this.errorDetails = error.message;\n if (error.stack) {\n this.errorDetails += '\\n\\nStack trace:\\n' + error.stack;\n }\n } else if (error) {\n this.errorDetails = String(error);\n }\n }\n\n /**\n * Clears any previous error state\n */\n private clearError(): void {\n this.errorMessage = null;\n this.errorDetails = null;\n }\n\n constructor(\n private viewContainer: ViewContainerRef,\n private navigationService: NavigationService,\n private cdr: ChangeDetectorRef\n ) {\n super();\n }\n\n override set Data(value: ResourceData) {\n const previousRecordId = super.Data?.ResourceRecordID;\n super.Data = value;\n\n const newRecordId = value?.ResourceRecordID;\n\n // Load on first set, or when the dashboard has changed\n if (!this.dataLoaded || newRecordId !== previousRecordId) {\n this.dataLoaded = true;\n // Destroy previous component before loading new one\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = null;\n }\n this.clearError();\n this.configDashboard = null;\n this.viewerInstance = null;\n this.loadDashboard();\n }\n }\n\n // Need to override the getter too in TS otherwise the override to the setter alone above would break things\n override get Data(): ResourceData {\n return super.Data;\n }\n\n ngOnDestroy(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n }\n }\n\n // ========================================\n // Edit Mode Methods\n // ========================================\n\n /**\n * Toggle between view and edit mode\n */\n public toggleEditMode(): void {\n if (this.isEditMode) {\n this.cancelEdit();\n } else {\n this.enterEditMode();\n }\n }\n\n /**\n * Enter edit mode\n */\n private enterEditMode(): void {\n if (!this.configDashboard) return;\n\n this.isEditMode = true;\n this.editingName = this.configDashboard.Name;\n this.editingDescription = this.configDashboard.Description || '';\n\n // Tell the viewer to enter edit mode\n if (this.viewerInstance) {\n this.viewerInstance.isEditing = true;\n }\n\n this.cdr.detectChanges();\n }\n\n /**\n * Cancel edit mode and discard changes\n */\n public cancelEdit(): void {\n this.isEditMode = false;\n\n // Tell the viewer to exit edit mode\n if (this.viewerInstance) {\n this.viewerInstance.isEditing = false;\n }\n\n this.cdr.detectChanges();\n }\n\n /**\n * Save dashboard changes\n */\n public async saveDashboard(): Promise<void> {\n if (!this.configDashboard || !this.viewerInstance) return;\n\n try {\n // Update dashboard name and description\n this.configDashboard.Name = this.editingName;\n this.configDashboard.Description = this.editingDescription;\n\n // Save via the viewer (which handles layout saving)\n await this.viewerInstance.save();\n\n // Exit edit mode\n this.isEditMode = false;\n this.viewerInstance.isEditing = false;\n\n this.cdr.detectChanges();\n } catch (error) {\n console.error('Error saving dashboard:', error);\n }\n }\n\n /**\n * Open the add panel dialog\n */\n public openAddPartDialog(): void {\n if (this.viewerInstance) {\n // Trigger the viewer's add panel flow\n this.viewerInstance.onAddPanelClick();\n }\n }\n\n /**\n * Open the share dialog for this dashboard\n */\n public openShareDialog(): void {\n this.showShareDialog = true;\n this.cdr.detectChanges();\n }\n\n /**\n * Close the share dialog\n */\n public closeShareDialog(): void {\n this.showShareDialog = false;\n this.cdr.detectChanges();\n }\n\n /**\n * Handle share dialog result\n */\n public onShareDialogResult(result: ShareDialogResult): void {\n this.showShareDialog = false;\n\n if (result.Action === 'save' && this.configDashboard) {\n // Recompute permissions after sharing changes\n const md = new Metadata();\n this.dashboardPermissions = DashboardEngine.Instance.GetDashboardPermissions(\n this.configDashboard.ID,\n md.CurrentUser.ID\n );\n }\n\n this.cdr.detectChanges();\n }\n\n /**\n * Load the appropriate dashboard component based on dashboard type\n * Routes between code-based dashboards (registered classes) and config-based dashboards\n */\n private async loadDashboard(): Promise<void> {\n // Clear any previous error state\n this.clearError();\n\n const data = this.Data;\n\n if (!data?.ResourceRecordID) {\n this.NotifyLoadStarted();\n this.NotifyLoadComplete();\n return;\n }\n\n this.NotifyLoadStarted();\n\n try {\n // Check if this is a special dashboard type (not a database record)\n const config = data.Configuration || {};\n\n if (config['dashboardType'] === 'DataExplorer' || data.ResourceRecordID === 'DataExplorer') {\n // Special case: Data Explorer dashboard with optional entity filter\n await this.loadDataExplorer(\n config['entityFilter'],\n config['appName'] as string | undefined,\n config['appIcon'] as string | undefined\n );\n return;\n }\n\n await DashboardEngine.Instance.Config(false); // make sure it is configured, if already configured does nothing\n const dashboard = DashboardEngine.Instance.Dashboards.find(d => UUIDsEqual(d.ID, data.ResourceRecordID));\n if (!dashboard) {\n throw new Error(`Dashboard with ID ${data.ResourceRecordID} not found.`);\n }\n\n // Determine which dashboard component to load based on dashboard type\n if (dashboard.Type === 'Code') {\n // CODE-BASED DASHBOARD: Use registered class via DriverClass\n await this.loadCodeBasedDashboard(dashboard);\n } else {\n // CONFIG-BASED DASHBOARD: Use the generic metadata-driven renderer\n await this.loadConfigBasedDashboard(dashboard);\n }\n } catch (error) {\n console.error('Error loading dashboard:', error);\n this.setError('The dashboard could not be loaded. This may be due to a missing component or configuration issue.', error);\n this.NotifyLoadComplete();\n }\n }\n\n /**\n * Load the Data Explorer dashboard component with optional entity filter and context info\n * @param entityFilter Optional filter to constrain which entities are shown\n * @param contextName Optional name to display in the header (e.g., \"CRM\", \"Association Demo\")\n * @param contextIcon Optional Font Awesome icon class for the header\n */\n private async loadDataExplorer(\n entityFilter?: DataExplorerFilter,\n contextName?: string,\n contextIcon?: string\n ): Promise<void> {\n try {\n // Lazy-load the Data Explorer component to keep it out of the initial bundle\n const { DataExplorerDashboardComponent } = await import('@memberjunction/ng-dashboards/data-explorer-dashboards.module');\n this.containerElement.nativeElement.innerHTML = '';\n const componentRef = this.viewContainer.createComponent(DataExplorerDashboardComponent);\n this.componentRef = componentRef;\n const instance = componentRef.instance;\n\n // Set the entity filter - ngOnInit will use this when it runs\n if (entityFilter) {\n instance.entityFilter = entityFilter;\n }\n\n // Set context name and icon for customized header display\n if (contextName) {\n instance.contextName = contextName;\n }\n if (contextIcon) {\n instance.contextIcon = contextIcon;\n }\n\n // Manually append the component's native element inside the div\n const nativeElement = (componentRef.hostView as any).rootNodes[0];\n nativeElement.style.width = '100%';\n nativeElement.style.height = '100%';\n this.containerElement.nativeElement.appendChild(nativeElement);\n\n // Handle open entity record events\n instance.OpenEntityRecord.subscribe((eventData: { EntityName: string; RecordPKey: CompositeKey }) => {\n if (eventData && eventData.EntityName && eventData.RecordPKey) {\n this.navigationService.OpenEntityRecord(eventData.EntityName, eventData.RecordPKey);\n }\n });\n\n // Setup LoadCompleteEvent to know when the dashboard is ready\n instance.LoadCompleteEvent = () => {\n this.NotifyLoadComplete();\n };\n\n // Initialize dashboard (no database config needed for DataExplorer)\n const config: DashboardConfig = {\n dashboard: null as unknown as MJDashboardEntity, // No database record\n userState: {}\n };\n instance.Config = config;\n instance.Refresh();\n\n // Trigger change detection to ensure the component updates\n componentRef.changeDetectorRef.detectChanges();\n } catch (error) {\n console.error('Error loading Data Explorer:', error);\n this.setError('The Data Explorer could not be loaded.', error);\n this.NotifyLoadComplete();\n }\n }\n\n /**\n * Load a code-based dashboard by looking up the registered class\n */\n private async loadCodeBasedDashboard(dashboard: MJDashboardEntity): Promise<void> {\n try {\n if (!dashboard.DriverClass) {\n throw new Error(`Dashboard '${dashboard.Name}' is marked as Code type but has no DriverClass specified`);\n }\n\n // Look up the registered class using the DriverClass name (with lazy loading fallback via ClassFactory)\n const classReg = await MJGlobal.Instance.ClassFactory.GetRegistrationAsync(\n BaseDashboard,\n dashboard.DriverClass\n );\n\n if (!classReg?.SubClass) {\n throw new Error(`Dashboard class '${dashboard.DriverClass}' is not registered. Please check the class registration.`);\n }\n\n // Create the component instance\n this.containerElement.nativeElement.innerHTML = '';\n this.componentRef = this.viewContainer.createComponent<BaseDashboard>(classReg.SubClass);\n const instance = this.componentRef.instance as BaseDashboard;\n\n // Setup LoadCompleteEvent() to know when the dashboard is ready\n instance.LoadCompleteEvent = () => {\n this.NotifyLoadComplete();\n };\n\n // Initialize with dashboard data\n const userStateEntity = await this.loadDashboardUserState(dashboard.ID);\n const config: DashboardConfig = {\n dashboard,\n userState: userStateEntity.UserState ? SafeJSONParse(userStateEntity.UserState) : {}\n };\n\n instance.Config = config;\n\n // Manually append the component's native element inside the div\n const nativeElement = (this.componentRef.hostView as any).rootNodes[0];\n nativeElement.style.width = '100%';\n nativeElement.style.height = '100%';\n this.containerElement.nativeElement.appendChild(nativeElement);\n\n // handle open entity record events in MJ Explorer with routing\n instance.OpenEntityRecord.subscribe((data: { EntityName: string; RecordPKey: CompositeKey }) => {\n // check to see if the data has entityname/pkey\n if (data && data.EntityName && data.RecordPKey) {\n // Use NavigationService to open entity record in new tab\n this.navigationService.OpenEntityRecord(data.EntityName, data.RecordPKey);\n } else {\n console.warn('DashboardResource - invalid data, missing EntityName or RecordPKey:', data);\n }\n });\n\n instance.UserStateChanged.subscribe(async (userState: any) => {\n if (!userState) {\n // if the user state is null, we need to remove it from the user state\n userState = {};\n }\n // save the user state to the dashboard user state entity\n userStateEntity.UserState = JSON.stringify(userState);\n if (!await userStateEntity.Save()) {\n LogError('Error saving user state', null, userStateEntity.LatestResult?.CompleteMessage);\n }\n });\n\n instance.Refresh();\n } catch (error) {\n console.error('Error loading code-based dashboard:', error);\n this.setError(`The dashboard \"${dashboard.Name}\" could not be loaded. The dashboard class may not be registered or may have failed to initialize.`, error);\n this.NotifyLoadComplete();\n }\n }\n\n protected async loadDashboardUserState(dashboardId: string): Promise<MJDashboardUserStateEntity> {\n // handle user state changes for the dashboard\n const md = new Metadata();\n const stateResult = DashboardEngine.Instance.DashboardUserStates.filter(dus => UUIDsEqual(dus.DashboardID, dashboardId) && UUIDsEqual(dus.UserID, md.CurrentUser.ID));\n let stateObject: MJDashboardUserStateEntity;\n if (stateResult && stateResult.length > 0) {\n stateObject = stateResult[0];\n }\n else {\n stateObject = await md.GetEntityObject<MJDashboardUserStateEntity>('MJ: Dashboard User States');\n stateObject.DashboardID = dashboardId;\n stateObject.UserID = md.CurrentUser.ID;\n // don't save becuase we don't care about the state until something changes\n }\n return stateObject;\n }\n\n /**\n * Load a config-based dashboard using the new DashboardViewerComponent (Golden Layout)\n */\n private async loadConfigBasedDashboard(dashboard: MJDashboardEntity): Promise<void> {\n try {\n this.containerElement.nativeElement.innerHTML = '';\n const componentRef = this.viewContainer.createComponent(DashboardViewerComponent);\n this.componentRef = componentRef;\n const instance = componentRef.instance;\n\n // Store references for external toolbar control\n this.viewerInstance = instance;\n this.configDashboard = dashboard;\n\n // Compute user permissions for this dashboard\n const md = new Metadata();\n this.dashboardPermissions = DashboardEngine.Instance.GetDashboardPermissions(\n dashboard.ID,\n md.CurrentUser.ID\n );\n\n // Manually append the component's native element inside the div\n const nativeElement = (this.componentRef.hostView as any).rootNodes[0];\n nativeElement.style.width = '100%';\n nativeElement.style.height = '100%';\n this.containerElement.nativeElement.appendChild(nativeElement);\n\n // Load categories for breadcrumb navigation (if not already loaded)\n if (this.categories.length === 0) {\n this.categories = DashboardEngine.Instance.DashboardCategories;\n }\n\n // Set the dashboard entity directly on the viewer\n // We provide our own external toolbar, so disable the viewer's internal toolbar\n instance.dashboard = dashboard;\n instance.showToolbar = false; // We provide external toolbar\n instance.showBreadcrumb = false; // Already in its own tab, no breadcrumb needed\n instance.showOpenInTabButton = false; // Already in its own tab\n instance.showEditButton = false; // External toolbar handles edit\n instance.Categories = this.categories;\n\n // Wire up navigation events - handle navigation requests from the dashboard\n instance.navigationRequested.subscribe((event: DashboardNavRequestEvent) => {\n this.handleNavigationRequest(event);\n });\n\n // Wire up \"Open in Tab\" button click\n instance.openInTab.subscribe((event: { dashboardId: string; dashboardName: string }) => {\n this.navigationService.OpenDashboard(event.dashboardId, event.dashboardName);\n });\n\n // Wire up dashboard saved event\n instance.dashboardSaved.subscribe((savedDashboard: MJDashboardEntity) => {\n this.ResourceRecordSaved(savedDashboard);\n });\n\n // Wire up error events\n instance.error.subscribe((errorEvent: { message: string; error?: Error }) => {\n console.error('Dashboard error:', errorEvent.message, errorEvent.error);\n });\n\n // Notify load complete after a brief delay to let Golden Layout initialize\n setTimeout(() => {\n this.NotifyLoadComplete();\n this.cdr.detectChanges();\n }, 150);\n\n } catch (error) {\n console.error('Error loading config-based dashboard:', error);\n this.setError(`The dashboard \"${dashboard.Name}\" could not be loaded. There may be an issue with the dashboard configuration.`, error);\n this.NotifyLoadComplete();\n }\n }\n\n /**\n * Handle navigation requests from the dashboard viewer\n */\n private handleNavigationRequest(event: DashboardNavRequestEvent): void {\n const request = event.request;\n\n switch (request.type) {\n case 'OpenEntityRecord': {\n const entityRequest = request as { type: 'OpenEntityRecord'; entityName: string; recordId: string };\n const pkey = new CompositeKey([{ FieldName: 'ID', Value: entityRequest.recordId }]);\n this.navigationService.OpenEntityRecord(entityRequest.entityName, pkey);\n break;\n }\n case 'OpenDashboard': {\n const dashRequest = request as { type: 'OpenDashboard'; dashboardId: string };\n // Load dashboard name from engine cache\n const targetDashboard = DashboardEngine.Instance.Dashboards.find(d => UUIDsEqual(d.ID, dashRequest.dashboardId));\n const name = targetDashboard?.Name || 'Dashboard';\n this.navigationService.OpenDashboard(dashRequest.dashboardId, name);\n break;\n }\n case 'OpenQuery': {\n const queryRequest = request as { type: 'OpenQuery'; queryId: string };\n this.navigationService.OpenQuery(queryRequest.queryId, 'Query');\n break;\n }\n default:\n console.warn('Unhandled navigation request type:', request.type);\n }\n }\n\n /**\n * Get the display name for a dashboard resource\n * Loads the actual dashboard name from the database if available\n */\n override async GetResourceDisplayName(data: ResourceData): Promise<string> {\n try {\n // Try to load dashboard metadata if we have the record ID\n if (data.ResourceRecordID && data.ResourceRecordID.length > 0) {\n const md = new Metadata();\n const compositeKey = new CompositeKey([{ FieldName: 'ID', Value: data.ResourceRecordID }]);\n const name = await md.GetEntityRecordName('Dashboards', compositeKey);\n if (name) {\n return name;\n }\n }\n } catch (error) {\n // Silently fail and use fallback\n }\n\n // Fallback: use provided name or generic label\n return data.Name || 'Dashboard';\n }\n\n /**\n * Get the icon class for dashboard resources\n */\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-table-columns';\n }\n}\n"]}
@@ -3,7 +3,7 @@ import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-sha
3
3
  import { ResourceData, MJUserViewEntityExtended } from '@memberjunction/core-entities';
4
4
  import { EntityInfo } from '@memberjunction/core';
5
5
  import { RecordOpenedEvent, ViewGridState, EntityViewerComponent } from '@memberjunction/ng-entity-viewer';
6
- import { ExcelExportComponent } from '@progress/kendo-angular-excel-export';
6
+ import { ExportService } from '@memberjunction/ng-export-service';
7
7
  import * as i0 from "@angular/core";
8
8
  /**
9
9
  * UserViewResource - Resource wrapper for displaying User Views in tabs
@@ -20,24 +20,18 @@ import * as i0 from "@angular/core";
20
20
  export declare class UserViewResource extends BaseResourceComponent {
21
21
  private navigationService;
22
22
  private cdr;
23
+ private exportService;
23
24
  containerElement: ElementRef<HTMLDivElement>;
24
25
  entityViewerRef?: EntityViewerComponent;
25
- excelExportRef?: ExcelExportComponent;
26
26
  isLoading: boolean;
27
27
  errorMessage: string | null;
28
28
  entityInfo: EntityInfo | null;
29
29
  viewEntity: MJUserViewEntityExtended | null;
30
30
  gridState: ViewGridState | null;
31
31
  isExporting: boolean;
32
- exportData: any[];
33
- exportColumns: {
34
- Name: string;
35
- DisplayName: string;
36
- }[];
37
- exportFileName: string;
38
32
  private dataLoaded;
39
33
  private metadata;
40
- constructor(navigationService: NavigationService, cdr: ChangeDetectorRef);
34
+ constructor(navigationService: NavigationService, cdr: ChangeDetectorRef, exportService: ExportService);
41
35
  set Data(value: ResourceData);
42
36
  get Data(): ResourceData;
43
37
  /**
@@ -77,9 +71,17 @@ export declare class UserViewResource extends BaseResourceComponent {
77
71
  */
78
72
  onExport(): Promise<void>;
79
73
  /**
80
- * Get the data for export - loads all records for the current view/entity
74
+ * Load all records for the current view/entity for export
81
75
  */
82
- private getExportData;
76
+ private loadExportRows;
77
+ /**
78
+ * Determine which columns to export based on grid state, view entity, or entity fields
79
+ */
80
+ private buildExportColumns;
81
+ /**
82
+ * Build the export file name based on entity and view
83
+ */
84
+ private buildExportFileName;
83
85
  /**
84
86
  * Show a notification to the user
85
87
  */
@@ -1 +1 @@
1
- {"version":3,"file":"view-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/view-resource.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAY,MAAM,+BAA+B,CAAC;AAEjG,OAAO,EAA0B,UAAU,EAAW,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;;AAC5E;;;;;;;;;;;GAWG;AACH,qBAsHa,gBAAiB,SAAQ,qBAAqB;IAqBnD,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,GAAG;IArB2B,gBAAgB,EAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC7D,eAAe,CAAC,EAAE,qBAAqB,CAAC;IACzC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IAEzD,SAAS,EAAE,OAAO,CAAS;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IACnC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAQ;IACrC,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAAQ;IACnD,SAAS,EAAE,aAAa,GAAG,IAAI,CAAQ;IAGvC,WAAW,EAAE,OAAO,CAAS;IAC7B,UAAU,EAAE,GAAG,EAAE,CAAM;IACvB,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAM;IAC5D,cAAc,EAAE,MAAM,CAAiB;IAE9C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAkB;gBAGtB,iBAAiB,EAAE,iBAAiB,EACpC,GAAG,EAAE,iBAAiB;IAKlC,IAAa,IAAI,CAAC,KAAK,EAAE,YAAY,EAkBpC;IAED,IAAa,IAAI,IAAI,YAAY,CAEhC;IAED;;OAEG;YACW,QAAQ;IA2CtB;;OAEG;YACW,YAAY;IAmC1B;;OAEG;YACW,eAAe;IAiB7B;;OAEG;IACI,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAMrD;;OAEG;IACI,YAAY,IAAI,IAAI;IAI3B;;OAEG;IACY,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAc1E;;OAEG;IACY,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAIzE;;OAEG;IACI,iBAAiB,IAAI,IAAI;IAOhC;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA4DtC;;OAEG;YACW,aAAa;IA2B3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;yCA7Sf,gBAAgB;2CAAhB,gBAAgB;CAyT5B"}
1
+ {"version":3,"file":"view-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/view-resource.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAY,MAAM,+BAA+B,CAAC;AAEjG,OAAO,EAA0B,UAAU,EAAW,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;;AAElE;;;;;;;;;;;GAWG;AACH,qBAmHa,gBAAiB,SAAQ,qBAAqB;IAiBnD,OAAO,CAAC,iBAAiB;IACzB,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,aAAa;IAlBiB,gBAAgB,EAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC7D,eAAe,CAAC,EAAE,qBAAqB,CAAC;IAE5D,SAAS,EAAE,OAAO,CAAS;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IACnC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAQ;IACrC,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAAQ;IACnD,SAAS,EAAE,aAAa,GAAG,IAAI,CAAQ;IAGvC,WAAW,EAAE,OAAO,CAAS;IAEpC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAkB;gBAGtB,iBAAiB,EAAE,iBAAiB,EACpC,GAAG,EAAE,iBAAiB,EACtB,aAAa,EAAE,aAAa;IAKxC,IAAa,IAAI,CAAC,KAAK,EAAE,YAAY,EAkBpC;IAED,IAAa,IAAI,IAAI,YAAY,CAEhC;IAED;;OAEG;YACW,QAAQ;IA2CtB;;OAEG;YACW,YAAY;IAmC1B;;OAEG;YACW,eAAe;IAiB7B;;OAEG;IACI,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAMrD;;OAEG;IACI,YAAY,IAAI,IAAI;IAI3B;;OAEG;IACY,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAc1E;;OAEG;IACY,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAIzE;;OAEG;IACI,iBAAiB,IAAI,IAAI;IAOhC;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCtC;;OAEG;YACW,cAAc;IAyB5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA0B1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;yCAxTf,gBAAgB;2CAAhB,gBAAgB;CAoU5B"}