@memberjunction/ng-dashboard-viewer 5.42.0 → 5.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/lib/config-panels/artifact-config-panel.component.d.ts +0 -1
  2. package/dist/lib/config-panels/artifact-config-panel.component.d.ts.map +1 -1
  3. package/dist/lib/config-panels/artifact-config-panel.component.js +49 -63
  4. package/dist/lib/config-panels/artifact-config-panel.component.js.map +1 -1
  5. package/dist/lib/config-panels/query-config-panel.component.d.ts +0 -1
  6. package/dist/lib/config-panels/query-config-panel.component.d.ts.map +1 -1
  7. package/dist/lib/config-panels/query-config-panel.component.js +110 -124
  8. package/dist/lib/config-panels/query-config-panel.component.js.map +1 -1
  9. package/dist/lib/config-panels/view-config-panel.component.d.ts +0 -2
  10. package/dist/lib/config-panels/view-config-panel.component.d.ts.map +1 -1
  11. package/dist/lib/config-panels/view-config-panel.component.js +142 -171
  12. package/dist/lib/config-panels/view-config-panel.component.js.map +1 -1
  13. package/dist/lib/config-panels/weburl-config-panel.component.js +2 -2
  14. package/dist/lib/dashboard-browser/dashboard-browser.component.d.ts +4 -0
  15. package/dist/lib/dashboard-browser/dashboard-browser.component.d.ts.map +1 -1
  16. package/dist/lib/dashboard-browser/dashboard-browser.component.js +205 -272
  17. package/dist/lib/dashboard-browser/dashboard-browser.component.js.map +1 -1
  18. package/dist/lib/dashboard-viewer/dashboard-viewer.component.d.ts +46 -1
  19. package/dist/lib/dashboard-viewer/dashboard-viewer.component.d.ts.map +1 -1
  20. package/dist/lib/dashboard-viewer/dashboard-viewer.component.js +229 -49
  21. package/dist/lib/dashboard-viewer/dashboard-viewer.component.js.map +1 -1
  22. package/dist/lib/dashboard-viewer.module.d.ts +2 -1
  23. package/dist/lib/dashboard-viewer.module.d.ts.map +1 -1
  24. package/dist/lib/dashboard-viewer.module.js +11 -3
  25. package/dist/lib/dashboard-viewer.module.js.map +1 -1
  26. package/dist/lib/parts/artifact-part.component.d.ts.map +1 -1
  27. package/dist/lib/parts/artifact-part.component.js +25 -32
  28. package/dist/lib/parts/artifact-part.component.js.map +1 -1
  29. package/dist/lib/parts/query-part.component.d.ts.map +1 -1
  30. package/dist/lib/parts/query-part.component.js +25 -32
  31. package/dist/lib/parts/query-part.component.js.map +1 -1
  32. package/dist/lib/parts/view-part.component.d.ts.map +1 -1
  33. package/dist/lib/parts/view-part.component.js +25 -32
  34. package/dist/lib/parts/view-part.component.js.map +1 -1
  35. package/dist/lib/parts/weburl-part.component.d.ts.map +1 -1
  36. package/dist/lib/parts/weburl-part.component.js +46 -52
  37. package/dist/lib/parts/weburl-part.component.js.map +1 -1
  38. package/package.json +13 -11
  39. package/dist/__tests__/exports.test.d.ts +0 -2
  40. package/dist/__tests__/exports.test.d.ts.map +0 -1
  41. package/dist/__tests__/exports.test.js +0 -17
  42. package/dist/__tests__/exports.test.js.map +0 -1
  43. package/dist/__tests__/index.test.d.ts +0 -2
  44. package/dist/__tests__/index.test.d.ts.map +0 -1
  45. package/dist/__tests__/index.test.js +0 -7
  46. package/dist/__tests__/index.test.js.map +0 -1
@@ -11,35 +11,24 @@ import { Subject } from 'rxjs';
11
11
  import * as i0 from "@angular/core";
12
12
  import * as i1 from "@memberjunction/ng-artifacts";
13
13
  import * as i2 from "@memberjunction/ng-shared-generic";
14
+ import * as i3 from "@memberjunction/ng-ui-components";
14
15
  function ArtifactPartComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
15
16
  i0.ɵɵelementStart(0, "div", 1);
16
17
  i0.ɵɵelement(1, "mj-loading", 5);
17
18
  i0.ɵɵelementEnd();
18
19
  } }
19
20
  function ArtifactPartComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
20
- i0.ɵɵelementStart(0, "div", 2);
21
- i0.ɵɵelement(1, "i", 6);
22
- i0.ɵɵelementStart(2, "span");
23
- i0.ɵɵtext(3);
24
- i0.ɵɵelementEnd()();
21
+ i0.ɵɵelement(0, "mj-empty-state", 2);
25
22
  } if (rf & 2) {
26
23
  const ctx_r0 = i0.ɵɵnextContext();
27
- i0.ɵɵadvance(3);
28
- i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
24
+ i0.ɵɵproperty("Message", ctx_r0.ErrorMessage);
29
25
  } }
30
26
  function ArtifactPartComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
31
- i0.ɵɵelementStart(0, "div", 3);
32
- i0.ɵɵelement(1, "i", 7);
33
- i0.ɵɵelementStart(2, "h4");
34
- i0.ɵɵtext(3, "No Artifact Selected");
35
- i0.ɵɵelementEnd();
36
- i0.ɵɵelementStart(4, "p");
37
- i0.ɵɵtext(5, "Click the configure button to select an artifact for this part.");
38
- i0.ɵɵelementEnd()();
27
+ i0.ɵɵelement(0, "mj-empty-state", 3);
39
28
  } }
40
29
  function ArtifactPartComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
41
30
  const _r2 = i0.ɵɵgetCurrentView();
42
- i0.ɵɵelementStart(0, "mj-artifact-viewer-panel", 8);
31
+ i0.ɵɵelementStart(0, "mj-artifact-viewer-panel", 6);
43
32
  i0.ɵɵlistener("navigateToLink", function ArtifactPartComponent_Conditional_4_Template_mj_artifact_viewer_panel_navigateToLink_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onNavigateToLink($event)); })("openEntityRecord", function ArtifactPartComponent_Conditional_4_Template_mj_artifact_viewer_panel_openEntityRecord_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onOpenEntityRecord($event)); })("navigationRequest", function ArtifactPartComponent_Conditional_4_Template_mj_artifact_viewer_panel_navigationRequest_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onNavigationRequest($event)); })("analyzeRequested", function ArtifactPartComponent_Conditional_4_Template_mj_artifact_viewer_panel_analyzeRequested_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onAnalyzeRequested($event)); });
44
33
  i0.ɵɵelementEnd();
45
34
  } if (rf & 2) {
@@ -194,11 +183,11 @@ let ArtifactPartComponent = class ArtifactPartComponent extends BaseDashboardPar
194
183
  this.versionNumber = undefined;
195
184
  }
196
185
  static ɵfac = function ArtifactPartComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ArtifactPartComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i1.AnalyzeArtifactService)); };
197
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactPartComponent, selectors: [["mj-artifact-part"]], inputs: { CurrentUser: "CurrentUser", EnvironmentId: "EnvironmentId" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 8, consts: [[1, "artifact-part"], [1, "loading-state"], [1, "error-state"], [1, "empty-state"], [3, "artifactId", "currentUser", "environmentId", "versionNumber", "showSaveToCollection", "showHeader", "showTabs", "showCloseButton", "showMaximizeButton", "viewContext", "canShare", "canEdit", "isMaximized", "refreshTrigger"], ["text", "Loading artifact..."], [1, "fa-solid", "fa-exclamation-triangle"], [1, "fa-solid", "fa-palette"], [3, "navigateToLink", "openEntityRecord", "navigationRequest", "analyzeRequested", "artifactId", "currentUser", "environmentId", "versionNumber", "showSaveToCollection", "showHeader", "showTabs", "showCloseButton", "showMaximizeButton", "viewContext", "canShare", "canEdit", "isMaximized", "refreshTrigger"]], template: function ArtifactPartComponent_Template(rf, ctx) { if (rf & 1) {
186
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactPartComponent, selectors: [["mj-artifact-part"]], inputs: { CurrentUser: "CurrentUser", EnvironmentId: "EnvironmentId" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 8, consts: [[1, "artifact-part"], [1, "loading-state"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Title", "Couldn't load artifact", "Size", "compact", 1, "part-placeholder", 3, "Message"], ["Icon", "fa-solid fa-palette", "Title", "No Artifact Selected", "Message", "Click the configure button to select an artifact for this part.", "Size", "compact", 1, "part-placeholder"], [3, "artifactId", "currentUser", "environmentId", "versionNumber", "showSaveToCollection", "showHeader", "showTabs", "showCloseButton", "showMaximizeButton", "viewContext", "canShare", "canEdit", "isMaximized", "refreshTrigger"], ["text", "Loading artifact..."], [3, "navigateToLink", "openEntityRecord", "navigationRequest", "analyzeRequested", "artifactId", "currentUser", "environmentId", "versionNumber", "showSaveToCollection", "showHeader", "showTabs", "showCloseButton", "showMaximizeButton", "viewContext", "canShare", "canEdit", "isMaximized", "refreshTrigger"]], template: function ArtifactPartComponent_Template(rf, ctx) { if (rf & 1) {
198
187
  i0.ɵɵelementStart(0, "div", 0);
199
188
  i0.ɵɵconditionalCreate(1, ArtifactPartComponent_Conditional_1_Template, 2, 0, "div", 1);
200
- i0.ɵɵconditionalCreate(2, ArtifactPartComponent_Conditional_2_Template, 4, 1, "div", 2);
201
- i0.ɵɵconditionalCreate(3, ArtifactPartComponent_Conditional_3_Template, 6, 0, "div", 3);
189
+ i0.ɵɵconditionalCreate(2, ArtifactPartComponent_Conditional_2_Template, 1, 1, "mj-empty-state", 2);
190
+ i0.ɵɵconditionalCreate(3, ArtifactPartComponent_Conditional_3_Template, 1, 0, "mj-empty-state", 3);
202
191
  i0.ɵɵconditionalCreate(4, ArtifactPartComponent_Conditional_4_Template, 1, 14, "mj-artifact-viewer-panel", 4);
203
192
  i0.ɵɵelementEnd();
204
193
  } if (rf & 2) {
@@ -211,7 +200,7 @@ let ArtifactPartComponent = class ArtifactPartComponent extends BaseDashboardPar
211
200
  i0.ɵɵconditional(!ctx.IsLoading && !ctx.ErrorMessage && !ctx.hasArtifact ? 3 : -1);
212
201
  i0.ɵɵadvance();
213
202
  i0.ɵɵconditional(!ctx.IsLoading && !ctx.ErrorMessage && ctx.hasArtifact && ctx.artifactId ? 4 : -1);
214
- } }, dependencies: [i2.LoadingComponent, i1.ArtifactViewerPanelComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .artifact-part[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state[_ngcontent-%COMP%], \n .error-state[_ngcontent-%COMP%], \n .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n }\n\n mj-artifact-viewer-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n }"] });
203
+ } }, dependencies: [i2.LoadingComponent, i1.ArtifactViewerPanelComponent, i3.MJEmptyStateComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .artifact-part[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder[_ngcontent-%COMP%] {\n height: 100%;\n }\n\n mj-artifact-viewer-panel[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n }"] });
215
204
  };
216
205
  ArtifactPartComponent = __decorate([
217
206
  RegisterClass(BaseDashboardPart, 'ArtifactPanelRenderer')
@@ -230,19 +219,23 @@ export { ArtifactPartComponent };
230
219
 
231
220
  <!-- Error state -->
232
221
  @if (ErrorMessage && !IsLoading) {
233
- <div class="error-state">
234
- <i class="fa-solid fa-exclamation-triangle"></i>
235
- <span>{{ ErrorMessage }}</span>
236
- </div>
222
+ <mj-empty-state
223
+ class="part-placeholder"
224
+ Variant="error"
225
+ Icon="fa-solid fa-triangle-exclamation"
226
+ Title="Couldn't load artifact"
227
+ [Message]="ErrorMessage"
228
+ Size="compact" />
237
229
  }
238
-
230
+
239
231
  <!-- No artifact configured -->
240
232
  @if (!IsLoading && !ErrorMessage && !hasArtifact) {
241
- <div class="empty-state">
242
- <i class="fa-solid fa-palette"></i>
243
- <h4>No Artifact Selected</h4>
244
- <p>Click the configure button to select an artifact for this part.</p>
245
- </div>
233
+ <mj-empty-state
234
+ class="part-placeholder"
235
+ Icon="fa-solid fa-palette"
236
+ Title="No Artifact Selected"
237
+ Message="Click the configure button to select an artifact for this part."
238
+ Size="compact" />
246
239
  }
247
240
 
248
241
  <!-- Artifact Viewer Panel -->
@@ -269,11 +262,11 @@ export { ArtifactPartComponent };
269
262
  </mj-artifact-viewer-panel>
270
263
  }
271
264
  </div>
272
- `, styles: ["\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .artifact-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state,\n .error-state,\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state i,\n .empty-state i {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state i {\n color: var(--mj-status-error);\n }\n\n .empty-state h4 {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state p {\n margin: 0;\n font-size: 13px;\n }\n\n mj-artifact-viewer-panel {\n flex: 1;\n min-height: 0;\n }\n "] }]
265
+ `, styles: ["\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .artifact-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder {\n height: 100%;\n }\n\n mj-artifact-viewer-panel {\n flex: 1;\n min-height: 0;\n }\n "] }]
273
266
  }], () => [{ type: i0.ChangeDetectorRef }, { type: i1.AnalyzeArtifactService }], { CurrentUser: [{
274
267
  type: Input
275
268
  }], EnvironmentId: [{
276
269
  type: Input
277
270
  }] }); })();
278
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactPartComponent, { className: "ArtifactPartComponent", filePath: "src/lib/parts/artifact-part.component.ts", lineNumber: 123 }); })();
271
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactPartComponent, { className: "ArtifactPartComponent", filePath: "src/lib/parts/artifact-part.component.ts", lineNumber: 108 }); })();
279
272
  //# sourceMappingURL=artifact-part.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-part.component.js","sourceRoot":"","sources":["../../../src/lib/parts/artifact-part.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ChangeDetectorRef, AfterViewInit, OnDestroy, Input } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseDashboardPart } from './base-dashboard-part';\nimport { PanelConfig } from '../models/dashboard-types';\nimport { AnalyzeArtifactService, NavigationRequest } from '@memberjunction/ng-artifacts';\nimport { DataSnapshot, UserInfo, CompositeKey } from '@memberjunction/core';\nimport { Subject } from 'rxjs';\n\n/**\n * Runtime renderer for Artifact dashboard parts.\n * Displays artifacts using mj-artifact-viewer-panel including reports, charts, and AI-generated content.\n */\n@RegisterClass(BaseDashboardPart, 'ArtifactPanelRenderer')\n@Component({\n standalone: false,\n selector: 'mj-artifact-part',\n template: `\n <div class=\"artifact-part\" [class.loading]=\"IsLoading\" [class.error]=\"ErrorMessage\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading artifact...\"></mj-loading>\n </div>\n }\n \n <!-- Error state -->\n @if (ErrorMessage && !IsLoading) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n </div>\n }\n \n <!-- No artifact configured -->\n @if (!IsLoading && !ErrorMessage && !hasArtifact) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-palette\"></i>\n <h4>No Artifact Selected</h4>\n <p>Click the configure button to select an artifact for this part.</p>\n </div>\n }\n \n <!-- Artifact Viewer Panel -->\n @if (!IsLoading && !ErrorMessage && hasArtifact && artifactId) {\n <mj-artifact-viewer-panel\n [artifactId]=\"artifactId\"\n [currentUser]=\"currentUser\"\n [environmentId]=\"environmentId\"\n [versionNumber]=\"versionNumber\"\n [showSaveToCollection]=\"false\"\n [showHeader]=\"showHeader\"\n [showTabs]=\"showTabs\"\n [showCloseButton]=\"showCloseButton\"\n [showMaximizeButton]=\"showMaximizeButton\"\n [viewContext]=\"null\"\n [canShare]=\"false\"\n [canEdit]=\"false\"\n [isMaximized]=\"false\"\n [refreshTrigger]=\"refreshTrigger\"\n (navigateToLink)=\"onNavigateToLink($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (navigationRequest)=\"onNavigationRequest($event)\"\n (analyzeRequested)=\"onAnalyzeRequested($event)\">\n </mj-artifact-viewer-panel>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .artifact-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state,\n .error-state,\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state i,\n .empty-state i {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state i {\n color: var(--mj-status-error);\n }\n\n .empty-state h4 {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state p {\n margin: 0;\n font-size: 13px;\n }\n\n mj-artifact-viewer-panel {\n flex: 1;\n min-height: 0;\n }\n `]\n})\nexport class ArtifactPartComponent extends BaseDashboardPart implements AfterViewInit, OnDestroy {\n /**\n * Current user - required by the artifact viewer panel.\n * Should be provided by the dashboard host or retrieved from a service.\n */\n @Input() CurrentUser: UserInfo | null = null;\n\n /**\n * Environment ID - required by the artifact viewer panel.\n * Should be provided by the dashboard host.\n */\n @Input() EnvironmentId: string = '';\n\n public hasArtifact = false;\n public artifactId: string | null = null;\n public versionNumber: number | undefined;\n public showHeader: boolean = false; // Default to false for dashboard embedding\n public showTabs: boolean = true;\n public showCloseButton: boolean = false; // Always false in dashboard context - close handled by dashboard\n public showMaximizeButton: boolean = false; // Always false in dashboard context - maximize handled by dashboard\n public refreshTrigger = new Subject<{ artifactId: string; versionNumber: number }>();\n\n // Expose for template\n public get currentUser(): UserInfo {\n // Use provided CurrentUser, or fall back to Metadata.CurrentUser\n // In client-side Angular context, Metadata.CurrentUser should always be available\n const user = this.CurrentUser || this.ProviderToUse.CurrentUser;\n if (!user) {\n throw new Error('No current user available - user must be logged in to view artifacts');\n }\n return user;\n }\n\n public get environmentId(): string {\n return this.EnvironmentId || '';\n }\n\n constructor(cdr: ChangeDetectorRef, private analyzeService: AnalyzeArtifactService) {\n // Note: this component is instantiated twice — once via bare `new` by\n // ClassFactory.CreateInstanceAsync (just to extract the constructor\n // reference), then properly via createComponent() with a full injector.\n // Constructor parameters are undefined on the bare path but Angular DI\n // populates them on the real path. Field initializers calling inject()\n // would throw on the bare path, so we use constructor injection.\n super(cdr);\n }\n\n ngAfterViewInit(): void {\n if (this.Panel) {\n this.loadContent();\n }\n }\n\n public async loadContent(): Promise<void> {\n const config = this.getConfig<PanelConfig>();\n const artifactId = config?.['artifactId'] as string | undefined;\n\n if (!artifactId) {\n this.hasArtifact = false;\n this.cdr.detectChanges();\n return;\n }\n\n this.setLoading(true);\n\n try {\n // Set artifact ID and version from config\n this.artifactId = artifactId;\n this.versionNumber = config?.['versionNumber'] as number | undefined;\n // Display options - showHeader defaults to false for clean dashboard embedding\n this.showHeader = (config?.['showHeader'] as boolean) ?? false;\n this.showTabs = (config?.['showTabs'] as boolean) ?? true;\n this.hasArtifact = true;\n\n this.setLoading(false);\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to load artifact');\n }\n }\n\n /**\n * Refresh the artifact display\n */\n public refresh(): void {\n if (this.artifactId && this.versionNumber) {\n this.refreshTrigger.next({\n artifactId: this.artifactId,\n versionNumber: this.versionNumber\n });\n }\n }\n\n /**\n * Handle navigation link events from artifact viewer (conversation/collection links)\n */\n public onNavigateToLink(event: { type: 'conversation' | 'collection'; id: string; artifactId?: string; versionNumber?: number; versionId?: string }): void {\n // Emit data change event for navigation link (for listeners)\n this.emitDataChanged({\n type: 'navigate-to-link',\n linkType: event.type,\n linkId: event.id,\n artifactId: event.artifactId,\n versionNumber: event.versionNumber,\n versionId: event.versionId\n });\n\n // TODO: Add navigation request methods for conversation/collection when needed\n // For now, these are emitted as data change events for parent components to handle\n }\n\n /**\n * Handle entity record navigation events from artifact viewer\n */\n public onOpenEntityRecord(event: { entityName: string; compositeKey: CompositeKey }): void {\n // Emit data change event for listeners\n this.emitDataChanged({\n type: 'open-entity-record',\n entityName: event.entityName,\n compositeKey: event.compositeKey\n });\n\n // Use proper navigation request to bubble up through the stack\n if (event.entityName && event.compositeKey) {\n this.RequestOpenEntityRecord(\n event.entityName,\n event.compositeKey.ToURLSegment(),\n 'view',\n false\n );\n }\n }\n\n /**\n * Handle general navigation request events from artifact viewer plugins\n */\n public onNavigationRequest(event: NavigationRequest): void {\n this.RequestOpenNavItem(\n event.navItemName,\n event.appName,\n event.queryParams,\n false\n );\n }\n\n /**\n * Handler for the Analyze button on the embedded artifact viewer.\n * Captures the live DataSnapshot, creates an analysis conversation with\n * the snapshot attached as input, and emits a navigation request to open\n * the new conversation in the host application.\n */\n public async onAnalyzeRequested(event: { artifactId: string; snapshot: DataSnapshot }): Promise<void> {\n try {\n const result = await this.analyzeService.StartAnalysisConversation({\n snapshot: event.snapshot,\n currentUser: this.currentUser,\n environmentId: this.environmentId,\n });\n\n this.RequestOpenNavItem(\n 'Conversations',\n undefined,\n { conversationId: result.conversationId },\n false,\n );\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to start analysis conversation');\n }\n }\n\n protected override cleanup(): void {\n this.refreshTrigger.complete();\n this.artifactId = null;\n this.versionNumber = undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"artifact-part.component.js","sourceRoot":"","sources":["../../../src/lib/parts/artifact-part.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ChangeDetectorRef, AfterViewInit, OnDestroy, Input } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseDashboardPart } from './base-dashboard-part';\nimport { PanelConfig } from '../models/dashboard-types';\nimport { AnalyzeArtifactService, NavigationRequest } from '@memberjunction/ng-artifacts';\nimport { DataSnapshot, UserInfo, CompositeKey } from '@memberjunction/core';\nimport { Subject } from 'rxjs';\n\n/**\n * Runtime renderer for Artifact dashboard parts.\n * Displays artifacts using mj-artifact-viewer-panel including reports, charts, and AI-generated content.\n */\n@RegisterClass(BaseDashboardPart, 'ArtifactPanelRenderer')\n@Component({\n standalone: false,\n selector: 'mj-artifact-part',\n template: `\n <div class=\"artifact-part\" [class.loading]=\"IsLoading\" [class.error]=\"ErrorMessage\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading artifact...\"></mj-loading>\n </div>\n }\n \n <!-- Error state -->\n @if (ErrorMessage && !IsLoading) {\n <mj-empty-state\n class=\"part-placeholder\"\n Variant=\"error\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n Title=\"Couldn't load artifact\"\n [Message]=\"ErrorMessage\"\n Size=\"compact\" />\n }\n\n <!-- No artifact configured -->\n @if (!IsLoading && !ErrorMessage && !hasArtifact) {\n <mj-empty-state\n class=\"part-placeholder\"\n Icon=\"fa-solid fa-palette\"\n Title=\"No Artifact Selected\"\n Message=\"Click the configure button to select an artifact for this part.\"\n Size=\"compact\" />\n }\n \n <!-- Artifact Viewer Panel -->\n @if (!IsLoading && !ErrorMessage && hasArtifact && artifactId) {\n <mj-artifact-viewer-panel\n [artifactId]=\"artifactId\"\n [currentUser]=\"currentUser\"\n [environmentId]=\"environmentId\"\n [versionNumber]=\"versionNumber\"\n [showSaveToCollection]=\"false\"\n [showHeader]=\"showHeader\"\n [showTabs]=\"showTabs\"\n [showCloseButton]=\"showCloseButton\"\n [showMaximizeButton]=\"showMaximizeButton\"\n [viewContext]=\"null\"\n [canShare]=\"false\"\n [canEdit]=\"false\"\n [isMaximized]=\"false\"\n [refreshTrigger]=\"refreshTrigger\"\n (navigateToLink)=\"onNavigateToLink($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (navigationRequest)=\"onNavigationRequest($event)\"\n (analyzeRequested)=\"onAnalyzeRequested($event)\">\n </mj-artifact-viewer-panel>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .artifact-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder {\n height: 100%;\n }\n\n mj-artifact-viewer-panel {\n flex: 1;\n min-height: 0;\n }\n `]\n})\nexport class ArtifactPartComponent extends BaseDashboardPart implements AfterViewInit, OnDestroy {\n /**\n * Current user - required by the artifact viewer panel.\n * Should be provided by the dashboard host or retrieved from a service.\n */\n @Input() CurrentUser: UserInfo | null = null;\n\n /**\n * Environment ID - required by the artifact viewer panel.\n * Should be provided by the dashboard host.\n */\n @Input() EnvironmentId: string = '';\n\n public hasArtifact = false;\n public artifactId: string | null = null;\n public versionNumber: number | undefined;\n public showHeader: boolean = false; // Default to false for dashboard embedding\n public showTabs: boolean = true;\n public showCloseButton: boolean = false; // Always false in dashboard context - close handled by dashboard\n public showMaximizeButton: boolean = false; // Always false in dashboard context - maximize handled by dashboard\n public refreshTrigger = new Subject<{ artifactId: string; versionNumber: number }>();\n\n // Expose for template\n public get currentUser(): UserInfo {\n // Use provided CurrentUser, or fall back to Metadata.CurrentUser\n // In client-side Angular context, Metadata.CurrentUser should always be available\n const user = this.CurrentUser || this.ProviderToUse.CurrentUser;\n if (!user) {\n throw new Error('No current user available - user must be logged in to view artifacts');\n }\n return user;\n }\n\n public get environmentId(): string {\n return this.EnvironmentId || '';\n }\n\n constructor(cdr: ChangeDetectorRef, private analyzeService: AnalyzeArtifactService) {\n // Note: this component is instantiated twice — once via bare `new` by\n // ClassFactory.CreateInstanceAsync (just to extract the constructor\n // reference), then properly via createComponent() with a full injector.\n // Constructor parameters are undefined on the bare path but Angular DI\n // populates them on the real path. Field initializers calling inject()\n // would throw on the bare path, so we use constructor injection.\n super(cdr);\n }\n\n ngAfterViewInit(): void {\n if (this.Panel) {\n this.loadContent();\n }\n }\n\n public async loadContent(): Promise<void> {\n const config = this.getConfig<PanelConfig>();\n const artifactId = config?.['artifactId'] as string | undefined;\n\n if (!artifactId) {\n this.hasArtifact = false;\n this.cdr.detectChanges();\n return;\n }\n\n this.setLoading(true);\n\n try {\n // Set artifact ID and version from config\n this.artifactId = artifactId;\n this.versionNumber = config?.['versionNumber'] as number | undefined;\n // Display options - showHeader defaults to false for clean dashboard embedding\n this.showHeader = (config?.['showHeader'] as boolean) ?? false;\n this.showTabs = (config?.['showTabs'] as boolean) ?? true;\n this.hasArtifact = true;\n\n this.setLoading(false);\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to load artifact');\n }\n }\n\n /**\n * Refresh the artifact display\n */\n public refresh(): void {\n if (this.artifactId && this.versionNumber) {\n this.refreshTrigger.next({\n artifactId: this.artifactId,\n versionNumber: this.versionNumber\n });\n }\n }\n\n /**\n * Handle navigation link events from artifact viewer (conversation/collection links)\n */\n public onNavigateToLink(event: { type: 'conversation' | 'collection'; id: string; artifactId?: string; versionNumber?: number; versionId?: string }): void {\n // Emit data change event for navigation link (for listeners)\n this.emitDataChanged({\n type: 'navigate-to-link',\n linkType: event.type,\n linkId: event.id,\n artifactId: event.artifactId,\n versionNumber: event.versionNumber,\n versionId: event.versionId\n });\n\n // TODO: Add navigation request methods for conversation/collection when needed\n // For now, these are emitted as data change events for parent components to handle\n }\n\n /**\n * Handle entity record navigation events from artifact viewer\n */\n public onOpenEntityRecord(event: { entityName: string; compositeKey: CompositeKey }): void {\n // Emit data change event for listeners\n this.emitDataChanged({\n type: 'open-entity-record',\n entityName: event.entityName,\n compositeKey: event.compositeKey\n });\n\n // Use proper navigation request to bubble up through the stack\n if (event.entityName && event.compositeKey) {\n this.RequestOpenEntityRecord(\n event.entityName,\n event.compositeKey.ToURLSegment(),\n 'view',\n false\n );\n }\n }\n\n /**\n * Handle general navigation request events from artifact viewer plugins\n */\n public onNavigationRequest(event: NavigationRequest): void {\n this.RequestOpenNavItem(\n event.navItemName,\n event.appName,\n event.queryParams,\n false\n );\n }\n\n /**\n * Handler for the Analyze button on the embedded artifact viewer.\n * Captures the live DataSnapshot, creates an analysis conversation with\n * the snapshot attached as input, and emits a navigation request to open\n * the new conversation in the host application.\n */\n public async onAnalyzeRequested(event: { artifactId: string; snapshot: DataSnapshot }): Promise<void> {\n try {\n const result = await this.analyzeService.StartAnalysisConversation({\n snapshot: event.snapshot,\n currentUser: this.currentUser,\n environmentId: this.environmentId,\n });\n\n this.RequestOpenNavItem(\n 'Conversations',\n undefined,\n { conversationId: result.conversationId },\n false,\n );\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to start analysis conversation');\n }\n }\n\n protected override cleanup(): void {\n this.refreshTrigger.complete();\n this.artifactId = null;\n this.versionNumber = undefined;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"query-part.component.d.ts","sourceRoot":"","sources":["../../../src/lib/parts/query-part.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAAa,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAElG,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG1D,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;;AAElG;;;GAGG;AACH,qBA6Ga,kBAAmB,SAAQ,iBAAkB,YAAW,aAAa,EAAE,SAAS;IAC/D,WAAW,EAAG,oBAAoB,CAAC;IAEtD,QAAQ,UAAS;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC9B,WAAW,UAAQ;IAE1B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,gBAAgB,CAA+C;gBAE3D,GAAG,EAAE,iBAAiB;IAIlC,eAAe,IAAI,IAAI;IAMV,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAoDlC,iBAAiB,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI;IAmBzD,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAIhC,YAAY,IAAI,IAAI;IAM3B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,eAAe;cAOJ,OAAO,IAAI,IAAI;yCArHzB,kBAAkB;2CAAlB,kBAAkB;CA0H9B"}
1
+ {"version":3,"file":"query-part.component.d.ts","sourceRoot":"","sources":["../../../src/lib/parts/query-part.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAAa,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAElG,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG1D,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;;AAElG;;;GAGG;AACH,qBA8Fa,kBAAmB,SAAQ,iBAAkB,YAAW,aAAa,EAAE,SAAS;IAC/D,WAAW,EAAG,oBAAoB,CAAC;IAEtD,QAAQ,UAAS;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC9B,WAAW,UAAQ;IAE1B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,gBAAgB,CAA+C;gBAE3D,GAAG,EAAE,iBAAiB;IAIlC,eAAe,IAAI,IAAI;IAMV,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAoDlC,iBAAiB,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI;IAmBzD,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAIhC,YAAY,IAAI,IAAI;IAM3B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,eAAe;cAOJ,OAAO,IAAI,IAAI;yCArHzB,kBAAkB;2CAAlB,kBAAkB;CA0H9B"}
@@ -10,6 +10,7 @@ import { BaseDashboardPart } from './base-dashboard-part';
10
10
  import * as i0 from "@angular/core";
11
11
  import * as i1 from "@memberjunction/ng-shared-generic";
12
12
  import * as i2 from "@memberjunction/ng-query-viewer";
13
+ import * as i3 from "@memberjunction/ng-ui-components";
13
14
  const _c0 = ["queryViewer"];
14
15
  function QueryPartComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
15
16
  i0.ɵɵelementStart(0, "div", 2);
@@ -17,29 +18,17 @@ function QueryPartComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
17
18
  i0.ɵɵelementEnd();
18
19
  } }
19
20
  function QueryPartComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
20
- i0.ɵɵelementStart(0, "div", 3);
21
- i0.ɵɵelement(1, "i", 7);
22
- i0.ɵɵelementStart(2, "span");
23
- i0.ɵɵtext(3);
24
- i0.ɵɵelementEnd()();
21
+ i0.ɵɵelement(0, "mj-empty-state", 3);
25
22
  } if (rf & 2) {
26
23
  const ctx_r0 = i0.ɵɵnextContext();
27
- i0.ɵɵadvance(3);
28
- i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
24
+ i0.ɵɵproperty("Message", ctx_r0.ErrorMessage);
29
25
  } }
30
26
  function QueryPartComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
31
- i0.ɵɵelementStart(0, "div", 4);
32
- i0.ɵɵelement(1, "i", 8);
33
- i0.ɵɵelementStart(2, "h4");
34
- i0.ɵɵtext(3, "No Query Selected");
35
- i0.ɵɵelementEnd();
36
- i0.ɵɵelementStart(4, "p");
37
- i0.ɵɵtext(5, "Click the configure button to select a query for this part.");
38
- i0.ɵɵelementEnd()();
27
+ i0.ɵɵelement(0, "mj-empty-state", 4);
39
28
  } }
40
29
  function QueryPartComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
41
30
  const _r2 = i0.ɵɵgetCurrentView();
42
- i0.ɵɵelementStart(0, "div", 5)(1, "mj-query-viewer", 9, 0);
31
+ i0.ɵɵelementStart(0, "div", 5)(1, "mj-query-viewer", 7, 0);
43
32
  i0.ɵɵlistener("EntityLinkClick", function QueryPartComponent_Conditional_4_Template_mj_query_viewer_EntityLinkClick_1_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onEntityLinkClick($event)); })("QueryError", function QueryPartComponent_Conditional_4_Template_mj_query_viewer_QueryError_1_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onQueryError($event)); });
44
33
  i0.ɵɵelementEnd()();
45
34
  } if (rf & 2) {
@@ -156,11 +145,11 @@ let QueryPartComponent = class QueryPartComponent extends BaseDashboardPart {
156
145
  } if (rf & 2) {
157
146
  let _t;
158
147
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.queryViewer = _t.first);
159
- } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 8, consts: [["queryViewer", ""], [1, "query-part"], [1, "loading-state"], [1, "error-state"], [1, "empty-state"], [1, "query-content"], ["text", "Loading query..."], [1, "fa-solid", "fa-exclamation-triangle"], [1, "fa-solid", "fa-flask"], [3, "EntityLinkClick", "QueryError", "QueryId", "AutoRun", "ShowToolbar", "PersistState", "PersistParameters"]], template: function QueryPartComponent_Template(rf, ctx) { if (rf & 1) {
148
+ } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 8, consts: [["queryViewer", ""], [1, "query-part"], [1, "loading-state"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Title", "Couldn't load query", "Size", "compact", 1, "part-placeholder", 3, "Message"], ["Icon", "fa-solid fa-flask", "Title", "No Query Selected", "Message", "Click the configure button to select a query for this part.", "Size", "compact", 1, "part-placeholder"], [1, "query-content"], ["text", "Loading query..."], [3, "EntityLinkClick", "QueryError", "QueryId", "AutoRun", "ShowToolbar", "PersistState", "PersistParameters"]], template: function QueryPartComponent_Template(rf, ctx) { if (rf & 1) {
160
149
  i0.ɵɵelementStart(0, "div", 1);
161
150
  i0.ɵɵconditionalCreate(1, QueryPartComponent_Conditional_1_Template, 2, 0, "div", 2);
162
- i0.ɵɵconditionalCreate(2, QueryPartComponent_Conditional_2_Template, 4, 1, "div", 3);
163
- i0.ɵɵconditionalCreate(3, QueryPartComponent_Conditional_3_Template, 6, 0, "div", 4);
151
+ i0.ɵɵconditionalCreate(2, QueryPartComponent_Conditional_2_Template, 1, 1, "mj-empty-state", 3);
152
+ i0.ɵɵconditionalCreate(3, QueryPartComponent_Conditional_3_Template, 1, 0, "mj-empty-state", 4);
164
153
  i0.ɵɵconditionalCreate(4, QueryPartComponent_Conditional_4_Template, 3, 5, "div", 5);
165
154
  i0.ɵɵelementEnd();
166
155
  } if (rf & 2) {
@@ -173,7 +162,7 @@ let QueryPartComponent = class QueryPartComponent extends BaseDashboardPart {
173
162
  i0.ɵɵconditional(!ctx.IsLoading && !ctx.ErrorMessage && !ctx.hasQuery ? 3 : -1);
174
163
  i0.ɵɵadvance();
175
164
  i0.ɵɵconditional(!ctx.IsLoading && !ctx.ErrorMessage && ctx.hasQuery && ctx.queryId ? 4 : -1);
176
- } }, dependencies: [i1.LoadingComponent, i2.QueryViewerComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .query-part[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state[_ngcontent-%COMP%], \n .error-state[_ngcontent-%COMP%], \n .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n }\n\n .query-content[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n mj-query-viewer[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }"] });
165
+ } }, dependencies: [i1.LoadingComponent, i2.QueryViewerComponent, i3.MJEmptyStateComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .query-part[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder[_ngcontent-%COMP%] {\n height: 100%;\n }\n\n .query-content[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n mj-query-viewer[_ngcontent-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }"] });
177
166
  };
178
167
  QueryPartComponent = __decorate([
179
168
  RegisterClass(BaseDashboardPart, 'QueryPanelRenderer')
@@ -192,19 +181,23 @@ export { QueryPartComponent };
192
181
 
193
182
  <!-- Error state -->
194
183
  @if (ErrorMessage && !IsLoading) {
195
- <div class="error-state">
196
- <i class="fa-solid fa-exclamation-triangle"></i>
197
- <span>{{ ErrorMessage }}</span>
198
- </div>
184
+ <mj-empty-state
185
+ class="part-placeholder"
186
+ Variant="error"
187
+ Icon="fa-solid fa-triangle-exclamation"
188
+ Title="Couldn't load query"
189
+ [Message]="ErrorMessage"
190
+ Size="compact" />
199
191
  }
200
-
192
+
201
193
  <!-- No query configured -->
202
194
  @if (!IsLoading && !ErrorMessage && !hasQuery) {
203
- <div class="empty-state">
204
- <i class="fa-solid fa-flask"></i>
205
- <h4>No Query Selected</h4>
206
- <p>Click the configure button to select a query for this part.</p>
207
- </div>
195
+ <mj-empty-state
196
+ class="part-placeholder"
197
+ Icon="fa-solid fa-flask"
198
+ Title="No Query Selected"
199
+ Message="Click the configure button to select a query for this part."
200
+ Size="compact" />
208
201
  }
209
202
 
210
203
  <!-- Query Viewer -->
@@ -223,10 +216,10 @@ export { QueryPartComponent };
223
216
  </div>
224
217
  }
225
218
  </div>
226
- `, styles: ["\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .query-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state,\n .error-state,\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state i,\n .empty-state i {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state i {\n color: var(--mj-status-error);\n }\n\n .empty-state h4 {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state p {\n margin: 0;\n font-size: 13px;\n }\n\n .query-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n mj-query-viewer {\n display: block;\n width: 100%;\n height: 100%;\n }\n "] }]
219
+ `, styles: ["\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .query-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder {\n height: 100%;\n }\n\n .query-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n mj-query-viewer {\n display: block;\n width: 100%;\n height: 100%;\n }\n "] }]
227
220
  }], () => [{ type: i0.ChangeDetectorRef }], { queryViewer: [{
228
221
  type: ViewChild,
229
222
  args: ['queryViewer']
230
223
  }] }); })();
231
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(QueryPartComponent, { className: "QueryPartComponent", filePath: "src/lib/parts/query-part.component.ts", lineNumber: 121 }); })();
224
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(QueryPartComponent, { className: "QueryPartComponent", filePath: "src/lib/parts/query-part.component.ts", lineNumber: 106 }); })();
232
225
  //# sourceMappingURL=query-part.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-part.component.js","sourceRoot":"","sources":["../../../src/lib/parts/query-part.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAqB,SAAS,EAA4B,MAAM,eAAe,CAAC;AAClG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;;;;;;IAiB9C,8BAA2B;IACzB,gCAAiD;IACnD,iBAAM;;;IAKN,8BAAyB;IACvB,uBAAgD;IAChD,4BAAM;IAAA,YAAkB;IAC1B,AAD0B,iBAAO,EAC3B;;;IADE,eAAkB;IAAlB,yCAAkB;;;IAM1B,8BAAyB;IACvB,uBAAiC;IACjC,0BAAI;IAAA,iCAAiB;IAAA,iBAAK;IAC1B,yBAAG;IAAA,2EAA2D;IAChE,AADgE,iBAAI,EAC9D;;;;IAMJ,AADF,8BAA2B,4BASa;IAApC,AADA,yNAAmB,gCAAyB,KAAC,kMAC/B,2BAAoB,KAAC;IAEvC,AADE,iBAAkB,EACd;;;IARF,cAAmB;IAInB,AADA,AADA,AADA,AADA,wCAAmB,iBACH,mCACW,sBACN,2BACK;;AA3C1C;;;GAGG;AA8GI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,iBAAiB;IAC3B,WAAW,CAAwB;IAEtD,QAAQ,GAAG,KAAK,CAAC;IACjB,OAAO,GAAkB,IAAI,CAAC;IAC9B,WAAW,GAAG,IAAI,CAAC;IAElB,WAAW,GAAyB,IAAI,CAAC;IACzC,gBAAgB,GAA0C,IAAI,CAAC;IAEvE,YAAY,GAAsB;QAC9B,KAAK,CAAC,GAAG,CAAC,CAAC;IACf,CAAC;IAED,eAAe;QACX,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,WAAW,EAAE,CAAC;QACvB,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,WAAW;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAe,CAAC;QAC7C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,SAAS,CAAuB,CAAC;QAC1D,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,WAAW,CAAuB,CAAC;QAE9D,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;YACzB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;YACzB,OAAO;QACX,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,eAAe,EAAE,CAAC;QAEvB,IAAI,CAAC;YACD,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC;YAE7B,IAAI,OAAO,EAAE,CAAC;gBACV,uCAAuC;gBACvC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,CAAC,eAAe,CAAgB,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;gBACxF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAEpD,IAAI,CAAC,MAAM,EAAE,CAAC;oBACV,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBACvC,CAAC;gBAED,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YAC3B,CAAC;iBAAM,IAAI,SAAS,EAAE,CAAC;gBACnB,kDAAkD;gBAClD,MAAM,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;gBAC5D,IAAI,SAAS,EAAE,CAAC;oBACZ,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,EAAE,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACJ,MAAM,IAAI,KAAK,CAAC,UAAU,SAAS,aAAa,CAAC,CAAC;gBACtD,CAAC;YACL,CAAC;YAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,WAAW,GAAI,MAAM,EAAE,CAAC,uBAAuB,CAAa,KAAK,KAAK,CAAC;YAE5E,iCAAiC;YACjC,MAAM,kBAAkB,GAAI,MAAM,EAAE,CAAC,oBAAoB,CAAY,IAAI,CAAC,CAAC;YAC3E,IAAI,kBAAkB,GAAG,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;YAC9C,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,QAAQ,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACnF,CAAC;IACL,CAAC;IAEM,iBAAiB,CAAC,KAAgC;QACrD,mFAAmF;QACnF,IAAI,CAAC,eAAe,CAAC;YACjB,IAAI,EAAE,mBAAmB;YACzB,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ;SAC3B,CAAC,CAAC;QAEH,wCAAwC;QACxC,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACrC,IAAI,CAAC,uBAAuB,CACxB,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,QAAQ,EACd,MAAM,EACN,KAAK,CACR,CAAC;QACN,CAAC;IACL,CAAC;IAEM,YAAY,CAAC,KAAY;QAC5B,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7D,CAAC;IAEM,YAAY;QACf,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QAC/B,CAAC;IACL,CAAC;IAEO,gBAAgB,CAAC,OAAe;QACpC,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YACd,IAAI,CAAC,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;gBACrC,IAAI,CAAC,YAAY,EAAE,CAAC;YACxB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;QACvB,CAAC;IACL,CAAC;IAEO,eAAe;QACnB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACrC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;QACjC,CAAC;IACL,CAAC;IAEkB,OAAO;QACtB,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACxB,CAAC;4GAzHQ,kBAAkB;6DAAlB,kBAAkB;;;;;;YAxGvB,8BAAiF;YAE/E,oFAAiB;YAOjB,oFAAkC;YAQlC,oFAAgD;YAShD,oFAA0D;YAc5D,iBAAM;;YAxC8C,AAA5B,wCAA2B,2BAA6B;YAE9E,cAIC;YAJD,wCAIC;YAGD,cAKC;YALD,6DAKC;YAGD,cAMC;YAND,+EAMC;YAGD,cAaC;YAbD,6FAaC;;;AAiEE,kBAAkB;IA7G9B,aAAa,CAAC,iBAAiB,EAAE,oBAAoB,CAAC;GA6G1C,kBAAkB,CA0H9B;;iFA1HY,kBAAkB;cA5G9B,SAAS;6BACI,KAAK,YACL,eAAe,YACf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA0CL;;kBAgEJ,SAAS;mBAAC,aAAa;;kFADf,kBAAkB","sourcesContent":["import { Component, ChangeDetectorRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseDashboardPart } from './base-dashboard-part';\nimport { PanelConfig } from '../models/dashboard-types';\nimport { MJQueryEntity } from '@memberjunction/core-entities';\nimport { QueryViewerComponent, QueryEntityLinkClickEvent } from '@memberjunction/ng-query-viewer';\n\n/**\n * Runtime renderer for Query dashboard parts.\n * Displays query results using mj-query-viewer with parameter controls and auto-refresh support.\n */\n@RegisterClass(BaseDashboardPart, 'QueryPanelRenderer')\n@Component({\n standalone: false,\n selector: 'mj-query-part',\n template: `\n <div class=\"query-part\" [class.loading]=\"IsLoading\" [class.error]=\"ErrorMessage\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading query...\"></mj-loading>\n </div>\n }\n \n <!-- Error state -->\n @if (ErrorMessage && !IsLoading) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n </div>\n }\n \n <!-- No query configured -->\n @if (!IsLoading && !ErrorMessage && !hasQuery) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-flask\"></i>\n <h4>No Query Selected</h4>\n <p>Click the configure button to select a query for this part.</p>\n </div>\n }\n \n <!-- Query Viewer -->\n @if (!IsLoading && !ErrorMessage && hasQuery && queryId) {\n <div class=\"query-content\">\n <mj-query-viewer\n #queryViewer\n [QueryId]=\"queryId\"\n [AutoRun]=\"true\"\n [ShowToolbar]=\"showToolbar\"\n [PersistState]=\"true\"\n [PersistParameters]=\"true\"\n (EntityLinkClick)=\"onEntityLinkClick($event)\"\n (QueryError)=\"onQueryError($event)\">\n </mj-query-viewer>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .query-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state,\n .error-state,\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state i,\n .empty-state i {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state i {\n color: var(--mj-status-error);\n }\n\n .empty-state h4 {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state p {\n margin: 0;\n font-size: 13px;\n }\n\n .query-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n mj-query-viewer {\n display: block;\n width: 100%;\n height: 100%;\n }\n `]\n})\nexport class QueryPartComponent extends BaseDashboardPart implements AfterViewInit, OnDestroy {\n @ViewChild('queryViewer') queryViewer!: QueryViewerComponent;\n\n public hasQuery = false;\n public queryId: string | null = null;\n public showToolbar = true;\n\n private queryEntity: MJQueryEntity | null = null;\n private autoRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(cdr: ChangeDetectorRef) {\n super(cdr);\n }\n\n ngAfterViewInit(): void {\n if (this.Panel) {\n this.loadContent();\n }\n }\n\n public async loadContent(): Promise<void> {\n const config = this.getConfig<PanelConfig>();\n const queryId = config?.['queryId'] as string | undefined;\n const queryName = config?.['queryName'] as string | undefined;\n\n if (!queryId && !queryName) {\n this.hasQuery = false;\n this.cdr.detectChanges();\n return;\n }\n\n this.setLoading(true);\n this.stopAutoRefresh();\n\n try {\n const p = this.ProviderToUse;\n\n if (queryId) {\n // Load query by ID to verify it exists\n this.queryEntity = await p.GetEntityObject<MJQueryEntity>('MJ: Queries', p.CurrentUser);\n const loaded = await this.queryEntity.Load(queryId);\n\n if (!loaded) {\n throw new Error('Query not found');\n }\n\n this.queryId = queryId;\n } else if (queryName) {\n // Query by name - find the query ID from metadata\n const queryInfo = p.Queries.find(q => q.Name === queryName);\n if (queryInfo) {\n this.queryId = queryInfo.ID;\n } else {\n throw new Error(`Query \"${queryName}\" not found`);\n }\n }\n\n this.hasQuery = true;\n this.showToolbar = (config?.['showParameterControls'] as boolean) !== false;\n\n // Set auto-refresh if configured\n const autoRefreshSeconds = (config?.['autoRefreshSeconds'] as number) || 0;\n if (autoRefreshSeconds > 0) {\n this.startAutoRefresh(autoRefreshSeconds);\n }\n\n this.setLoading(false);\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to load query');\n }\n }\n\n public onEntityLinkClick(event: QueryEntityLinkClickEvent): void {\n // Emit data change event with clicked entity info (for any listeners that need it)\n this.emitDataChanged({\n type: 'entity-link-click',\n entityName: event.entityName,\n recordId: event.recordId\n });\n\n // Request navigation to open the record\n if (event.entityName && event.recordId) {\n this.RequestOpenEntityRecord(\n event.entityName,\n event.recordId,\n 'view',\n false\n );\n }\n }\n\n public onQueryError(error: Error): void {\n console.error('[QueryPart] Query error:', error.message);\n }\n\n public refreshQuery(): void {\n if (this.queryViewer) {\n this.queryViewer.Refresh();\n }\n }\n\n private startAutoRefresh(seconds: number): void {\n this.stopAutoRefresh();\n if (seconds > 0) {\n this.autoRefreshTimer = setInterval(() => {\n this.refreshQuery();\n }, seconds * 1000);\n }\n }\n\n private stopAutoRefresh(): void {\n if (this.autoRefreshTimer) {\n clearInterval(this.autoRefreshTimer);\n this.autoRefreshTimer = null;\n }\n }\n\n protected override cleanup(): void {\n this.stopAutoRefresh();\n this.queryEntity = null;\n this.queryId = null;\n }\n}\n"]}
1
+ {"version":3,"file":"query-part.component.js","sourceRoot":"","sources":["../../../src/lib/parts/query-part.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ChangeDetectorRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseDashboardPart } from './base-dashboard-part';\nimport { PanelConfig } from '../models/dashboard-types';\nimport { MJQueryEntity } from '@memberjunction/core-entities';\nimport { QueryViewerComponent, QueryEntityLinkClickEvent } from '@memberjunction/ng-query-viewer';\n\n/**\n * Runtime renderer for Query dashboard parts.\n * Displays query results using mj-query-viewer with parameter controls and auto-refresh support.\n */\n@RegisterClass(BaseDashboardPart, 'QueryPanelRenderer')\n@Component({\n standalone: false,\n selector: 'mj-query-part',\n template: `\n <div class=\"query-part\" [class.loading]=\"IsLoading\" [class.error]=\"ErrorMessage\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading query...\"></mj-loading>\n </div>\n }\n \n <!-- Error state -->\n @if (ErrorMessage && !IsLoading) {\n <mj-empty-state\n class=\"part-placeholder\"\n Variant=\"error\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n Title=\"Couldn't load query\"\n [Message]=\"ErrorMessage\"\n Size=\"compact\" />\n }\n\n <!-- No query configured -->\n @if (!IsLoading && !ErrorMessage && !hasQuery) {\n <mj-empty-state\n class=\"part-placeholder\"\n Icon=\"fa-solid fa-flask\"\n Title=\"No Query Selected\"\n Message=\"Click the configure button to select a query for this part.\"\n Size=\"compact\" />\n }\n \n <!-- Query Viewer -->\n @if (!IsLoading && !ErrorMessage && hasQuery && queryId) {\n <div class=\"query-content\">\n <mj-query-viewer\n #queryViewer\n [QueryId]=\"queryId\"\n [AutoRun]=\"true\"\n [ShowToolbar]=\"showToolbar\"\n [PersistState]=\"true\"\n [PersistParameters]=\"true\"\n (EntityLinkClick)=\"onEntityLinkClick($event)\"\n (QueryError)=\"onQueryError($event)\">\n </mj-query-viewer>\n </div>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .query-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder {\n height: 100%;\n }\n\n .query-content {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n }\n\n mj-query-viewer {\n display: block;\n width: 100%;\n height: 100%;\n }\n `]\n})\nexport class QueryPartComponent extends BaseDashboardPart implements AfterViewInit, OnDestroy {\n @ViewChild('queryViewer') queryViewer!: QueryViewerComponent;\n\n public hasQuery = false;\n public queryId: string | null = null;\n public showToolbar = true;\n\n private queryEntity: MJQueryEntity | null = null;\n private autoRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(cdr: ChangeDetectorRef) {\n super(cdr);\n }\n\n ngAfterViewInit(): void {\n if (this.Panel) {\n this.loadContent();\n }\n }\n\n public async loadContent(): Promise<void> {\n const config = this.getConfig<PanelConfig>();\n const queryId = config?.['queryId'] as string | undefined;\n const queryName = config?.['queryName'] as string | undefined;\n\n if (!queryId && !queryName) {\n this.hasQuery = false;\n this.cdr.detectChanges();\n return;\n }\n\n this.setLoading(true);\n this.stopAutoRefresh();\n\n try {\n const p = this.ProviderToUse;\n\n if (queryId) {\n // Load query by ID to verify it exists\n this.queryEntity = await p.GetEntityObject<MJQueryEntity>('MJ: Queries', p.CurrentUser);\n const loaded = await this.queryEntity.Load(queryId);\n\n if (!loaded) {\n throw new Error('Query not found');\n }\n\n this.queryId = queryId;\n } else if (queryName) {\n // Query by name - find the query ID from metadata\n const queryInfo = p.Queries.find(q => q.Name === queryName);\n if (queryInfo) {\n this.queryId = queryInfo.ID;\n } else {\n throw new Error(`Query \"${queryName}\" not found`);\n }\n }\n\n this.hasQuery = true;\n this.showToolbar = (config?.['showParameterControls'] as boolean) !== false;\n\n // Set auto-refresh if configured\n const autoRefreshSeconds = (config?.['autoRefreshSeconds'] as number) || 0;\n if (autoRefreshSeconds > 0) {\n this.startAutoRefresh(autoRefreshSeconds);\n }\n\n this.setLoading(false);\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to load query');\n }\n }\n\n public onEntityLinkClick(event: QueryEntityLinkClickEvent): void {\n // Emit data change event with clicked entity info (for any listeners that need it)\n this.emitDataChanged({\n type: 'entity-link-click',\n entityName: event.entityName,\n recordId: event.recordId\n });\n\n // Request navigation to open the record\n if (event.entityName && event.recordId) {\n this.RequestOpenEntityRecord(\n event.entityName,\n event.recordId,\n 'view',\n false\n );\n }\n }\n\n public onQueryError(error: Error): void {\n console.error('[QueryPart] Query error:', error.message);\n }\n\n public refreshQuery(): void {\n if (this.queryViewer) {\n this.queryViewer.Refresh();\n }\n }\n\n private startAutoRefresh(seconds: number): void {\n this.stopAutoRefresh();\n if (seconds > 0) {\n this.autoRefreshTimer = setInterval(() => {\n this.refreshQuery();\n }, seconds * 1000);\n }\n }\n\n private stopAutoRefresh(): void {\n if (this.autoRefreshTimer) {\n clearInterval(this.autoRefreshTimer);\n this.autoRefreshTimer = null;\n }\n }\n\n protected override cleanup(): void {\n this.stopAutoRefresh();\n this.queryEntity = null;\n this.queryId = null;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"view-part.component.d.ts","sourceRoot":"","sources":["../../../src/lib/parts/view-part.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;;AAEvH;;;GAGG;AACH,qBAiGa,iBAAkB,SAAQ,iBAAkB,YAAW,aAAa,EAAE,SAAS;IACjF,OAAO,UAAS;IAChB,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAAQ;IACnD,UAAU,EAAE,UAAU,GAAG,IAAI,CAAQ;gBAEhC,GAAG,EAAE,iBAAiB;IAIlC,eAAe,IAAI,IAAI;IAMV,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IA2DlC,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IASlD,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAmBrD;;;;;;OAMG;IACI,4BAA4B,CAAC,GAAG,EAAE,2BAA2B,GAAG,IAAI;cAWxD,OAAO,IAAI,IAAI;yCAxHzB,iBAAiB;2CAAjB,iBAAiB;CA6H7B"}
1
+ {"version":3,"file":"view-part.component.d.ts","sourceRoot":"","sources":["../../../src/lib/parts/view-part.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEvF,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;;AAEvH;;;GAGG;AACH,qBAkFa,iBAAkB,SAAQ,iBAAkB,YAAW,aAAa,EAAE,SAAS;IACjF,OAAO,UAAS;IAChB,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAAQ;IACnD,UAAU,EAAE,UAAU,GAAG,IAAI,CAAQ;gBAEhC,GAAG,EAAE,iBAAiB;IAIlC,eAAe,IAAI,IAAI;IAMV,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IA2DlC,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IASlD,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAmBrD;;;;;;OAMG;IACI,4BAA4B,CAAC,GAAG,EAAE,2BAA2B,GAAG,IAAI;cAWxD,OAAO,IAAI,IAAI;yCAxHzB,iBAAiB;2CAAjB,iBAAiB;CA6H7B"}
@@ -10,35 +10,24 @@ import { BaseDashboardPart } from './base-dashboard-part';
10
10
  import * as i0 from "@angular/core";
11
11
  import * as i1 from "@memberjunction/ng-shared-generic";
12
12
  import * as i2 from "@memberjunction/ng-entity-viewer";
13
+ import * as i3 from "@memberjunction/ng-ui-components";
13
14
  function ViewPartComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
14
15
  i0.ɵɵelementStart(0, "div", 1);
15
16
  i0.ɵɵelement(1, "mj-loading", 5);
16
17
  i0.ɵɵelementEnd();
17
18
  } }
18
19
  function ViewPartComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
19
- i0.ɵɵelementStart(0, "div", 2);
20
- i0.ɵɵelement(1, "i", 6);
21
- i0.ɵɵelementStart(2, "span");
22
- i0.ɵɵtext(3);
23
- i0.ɵɵelementEnd()();
20
+ i0.ɵɵelement(0, "mj-empty-state", 2);
24
21
  } if (rf & 2) {
25
22
  const ctx_r0 = i0.ɵɵnextContext();
26
- i0.ɵɵadvance(3);
27
- i0.ɵɵtextInterpolate(ctx_r0.ErrorMessage);
23
+ i0.ɵɵproperty("Message", ctx_r0.ErrorMessage);
28
24
  } }
29
25
  function ViewPartComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
30
- i0.ɵɵelementStart(0, "div", 3);
31
- i0.ɵɵelement(1, "i", 7);
32
- i0.ɵɵelementStart(2, "h4");
33
- i0.ɵɵtext(3, "No View Selected");
34
- i0.ɵɵelementEnd();
35
- i0.ɵɵelementStart(4, "p");
36
- i0.ɵɵtext(5, "Click the configure button to select a view for this part.");
37
- i0.ɵɵelementEnd()();
26
+ i0.ɵɵelement(0, "mj-empty-state", 3);
38
27
  } }
39
28
  function ViewPartComponent_Conditional_4_Template(rf, ctx) { if (rf & 1) {
40
29
  const _r2 = i0.ɵɵgetCurrentView();
41
- i0.ɵɵelementStart(0, "mj-entity-viewer", 8);
30
+ i0.ɵɵelementStart(0, "mj-entity-viewer", 6);
42
31
  i0.ɵɵlistener("RecordSelected", function ViewPartComponent_Conditional_4_Template_mj_entity_viewer_RecordSelected_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onRecordSelected($event)); })("RecordOpened", function ViewPartComponent_Conditional_4_Template_mj_entity_viewer_RecordOpened_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onRecordOpened($event)); })("OpenRelatedRecordRequested", function ViewPartComponent_Conditional_4_Template_mj_entity_viewer_OpenRelatedRecordRequested_0_listener($event) { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.onOpenRelatedRecordRequested($event)); });
43
32
  i0.ɵɵelementEnd();
44
33
  } if (rf & 2) {
@@ -151,11 +140,11 @@ let ViewPartComponent = class ViewPartComponent extends BaseDashboardPart {
151
140
  this.entityInfo = null;
152
141
  }
153
142
  static ɵfac = function ViewPartComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ViewPartComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
154
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ViewPartComponent, selectors: [["mj-view-part"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 8, consts: [[1, "view-part"], [1, "loading-state"], [1, "error-state"], [1, "empty-state"], [3, "Entity", "ViewEntity"], ["text", "Loading view..."], [1, "fa-solid", "fa-exclamation-triangle"], [1, "fa-solid", "fa-table"], [3, "RecordSelected", "RecordOpened", "OpenRelatedRecordRequested", "Entity", "ViewEntity"]], template: function ViewPartComponent_Template(rf, ctx) { if (rf & 1) {
143
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ViewPartComponent, selectors: [["mj-view-part"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 5, vars: 8, consts: [[1, "view-part"], [1, "loading-state"], ["Variant", "error", "Icon", "fa-solid fa-triangle-exclamation", "Title", "Couldn't load view", "Size", "compact", 1, "part-placeholder", 3, "Message"], ["Icon", "fa-solid fa-table", "Title", "No View Selected", "Message", "Click the configure button to select a view for this part.", "Size", "compact", 1, "part-placeholder"], [3, "Entity", "ViewEntity"], ["text", "Loading view..."], [3, "RecordSelected", "RecordOpened", "OpenRelatedRecordRequested", "Entity", "ViewEntity"]], template: function ViewPartComponent_Template(rf, ctx) { if (rf & 1) {
155
144
  i0.ɵɵelementStart(0, "div", 0);
156
145
  i0.ɵɵconditionalCreate(1, ViewPartComponent_Conditional_1_Template, 2, 0, "div", 1);
157
- i0.ɵɵconditionalCreate(2, ViewPartComponent_Conditional_2_Template, 4, 1, "div", 2);
158
- i0.ɵɵconditionalCreate(3, ViewPartComponent_Conditional_3_Template, 6, 0, "div", 3);
146
+ i0.ɵɵconditionalCreate(2, ViewPartComponent_Conditional_2_Template, 1, 1, "mj-empty-state", 2);
147
+ i0.ɵɵconditionalCreate(3, ViewPartComponent_Conditional_3_Template, 1, 0, "mj-empty-state", 3);
159
148
  i0.ɵɵconditionalCreate(4, ViewPartComponent_Conditional_4_Template, 1, 2, "mj-entity-viewer", 4);
160
149
  i0.ɵɵelementEnd();
161
150
  } if (rf & 2) {
@@ -168,7 +157,7 @@ let ViewPartComponent = class ViewPartComponent extends BaseDashboardPart {
168
157
  i0.ɵɵconditional(!ctx.IsLoading && !ctx.ErrorMessage && !ctx.hasView ? 3 : -1);
169
158
  i0.ɵɵadvance();
170
159
  i0.ɵɵconditional(!ctx.IsLoading && !ctx.ErrorMessage && ctx.hasView && ctx.entityInfo ? 4 : -1);
171
- } }, dependencies: [i1.LoadingComponent, i2.EntityViewerComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .view-part[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state[_ngcontent-%COMP%], \n .error-state[_ngcontent-%COMP%], \n .empty-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%], \n .empty-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n }\n\n .empty-state[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state[_ngcontent-%COMP%] p[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n }\n\n mj-entity-viewer[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n }"] });
160
+ } }, dependencies: [i1.LoadingComponent, i2.EntityViewerComponent, i3.MJEmptyStateComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .view-part[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder[_ngcontent-%COMP%] {\n height: 100%;\n }\n\n mj-entity-viewer[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n }"] });
172
161
  };
173
162
  ViewPartComponent = __decorate([
174
163
  RegisterClass(BaseDashboardPart, 'ViewPanelRenderer')
@@ -187,19 +176,23 @@ export { ViewPartComponent };
187
176
 
188
177
  <!-- Error state -->
189
178
  @if (ErrorMessage && !IsLoading) {
190
- <div class="error-state">
191
- <i class="fa-solid fa-exclamation-triangle"></i>
192
- <span>{{ ErrorMessage }}</span>
193
- </div>
179
+ <mj-empty-state
180
+ class="part-placeholder"
181
+ Variant="error"
182
+ Icon="fa-solid fa-triangle-exclamation"
183
+ Title="Couldn't load view"
184
+ [Message]="ErrorMessage"
185
+ Size="compact" />
194
186
  }
195
-
187
+
196
188
  <!-- No view configured -->
197
189
  @if (!IsLoading && !ErrorMessage && !hasView) {
198
- <div class="empty-state">
199
- <i class="fa-solid fa-table"></i>
200
- <h4>No View Selected</h4>
201
- <p>Click the configure button to select a view for this part.</p>
202
- </div>
190
+ <mj-empty-state
191
+ class="part-placeholder"
192
+ Icon="fa-solid fa-table"
193
+ Title="No View Selected"
194
+ Message="Click the configure button to select a view for this part."
195
+ Size="compact" />
203
196
  }
204
197
 
205
198
  <!-- Entity Viewer -->
@@ -213,7 +206,7 @@ export { ViewPartComponent };
213
206
  </mj-entity-viewer>
214
207
  }
215
208
  </div>
216
- `, styles: ["\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .view-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state,\n .error-state,\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state i,\n .empty-state i {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state i {\n color: var(--mj-status-error);\n }\n\n .empty-state h4 {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state p {\n margin: 0;\n font-size: 13px;\n }\n\n mj-entity-viewer {\n flex: 1;\n min-height: 0;\n }\n "] }]
209
+ `, styles: ["\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .view-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder {\n height: 100%;\n }\n\n mj-entity-viewer {\n flex: 1;\n min-height: 0;\n }\n "] }]
217
210
  }], () => [{ type: i0.ChangeDetectorRef }], null); })();
218
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ViewPartComponent, { className: "ViewPartComponent", filePath: "src/lib/parts/view-part.component.ts", lineNumber: 110 }); })();
211
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ViewPartComponent, { className: "ViewPartComponent", filePath: "src/lib/parts/view-part.component.ts", lineNumber: 95 }); })();
219
212
  //# sourceMappingURL=view-part.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"view-part.component.js","sourceRoot":"","sources":["../../../src/lib/parts/view-part.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ChangeDetectorRef, AfterViewInit, OnDestroy } from '@angular/core';\nimport { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { BaseDashboardPart } from './base-dashboard-part';\nimport { PanelConfig } from '../models/dashboard-types';\nimport { EntityInfo } from '@memberjunction/core';\nimport { MJUserViewEntityExtended } from '@memberjunction/core-entities';\nimport { RecordSelectedEvent, RecordOpenedEvent, ViewRelatedRecordNavigation } from '@memberjunction/ng-entity-viewer';\n\n/**\n * Runtime renderer for View dashboard parts.\n * Displays entity data using mj-entity-viewer with grid, cards, or timeline layout.\n */\n@RegisterClass(BaseDashboardPart, 'ViewPanelRenderer')\n@Component({\n standalone: false,\n selector: 'mj-view-part',\n template: `\n <div class=\"view-part\" [class.loading]=\"IsLoading\" [class.error]=\"ErrorMessage\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading view...\"></mj-loading>\n </div>\n }\n \n <!-- Error state -->\n @if (ErrorMessage && !IsLoading) {\n <div class=\"error-state\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n <span>{{ ErrorMessage }}</span>\n </div>\n }\n \n <!-- No view configured -->\n @if (!IsLoading && !ErrorMessage && !hasView) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-table\"></i>\n <h4>No View Selected</h4>\n <p>Click the configure button to select a view for this part.</p>\n </div>\n }\n \n <!-- Entity Viewer -->\n @if (!IsLoading && !ErrorMessage && hasView && entityInfo) {\n <mj-entity-viewer\n [Entity]=\"entityInfo\"\n [ViewEntity]=\"viewEntity\"\n (RecordSelected)=\"onRecordSelected($event)\"\n (RecordOpened)=\"onRecordOpened($event)\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecordRequested($event)\">\n </mj-entity-viewer>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .view-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state,\n .error-state,\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .error-state i,\n .empty-state i {\n font-size: 48px;\n color: var(--mj-text-muted);\n margin-bottom: 16px;\n }\n\n .error-state i {\n color: var(--mj-status-error);\n }\n\n .empty-state h4 {\n margin: 0 0 8px 0;\n color: var(--mj-text-primary);\n }\n\n .empty-state p {\n margin: 0;\n font-size: 13px;\n }\n\n mj-entity-viewer {\n flex: 1;\n min-height: 0;\n }\n `]\n})\nexport class ViewPartComponent extends BaseDashboardPart implements AfterViewInit, OnDestroy {\n public hasView = false;\n public viewEntity: MJUserViewEntityExtended | null = null;\n public entityInfo: EntityInfo | null = null;\n\n constructor(cdr: ChangeDetectorRef) {\n super(cdr);\n }\n\n ngAfterViewInit(): void {\n if (this.Panel) {\n this.loadContent();\n }\n }\n\n public async loadContent(): Promise<void> {\n const config = this.getConfig<PanelConfig>();\n const viewId = config?.['viewId'] as string | undefined;\n const entityName = config?.['entityName'] as string | undefined;\n\n if (!viewId && !entityName) {\n this.hasView = false;\n this.cdr.detectChanges();\n return;\n }\n\n this.setLoading(true);\n\n try {\n const p = this.ProviderToUse;\n\n if (viewId) {\n // Load saved view by ID\n const viewEntity = await p.GetEntityObject<MJUserViewEntityExtended>('MJ: User Views', p.CurrentUser);\n const loaded = await viewEntity.Load(viewId);\n this.viewEntity = viewEntity; // IMPORTANT - only set this.viewEntity AFTER we have it loaded in the above\n\n if (!loaded) {\n throw new Error('View not found');\n }\n\n // Get entity info from the view - prefer ViewEntityInfo if available (set by MJUserViewEntityExtended.Load)\n // Fall back to looking up by Entity name (virtual field) or EntityID\n if (viewEntity.ViewEntityInfo) {\n this.entityInfo = viewEntity.ViewEntityInfo;\n } else if (viewEntity.Entity) {\n this.entityInfo = p.EntityByName(viewEntity!.Entity) || null;\n } else if (viewEntity.EntityID) {\n // Last resort: look up by EntityID\n this.entityInfo = p.Entities.find(e => UUIDsEqual(e.ID, viewEntity!.EntityID)) || null;\n }\n\n if (!this.entityInfo) {\n throw new Error(`Could not determine entity for view \"${this.viewEntity.Name}\" (ID: ${viewId})`);\n }\n } else if (entityName) {\n // Create dynamic view for entity (no saved view)\n this.entityInfo = p.EntityByName(entityName) || null;\n\n if (!this.entityInfo) {\n throw new Error(`Entity \"${entityName}\" not found`);\n }\n\n // No viewEntity means the entity-viewer will show all records\n this.viewEntity = null;\n }\n\n this.hasView = true;\n this.setLoading(false);\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to load view');\n }\n }\n\n public onRecordSelected(event: RecordSelectedEvent): void {\n // Emit data change event with selected record\n this.emitDataChanged({\n type: 'record-selected',\n record: event.record,\n primaryKey: event.record?.PrimaryKey\n });\n }\n\n public onRecordOpened(event: RecordOpenedEvent): void {\n // Emit data change event for record open (for any listeners that need it)\n this.emitDataChanged({\n type: 'record-opened',\n record: event.record,\n primaryKey: event.record?.PrimaryKey\n });\n\n // Request navigation to open the record\n if (event.entity && event.compositeKey) {\n this.RequestOpenEntityRecord(\n event.entity.Name,\n event.compositeKey.ToURLSegment(),\n 'view',\n false\n );\n }\n }\n\n /**\n * Handle a plug-in renderer's request (bubbled up via the inner entity-viewer) to open a\n * *related* record on a (possibly different) entity — e.g. a grid foreign-key drill-through.\n * Requests navigation through the dashboard-part routing contract.\n *\n * @param nav the related-record navigation payload: the target entity name and the record's key.\n */\n public onOpenRelatedRecordRequested(nav: ViewRelatedRecordNavigation): void {\n if (nav?.entityName && nav.recordKey != null) {\n this.RequestOpenEntityRecord(\n nav.entityName,\n String(nav.recordKey),\n 'view',\n false\n );\n }\n }\n\n protected override cleanup(): void {\n // EntityViewer handles its own cleanup\n this.viewEntity = null;\n this.entityInfo = null;\n }\n}\n"]}
1
+ {"version":3,"file":"view-part.component.js","sourceRoot":"","sources":["../../../src/lib/parts/view-part.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ChangeDetectorRef, AfterViewInit, OnDestroy } from '@angular/core';\nimport { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { BaseDashboardPart } from './base-dashboard-part';\nimport { PanelConfig } from '../models/dashboard-types';\nimport { EntityInfo } from '@memberjunction/core';\nimport { MJUserViewEntityExtended } from '@memberjunction/core-entities';\nimport { RecordSelectedEvent, RecordOpenedEvent, ViewRelatedRecordNavigation } from '@memberjunction/ng-entity-viewer';\n\n/**\n * Runtime renderer for View dashboard parts.\n * Displays entity data using mj-entity-viewer with grid, cards, or timeline layout.\n */\n@RegisterClass(BaseDashboardPart, 'ViewPanelRenderer')\n@Component({\n standalone: false,\n selector: 'mj-view-part',\n template: `\n <div class=\"view-part\" [class.loading]=\"IsLoading\" [class.error]=\"ErrorMessage\">\n <!-- Loading state -->\n @if (IsLoading) {\n <div class=\"loading-state\">\n <mj-loading text=\"Loading view...\"></mj-loading>\n </div>\n }\n \n <!-- Error state -->\n @if (ErrorMessage && !IsLoading) {\n <mj-empty-state\n class=\"part-placeholder\"\n Variant=\"error\"\n Icon=\"fa-solid fa-triangle-exclamation\"\n Title=\"Couldn't load view\"\n [Message]=\"ErrorMessage\"\n Size=\"compact\" />\n }\n\n <!-- No view configured -->\n @if (!IsLoading && !ErrorMessage && !hasView) {\n <mj-empty-state\n class=\"part-placeholder\"\n Icon=\"fa-solid fa-table\"\n Title=\"No View Selected\"\n Message=\"Click the configure button to select a view for this part.\"\n Size=\"compact\" />\n }\n \n <!-- Entity Viewer -->\n @if (!IsLoading && !ErrorMessage && hasView && entityInfo) {\n <mj-entity-viewer\n [Entity]=\"entityInfo\"\n [ViewEntity]=\"viewEntity\"\n (RecordSelected)=\"onRecordSelected($event)\"\n (RecordOpened)=\"onRecordOpened($event)\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecordRequested($event)\">\n </mj-entity-viewer>\n }\n </div>\n `,\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .view-part {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface);\n }\n\n .loading-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--mj-text-secondary);\n text-align: center;\n padding: 24px;\n }\n\n .part-placeholder {\n height: 100%;\n }\n\n mj-entity-viewer {\n flex: 1;\n min-height: 0;\n }\n `]\n})\nexport class ViewPartComponent extends BaseDashboardPart implements AfterViewInit, OnDestroy {\n public hasView = false;\n public viewEntity: MJUserViewEntityExtended | null = null;\n public entityInfo: EntityInfo | null = null;\n\n constructor(cdr: ChangeDetectorRef) {\n super(cdr);\n }\n\n ngAfterViewInit(): void {\n if (this.Panel) {\n this.loadContent();\n }\n }\n\n public async loadContent(): Promise<void> {\n const config = this.getConfig<PanelConfig>();\n const viewId = config?.['viewId'] as string | undefined;\n const entityName = config?.['entityName'] as string | undefined;\n\n if (!viewId && !entityName) {\n this.hasView = false;\n this.cdr.detectChanges();\n return;\n }\n\n this.setLoading(true);\n\n try {\n const p = this.ProviderToUse;\n\n if (viewId) {\n // Load saved view by ID\n const viewEntity = await p.GetEntityObject<MJUserViewEntityExtended>('MJ: User Views', p.CurrentUser);\n const loaded = await viewEntity.Load(viewId);\n this.viewEntity = viewEntity; // IMPORTANT - only set this.viewEntity AFTER we have it loaded in the above\n\n if (!loaded) {\n throw new Error('View not found');\n }\n\n // Get entity info from the view - prefer ViewEntityInfo if available (set by MJUserViewEntityExtended.Load)\n // Fall back to looking up by Entity name (virtual field) or EntityID\n if (viewEntity.ViewEntityInfo) {\n this.entityInfo = viewEntity.ViewEntityInfo;\n } else if (viewEntity.Entity) {\n this.entityInfo = p.EntityByName(viewEntity!.Entity) || null;\n } else if (viewEntity.EntityID) {\n // Last resort: look up by EntityID\n this.entityInfo = p.Entities.find(e => UUIDsEqual(e.ID, viewEntity!.EntityID)) || null;\n }\n\n if (!this.entityInfo) {\n throw new Error(`Could not determine entity for view \"${this.viewEntity.Name}\" (ID: ${viewId})`);\n }\n } else if (entityName) {\n // Create dynamic view for entity (no saved view)\n this.entityInfo = p.EntityByName(entityName) || null;\n\n if (!this.entityInfo) {\n throw new Error(`Entity \"${entityName}\" not found`);\n }\n\n // No viewEntity means the entity-viewer will show all records\n this.viewEntity = null;\n }\n\n this.hasView = true;\n this.setLoading(false);\n } catch (error) {\n this.setError(error instanceof Error ? error.message : 'Failed to load view');\n }\n }\n\n public onRecordSelected(event: RecordSelectedEvent): void {\n // Emit data change event with selected record\n this.emitDataChanged({\n type: 'record-selected',\n record: event.record,\n primaryKey: event.record?.PrimaryKey\n });\n }\n\n public onRecordOpened(event: RecordOpenedEvent): void {\n // Emit data change event for record open (for any listeners that need it)\n this.emitDataChanged({\n type: 'record-opened',\n record: event.record,\n primaryKey: event.record?.PrimaryKey\n });\n\n // Request navigation to open the record\n if (event.entity && event.compositeKey) {\n this.RequestOpenEntityRecord(\n event.entity.Name,\n event.compositeKey.ToURLSegment(),\n 'view',\n false\n );\n }\n }\n\n /**\n * Handle a plug-in renderer's request (bubbled up via the inner entity-viewer) to open a\n * *related* record on a (possibly different) entity — e.g. a grid foreign-key drill-through.\n * Requests navigation through the dashboard-part routing contract.\n *\n * @param nav the related-record navigation payload: the target entity name and the record's key.\n */\n public onOpenRelatedRecordRequested(nav: ViewRelatedRecordNavigation): void {\n if (nav?.entityName && nav.recordKey != null) {\n this.RequestOpenEntityRecord(\n nav.entityName,\n String(nav.recordKey),\n 'view',\n false\n );\n }\n }\n\n protected override cleanup(): void {\n // EntityViewer handles its own cleanup\n this.viewEntity = null;\n this.entityInfo = null;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"weburl-part.component.d.ts","sourceRoot":"","sources":["../../../src/lib/parts/weburl-part.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAAE,UAAU,EAAa,aAAa,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;;AAG1D;;;GAGG;AACH,qBAoOa,mBAAoB,SAAQ,iBAAkB,YAAW,aAAa;IAC1D,SAAS,EAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAExD,OAAO,EAAE,eAAe,GAAG,IAAI,CAAQ;IACvC,MAAM,EAAE,MAAM,CAAM;IACpB,WAAW,EAAE,UAAU,GAAG,QAAQ,GAAG,YAAY,CAAc;IAC/D,eAAe,EAAE,OAAO,CAAQ;IAChC,gBAAgB,EAAE,OAAO,CAAS;IAEzC,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,YAAY,CAAkB;gBAE1B,GAAG,EAAE,iBAAiB,EAAE,SAAS,EAAE,YAAY;IAK3D,eAAe,IAAI,IAAI;IAOV,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAkDzC;;;OAGG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACI,YAAY,IAAI,IAAI;IAgB3B;;OAEG;IACI,aAAa,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI;yCA9GhC,mBAAmB;2CAAnB,mBAAmB;CAkH/B"}
1
+ {"version":3,"file":"weburl-part.component.d.ts","sourceRoot":"","sources":["../../../src/lib/parts/weburl-part.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,iBAAiB,EAAE,UAAU,EAAa,aAAa,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;;AAG1D;;;GAGG;AACH,qBA2Na,mBAAoB,SAAQ,iBAAkB,YAAW,aAAa;IAC1D,SAAS,EAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAExD,OAAO,EAAE,eAAe,GAAG,IAAI,CAAQ;IACvC,MAAM,EAAE,MAAM,CAAM;IACpB,WAAW,EAAE,UAAU,GAAG,QAAQ,GAAG,YAAY,CAAc;IAC/D,eAAe,EAAE,OAAO,CAAQ;IAChC,gBAAgB,EAAE,OAAO,CAAS;IAEzC,OAAO,CAAC,SAAS,CAAe;IAChC,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,YAAY,CAAkB;gBAE1B,GAAG,EAAE,iBAAiB,EAAE,SAAS,EAAE,YAAY;IAK3D,eAAe,IAAI,IAAI;IAOV,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAkDzC;;;OAGG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACI,YAAY,IAAI,IAAI;IAgB3B;;OAEG;IACI,aAAa,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI;yCA9GhC,mBAAmB;2CAAnB,mBAAmB;CAkH/B"}