@memberjunction/ng-dashboards 5.51.0 → 6.1.0-edge.1

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 (98) hide show
  1. package/LICENSE +7 -0
  2. package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
  3. package/dist/AI/components/agents/agent-configuration.component.js +59 -63
  4. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  5. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +7 -7
  6. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  7. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +21 -21
  8. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  9. package/dist/AI/components/autotagging/shared/classify.types.d.ts +4 -4
  10. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -1
  11. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -1
  12. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +14 -19
  13. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
  14. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +53 -77
  15. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
  16. package/dist/AI/components/models/model-management.component.d.ts.map +1 -1
  17. package/dist/AI/components/models/model-management.component.js +67 -70
  18. package/dist/AI/components/models/model-management.component.js.map +1 -1
  19. package/dist/AI/components/prompts/prompt-management.component.d.ts.map +1 -1
  20. package/dist/AI/components/prompts/prompt-management.component.js +55 -59
  21. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  22. package/dist/AI/components/system/system-configuration.component.d.ts.map +1 -1
  23. package/dist/AI/components/system/system-configuration.component.js +59 -63
  24. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  25. package/dist/AI/components/tags/tags-resource.component.d.ts +15 -20
  26. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  27. package/dist/AI/components/tags/tags-resource.component.js +51 -77
  28. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  29. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +1 -3
  30. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  31. package/dist/AI/components/vectors/vector-management-resource.component.js +22 -43
  32. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  33. package/dist/Actions/components/explorer/action-card.component.js +6 -6
  34. package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
  35. package/dist/Actions/components/explorer/action-list-item.component.js +3 -3
  36. package/dist/Actions/components/explorer/action-list-item.component.js.map +1 -1
  37. package/dist/Actions/index.d.ts +0 -1
  38. package/dist/Actions/index.d.ts.map +1 -1
  39. package/dist/Actions/index.js +0 -1
  40. package/dist/Actions/index.js.map +1 -1
  41. package/dist/Admin/admin-dev-tools-resource.component.d.ts.map +1 -1
  42. package/dist/Admin/admin-dev-tools-resource.component.js +14 -0
  43. package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
  44. package/dist/Admin/base-admin-container.component.d.ts.map +1 -1
  45. package/dist/Admin/base-admin-container.component.js +15 -0
  46. package/dist/Admin/base-admin-container.component.js.map +1 -1
  47. package/dist/DevTools/grid-width-lab.component.d.ts +78 -0
  48. package/dist/DevTools/grid-width-lab.component.d.ts.map +1 -0
  49. package/dist/DevTools/grid-width-lab.component.js +248 -0
  50. package/dist/DevTools/grid-width-lab.component.js.map +1 -0
  51. package/dist/DevTools/index.d.ts +2 -0
  52. package/dist/DevTools/index.d.ts.map +1 -1
  53. package/dist/DevTools/index.js +2 -0
  54. package/dist/DevTools/index.js.map +1 -1
  55. package/dist/DevTools/tab-strip-lab.component.d.ts +76 -0
  56. package/dist/DevTools/tab-strip-lab.component.d.ts.map +1 -0
  57. package/dist/DevTools/tab-strip-lab.component.js +247 -0
  58. package/dist/DevTools/tab-strip-lab.component.js.map +1 -0
  59. package/dist/Home/home-application.d.ts +5 -0
  60. package/dist/Home/home-application.d.ts.map +1 -1
  61. package/dist/Home/home-application.js +9 -0
  62. package/dist/Home/home-application.js.map +1 -1
  63. package/dist/Home/home-dashboard.component.d.ts.map +1 -1
  64. package/dist/Home/home-dashboard.component.js +0 -6
  65. package/dist/Home/home-dashboard.component.js.map +1 -1
  66. package/dist/SystemDiagnostics/system-diagnostics.component.d.ts +7 -3
  67. package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
  68. package/dist/SystemDiagnostics/system-diagnostics.component.js +22 -21
  69. package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
  70. package/dist/Testing/components/testing-explorer.component.d.ts +9 -0
  71. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  72. package/dist/Testing/components/testing-explorer.component.js +28 -5
  73. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  74. package/dist/actions-dashboards.module.d.ts +23 -24
  75. package/dist/actions-dashboards.module.d.ts.map +1 -1
  76. package/dist/actions-dashboards.module.js +0 -5
  77. package/dist/actions-dashboards.module.js.map +1 -1
  78. package/dist/ai-dashboards.module.d.ts +1 -1
  79. package/dist/ai-dashboards.module.d.ts.map +1 -1
  80. package/dist/ai-dashboards.module.js +4 -1
  81. package/dist/ai-dashboards.module.js.map +1 -1
  82. package/dist/core-dashboards.module.d.ts +46 -42
  83. package/dist/core-dashboards.module.d.ts.map +1 -1
  84. package/dist/core-dashboards.module.js +22 -0
  85. package/dist/core-dashboards.module.js.map +1 -1
  86. package/dist/public-api.d.ts +1 -1
  87. package/dist/public-api.d.ts.map +1 -1
  88. package/dist/public-api.js +1 -1
  89. package/dist/public-api.js.map +1 -1
  90. package/dist/shared/action-scheduled-job.d.ts +58 -0
  91. package/dist/shared/action-scheduled-job.d.ts.map +1 -0
  92. package/dist/shared/action-scheduled-job.js +77 -0
  93. package/dist/shared/action-scheduled-job.js.map +1 -0
  94. package/package.json +73 -70
  95. package/dist/Actions/components/scheduled-actions.component.d.ts +0 -16
  96. package/dist/Actions/components/scheduled-actions.component.d.ts.map +0 -1
  97. package/dist/Actions/components/scheduled-actions.component.js +0 -57
  98. package/dist/Actions/components/scheduled-actions.component.js.map +0 -1
@@ -71,7 +71,7 @@ function ActionCardComponent_Conditional_28_Conditional_2_Conditional_21_Conditi
71
71
  } if (rf & 2) {
72
72
  const ctx_r0 = i0.ɵɵnextContext(4);
73
73
  i0.ɵɵadvance();
74
- i0.ɵɵtextInterpolate1("+", ctx_r0.Action.Params.length - 4, " more");
74
+ i0.ɵɵtextInterpolate1("+", ctx_r0.Action.Params.Items.length - 4, " more");
75
75
  } }
76
76
  function ActionCardComponent_Conditional_28_Conditional_2_Conditional_21_Template(rf, ctx) { if (rf & 1) {
77
77
  i0.ɵɵelementStart(0, "div", 30)(1, "div", 31);
@@ -85,9 +85,9 @@ function ActionCardComponent_Conditional_28_Conditional_2_Conditional_21_Templat
85
85
  } if (rf & 2) {
86
86
  const ctx_r0 = i0.ɵɵnextContext(3);
87
87
  i0.ɵɵadvance(5);
88
- i0.ɵɵrepeater(ctx_r0.Action.Params.slice(0, 4));
88
+ i0.ɵɵrepeater(ctx_r0.Action.Params.Items.slice(0, 4));
89
89
  i0.ɵɵadvance(2);
90
- i0.ɵɵconditional(ctx_r0.Action.Params.length > 4 ? 7 : -1);
90
+ i0.ɵɵconditional(ctx_r0.Action.Params.Items.length > 4 ? 7 : -1);
91
91
  } }
92
92
  function ActionCardComponent_Conditional_28_Conditional_2_Template(rf, ctx) { if (rf & 1) {
93
93
  i0.ɵɵelementStart(0, "div", 25)(1, "div", 26)(2, "div", 27);
@@ -126,9 +126,9 @@ function ActionCardComponent_Conditional_28_Conditional_2_Template(rf, ctx) { if
126
126
  i0.ɵɵadvance(5);
127
127
  i0.ɵɵtextInterpolate(ctx_r0.formatDate(ctx_r0.ExecutionStats.lastExecuted));
128
128
  i0.ɵɵadvance(5);
129
- i0.ɵɵtextInterpolate(ctx_r0.Action.Params.length || 0);
129
+ i0.ɵɵtextInterpolate(ctx_r0.Action.Params.Items.length || 0);
130
130
  i0.ɵɵadvance(3);
131
- i0.ɵɵconditional(ctx_r0.Action.Params && ctx_r0.Action.Params.length > 0 ? 21 : -1);
131
+ i0.ɵɵconditional(ctx_r0.Action.Params && ctx_r0.Action.Params.Items.length > 0 ? 21 : -1);
132
132
  } }
133
133
  function ActionCardComponent_Conditional_28_Template(rf, ctx) { if (rf & 1) {
134
134
  i0.ɵɵelementStart(0, "div", 20);
@@ -389,7 +389,7 @@ export class ActionCardComponent extends BaseAngularComponent {
389
389
  }
390
390
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ActionCardComponent, [{
391
391
  type: Component,
392
- args: [{ standalone: false, selector: 'mj-action-card', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"action-card\" [class.expanded]=\"IsExpanded\" (click)=\"onCardClick()\">\n <div class=\"card-main\">\n <!-- Icon -->\n <div class=\"action-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Content -->\n <div class=\"action-content\">\n <div class=\"action-header\">\n <h3 class=\"action-name\" [title]=\"Action.Name\">{{ Action.Name }}</h3>\n <div class=\"action-badges\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n @if (Action.Type === 'Generated') {\n <span class=\"status-chip\" data-color=\"info\">\n <i class=\"fa-solid fa-robot\"></i> AI\n </span>\n }\n </div>\n </div>\n\n <p class=\"action-description\" [title]=\"Action.Description || 'No description'\">\n {{ Action.Description || 'No description available' }}\n </p>\n\n <div class=\"action-meta\">\n <button class=\"meta-item category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n @if (Action.__mj_UpdatedAt) {\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n <span>{{ formatDate(Action.__mj_UpdatedAt) }}</span>\n </span>\n }\n\n @if (Action.Type === 'Generated' && Action.CodeApprovalStatus) {\n <span class=\"meta-item\" [attr.data-status]=\"Action.CodeApprovalStatus\">\n <i [class]=\"getApprovalStatusIcon()\"></i>\n <span>{{ Action.CodeApprovalStatus }}</span>\n </span>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"action-buttons\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"View Stats\"\n (click)=\"toggleExpanded($event)\">\n <i [class]=\"IsExpanded ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chart-line'\"></i>\n </button>\n <button mjButton\n variant=\"primary\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n </div>\n\n <!-- Expanded Stats Section -->\n @if (IsExpanded) {\n <div class=\"card-expanded\">\n @if (ExecutionStats.isLoading) {\n <div class=\"stats-loading\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span>Loading execution stats...</span>\n </div>\n } @else {\n <div class=\"stats-grid\">\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ ExecutionStats.totalExecutions }}</div>\n <div class=\"stat-label\">Total Runs</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\" [class.success]=\"ExecutionStats.successRate >= 90\" [class.warning]=\"ExecutionStats.successRate >= 50 && ExecutionStats.successRate < 90\" [class.error]=\"ExecutionStats.successRate < 50\">\n {{ ExecutionStats.successRate }}%\n </div>\n <div class=\"stat-label\">Success Rate</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ formatDate(ExecutionStats.lastExecuted) }}</div>\n <div class=\"stat-label\">Last Run</div>\n </div>\n <div class=\"stat-item params\">\n <div class=\"stat-value\">{{ Action.Params.length || 0 }}</div>\n <div class=\"stat-label\">Parameters</div>\n </div>\n </div>\n\n @if (Action.Params && Action.Params.length > 0) {\n <div class=\"params-preview\">\n <div class=\"params-header\">\n <i class=\"fa-solid fa-sliders\"></i>\n Parameters\n </div>\n <div class=\"params-list\">\n @for (param of Action.Params.slice(0, 4); track param.Name) {\n <span class=\"param-tag\" [class.required]=\"param.IsRequired\">\n {{ param.Name }}\n @if (param.IsRequired) {\n <span class=\"required-marker\">*</span>\n }\n </span>\n }\n @if (Action.Params.length > 4) {\n <span class=\"param-more\">+{{ Action.Params.length - 4 }} more</span>\n }\n </div>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".action-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.action-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\n.action-card.expanded {\n border-color: var(--mj-brand-primary);\n}\n\n.card-main {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n padding: 20px;\n}\n\n/* Icon */\n.action-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n flex-shrink: 0;\n}\n\n.action-icon i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.action-icon.ai-generated {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface)), color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)));\n}\n\n.action-icon.ai-generated i {\n background: linear-gradient(135deg, var(--mj-status-info), var(--mj-brand-primary));\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n}\n\n/* Content */\n.action-content {\n flex: 1;\n min-width: 0;\n}\n\n.action-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n.action-name {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.action-badges {\n display: flex;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.action-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.action-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n}\n\n.meta-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: none;\n border: none;\n padding: 0;\n cursor: default;\n}\n\n.meta-item.category {\n cursor: pointer;\n padding: 2px 6px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.meta-item.category:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n.meta-item i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.meta-item[data-status=\"Approved\"] i {\n color: var(--mj-status-success);\n}\n\n.meta-item[data-status=\"Pending\"] i {\n color: var(--mj-status-warning);\n}\n\n.meta-item[data-status=\"Rejected\"] i {\n color: var(--mj-status-error);\n}\n\n/* Action Buttons */\n.action-buttons {\n display: flex;\n flex-direction: column;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.action-card:hover .action-buttons {\n opacity: 1;\n}\n\n.action-buttons button {\n padding: 6px;\n}\n\n/* Expanded Section */\n.card-expanded {\n padding: 0 20px 20px 20px;\n border-top: 1px solid var(--mj-border-default);\n margin-top: -1px;\n padding-top: 16px;\n background: var(--mj-bg-page);\n}\n\n.stats-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.stats-grid {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 16px;\n}\n\n.stat-item {\n text-align: center;\n padding: 12px 8px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n}\n\n.stat-value {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.stat-value.success {\n color: var(--mj-status-success);\n}\n\n.stat-value.warning {\n color: var(--mj-status-warning);\n}\n\n.stat-value.error {\n color: var(--mj-status-error);\n}\n\n.stat-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Params Preview */\n.params-preview {\n padding: 12px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n}\n\n.params-header {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.params-header i {\n font-size: 12px;\n}\n\n.params-list {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.param-tag {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 4px 10px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 14px;\n font-size: 12px;\n color: var(--mj-text-primary);\n}\n\n.param-tag.required {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.required-marker {\n color: var(--mj-status-error);\n font-weight: 600;\n}\n\n.param-more {\n padding: 4px 10px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .card-main {\n flex-wrap: wrap;\n }\n\n .action-icon {\n width: 40px;\n height: 40px;\n }\n\n .action-icon i {\n font-size: 16px;\n }\n\n .action-header {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .action-buttons {\n flex-direction: row;\n opacity: 1;\n width: 100%;\n justify-content: flex-end;\n }\n\n .stats-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n"] }]
392
+ args: [{ standalone: false, selector: 'mj-action-card', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"action-card\" [class.expanded]=\"IsExpanded\" (click)=\"onCardClick()\">\n <div class=\"card-main\">\n <!-- Icon -->\n <div class=\"action-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Content -->\n <div class=\"action-content\">\n <div class=\"action-header\">\n <h3 class=\"action-name\" [title]=\"Action.Name\">{{ Action.Name }}</h3>\n <div class=\"action-badges\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n @if (Action.Type === 'Generated') {\n <span class=\"status-chip\" data-color=\"info\">\n <i class=\"fa-solid fa-robot\"></i> AI\n </span>\n }\n </div>\n </div>\n\n <p class=\"action-description\" [title]=\"Action.Description || 'No description'\">\n {{ Action.Description || 'No description available' }}\n </p>\n\n <div class=\"action-meta\">\n <button class=\"meta-item category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n @if (Action.__mj_UpdatedAt) {\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n <span>{{ formatDate(Action.__mj_UpdatedAt) }}</span>\n </span>\n }\n\n @if (Action.Type === 'Generated' && Action.CodeApprovalStatus) {\n <span class=\"meta-item\" [attr.data-status]=\"Action.CodeApprovalStatus\">\n <i [class]=\"getApprovalStatusIcon()\"></i>\n <span>{{ Action.CodeApprovalStatus }}</span>\n </span>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"action-buttons\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"View Stats\"\n (click)=\"toggleExpanded($event)\">\n <i [class]=\"IsExpanded ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chart-line'\"></i>\n </button>\n <button mjButton\n variant=\"primary\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n </div>\n\n <!-- Expanded Stats Section -->\n @if (IsExpanded) {\n <div class=\"card-expanded\">\n @if (ExecutionStats.isLoading) {\n <div class=\"stats-loading\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span>Loading execution stats...</span>\n </div>\n } @else {\n <div class=\"stats-grid\">\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ ExecutionStats.totalExecutions }}</div>\n <div class=\"stat-label\">Total Runs</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\" [class.success]=\"ExecutionStats.successRate >= 90\" [class.warning]=\"ExecutionStats.successRate >= 50 && ExecutionStats.successRate < 90\" [class.error]=\"ExecutionStats.successRate < 50\">\n {{ ExecutionStats.successRate }}%\n </div>\n <div class=\"stat-label\">Success Rate</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ formatDate(ExecutionStats.lastExecuted) }}</div>\n <div class=\"stat-label\">Last Run</div>\n </div>\n <div class=\"stat-item params\">\n <div class=\"stat-value\">{{ Action.Params.Items.length || 0 }}</div>\n <div class=\"stat-label\">Parameters</div>\n </div>\n </div>\n\n @if (Action.Params && Action.Params.Items.length > 0) {\n <div class=\"params-preview\">\n <div class=\"params-header\">\n <i class=\"fa-solid fa-sliders\"></i>\n Parameters\n </div>\n <div class=\"params-list\">\n @for (param of Action.Params.Items.slice(0, 4); track param.Name) {\n <span class=\"param-tag\" [class.required]=\"param.IsRequired\">\n {{ param.Name }}\n @if (param.IsRequired) {\n <span class=\"required-marker\">*</span>\n }\n </span>\n }\n @if (Action.Params.Items.length > 4) {\n <span class=\"param-more\">+{{ Action.Params.Items.length - 4 }} more</span>\n }\n </div>\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".action-card {\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n\n.action-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\n.action-card.expanded {\n border-color: var(--mj-brand-primary);\n}\n\n.card-main {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n padding: 20px;\n}\n\n/* Icon */\n.action-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 12px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n flex-shrink: 0;\n}\n\n.action-icon i {\n font-size: 20px;\n color: var(--mj-brand-primary);\n}\n\n.action-icon.ai-generated {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface)), color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)));\n}\n\n.action-icon.ai-generated i {\n background: linear-gradient(135deg, var(--mj-status-info), var(--mj-brand-primary));\n -webkit-background-clip: text;\n -webkit-text-fill-color: transparent;\n background-clip: text;\n}\n\n/* Content */\n.action-content {\n flex: 1;\n min-width: 0;\n}\n\n.action-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 12px;\n margin-bottom: 8px;\n}\n\n.action-name {\n margin: 0;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.action-badges {\n display: flex;\n gap: 6px;\n flex-shrink: 0;\n}\n\n.action-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-muted);\n line-height: 1.5;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.action-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n}\n\n.meta-item {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--mj-text-muted);\n background: none;\n border: none;\n padding: 0;\n cursor: default;\n}\n\n.meta-item.category {\n cursor: pointer;\n padding: 2px 6px;\n border-radius: 4px;\n transition: background 0.15s ease;\n}\n\n.meta-item.category:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-brand-primary);\n}\n\n.meta-item i {\n font-size: 11px;\n color: var(--mj-brand-primary);\n}\n\n.meta-item[data-status=\"Approved\"] i {\n color: var(--mj-status-success);\n}\n\n.meta-item[data-status=\"Pending\"] i {\n color: var(--mj-status-warning);\n}\n\n.meta-item[data-status=\"Rejected\"] i {\n color: var(--mj-status-error);\n}\n\n/* Action Buttons */\n.action-buttons {\n display: flex;\n flex-direction: column;\n gap: 4px;\n opacity: 0;\n transition: opacity 0.2s ease;\n}\n\n.action-card:hover .action-buttons {\n opacity: 1;\n}\n\n.action-buttons button {\n padding: 6px;\n}\n\n/* Expanded Section */\n.card-expanded {\n padding: 0 20px 20px 20px;\n border-top: 1px solid var(--mj-border-default);\n margin-top: -1px;\n padding-top: 16px;\n background: var(--mj-bg-page);\n}\n\n.stats-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 20px;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n.stats-grid {\n display: grid;\n grid-template-columns: repeat(4, 1fr);\n gap: 16px;\n margin-bottom: 16px;\n}\n\n.stat-item {\n text-align: center;\n padding: 12px 8px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n}\n\n.stat-value {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n margin-bottom: 4px;\n}\n\n.stat-value.success {\n color: var(--mj-status-success);\n}\n\n.stat-value.warning {\n color: var(--mj-status-warning);\n}\n\n.stat-value.error {\n color: var(--mj-status-error);\n}\n\n.stat-label {\n font-size: 11px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Params Preview */\n.params-preview {\n padding: 12px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n}\n\n.params-header {\n font-size: 11px;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.params-header i {\n font-size: 12px;\n}\n\n.params-list {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.param-tag {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 4px 10px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 14px;\n font-size: 12px;\n color: var(--mj-text-primary);\n}\n\n.param-tag.required {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.required-marker {\n color: var(--mj-status-error);\n font-weight: 600;\n}\n\n.param-more {\n padding: 4px 10px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* Responsive */\n@media (max-width: 640px) {\n .card-main {\n flex-wrap: wrap;\n }\n\n .action-icon {\n width: 40px;\n height: 40px;\n }\n\n .action-icon i {\n font-size: 16px;\n }\n\n .action-header {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .action-buttons {\n flex-direction: row;\n opacity: 1;\n width: 100%;\n justify-content: flex-end;\n }\n\n .stats-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n"] }]
393
393
  }], () => [{ type: i0.ChangeDetectorRef }], { Action: [{
394
394
  type: Input
395
395
  }], Categories: [{
@@ -1 +1 @@
1
- {"version":3,"file":"action-card.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/action-card.component.ts","../../../../src/Actions/components/explorer/action-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { MJActionCategoryEntity, MJActionExecutionLogEntity } from '@memberjunction/core-entities';\nimport { MJActionEntityExtended } from '@memberjunction/actions-base';\nimport { RunView } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\nexport interface ActionExecutionStats {\n totalExecutions: number;\n successRate: number;\n lastExecuted: Date | null;\n isLoading: boolean;\n isLoaded: boolean;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-action-card',\n templateUrl: './action-card.component.html',\n styleUrls: ['./action-card.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ActionCardComponent extends BaseAngularComponent {\n @Input() Action!: MJActionEntityExtended;\n @Input() Categories: Map<string, MJActionCategoryEntity> = new Map();\n @Output() ActionClick = new EventEmitter<MJActionEntityExtended>();\n @Output() EditClick = new EventEmitter<MJActionEntityExtended>();\n @Output() RunClick = new EventEmitter<MJActionEntityExtended>();\n @Output() CategoryClick = new EventEmitter<string>();\n\n public IsExpanded = false;\n public ExecutionStats: ActionExecutionStats = {\n totalExecutions: 0,\n successRate: 0,\n lastExecuted: null,\n isLoading: false,\n isLoaded: false\n };\n\n constructor(private cdr: ChangeDetectorRef) { super(); }\n\n public onCardClick(): void {\n this.ActionClick.emit(this.Action);\n }\n\n public onEditClick(event: MouseEvent): void {\n event.stopPropagation();\n this.EditClick.emit(this.Action);\n }\n\n public onRunClick(event: MouseEvent): void {\n event.stopPropagation();\n this.RunClick.emit(this.Action);\n }\n\n public onCategoryClick(event: MouseEvent): void {\n event.stopPropagation();\n if (this.Action.CategoryID) {\n this.CategoryClick.emit(this.Action.CategoryID);\n }\n }\n\n public toggleExpanded(event: MouseEvent): void {\n event.stopPropagation();\n this.IsExpanded = !this.IsExpanded;\n\n if (this.IsExpanded && !this.ExecutionStats.isLoaded && !this.ExecutionStats.isLoading) {\n this.loadExecutionStats();\n }\n }\n\n private async loadExecutionStats(): Promise<void> {\n this.ExecutionStats.isLoading = true;\n this.cdr.markForCheck();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n\n // Load both executions and result codes in parallel\n const [executionsResult, resultCodesResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Action Execution Logs',\n ExtraFilter: `ActionID='${this.Action.ID}'`,\n OrderBy: 'StartedAt DESC',\n MaxRows: 100,\n ResultType: 'simple',\n Fields: ['ID', 'ResultCode', 'StartedAt']\n },\n {\n EntityName: 'MJ: Action Result Codes',\n ExtraFilter: `ActionID='${this.Action.ID}'`,\n ResultType: 'simple',\n Fields: ['ResultCode', 'IsSuccess']\n }\n ]);\n\n if (executionsResult.Success && executionsResult.Results) {\n const executions = executionsResult.Results as { ID: string; ResultCode: string; StartedAt: Date }[];\n\n // Build a map of result codes to IsSuccess\n const successMap = new Map<string, boolean>();\n if (resultCodesResult.Success && resultCodesResult.Results) {\n const resultCodes = resultCodesResult.Results as { ResultCode: string; IsSuccess: boolean }[];\n resultCodes.forEach(rc => {\n successMap.set(rc.ResultCode, rc.IsSuccess);\n });\n }\n\n // Count successful executions using result code lookup\n const successful = executions.filter(e => {\n if (!e.ResultCode) return false;\n // Look up the result code in the map\n const isSuccess = successMap.get(e.ResultCode);\n // If result code is defined in the map, use it; otherwise fall back to heuristic\n if (isSuccess !== undefined) {\n return isSuccess;\n }\n // Fallback heuristic for unknown result codes\n const code = e.ResultCode.toLowerCase();\n return code === 'success' || code === 'ok' || code === 'completed';\n }).length;\n\n this.ExecutionStats = {\n totalExecutions: executions.length,\n successRate: executions.length > 0 ? Math.round((successful / executions.length) * 100) : 0,\n lastExecuted: executions.length > 0 ? new Date(executions[0].StartedAt) : null,\n isLoading: false,\n isLoaded: true\n };\n } else {\n this.ExecutionStats.isLoading = false;\n this.ExecutionStats.isLoaded = true;\n }\n } catch (error) {\n console.error('Failed to load execution stats:', error);\n this.ExecutionStats.isLoading = false;\n this.ExecutionStats.isLoaded = true;\n }\n\n this.cdr.markForCheck();\n }\n\n public getCategoryName(): string {\n if (!this.Action.CategoryID) return 'Uncategorized';\n return this.Categories.get(this.Action.CategoryID)?.Name || 'Unknown Category';\n }\n\n public getStatusColor(): 'success' | 'warning' | 'error' | 'info' {\n switch (this.Action.Status) {\n case 'Active': return 'success';\n case 'Pending': return 'warning';\n case 'Disabled': return 'error';\n default: return 'info';\n }\n }\n\n public getActionIcon(): string {\n // Use custom icon if set, otherwise derive from type\n if (this.Action.IconClass) {\n return this.Action.IconClass;\n }\n switch (this.Action.Type) {\n case 'Generated': return 'fa-solid fa-robot';\n case 'Custom': return 'fa-solid fa-code';\n default: return 'fa-solid fa-bolt';\n }\n }\n\n public getTypeLabel(): string {\n return this.Action.Type === 'Generated' ? 'AI Generated' : 'Custom';\n }\n\n public getApprovalStatusIcon(): string {\n switch (this.Action.CodeApprovalStatus) {\n case 'Approved': return 'fa-solid fa-check-circle';\n case 'Pending': return 'fa-solid fa-clock';\n case 'Rejected': return 'fa-solid fa-times-circle';\n default: return 'fa-solid fa-question-circle';\n }\n }\n\n public getApprovalStatusColor(): string {\n switch (this.Action.CodeApprovalStatus) {\n case 'Approved': return 'success';\n case 'Pending': return 'warning';\n case 'Rejected': return 'error';\n default: return 'info';\n }\n }\n\n public formatDate(date: Date | null): string {\n if (!date) return 'Never';\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n if (days < 7) return `${days}d ago`;\n return date.toLocaleDateString();\n }\n}\n","<div class=\"action-card\" [class.expanded]=\"IsExpanded\" (click)=\"onCardClick()\">\n <div class=\"card-main\">\n <!-- Icon -->\n <div class=\"action-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Content -->\n <div class=\"action-content\">\n <div class=\"action-header\">\n <h3 class=\"action-name\" [title]=\"Action.Name\">{{ Action.Name }}</h3>\n <div class=\"action-badges\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n @if (Action.Type === 'Generated') {\n <span class=\"status-chip\" data-color=\"info\">\n <i class=\"fa-solid fa-robot\"></i> AI\n </span>\n }\n </div>\n </div>\n\n <p class=\"action-description\" [title]=\"Action.Description || 'No description'\">\n {{ Action.Description || 'No description available' }}\n </p>\n\n <div class=\"action-meta\">\n <button class=\"meta-item category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n @if (Action.__mj_UpdatedAt) {\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n <span>{{ formatDate(Action.__mj_UpdatedAt) }}</span>\n </span>\n }\n\n @if (Action.Type === 'Generated' && Action.CodeApprovalStatus) {\n <span class=\"meta-item\" [attr.data-status]=\"Action.CodeApprovalStatus\">\n <i [class]=\"getApprovalStatusIcon()\"></i>\n <span>{{ Action.CodeApprovalStatus }}</span>\n </span>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"action-buttons\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"View Stats\"\n (click)=\"toggleExpanded($event)\">\n <i [class]=\"IsExpanded ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chart-line'\"></i>\n </button>\n <button mjButton\n variant=\"primary\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n </div>\n\n <!-- Expanded Stats Section -->\n @if (IsExpanded) {\n <div class=\"card-expanded\">\n @if (ExecutionStats.isLoading) {\n <div class=\"stats-loading\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span>Loading execution stats...</span>\n </div>\n } @else {\n <div class=\"stats-grid\">\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ ExecutionStats.totalExecutions }}</div>\n <div class=\"stat-label\">Total Runs</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\" [class.success]=\"ExecutionStats.successRate >= 90\" [class.warning]=\"ExecutionStats.successRate >= 50 && ExecutionStats.successRate < 90\" [class.error]=\"ExecutionStats.successRate < 50\">\n {{ ExecutionStats.successRate }}%\n </div>\n <div class=\"stat-label\">Success Rate</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ formatDate(ExecutionStats.lastExecuted) }}</div>\n <div class=\"stat-label\">Last Run</div>\n </div>\n <div class=\"stat-item params\">\n <div class=\"stat-value\">{{ Action.Params.length || 0 }}</div>\n <div class=\"stat-label\">Parameters</div>\n </div>\n </div>\n\n @if (Action.Params && Action.Params.length > 0) {\n <div class=\"params-preview\">\n <div class=\"params-header\">\n <i class=\"fa-solid fa-sliders\"></i>\n Parameters\n </div>\n <div class=\"params-list\">\n @for (param of Action.Params.slice(0, 4); track param.Name) {\n <span class=\"param-tag\" [class.required]=\"param.IsRequired\">\n {{ param.Name }}\n @if (param.IsRequired) {\n <span class=\"required-marker\">*</span>\n }\n </span>\n }\n @if (Action.Params.length > 4) {\n <span class=\"param-more\">+{{ Action.Params.length - 4 }} more</span>\n }\n </div>\n </div>\n }\n }\n </div>\n }\n</div>\n"]}
1
+ {"version":3,"file":"action-card.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/action-card.component.ts","../../../../src/Actions/components/explorer/action-card.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ChangeDetectionStrategy,\n ChangeDetectorRef\n} from '@angular/core';\nimport { MJActionCategoryEntity, MJActionExecutionLogEntity } from '@memberjunction/core-entities';\nimport { MJActionEntityExtended } from '@memberjunction/actions-base';\nimport { RunView } from '@memberjunction/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\nexport interface ActionExecutionStats {\n totalExecutions: number;\n successRate: number;\n lastExecuted: Date | null;\n isLoading: boolean;\n isLoaded: boolean;\n}\n\n@Component({\n standalone: false,\n selector: 'mj-action-card',\n templateUrl: './action-card.component.html',\n styleUrls: ['./action-card.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ActionCardComponent extends BaseAngularComponent {\n @Input() Action!: MJActionEntityExtended;\n @Input() Categories: Map<string, MJActionCategoryEntity> = new Map();\n @Output() ActionClick = new EventEmitter<MJActionEntityExtended>();\n @Output() EditClick = new EventEmitter<MJActionEntityExtended>();\n @Output() RunClick = new EventEmitter<MJActionEntityExtended>();\n @Output() CategoryClick = new EventEmitter<string>();\n\n public IsExpanded = false;\n public ExecutionStats: ActionExecutionStats = {\n totalExecutions: 0,\n successRate: 0,\n lastExecuted: null,\n isLoading: false,\n isLoaded: false\n };\n\n constructor(private cdr: ChangeDetectorRef) { super(); }\n\n public onCardClick(): void {\n this.ActionClick.emit(this.Action);\n }\n\n public onEditClick(event: MouseEvent): void {\n event.stopPropagation();\n this.EditClick.emit(this.Action);\n }\n\n public onRunClick(event: MouseEvent): void {\n event.stopPropagation();\n this.RunClick.emit(this.Action);\n }\n\n public onCategoryClick(event: MouseEvent): void {\n event.stopPropagation();\n if (this.Action.CategoryID) {\n this.CategoryClick.emit(this.Action.CategoryID);\n }\n }\n\n public toggleExpanded(event: MouseEvent): void {\n event.stopPropagation();\n this.IsExpanded = !this.IsExpanded;\n\n if (this.IsExpanded && !this.ExecutionStats.isLoaded && !this.ExecutionStats.isLoading) {\n this.loadExecutionStats();\n }\n }\n\n private async loadExecutionStats(): Promise<void> {\n this.ExecutionStats.isLoading = true;\n this.cdr.markForCheck();\n\n try {\n const rv = RunView.FromMetadataProvider(this.ProviderToUse);\n\n // Load both executions and result codes in parallel\n const [executionsResult, resultCodesResult] = await rv.RunViews([\n {\n EntityName: 'MJ: Action Execution Logs',\n ExtraFilter: `ActionID='${this.Action.ID}'`,\n OrderBy: 'StartedAt DESC',\n MaxRows: 100,\n ResultType: 'simple',\n Fields: ['ID', 'ResultCode', 'StartedAt']\n },\n {\n EntityName: 'MJ: Action Result Codes',\n ExtraFilter: `ActionID='${this.Action.ID}'`,\n ResultType: 'simple',\n Fields: ['ResultCode', 'IsSuccess']\n }\n ]);\n\n if (executionsResult.Success && executionsResult.Results) {\n const executions = executionsResult.Results as { ID: string; ResultCode: string; StartedAt: Date }[];\n\n // Build a map of result codes to IsSuccess\n const successMap = new Map<string, boolean>();\n if (resultCodesResult.Success && resultCodesResult.Results) {\n const resultCodes = resultCodesResult.Results as { ResultCode: string; IsSuccess: boolean }[];\n resultCodes.forEach(rc => {\n successMap.set(rc.ResultCode, rc.IsSuccess);\n });\n }\n\n // Count successful executions using result code lookup\n const successful = executions.filter(e => {\n if (!e.ResultCode) return false;\n // Look up the result code in the map\n const isSuccess = successMap.get(e.ResultCode);\n // If result code is defined in the map, use it; otherwise fall back to heuristic\n if (isSuccess !== undefined) {\n return isSuccess;\n }\n // Fallback heuristic for unknown result codes\n const code = e.ResultCode.toLowerCase();\n return code === 'success' || code === 'ok' || code === 'completed';\n }).length;\n\n this.ExecutionStats = {\n totalExecutions: executions.length,\n successRate: executions.length > 0 ? Math.round((successful / executions.length) * 100) : 0,\n lastExecuted: executions.length > 0 ? new Date(executions[0].StartedAt) : null,\n isLoading: false,\n isLoaded: true\n };\n } else {\n this.ExecutionStats.isLoading = false;\n this.ExecutionStats.isLoaded = true;\n }\n } catch (error) {\n console.error('Failed to load execution stats:', error);\n this.ExecutionStats.isLoading = false;\n this.ExecutionStats.isLoaded = true;\n }\n\n this.cdr.markForCheck();\n }\n\n public getCategoryName(): string {\n if (!this.Action.CategoryID) return 'Uncategorized';\n return this.Categories.get(this.Action.CategoryID)?.Name || 'Unknown Category';\n }\n\n public getStatusColor(): 'success' | 'warning' | 'error' | 'info' {\n switch (this.Action.Status) {\n case 'Active': return 'success';\n case 'Pending': return 'warning';\n case 'Disabled': return 'error';\n default: return 'info';\n }\n }\n\n public getActionIcon(): string {\n // Use custom icon if set, otherwise derive from type\n if (this.Action.IconClass) {\n return this.Action.IconClass;\n }\n switch (this.Action.Type) {\n case 'Generated': return 'fa-solid fa-robot';\n case 'Custom': return 'fa-solid fa-code';\n default: return 'fa-solid fa-bolt';\n }\n }\n\n public getTypeLabel(): string {\n return this.Action.Type === 'Generated' ? 'AI Generated' : 'Custom';\n }\n\n public getApprovalStatusIcon(): string {\n switch (this.Action.CodeApprovalStatus) {\n case 'Approved': return 'fa-solid fa-check-circle';\n case 'Pending': return 'fa-solid fa-clock';\n case 'Rejected': return 'fa-solid fa-times-circle';\n default: return 'fa-solid fa-question-circle';\n }\n }\n\n public getApprovalStatusColor(): string {\n switch (this.Action.CodeApprovalStatus) {\n case 'Approved': return 'success';\n case 'Pending': return 'warning';\n case 'Rejected': return 'error';\n default: return 'info';\n }\n }\n\n public formatDate(date: Date | null): string {\n if (!date) return 'Never';\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n if (days < 7) return `${days}d ago`;\n return date.toLocaleDateString();\n }\n}\n","<div class=\"action-card\" [class.expanded]=\"IsExpanded\" (click)=\"onCardClick()\">\n <div class=\"card-main\">\n <!-- Icon -->\n <div class=\"action-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Content -->\n <div class=\"action-content\">\n <div class=\"action-header\">\n <h3 class=\"action-name\" [title]=\"Action.Name\">{{ Action.Name }}</h3>\n <div class=\"action-badges\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n @if (Action.Type === 'Generated') {\n <span class=\"status-chip\" data-color=\"info\">\n <i class=\"fa-solid fa-robot\"></i> AI\n </span>\n }\n </div>\n </div>\n\n <p class=\"action-description\" [title]=\"Action.Description || 'No description'\">\n {{ Action.Description || 'No description available' }}\n </p>\n\n <div class=\"action-meta\">\n <button class=\"meta-item category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n @if (Action.__mj_UpdatedAt) {\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n <span>{{ formatDate(Action.__mj_UpdatedAt) }}</span>\n </span>\n }\n\n @if (Action.Type === 'Generated' && Action.CodeApprovalStatus) {\n <span class=\"meta-item\" [attr.data-status]=\"Action.CodeApprovalStatus\">\n <i [class]=\"getApprovalStatusIcon()\"></i>\n <span>{{ Action.CodeApprovalStatus }}</span>\n </span>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"action-buttons\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"View Stats\"\n (click)=\"toggleExpanded($event)\">\n <i [class]=\"IsExpanded ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chart-line'\"></i>\n </button>\n <button mjButton\n variant=\"primary\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n </div>\n\n <!-- Expanded Stats Section -->\n @if (IsExpanded) {\n <div class=\"card-expanded\">\n @if (ExecutionStats.isLoading) {\n <div class=\"stats-loading\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span>Loading execution stats...</span>\n </div>\n } @else {\n <div class=\"stats-grid\">\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ ExecutionStats.totalExecutions }}</div>\n <div class=\"stat-label\">Total Runs</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\" [class.success]=\"ExecutionStats.successRate >= 90\" [class.warning]=\"ExecutionStats.successRate >= 50 && ExecutionStats.successRate < 90\" [class.error]=\"ExecutionStats.successRate < 50\">\n {{ ExecutionStats.successRate }}%\n </div>\n <div class=\"stat-label\">Success Rate</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ formatDate(ExecutionStats.lastExecuted) }}</div>\n <div class=\"stat-label\">Last Run</div>\n </div>\n <div class=\"stat-item params\">\n <div class=\"stat-value\">{{ Action.Params.Items.length || 0 }}</div>\n <div class=\"stat-label\">Parameters</div>\n </div>\n </div>\n\n @if (Action.Params && Action.Params.Items.length > 0) {\n <div class=\"params-preview\">\n <div class=\"params-header\">\n <i class=\"fa-solid fa-sliders\"></i>\n Parameters\n </div>\n <div class=\"params-list\">\n @for (param of Action.Params.Items.slice(0, 4); track param.Name) {\n <span class=\"param-tag\" [class.required]=\"param.IsRequired\">\n {{ param.Name }}\n @if (param.IsRequired) {\n <span class=\"required-marker\">*</span>\n }\n </span>\n }\n @if (Action.Params.Items.length > 4) {\n <span class=\"param-more\">+{{ Action.Params.Items.length - 4 }} more</span>\n }\n </div>\n </div>\n }\n }\n </div>\n }\n</div>\n"]}
@@ -46,9 +46,9 @@ function ActionListItemComponent_Conditional_17_Template(rf, ctx) { if (rf & 1)
46
46
  i0.ɵɵelementEnd()();
47
47
  } if (rf & 2) {
48
48
  const ctx_r0 = i0.ɵɵnextContext();
49
- i0.ɵɵproperty("title", (ctx_r0.Action.Params.length || 0) + " parameters");
49
+ i0.ɵɵproperty("title", (ctx_r0.Action.Params.Items.length || 0) + " parameters");
50
50
  i0.ɵɵadvance(3);
51
- i0.ɵɵtextInterpolate(ctx_r0.Action.Params.length || 0);
51
+ i0.ɵɵtextInterpolate(ctx_r0.Action.Params.Items.length || 0);
52
52
  } }
53
53
  export class ActionListItemComponent {
54
54
  Action;
@@ -188,7 +188,7 @@ export class ActionListItemComponent {
188
188
  }
189
189
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ActionListItemComponent, [{
190
190
  type: Component,
191
- args: [{ standalone: false, selector: 'mj-action-list-item', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"action-list-item\" [class.compact]=\"IsCompact\" (click)=\"onRowClick()\">\n <!-- Icon -->\n <div class=\"item-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Name & Description -->\n <div class=\"item-main\">\n <span class=\"item-name\" [title]=\"Action.Name\">{{ Action.Name }}</span>\n @if (!IsCompact && Action.Description) {\n <span class=\"item-description\" [title]=\"Action.Description\">{{ Action.Description }}</span>\n }\n </div>\n\n <!-- Category -->\n <button class=\"item-category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n <!-- Status -->\n <div class=\"item-status\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n </div>\n\n <!-- Type -->\n <div class=\"item-type\">\n @if (Action.Type === 'Generated') {\n <span class=\"type-badge ai\">\n <i class=\"fa-solid fa-robot\"></i>\n @if (!IsCompact) {\n AI\n }\n </span>\n } @else {\n <span class=\"type-badge custom\">\n <i class=\"fa-solid fa-code\"></i>\n @if (!IsCompact) {\n Custom\n }\n </span>\n }\n </div>\n\n <!-- Params Count -->\n @if (!IsCompact) {\n <div class=\"item-params\" [title]=\"(Action.Params.length || 0) + ' parameters'\">\n <i class=\"fa-solid fa-sliders\"></i>\n <span>{{ Action.Params.length || 0 }}</span>\n </div>\n }\n\n <!-- Updated -->\n <div class=\"item-updated\" [title]=\"Action.__mj_UpdatedAt | date:'full'\">\n {{ formatDate(Action.__mj_UpdatedAt) }}\n </div>\n\n <!-- Actions -->\n <div class=\"item-actions\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n</div>\n", styles: [".action-list-item {\n display: grid;\n grid-template-columns: 40px 1fr 140px 90px 70px 50px 90px 70px;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.action-list-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.action-list-item.compact {\n grid-template-columns: 32px 1fr 120px 80px 50px 80px 60px;\n padding: 8px 16px;\n gap: 8px;\n}\n\n/* Icon */\n.item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.compact .item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n}\n\n.item-icon i {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n\n.compact .item-icon i {\n font-size: 12px;\n}\n\n.item-icon.ai-generated {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface)), color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)));\n}\n\n/* Main */\n.item-main {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.item-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.compact .item-name {\n font-size: 13px;\n}\n\n.item-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Category */\n.item-category {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border: none;\n background: transparent;\n border-radius: 4px;\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.item-category:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-brand-primary);\n}\n\n.item-category i {\n font-size: 11px;\n color: var(--mj-status-warning);\n flex-shrink: 0;\n}\n\n.item-category span {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Status */\n.item-status {\n display: flex;\n justify-content: flex-start;\n}\n\n/* Type */\n.item-type {\n display: flex;\n justify-content: flex-start;\n}\n\n.type-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.type-badge.ai {\n background: color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.type-badge.custom {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.type-badge i {\n font-size: 10px;\n}\n\n/* Params */\n.item-params {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.item-params i {\n font-size: 11px;\n}\n\n/* Updated */\n.item-updated {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n/* Actions */\n.item-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.action-list-item:hover .item-actions {\n opacity: 1;\n}\n\n.item-actions button {\n padding: 4px;\n}\n\n.item-actions button i {\n font-size: 12px;\n}\n\n/* Responsive */\n@media (max-width: 1024px) {\n .action-list-item {\n grid-template-columns: 36px 1fr 90px 50px 80px 60px;\n }\n\n .action-list-item .item-category,\n .action-list-item .item-params {\n display: none;\n }\n}\n\n@media (max-width: 768px) {\n .action-list-item {\n grid-template-columns: 32px 1fr 70px 70px;\n }\n\n .action-list-item .item-type,\n .action-list-item .item-updated {\n display: none;\n }\n\n .item-actions {\n opacity: 1;\n }\n}\n"] }]
191
+ args: [{ standalone: false, selector: 'mj-action-list-item', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"action-list-item\" [class.compact]=\"IsCompact\" (click)=\"onRowClick()\">\n <!-- Icon -->\n <div class=\"item-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Name & Description -->\n <div class=\"item-main\">\n <span class=\"item-name\" [title]=\"Action.Name\">{{ Action.Name }}</span>\n @if (!IsCompact && Action.Description) {\n <span class=\"item-description\" [title]=\"Action.Description\">{{ Action.Description }}</span>\n }\n </div>\n\n <!-- Category -->\n <button class=\"item-category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n <!-- Status -->\n <div class=\"item-status\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n </div>\n\n <!-- Type -->\n <div class=\"item-type\">\n @if (Action.Type === 'Generated') {\n <span class=\"type-badge ai\">\n <i class=\"fa-solid fa-robot\"></i>\n @if (!IsCompact) {\n AI\n }\n </span>\n } @else {\n <span class=\"type-badge custom\">\n <i class=\"fa-solid fa-code\"></i>\n @if (!IsCompact) {\n Custom\n }\n </span>\n }\n </div>\n\n <!-- Params Count -->\n @if (!IsCompact) {\n <div class=\"item-params\" [title]=\"(Action.Params.Items.length || 0) + ' parameters'\">\n <i class=\"fa-solid fa-sliders\"></i>\n <span>{{ Action.Params.Items.length || 0 }}</span>\n </div>\n }\n\n <!-- Updated -->\n <div class=\"item-updated\" [title]=\"Action.__mj_UpdatedAt | date:'full'\">\n {{ formatDate(Action.__mj_UpdatedAt) }}\n </div>\n\n <!-- Actions -->\n <div class=\"item-actions\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n</div>\n", styles: [".action-list-item {\n display: grid;\n grid-template-columns: 40px 1fr 140px 90px 70px 50px 90px 70px;\n align-items: center;\n gap: 12px;\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-bottom: 1px solid var(--mj-border-default);\n cursor: pointer;\n transition: background 0.15s ease;\n}\n\n.action-list-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.action-list-item.compact {\n grid-template-columns: 32px 1fr 120px 80px 50px 80px 60px;\n padding: 8px 16px;\n gap: 8px;\n}\n\n/* Icon */\n.item-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border-radius: 8px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.compact .item-icon {\n width: 28px;\n height: 28px;\n border-radius: 6px;\n}\n\n.item-icon i {\n font-size: 14px;\n color: var(--mj-brand-primary);\n}\n\n.compact .item-icon i {\n font-size: 12px;\n}\n\n.item-icon.ai-generated {\n background: linear-gradient(135deg, color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface)), color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface)));\n}\n\n/* Main */\n.item-main {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.item-name {\n font-size: 14px;\n font-weight: 600;\n color: var(--mj-text-primary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.compact .item-name {\n font-size: 13px;\n}\n\n.item-description {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Category */\n.item-category {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n border: none;\n background: transparent;\n border-radius: 4px;\n font-size: 12px;\n color: var(--mj-text-muted);\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.item-category:hover {\n background: var(--mj-bg-surface-active);\n color: var(--mj-brand-primary);\n}\n\n.item-category i {\n font-size: 11px;\n color: var(--mj-status-warning);\n flex-shrink: 0;\n}\n\n.item-category span {\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Status */\n.item-status {\n display: flex;\n justify-content: flex-start;\n}\n\n/* Type */\n.item-type {\n display: flex;\n justify-content: flex-start;\n}\n\n.type-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 11px;\n padding: 2px 8px;\n border-radius: 10px;\n}\n\n.type-badge.ai {\n background: color-mix(in srgb, var(--mj-status-info) 10%, var(--mj-bg-surface));\n color: var(--mj-status-info);\n}\n\n.type-badge.custom {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n.type-badge i {\n font-size: 10px;\n}\n\n/* Params */\n.item-params {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.item-params i {\n font-size: 11px;\n}\n\n/* Updated */\n.item-updated {\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n}\n\n/* Actions */\n.item-actions {\n display: flex;\n gap: 2px;\n opacity: 0;\n transition: opacity 0.15s ease;\n}\n\n.action-list-item:hover .item-actions {\n opacity: 1;\n}\n\n.item-actions button {\n padding: 4px;\n}\n\n.item-actions button i {\n font-size: 12px;\n}\n\n/* Responsive */\n@media (max-width: 1024px) {\n .action-list-item {\n grid-template-columns: 36px 1fr 90px 50px 80px 60px;\n }\n\n .action-list-item .item-category,\n .action-list-item .item-params {\n display: none;\n }\n}\n\n@media (max-width: 768px) {\n .action-list-item {\n grid-template-columns: 32px 1fr 70px 70px;\n }\n\n .action-list-item .item-type,\n .action-list-item .item-updated {\n display: none;\n }\n\n .item-actions {\n opacity: 1;\n }\n}\n"] }]
192
192
  }], null, { Action: [{
193
193
  type: Input
194
194
  }], Categories: [{
@@ -1 +1 @@
1
- {"version":3,"file":"action-list-item.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/action-list-item.component.ts","../../../../src/Actions/components/explorer/action-list-item.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { MJActionCategoryEntity } from '@memberjunction/core-entities';\nimport { MJActionEntityExtended } from '@memberjunction/actions-base';\n\n@Component({\n standalone: false,\n selector: 'mj-action-list-item',\n templateUrl: './action-list-item.component.html',\n styleUrls: ['./action-list-item.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ActionListItemComponent {\n @Input() Action!: MJActionEntityExtended;\n @Input() Categories: Map<string, MJActionCategoryEntity> = new Map();\n @Input() IsCompact = false;\n @Output() ActionClick = new EventEmitter<MJActionEntityExtended>();\n @Output() EditClick = new EventEmitter<MJActionEntityExtended>();\n @Output() RunClick = new EventEmitter<MJActionEntityExtended>();\n @Output() CategoryClick = new EventEmitter<string>();\n\n public onRowClick(): void {\n this.ActionClick.emit(this.Action);\n }\n\n public onEditClick(event: MouseEvent): void {\n event.stopPropagation();\n this.EditClick.emit(this.Action);\n }\n\n public onRunClick(event: MouseEvent): void {\n event.stopPropagation();\n this.RunClick.emit(this.Action);\n }\n\n public onCategoryClick(event: MouseEvent): void {\n event.stopPropagation();\n if (this.Action.CategoryID) {\n this.CategoryClick.emit(this.Action.CategoryID);\n }\n }\n\n public getCategoryName(): string {\n if (!this.Action.CategoryID) return 'Uncategorized';\n return this.Categories.get(this.Action.CategoryID)?.Name || 'Unknown';\n }\n\n public getStatusColor(): 'success' | 'warning' | 'error' | 'info' {\n switch (this.Action.Status) {\n case 'Active': return 'success';\n case 'Pending': return 'warning';\n case 'Disabled': return 'error';\n default: return 'info';\n }\n }\n\n public getActionIcon(): string {\n if (this.Action.IconClass) {\n return this.Action.IconClass;\n }\n switch (this.Action.Type) {\n case 'Generated': return 'fa-solid fa-robot';\n case 'Custom': return 'fa-solid fa-code';\n default: return 'fa-solid fa-bolt';\n }\n }\n\n public formatDate(date: Date | null | undefined): string {\n if (!date) return '-';\n const now = new Date();\n const d = new Date(date);\n const diff = now.getTime() - d.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n if (days < 7) return `${days}d ago`;\n return d.toLocaleDateString();\n }\n}\n","<div class=\"action-list-item\" [class.compact]=\"IsCompact\" (click)=\"onRowClick()\">\n <!-- Icon -->\n <div class=\"item-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Name & Description -->\n <div class=\"item-main\">\n <span class=\"item-name\" [title]=\"Action.Name\">{{ Action.Name }}</span>\n @if (!IsCompact && Action.Description) {\n <span class=\"item-description\" [title]=\"Action.Description\">{{ Action.Description }}</span>\n }\n </div>\n\n <!-- Category -->\n <button class=\"item-category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n <!-- Status -->\n <div class=\"item-status\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n </div>\n\n <!-- Type -->\n <div class=\"item-type\">\n @if (Action.Type === 'Generated') {\n <span class=\"type-badge ai\">\n <i class=\"fa-solid fa-robot\"></i>\n @if (!IsCompact) {\n AI\n }\n </span>\n } @else {\n <span class=\"type-badge custom\">\n <i class=\"fa-solid fa-code\"></i>\n @if (!IsCompact) {\n Custom\n }\n </span>\n }\n </div>\n\n <!-- Params Count -->\n @if (!IsCompact) {\n <div class=\"item-params\" [title]=\"(Action.Params.length || 0) + ' parameters'\">\n <i class=\"fa-solid fa-sliders\"></i>\n <span>{{ Action.Params.length || 0 }}</span>\n </div>\n }\n\n <!-- Updated -->\n <div class=\"item-updated\" [title]=\"Action.__mj_UpdatedAt | date:'full'\">\n {{ formatDate(Action.__mj_UpdatedAt) }}\n </div>\n\n <!-- Actions -->\n <div class=\"item-actions\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n</div>\n"]}
1
+ {"version":3,"file":"action-list-item.component.js","sourceRoot":"","sources":["../../../../src/Actions/components/explorer/action-list-item.component.ts","../../../../src/Actions/components/explorer/action-list-item.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n ChangeDetectionStrategy\n} from '@angular/core';\nimport { MJActionCategoryEntity } from '@memberjunction/core-entities';\nimport { MJActionEntityExtended } from '@memberjunction/actions-base';\n\n@Component({\n standalone: false,\n selector: 'mj-action-list-item',\n templateUrl: './action-list-item.component.html',\n styleUrls: ['./action-list-item.component.css'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ActionListItemComponent {\n @Input() Action!: MJActionEntityExtended;\n @Input() Categories: Map<string, MJActionCategoryEntity> = new Map();\n @Input() IsCompact = false;\n @Output() ActionClick = new EventEmitter<MJActionEntityExtended>();\n @Output() EditClick = new EventEmitter<MJActionEntityExtended>();\n @Output() RunClick = new EventEmitter<MJActionEntityExtended>();\n @Output() CategoryClick = new EventEmitter<string>();\n\n public onRowClick(): void {\n this.ActionClick.emit(this.Action);\n }\n\n public onEditClick(event: MouseEvent): void {\n event.stopPropagation();\n this.EditClick.emit(this.Action);\n }\n\n public onRunClick(event: MouseEvent): void {\n event.stopPropagation();\n this.RunClick.emit(this.Action);\n }\n\n public onCategoryClick(event: MouseEvent): void {\n event.stopPropagation();\n if (this.Action.CategoryID) {\n this.CategoryClick.emit(this.Action.CategoryID);\n }\n }\n\n public getCategoryName(): string {\n if (!this.Action.CategoryID) return 'Uncategorized';\n return this.Categories.get(this.Action.CategoryID)?.Name || 'Unknown';\n }\n\n public getStatusColor(): 'success' | 'warning' | 'error' | 'info' {\n switch (this.Action.Status) {\n case 'Active': return 'success';\n case 'Pending': return 'warning';\n case 'Disabled': return 'error';\n default: return 'info';\n }\n }\n\n public getActionIcon(): string {\n if (this.Action.IconClass) {\n return this.Action.IconClass;\n }\n switch (this.Action.Type) {\n case 'Generated': return 'fa-solid fa-robot';\n case 'Custom': return 'fa-solid fa-code';\n default: return 'fa-solid fa-bolt';\n }\n }\n\n public formatDate(date: Date | null | undefined): string {\n if (!date) return '-';\n const now = new Date();\n const d = new Date(date);\n const diff = now.getTime() - d.getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return 'Just now';\n if (minutes < 60) return `${minutes}m ago`;\n if (hours < 24) return `${hours}h ago`;\n if (days < 7) return `${days}d ago`;\n return d.toLocaleDateString();\n }\n}\n","<div class=\"action-list-item\" [class.compact]=\"IsCompact\" (click)=\"onRowClick()\">\n <!-- Icon -->\n <div class=\"item-icon\" [class.ai-generated]=\"Action.Type === 'Generated'\">\n <i [class]=\"getActionIcon()\"></i>\n </div>\n\n <!-- Name & Description -->\n <div class=\"item-main\">\n <span class=\"item-name\" [title]=\"Action.Name\">{{ Action.Name }}</span>\n @if (!IsCompact && Action.Description) {\n <span class=\"item-description\" [title]=\"Action.Description\">{{ Action.Description }}</span>\n }\n </div>\n\n <!-- Category -->\n <button class=\"item-category\" (click)=\"onCategoryClick($event)\" [title]=\"'View category: ' + getCategoryName()\">\n <i class=\"fa-solid fa-folder\"></i>\n <span>{{ getCategoryName() }}</span>\n </button>\n\n <!-- Status -->\n <div class=\"item-status\">\n <span class=\"status-chip\" [attr.data-color]=\"getStatusColor()\">\n {{ Action.Status }}\n </span>\n </div>\n\n <!-- Type -->\n <div class=\"item-type\">\n @if (Action.Type === 'Generated') {\n <span class=\"type-badge ai\">\n <i class=\"fa-solid fa-robot\"></i>\n @if (!IsCompact) {\n AI\n }\n </span>\n } @else {\n <span class=\"type-badge custom\">\n <i class=\"fa-solid fa-code\"></i>\n @if (!IsCompact) {\n Custom\n }\n </span>\n }\n </div>\n\n <!-- Params Count -->\n @if (!IsCompact) {\n <div class=\"item-params\" [title]=\"(Action.Params.Items.length || 0) + ' parameters'\">\n <i class=\"fa-solid fa-sliders\"></i>\n <span>{{ Action.Params.Items.length || 0 }}</span>\n </div>\n }\n\n <!-- Updated -->\n <div class=\"item-updated\" [title]=\"Action.__mj_UpdatedAt | date:'full'\">\n {{ formatDate(Action.__mj_UpdatedAt) }}\n </div>\n\n <!-- Actions -->\n <div class=\"item-actions\">\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Run Action\"\n [disabled]=\"Action.Status !== 'Active'\"\n (click)=\"onRunClick($event)\">\n <i class=\"fa-solid fa-play\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n title=\"Edit Action\"\n (click)=\"onEditClick($event)\">\n <i class=\"fa-solid fa-pen\"></i>\n </button>\n </div>\n</div>\n"]}
@@ -1,6 +1,5 @@
1
1
  export * from './components/actions-overview.component';
2
2
  export * from './components/execution-monitoring.component';
3
- export * from './components/scheduled-actions.component';
4
3
  export * from './components/code-management.component';
5
4
  export * from './components/entity-integration.component';
6
5
  export * from './components/security-permissions.component';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Actions/index.ts"],"names":[],"mappings":"AACA,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6CAA6C,CAAC;AAG5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,6CAA6C,CAAC;AAG5D,cAAc,uBAAuB,CAAC;AAGtC,cAAc,0CAA0C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Actions/index.ts"],"names":[],"mappings":"AACA,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,wCAAwC,CAAC;AACvD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6CAA6C,CAAC;AAG5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,6CAA6C,CAAC;AAG5D,cAAc,uBAAuB,CAAC;AAGtC,cAAc,0CAA0C,CAAC"}
@@ -1,7 +1,6 @@
1
1
  // Actions Resource Components (BaseResourceComponent-based)
2
2
  export * from './components/actions-overview.component';
3
3
  export * from './components/execution-monitoring.component';
4
- export * from './components/scheduled-actions.component';
5
4
  export * from './components/code-management.component';
6
5
  export * from './components/entity-integration.component';
7
6
  export * from './components/security-permissions.component';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Actions/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,wCAAwC,CAAC;AACvD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6CAA6C,CAAC;AAE5D,uBAAuB;AACvB,cAAc,0CAA0C,CAAC;AACzD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,6CAA6C,CAAC;AAE5D,mDAAmD;AACnD,cAAc,uBAAuB,CAAC;AAEtC,WAAW;AACX,cAAc,0CAA0C,CAAC","sourcesContent":["// Actions Resource Components (BaseResourceComponent-based)\nexport * from './components/actions-overview.component';\nexport * from './components/execution-monitoring.component';\nexport * from './components/scheduled-actions.component';\nexport * from './components/code-management.component';\nexport * from './components/entity-integration.component';\nexport * from './components/security-permissions.component';\n\n// List view components\nexport * from './components/actions-list-view.component';\nexport * from './components/executions-list-view.component';\nexport * from './components/categories-list-view.component';\n\n// Action Explorer (Windows Explorer-style browser)\nexport * from './components/explorer';\n\n// Services\nexport * from './services/action-explorer-state.service';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/Actions/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,cAAc,yCAAyC,CAAC;AACxD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,wCAAwC,CAAC;AACvD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,6CAA6C,CAAC;AAE5D,uBAAuB;AACvB,cAAc,0CAA0C,CAAC;AACzD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,6CAA6C,CAAC;AAE5D,mDAAmD;AACnD,cAAc,uBAAuB,CAAC;AAEtC,WAAW;AACX,cAAc,0CAA0C,CAAC","sourcesContent":["// Actions Resource Components (BaseResourceComponent-based)\nexport * from './components/actions-overview.component';\nexport * from './components/execution-monitoring.component';\nexport * from './components/code-management.component';\nexport * from './components/entity-integration.component';\nexport * from './components/security-permissions.component';\n\n// List view components\nexport * from './components/actions-list-view.component';\nexport * from './components/executions-list-view.component';\nexport * from './components/categories-list-view.component';\n\n// Action Explorer (Windows Explorer-style browser)\nexport * from './components/explorer';\n\n// Services\nexport * from './services/action-explorer-state.service';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"admin-dev-tools-resource.component.d.ts","sourceRoot":"","sources":["../../src/Admin/admin-dev-tools-resource.component.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;;AAE7F;;GAEG;AACH,qBAOa,8BAA+B,SAAQ,2BAA2B;IAC3E,SAAgB,cAAc,qBAAqB;IACnD,SAAgB,aAAa,oCAAoC;IACjE,SAAgB,iBAAiB,oDAAoD;IAErF,SAAgB,QAAQ,EAAE,YAAY,EAAE,CAkDtC;yCAvDO,8BAA8B;2CAA9B,8BAA8B;CAwD1C"}
1
+ {"version":3,"file":"admin-dev-tools-resource.component.d.ts","sourceRoot":"","sources":["../../src/Admin/admin-dev-tools-resource.component.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;;AAE7F;;GAEG;AACH,qBAOa,8BAA+B,SAAQ,2BAA2B;IAC3E,SAAgB,cAAc,qBAAqB;IACnD,SAAgB,aAAa,oCAAoC;IACjE,SAAgB,iBAAiB,oDAAoD;IAErF,SAAgB,QAAQ,EAAE,YAAY,EAAE,CAgEtC;yCArEO,8BAA8B;2CAA9B,8BAA8B;CAsE1C"}
@@ -66,6 +66,20 @@ let AdminDevToolsResourceComponent = class AdminDevToolsResourceComponent extend
66
66
  icon: 'fa-solid fa-table-columns',
67
67
  description: 'Workspace + Golden Layout config',
68
68
  source: { kind: 'resource', driverClass: 'LayoutInspector' }
69
+ },
70
+ {
71
+ id: 'grid-width-lab',
72
+ label: 'Grid Width Lab',
73
+ icon: 'fa-solid fa-arrows-left-right-to-line',
74
+ description: 'entity-data-grid width + column contract',
75
+ source: { kind: 'resource', driverClass: 'GridWidthLabInspector' }
76
+ },
77
+ {
78
+ id: 'tab-strip-lab',
79
+ label: 'Tab Strip Lab',
80
+ icon: 'fa-solid fa-folder-tree',
81
+ description: 'Both tab strips, one shared look',
82
+ source: { kind: 'resource', driverClass: 'TabStripLabInspector' }
69
83
  }
70
84
  ];
71
85
  static ɵfac = /*@__PURE__*/ (() => { let ɵAdminDevToolsResourceComponent_BaseFactory; return function AdminDevToolsResourceComponent_Factory(__ngFactoryType__) { return (ɵAdminDevToolsResourceComponent_BaseFactory || (ɵAdminDevToolsResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(AdminDevToolsResourceComponent)))(__ngFactoryType__ || AdminDevToolsResourceComponent); }; })();
@@ -1 +1 @@
1
- {"version":3,"file":"admin-dev-tools-resource.component.js","sourceRoot":"","sources":["../../src/Admin/admin-dev-tools-resource.component.ts","../../src/Admin/admin-container.component.html"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAgB,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;;;AAE7F;;GAEG;AAQI,IAAM,8BAA8B,GAApC,MAAM,8BAA+B,SAAQ,2BAA2B;IAC3D,cAAc,GAAG,iBAAiB,CAAC;IACnC,aAAa,GAAG,gCAAgC,CAAC;IACjD,iBAAiB,GAAG,gDAAgD,CAAC;IAErE,QAAQ,GAAmB;QACvC;YACI,EAAE,EAAE,SAAS;YACb,KAAK,EAAE,iBAAiB;YACxB,IAAI,EAAE,kBAAkB;YACxB,WAAW,EAAE,6BAA6B;YAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,yBAAyB,EAAE;SACvE;QACD;YACI,EAAE,EAAE,QAAQ;YACZ,KAAK,EAAE,eAAe;YACtB,IAAI,EAAE,kBAAkB;YACxB,WAAW,EAAE,wBAAwB;YACrC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,uBAAuB,EAAE;SACrE;QACD;YACI,EAAE,EAAE,SAAS;YACb,KAAK,EAAE,gBAAgB;YACvB,IAAI,EAAE,mBAAmB;YACzB,WAAW,EAAE,4BAA4B;YACzC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,wBAAwB,EAAE;SACtE;QACD;YACI,EAAE,EAAE,MAAM;YACV,KAAK,EAAE,cAAc;YACrB,IAAI,EAAE,0BAA0B;YAChC,WAAW,EAAE,yBAAyB;YACtC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,2BAA2B,EAAE;SACzE;QACD;YACI,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,mBAAmB;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,WAAW,EAAE,4BAA4B;YACzC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,2BAA2B,EAAE;SACzE;QACD;YACI,EAAE,EAAE,WAAW;YACf,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE,oCAAoC;YAC1C,WAAW,EAAE,uCAAuC;YACpD,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,mBAAmB,EAAE;SACjE;QACD;YACI,EAAE,EAAE,QAAQ;YACZ,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,2BAA2B;YACjC,WAAW,EAAE,kCAAkC;YAC/C,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE;SAC/D;KACJ,CAAC;qSAvDO,8BAA8B,yBAA9B,8BAA8B;6DAA9B,8BAA8B;;YCf3C,sCAAgB;YACZ,oCAIiB;YAGb,AADJ,uCAA8D,qBAKb;YAAzC,wKAAe,4BAAwB,KAAC;YAC5C,iBAAc;YACd,8CAA+D;YAC3D,iCAA0C;YAGtD,AADI,AADI,iBAAsB,EACX,EACF;;YAhBT,cAAwB;YAExB,AADA,AADA,0CAAwB,2BACF,mCACQ;YAGpB,cAAa;YAAC,AAAd,2BAAa,kBAAkB;YAGrC,cAAwB;YACxB,AADA,0CAAwB,+BACE;YAGT,cAAqB;YAAC,AAAtB,uCAAqB,wBAAoB;;;ADCzD,8BAA8B;IAP1C,aAAa,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;GAO/C,8BAA8B,CAwD1C;;iFAxDY,8BAA8B;cAN1C,SAAS;6BACM,KAAK,YACP,6BAA6B;;kFAI9B,8BAA8B","sourcesContent":["import { Component } from '@angular/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RegisterClass } from '@memberjunction/global';\nimport { AdminSection, BaseAdminContainerComponent } from './base-admin-container.component';\n\n/**\n * Admin → Developer Tools. Diagnostic and inspection sub-tools for developers.\n */\n@RegisterClass(BaseResourceComponent, 'AdminDeveloperTools')\n@Component({\n standalone: false,\n selector: 'mj-admin-dev-tools-resource',\n templateUrl: './admin-container.component.html',\n styleUrls: ['./admin-container.component.css']\n})\nexport class AdminDevToolsResourceComponent extends BaseAdminContainerComponent {\n public readonly ContainerTitle = 'Developer Tools';\n public readonly ContainerIcon = 'fa-solid fa-screwdriver-wrench';\n public readonly ContainerSubtitle = 'Diagnostic and inspection tools for developers';\n\n public readonly Sections: AdminSection[] = [\n {\n id: 'graphql',\n label: 'GraphQL Console',\n icon: 'fa-solid fa-code',\n description: 'Run queries against the API',\n source: { kind: 'resource', driverClass: 'GraphQLConsoleInspector' }\n },\n {\n id: 'events',\n label: 'Event Monitor',\n icon: 'fa-solid fa-bolt',\n description: 'Live tail of MJ events',\n source: { kind: 'resource', driverClass: 'EventMonitorInspector' }\n },\n {\n id: 'classes',\n label: 'Class Registry',\n icon: 'fa-solid fa-cubes',\n description: 'All @RegisterClass entries',\n source: { kind: 'resource', driverClass: 'ClassRegistryInspector' }\n },\n {\n id: 'lazy',\n label: 'Lazy Loading',\n icon: 'fa-solid fa-puzzle-piece',\n description: 'Code-split chunk status',\n source: { kind: 'resource', driverClass: 'LazyModuleStatusInspector' }\n },\n {\n id: 'settings',\n label: 'Settings Explorer',\n icon: 'fa-solid fa-sliders',\n description: 'User and instance settings',\n source: { kind: 'resource', driverClass: 'SettingsExplorerInspector' }\n },\n {\n id: 'app-state',\n label: 'App State',\n icon: 'fa-solid fa-magnifying-glass-chart',\n description: 'Snapshot of user, provider, workspace',\n source: { kind: 'resource', driverClass: 'AppStateInspector' }\n },\n {\n id: 'layout',\n label: 'Layout',\n icon: 'fa-solid fa-table-columns',\n description: 'Workspace + Golden Layout config',\n source: { kind: 'resource', driverClass: 'LayoutInspector' }\n }\n ];\n}\n","<mj-page-layout>\n <mj-page-header\n [Title]=\"ContainerTitle\"\n [Icon]=\"ContainerIcon\"\n [Subtitle]=\"ContainerSubtitle\">\n </mj-page-header>\n\n <mj-page-body [Flex]=\"true\" [Padding]=\"false\" Direction=\"row\">\n <mj-left-nav\n MobileTitle=\"Administration\"\n [Sections]=\"NavSections\"\n [ActiveId]=\"ActiveSection\"\n (ItemClicked)=\"OnNavItemClicked($event)\">\n </mj-left-nav>\n <mj-left-nav-content [Loading]=\"IsLoading\" [Error]=\"LoadError\">\n <ng-container #contentHost></ng-container>\n </mj-left-nav-content>\n </mj-page-body>\n</mj-page-layout>\n"]}
1
+ {"version":3,"file":"admin-dev-tools-resource.component.js","sourceRoot":"","sources":["../../src/Admin/admin-dev-tools-resource.component.ts","../../src/Admin/admin-container.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component } from '@angular/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RegisterClass } from '@memberjunction/global';\nimport { AdminSection, BaseAdminContainerComponent } from './base-admin-container.component';\n\n/**\n * Admin → Developer Tools. Diagnostic and inspection sub-tools for developers.\n */\n@RegisterClass(BaseResourceComponent, 'AdminDeveloperTools')\n@Component({\n standalone: false,\n selector: 'mj-admin-dev-tools-resource',\n templateUrl: './admin-container.component.html',\n styleUrls: ['./admin-container.component.css']\n})\nexport class AdminDevToolsResourceComponent extends BaseAdminContainerComponent {\n public readonly ContainerTitle = 'Developer Tools';\n public readonly ContainerIcon = 'fa-solid fa-screwdriver-wrench';\n public readonly ContainerSubtitle = 'Diagnostic and inspection tools for developers';\n\n public readonly Sections: AdminSection[] = [\n {\n id: 'graphql',\n label: 'GraphQL Console',\n icon: 'fa-solid fa-code',\n description: 'Run queries against the API',\n source: { kind: 'resource', driverClass: 'GraphQLConsoleInspector' }\n },\n {\n id: 'events',\n label: 'Event Monitor',\n icon: 'fa-solid fa-bolt',\n description: 'Live tail of MJ events',\n source: { kind: 'resource', driverClass: 'EventMonitorInspector' }\n },\n {\n id: 'classes',\n label: 'Class Registry',\n icon: 'fa-solid fa-cubes',\n description: 'All @RegisterClass entries',\n source: { kind: 'resource', driverClass: 'ClassRegistryInspector' }\n },\n {\n id: 'lazy',\n label: 'Lazy Loading',\n icon: 'fa-solid fa-puzzle-piece',\n description: 'Code-split chunk status',\n source: { kind: 'resource', driverClass: 'LazyModuleStatusInspector' }\n },\n {\n id: 'settings',\n label: 'Settings Explorer',\n icon: 'fa-solid fa-sliders',\n description: 'User and instance settings',\n source: { kind: 'resource', driverClass: 'SettingsExplorerInspector' }\n },\n {\n id: 'app-state',\n label: 'App State',\n icon: 'fa-solid fa-magnifying-glass-chart',\n description: 'Snapshot of user, provider, workspace',\n source: { kind: 'resource', driverClass: 'AppStateInspector' }\n },\n {\n id: 'layout',\n label: 'Layout',\n icon: 'fa-solid fa-table-columns',\n description: 'Workspace + Golden Layout config',\n source: { kind: 'resource', driverClass: 'LayoutInspector' }\n },\n {\n id: 'grid-width-lab',\n label: 'Grid Width Lab',\n icon: 'fa-solid fa-arrows-left-right-to-line',\n description: 'entity-data-grid width + column contract',\n source: { kind: 'resource', driverClass: 'GridWidthLabInspector' }\n },\n {\n id: 'tab-strip-lab',\n label: 'Tab Strip Lab',\n icon: 'fa-solid fa-folder-tree',\n description: 'Both tab strips, one shared look',\n source: { kind: 'resource', driverClass: 'TabStripLabInspector' }\n }\n ];\n}\n","<mj-page-layout>\n <mj-page-header\n [Title]=\"ContainerTitle\"\n [Icon]=\"ContainerIcon\"\n [Subtitle]=\"ContainerSubtitle\">\n </mj-page-header>\n\n <mj-page-body [Flex]=\"true\" [Padding]=\"false\" Direction=\"row\">\n <mj-left-nav\n MobileTitle=\"Administration\"\n [Sections]=\"NavSections\"\n [ActiveId]=\"ActiveSection\"\n (ItemClicked)=\"OnNavItemClicked($event)\">\n </mj-left-nav>\n <mj-left-nav-content [Loading]=\"IsLoading\" [Error]=\"LoadError\">\n <ng-container #contentHost></ng-container>\n </mj-left-nav-content>\n </mj-page-body>\n</mj-page-layout>\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"base-admin-container.component.d.ts","sourceRoot":"","sources":["../../src/Admin/base-admin-container.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,MAAM,EACN,SAAS,EACT,iBAAiB,EAEjB,gBAAgB,EAChB,YAAY,EAGf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAiB,MAAM,2BAA2B,CAAC;AAGjF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;;AAEnF,iEAAiE;AACjE,MAAM,WAAW,YAAY;IACzB,iEAAiE;IACjE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GACxB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD;;;;;;;;;GASG;AACH,8BACsB,2BAA4B,SAAQ,qBAAsB,YAAW,MAAM,EAAE,SAAS;IACxG,kBAAyB,cAAc,EAAE,MAAM,CAAC;IAChD,kBAAyB,aAAa,EAAE,MAAM,CAAC;IAC/C,kBAAyB,iBAAiB,EAAE,MAAM,CAAC;IACnD,kBAAyB,QAAQ,EAAE,YAAY,EAAE,CAAC;IAGlD,SAAS,CAAC,WAAW,EAAG,gBAAgB,CAAC;IAElC,aAAa,SAAM;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAChC,SAAS,UAAS;IAEzB;;;;;;OAMG;IACH,SAAS,CAAC,KAAK,qCAA4C;IAC3D,SAAS,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEjD,SAAS,CAAC,QAAQ,CAAC,GAAG,oBAA6B;IAE7B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B,WAAW,IAAI,IAAI;IASb,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC;IACzC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAE7D;;;;OAIG;IACH,IAAW,WAAW,IAAI,gBAAgB,EAAE,CAE3C;IAED,gFAAgF;IACzE,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAOlD,yEAAyE;cACtD,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI;IASlG,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;YAOnD,aAAa;YA+Bb,aAAa;IAwB3B,OAAO,CAAC,aAAa;YAQP,iBAAiB;YAYjB,kBAAkB;IA2BhC,OAAO,CAAC,WAAW;yCA/LD,2BAA2B;2CAA3B,2BAA2B;CAmMhD"}
1
+ {"version":3,"file":"base-admin-container.component.d.ts","sourceRoot":"","sources":["../../src/Admin/base-admin-container.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,MAAM,EACN,SAAS,EACT,iBAAiB,EAEjB,gBAAgB,EAChB,YAAY,EAGf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAiB,MAAM,2BAA2B,CAAC;AAGjF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;;AAEnF,iEAAiE;AACjE,MAAM,WAAW,YAAY;IACzB,iEAAiE;IACjE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GACxB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD;;;;;;;;;GASG;AACH,8BACsB,2BAA4B,SAAQ,qBAAsB,YAAW,MAAM,EAAE,SAAS;IACxG,kBAAyB,cAAc,EAAE,MAAM,CAAC;IAChD,kBAAyB,aAAa,EAAE,MAAM,CAAC;IAC/C,kBAAyB,iBAAiB,EAAE,MAAM,CAAC;IACnD,kBAAyB,QAAQ,EAAE,YAAY,EAAE,CAAC;IAGlD,SAAS,CAAC,WAAW,EAAG,gBAAgB,CAAC;IAElC,aAAa,SAAM;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAChC,SAAS,UAAS;IAEzB;;;;;;OAMG;IACH,SAAS,CAAC,KAAK,qCAA4C;IAC3D,SAAS,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEjD,SAAS,CAAC,QAAQ,CAAC,GAAG,oBAA6B;IAE7B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B,WAAW,IAAI,IAAI;IASb,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC;IACzC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAE7D;;;;OAIG;IACH,IAAW,WAAW,IAAI,gBAAgB,EAAE,CAE3C;IAED,gFAAgF;IACzE,gBAAgB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI;IAOlD,yEAAyE;cACtD,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI;IASlG,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;YAOnD,aAAa;YA+Bb,aAAa;IAwB3B,OAAO,CAAC,aAAa;YAQP,iBAAiB;YAYjB,kBAAkB;IAyChC,OAAO,CAAC,WAAW;yCA7MD,2BAA2B;2CAA3B,2BAA2B;CAiNhD"}
@@ -181,6 +181,21 @@ export class BaseAdminContainerComponent extends BaseResourceComponent {
181
181
  }
182
182
  const ref = this.contentHost.createComponent(reg.SubClass);
183
183
  const instance = ref.instance;
184
+ // BaseDashboard catches a failing initDashboard()/loadData(), emits Error and still signals
185
+ // load-complete — so without this subscription an embedded dashboard's load failure would
186
+ // render as a blank content pane with a console-only error. Surface it in LoadError, which
187
+ // the container already renders. Scoped to the INITIAL load (same reasoning as
188
+ // DashboardResource): sections are cached and kept alive across switches, and LoadError only
189
+ // resets on the next selectSection, so a post-mount Refresh() failure would otherwise pin a
190
+ // stale error banner — potentially while a different section is on screen.
191
+ let initialLoadSettled = false;
192
+ const onComplete = instance.LoadCompleteEvent;
193
+ instance.LoadCompleteEvent = () => { initialLoadSettled = true; onComplete?.(); };
194
+ instance.Error.subscribe((err) => {
195
+ if (initialLoadSettled)
196
+ return; // post-mount refresh failure — already logged by BaseDashboard.runGuardedLoad
197
+ this.LoadError = err.message;
198
+ });
184
199
  instance.Config = { dashboard, userState: undefined };
185
200
  instance.Refresh();
186
201
  return ref;
@@ -1 +1 @@
1
- {"version":3,"file":"base-admin-container.component.js","sourceRoot":"","sources":["../../src/Admin/base-admin-container.component.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,SAAS,EAGT,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EAGhB,MAAM,EACT,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;;;AAyBhE;;;;;;;;;GASG;AAEH,MAAM,OAAgB,2BAA4B,SAAQ,qBAAqB;IAOjE,WAAW,CAAoB;IAElC,aAAa,GAAG,EAAE,CAAC;IACnB,SAAS,GAAkB,IAAI,CAAC;IAChC,SAAS,GAAG,KAAK,CAAC;IAEzB;;;;;;OAMG;IACO,KAAK,GAAG,IAAI,GAAG,EAAiC,CAAC;IACjD,gBAAgB,GAAkB,IAAI,CAAC;IAE9B,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAEnC,KAAK,CAAC,QAAQ;QAC1B,KAAK,CAAC,QAAQ,EAAE,CAAC;QAEjB,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;QAC9E,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,MAAM,EAAE,CAAC;YACT,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;QACxD,CAAC;QAED,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACnC,IAAI,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC9B,CAAC;IAEe,WAAW;QACvB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACpC,IAAI,CAAC;gBAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QAC7B,KAAK,CAAC,WAAW,EAAE,CAAC;IACxB,CAAC;IAEe,KAAK,CAAC,sBAAsB,KAAsB,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAC/E,KAAK,CAAC,oBAAoB,KAAsB,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IAE5F;;;;OAIG;IACH,IAAW,WAAW;QAClB,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,gFAAgF;IACzE,gBAAgB,CAAC,IAAmB;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1D,IAAI,OAAO,EAAE,CAAC;YACV,KAAK,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;IACL,CAAC;IAED,yEAAyE;IACtD,oBAAoB,CAAC,MAA8B,EAAE,OAAgC;QACpG,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,IAAI,CAAC,aAAa;YAAE,OAAO;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,MAAM,EAAE,CAAC;YACT,KAAK,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;QACvD,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,OAAqB;QAC7C,IAAI,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC,aAAa;YAAE,OAAO;QAC9C,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,kCAAkC;IAE1B,KAAK,CAAC,aAAa,CAAC,OAAqB,EAAE,OAAgB;QAC/D,oEAAoE;QACpE,uEAAuE;QACvE,mEAAmE;QACnE,2DAA2D;QAC3D,oEAAoE;QACpE,iEAAiE;QACjE,kEAAkE;QAClE,sEAAsE;QACtE,IAAI,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;YACpC,OAAO;QACX,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,EAAE,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAExB,IAAI,OAAO,EAAE,CAAC;YACV,IAAI,CAAC,iBAAiB,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,CAAC;QAED,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,IAAI,CAAC,SAAS,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtE,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC5B,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,OAAqB;QAC7C,mEAAmE;QACnE,+CAA+C;QAC/C,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,qBAAqB;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,MAAM,EAAE,CAAC;YACT,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,EAAE,CAAC;YACnC,OAAO;QACX,CAAC;QAED,0BAA0B;QAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,UAAU;YAC1C,CAAC,CAAC,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC;YAC1D,CAAC,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAElE,IAAI,GAAG,EAAE,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YAChC,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,EAAE,CAAC;QACvC,CAAC;IACL,CAAC;IAEO,aAAa;QACjB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAClD,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,GAAG,IAAI,CAAC;YAAE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,WAAmB;QAC/C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,oBAAoB,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC;QAC1G,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,cAAc,WAAW,wDAAwD,CAAC;YACnG,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,GAAG,CAAC,QAAuC,CAAC,CAAC;QAC1F,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAiC,CAAC;QACvD,IAAI,IAAI,CAAC,IAAI;YAAE,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACzC,OAAO,GAAG,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,aAAqB;QAClD,MAAM,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,eAAe,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;QAC1F,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,IAAI,CAAC,SAAS,GAAG,cAAc,aAAa,8BAA8B,CAAC;YAC3E,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,SAAS,GAAG,cAAc,aAAa,eAAe,SAAS,CAAC,IAAI,gDAAgD,CAAC;YAC1H,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YACzB,IAAI,CAAC,SAAS,GAAG,cAAc,aAAa,2BAA2B,CAAC;YACxE,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,oBAAoB,CAAC,aAAa,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;QAC5G,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,iBAAiB,SAAS,CAAC,WAAW,4CAA4C,CAAC;YACpG,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,GAAG,CAAC,QAA+B,CAAC,CAAC;QAClF,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAyB,CAAC;QAC/C,QAAQ,CAAC,MAAM,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;QACtD,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,GAAG,CAAC;IACf,CAAC;IAEO,WAAW,CAAC,EAA6B;QAC7C,IAAI,CAAC,EAAE;YAAE,OAAO,SAAS,CAAC;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,CAAC;yRAlMiB,2BAA2B,yBAA3B,2BAA2B;6DAA3B,2BAA2B;mCAMX,gBAAgB;;;;;;iFANhC,2BAA2B;cADhD,SAAS;;kBAOL,SAAS;mBAAC,aAAa,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,IAAI,EAAE","sourcesContent":["import {\n Directive,\n OnInit,\n OnDestroy,\n ChangeDetectorRef,\n ViewChild,\n ViewContainerRef,\n ComponentRef,\n Type,\n inject\n} from '@angular/core';\nimport { BaseResourceComponent, BaseDashboard } from '@memberjunction/ng-shared';\nimport { MJGlobal } from '@memberjunction/global';\nimport { DashboardEngine } from '@memberjunction/core-entities';\nimport { MJLeftNavItem, MJLeftNavSection } from '@memberjunction/ng-ui-components';\n\n/** A single sub-section inside an admin container's left-nav. */\nexport interface AdminSection {\n /** Stable identifier — used in the URL `?section=` deep-link. */\n id: string;\n label: string;\n icon: string;\n description: string;\n source: AdminSectionSource;\n}\n\n/**\n * How to resolve and instantiate the component for this sub-section.\n *\n * - `resource`: looks up `@RegisterClass(BaseResourceComponent, driverClass)` and renders it directly.\n * - `dashboard`: looks up the MJ Dashboard record by name, then renders its `DriverClass` via the\n * BaseDashboard registry with a synthetic `{ dashboard }` config (mirrors the shell's flow for\n * `ResourceType: \"Dashboards\"` nav items).\n */\nexport type AdminSectionSource =\n | { kind: 'resource'; driverClass: string }\n | { kind: 'dashboard'; dashboardName: string };\n\n/**\n * Shared base for all Admin app container resources. Subclasses declare:\n * - ContainerTitle / ContainerIcon / ContainerSubtitle\n * - Sections[]\n * - @RegisterClass(BaseResourceComponent, '...')\n *\n * The base handles: left-nav state, URL deep-linking via NavigationService,\n * dynamic component instantiation for both resource and dashboard sections,\n * teardown on switch.\n */\n@Directive()\nexport abstract class BaseAdminContainerComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public abstract readonly ContainerTitle: string;\n public abstract readonly ContainerIcon: string;\n public abstract readonly ContainerSubtitle: string;\n public abstract readonly Sections: AdminSection[];\n\n @ViewChild('contentHost', { read: ViewContainerRef, static: true })\n protected contentHost!: ViewContainerRef;\n\n public ActiveSection = '';\n public LoadError: string | null = null;\n public IsLoading = false;\n\n /**\n * Cache of section.id → ComponentRef. Once a sub-section is rendered we\n * keep its component alive across switches by detaching + reattaching the\n * view (instead of destroying + recreating). This preserves state — Event\n * Monitor's captured events, GraphQL Console's history, query inputs,\n * scroll position, etc. — and avoids expensive re-init.\n */\n protected cache = new Map<string, ComponentRef<unknown>>();\n protected currentSectionId: string | null = null;\n\n protected readonly cdr = inject(ChangeDetectorRef);\n\n public override async ngOnInit(): Promise<void> {\n super.ngOnInit();\n\n const params = this.GetQueryParams();\n const requested = params['section'];\n const initial = this.findSection(requested)?.id ?? this.Sections[0]?.id ?? '';\n const target = this.findSection(initial);\n if (target) {\n await this.selectSection(target, /*syncUrl*/ false);\n }\n\n if (!requested && this.ActiveSection) {\n this.UpdateQueryParams({ section: this.ActiveSection });\n }\n\n this.NotifyLoadComplete();\n }\n\n public override ngOnDestroy(): void {\n for (const ref of this.cache.values()) {\n try { ref.destroy(); } catch { /* ignore */ }\n }\n this.cache.clear();\n this.currentSectionId = null;\n super.ngOnDestroy();\n }\n\n public override async GetResourceDisplayName(): Promise<string> { return this.ContainerTitle; }\n public override async GetResourceIconClass(): Promise<string> { return this.ContainerIcon; }\n\n /**\n * Single-section view of `Sections` shaped for `<mj-left-nav>`. AdminSection\n * already has the required id / label / icon / description fields, so it's\n * structurally compatible with MJLeftNavItem.\n */\n public get NavSections(): MJLeftNavSection[] {\n return [{ items: this.Sections }];\n }\n\n /** Adapter from `<mj-left-nav>`'s ItemClicked event back to `selectSection`. */\n public OnNavItemClicked(item: MJLeftNavItem): void {\n const section = this.Sections.find(s => s.id === item.id);\n if (section) {\n void this.OnSectionClick(section);\n }\n }\n\n /** Called by the framework on browser back/forward + deep-link entry. */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n const section = params['section'];\n if (!section || section === this.ActiveSection) return;\n const target = this.findSection(section);\n if (target) {\n void this.selectSection(target, /*syncUrl*/ false);\n }\n }\n\n public async OnSectionClick(section: AdminSection): Promise<void> {\n if (section.id === this.ActiveSection) return;\n await this.selectSection(section, /*syncUrl*/ true);\n }\n\n // ---------- protected ----------\n\n private async selectSection(section: AdminSection, syncUrl: boolean): Promise<void> {\n // Guard against duplicate calls for the same section. Without this,\n // ngOnInit's own GetQueryParams read races with the workspace stream's\n // synchronous replay through OnQueryParamsChanged on first mount —\n // both call selectSection with the same target, both reach\n // createComponent, and two instances of the sub-page end up mounted\n // in the contentHost. OnSectionClick + OnQueryParamsChanged each\n // guard their own call site, but defense-in-depth here covers any\n // future caller (and the ngOnInit ↔ stream-replay race specifically).\n if (section.id === this.ActiveSection) {\n return;\n }\n this.ActiveSection = section.id;\n this.IsLoading = true;\n this.LoadError = null;\n this.cdr.markForCheck();\n\n if (syncUrl) {\n this.UpdateQueryParams({ section: section.id });\n }\n\n try {\n await this.renderSection(section);\n } catch (err) {\n this.LoadError = err instanceof Error ? err.message : String(err);\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n private async renderSection(section: AdminSection): Promise<void> {\n // Detach (don't destroy) the currently visible sub-component so it\n // stays alive in memory with its state intact.\n this.detachCurrent();\n\n // Reattach if cached\n const cached = this.cache.get(section.id);\n if (cached) {\n this.contentHost.insert(cached.hostView);\n this.currentSectionId = section.id;\n return;\n }\n\n // Otherwise, create fresh\n const ref = section.source.kind === 'resource'\n ? await this.createResourceRef(section.source.driverClass)\n : await this.createDashboardRef(section.source.dashboardName);\n\n if (ref) {\n this.cache.set(section.id, ref);\n this.currentSectionId = section.id;\n }\n }\n\n private detachCurrent(): void {\n if (!this.currentSectionId) return;\n const cur = this.cache.get(this.currentSectionId);\n if (!cur) return;\n const idx = this.contentHost.indexOf(cur.hostView);\n if (idx >= 0) this.contentHost.detach(idx);\n }\n\n private async createResourceRef(driverClass: string): Promise<ComponentRef<unknown> | null> {\n const reg = await MJGlobal.Instance.ClassFactory.GetRegistrationAsync(BaseResourceComponent, driverClass);\n if (!reg) {\n this.LoadError = `Component \"${driverClass}\" is not registered. Make sure its module is imported.`;\n return null;\n }\n const ref = this.contentHost.createComponent(reg.SubClass as Type<BaseResourceComponent>);\n const instance = ref.instance as BaseResourceComponent;\n if (this.Data) instance.Data = this.Data;\n return ref;\n }\n\n private async createDashboardRef(dashboardName: string): Promise<ComponentRef<unknown> | null> {\n await DashboardEngine.Instance.Config(false);\n const dashboard = DashboardEngine.Instance.Dashboards.find(d => d.Name === dashboardName);\n if (!dashboard) {\n this.LoadError = `Dashboard \"${dashboardName}\" was not found in metadata.`;\n return null;\n }\n if (dashboard.Type !== 'Code') {\n this.LoadError = `Dashboard \"${dashboardName}\" has type \"${dashboard.Type}\" — only Code dashboards can be embedded here.`;\n return null;\n }\n if (!dashboard.DriverClass) {\n this.LoadError = `Dashboard \"${dashboardName}\" has no DriverClass set.`;\n return null;\n }\n const reg = await MJGlobal.Instance.ClassFactory.GetRegistrationAsync(BaseDashboard, dashboard.DriverClass);\n if (!reg) {\n this.LoadError = `Driver class \"${dashboard.DriverClass}\" is not registered against BaseDashboard.`;\n return null;\n }\n const ref = this.contentHost.createComponent(reg.SubClass as Type<BaseDashboard>);\n const instance = ref.instance as BaseDashboard;\n instance.Config = { dashboard, userState: undefined };\n instance.Refresh();\n return ref;\n }\n\n private findSection(id: string | undefined | null): AdminSection | undefined {\n if (!id) return undefined;\n return this.Sections.find(s => s.id === id);\n }\n}\n"]}
1
+ {"version":3,"file":"base-admin-container.component.js","sourceRoot":"","sources":["../../src/Admin/base-admin-container.component.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Directive,\n OnInit,\n OnDestroy,\n ChangeDetectorRef,\n ViewChild,\n ViewContainerRef,\n ComponentRef,\n Type,\n inject\n} from '@angular/core';\nimport { BaseResourceComponent, BaseDashboard } from '@memberjunction/ng-shared';\nimport { MJGlobal } from '@memberjunction/global';\nimport { DashboardEngine } from '@memberjunction/core-entities';\nimport { MJLeftNavItem, MJLeftNavSection } from '@memberjunction/ng-ui-components';\n\n/** A single sub-section inside an admin container's left-nav. */\nexport interface AdminSection {\n /** Stable identifier — used in the URL `?section=` deep-link. */\n id: string;\n label: string;\n icon: string;\n description: string;\n source: AdminSectionSource;\n}\n\n/**\n * How to resolve and instantiate the component for this sub-section.\n *\n * - `resource`: looks up `@RegisterClass(BaseResourceComponent, driverClass)` and renders it directly.\n * - `dashboard`: looks up the MJ Dashboard record by name, then renders its `DriverClass` via the\n * BaseDashboard registry with a synthetic `{ dashboard }` config (mirrors the shell's flow for\n * `ResourceType: \"Dashboards\"` nav items).\n */\nexport type AdminSectionSource =\n | { kind: 'resource'; driverClass: string }\n | { kind: 'dashboard'; dashboardName: string };\n\n/**\n * Shared base for all Admin app container resources. Subclasses declare:\n * - ContainerTitle / ContainerIcon / ContainerSubtitle\n * - Sections[]\n * - @RegisterClass(BaseResourceComponent, '...')\n *\n * The base handles: left-nav state, URL deep-linking via NavigationService,\n * dynamic component instantiation for both resource and dashboard sections,\n * teardown on switch.\n */\n@Directive()\nexport abstract class BaseAdminContainerComponent extends BaseResourceComponent implements OnInit, OnDestroy {\n public abstract readonly ContainerTitle: string;\n public abstract readonly ContainerIcon: string;\n public abstract readonly ContainerSubtitle: string;\n public abstract readonly Sections: AdminSection[];\n\n @ViewChild('contentHost', { read: ViewContainerRef, static: true })\n protected contentHost!: ViewContainerRef;\n\n public ActiveSection = '';\n public LoadError: string | null = null;\n public IsLoading = false;\n\n /**\n * Cache of section.id → ComponentRef. Once a sub-section is rendered we\n * keep its component alive across switches by detaching + reattaching the\n * view (instead of destroying + recreating). This preserves state — Event\n * Monitor's captured events, GraphQL Console's history, query inputs,\n * scroll position, etc. — and avoids expensive re-init.\n */\n protected cache = new Map<string, ComponentRef<unknown>>();\n protected currentSectionId: string | null = null;\n\n protected readonly cdr = inject(ChangeDetectorRef);\n\n public override async ngOnInit(): Promise<void> {\n super.ngOnInit();\n\n const params = this.GetQueryParams();\n const requested = params['section'];\n const initial = this.findSection(requested)?.id ?? this.Sections[0]?.id ?? '';\n const target = this.findSection(initial);\n if (target) {\n await this.selectSection(target, /*syncUrl*/ false);\n }\n\n if (!requested && this.ActiveSection) {\n this.UpdateQueryParams({ section: this.ActiveSection });\n }\n\n this.NotifyLoadComplete();\n }\n\n public override ngOnDestroy(): void {\n for (const ref of this.cache.values()) {\n try { ref.destroy(); } catch { /* ignore */ }\n }\n this.cache.clear();\n this.currentSectionId = null;\n super.ngOnDestroy();\n }\n\n public override async GetResourceDisplayName(): Promise<string> { return this.ContainerTitle; }\n public override async GetResourceIconClass(): Promise<string> { return this.ContainerIcon; }\n\n /**\n * Single-section view of `Sections` shaped for `<mj-left-nav>`. AdminSection\n * already has the required id / label / icon / description fields, so it's\n * structurally compatible with MJLeftNavItem.\n */\n public get NavSections(): MJLeftNavSection[] {\n return [{ items: this.Sections }];\n }\n\n /** Adapter from `<mj-left-nav>`'s ItemClicked event back to `selectSection`. */\n public OnNavItemClicked(item: MJLeftNavItem): void {\n const section = this.Sections.find(s => s.id === item.id);\n if (section) {\n void this.OnSectionClick(section);\n }\n }\n\n /** Called by the framework on browser back/forward + deep-link entry. */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n const section = params['section'];\n if (!section || section === this.ActiveSection) return;\n const target = this.findSection(section);\n if (target) {\n void this.selectSection(target, /*syncUrl*/ false);\n }\n }\n\n public async OnSectionClick(section: AdminSection): Promise<void> {\n if (section.id === this.ActiveSection) return;\n await this.selectSection(section, /*syncUrl*/ true);\n }\n\n // ---------- protected ----------\n\n private async selectSection(section: AdminSection, syncUrl: boolean): Promise<void> {\n // Guard against duplicate calls for the same section. Without this,\n // ngOnInit's own GetQueryParams read races with the workspace stream's\n // synchronous replay through OnQueryParamsChanged on first mount —\n // both call selectSection with the same target, both reach\n // createComponent, and two instances of the sub-page end up mounted\n // in the contentHost. OnSectionClick + OnQueryParamsChanged each\n // guard their own call site, but defense-in-depth here covers any\n // future caller (and the ngOnInit ↔ stream-replay race specifically).\n if (section.id === this.ActiveSection) {\n return;\n }\n this.ActiveSection = section.id;\n this.IsLoading = true;\n this.LoadError = null;\n this.cdr.markForCheck();\n\n if (syncUrl) {\n this.UpdateQueryParams({ section: section.id });\n }\n\n try {\n await this.renderSection(section);\n } catch (err) {\n this.LoadError = err instanceof Error ? err.message : String(err);\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n private async renderSection(section: AdminSection): Promise<void> {\n // Detach (don't destroy) the currently visible sub-component so it\n // stays alive in memory with its state intact.\n this.detachCurrent();\n\n // Reattach if cached\n const cached = this.cache.get(section.id);\n if (cached) {\n this.contentHost.insert(cached.hostView);\n this.currentSectionId = section.id;\n return;\n }\n\n // Otherwise, create fresh\n const ref = section.source.kind === 'resource'\n ? await this.createResourceRef(section.source.driverClass)\n : await this.createDashboardRef(section.source.dashboardName);\n\n if (ref) {\n this.cache.set(section.id, ref);\n this.currentSectionId = section.id;\n }\n }\n\n private detachCurrent(): void {\n if (!this.currentSectionId) return;\n const cur = this.cache.get(this.currentSectionId);\n if (!cur) return;\n const idx = this.contentHost.indexOf(cur.hostView);\n if (idx >= 0) this.contentHost.detach(idx);\n }\n\n private async createResourceRef(driverClass: string): Promise<ComponentRef<unknown> | null> {\n const reg = await MJGlobal.Instance.ClassFactory.GetRegistrationAsync(BaseResourceComponent, driverClass);\n if (!reg) {\n this.LoadError = `Component \"${driverClass}\" is not registered. Make sure its module is imported.`;\n return null;\n }\n const ref = this.contentHost.createComponent(reg.SubClass as Type<BaseResourceComponent>);\n const instance = ref.instance as BaseResourceComponent;\n if (this.Data) instance.Data = this.Data;\n return ref;\n }\n\n private async createDashboardRef(dashboardName: string): Promise<ComponentRef<unknown> | null> {\n await DashboardEngine.Instance.Config(false);\n const dashboard = DashboardEngine.Instance.Dashboards.find(d => d.Name === dashboardName);\n if (!dashboard) {\n this.LoadError = `Dashboard \"${dashboardName}\" was not found in metadata.`;\n return null;\n }\n if (dashboard.Type !== 'Code') {\n this.LoadError = `Dashboard \"${dashboardName}\" has type \"${dashboard.Type}\" — only Code dashboards can be embedded here.`;\n return null;\n }\n if (!dashboard.DriverClass) {\n this.LoadError = `Dashboard \"${dashboardName}\" has no DriverClass set.`;\n return null;\n }\n const reg = await MJGlobal.Instance.ClassFactory.GetRegistrationAsync(BaseDashboard, dashboard.DriverClass);\n if (!reg) {\n this.LoadError = `Driver class \"${dashboard.DriverClass}\" is not registered against BaseDashboard.`;\n return null;\n }\n const ref = this.contentHost.createComponent(reg.SubClass as Type<BaseDashboard>);\n const instance = ref.instance as BaseDashboard;\n // BaseDashboard catches a failing initDashboard()/loadData(), emits Error and still signals\n // load-complete — so without this subscription an embedded dashboard's load failure would\n // render as a blank content pane with a console-only error. Surface it in LoadError, which\n // the container already renders. Scoped to the INITIAL load (same reasoning as\n // DashboardResource): sections are cached and kept alive across switches, and LoadError only\n // resets on the next selectSection, so a post-mount Refresh() failure would otherwise pin a\n // stale error banner — potentially while a different section is on screen.\n let initialLoadSettled = false;\n const onComplete = instance.LoadCompleteEvent;\n instance.LoadCompleteEvent = () => { initialLoadSettled = true; onComplete?.(); };\n instance.Error.subscribe((err: Error) => {\n if (initialLoadSettled) return; // post-mount refresh failure — already logged by BaseDashboard.runGuardedLoad\n this.LoadError = err.message;\n });\n instance.Config = { dashboard, userState: undefined };\n instance.Refresh();\n return ref;\n }\n\n private findSection(id: string | undefined | null): AdminSection | undefined {\n if (!id) return undefined;\n return this.Sections.find(s => s.id === id);\n }\n}\n"]}