@memberjunction/ng-explorer-core 6.1.3 → 6.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/resource-wrappers/artifact-resource.component.d.ts +16 -1
- package/dist/lib/resource-wrappers/artifact-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/artifact-resource.component.js +27 -4
- package/dist/lib/resource-wrappers/artifact-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/view-resource.component.d.ts +5 -1
- package/dist/lib/resource-wrappers/view-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/view-resource.component.js +15 -5
- package/dist/lib/resource-wrappers/view-resource.component.js.map +1 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.d.ts +20 -5
- package/dist/lib/shell/components/tabs/component-cache-manager.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.js +32 -7
- package/dist/lib/shell/components/tabs/component-cache-manager.js.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts +6 -0
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.js +19 -3
- package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
- package/dist/lib/shell/shell.component.d.ts +2 -0
- package/dist/lib/shell/shell.component.d.ts.map +1 -1
- package/dist/lib/shell/shell.component.js +9 -2
- package/dist/lib/shell/shell.component.js.map +1 -1
- package/package.json +52 -52
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { DataSnapshot, UserInfo } from '@memberjunction/core';
|
|
1
|
+
import { CompositeKey, DataSnapshot, UserInfo } from '@memberjunction/core';
|
|
2
2
|
import { BaseResourceComponent } from '@memberjunction/ng-shared';
|
|
3
3
|
import { ResourceData } from '@memberjunction/core-entities';
|
|
4
|
+
import { NavigationRequest } from '@memberjunction/ng-artifacts';
|
|
4
5
|
import * as i0 from "@angular/core";
|
|
5
6
|
/**
|
|
6
7
|
* Artifact Resource - displays versioned content artifacts
|
|
@@ -32,6 +33,20 @@ export declare class ArtifactResource extends BaseResourceComponent {
|
|
|
32
33
|
artifactId: string;
|
|
33
34
|
snapshot: DataSnapshot;
|
|
34
35
|
}): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Opens an entity record requested by the artifact, e.g. an interactive component's
|
|
38
|
+
* OpenEntityRecord callback. Without this, record links in a standalone artifact tab do nothing.
|
|
39
|
+
*/
|
|
40
|
+
onOpenEntityRecord(event: {
|
|
41
|
+
entityName: string;
|
|
42
|
+
compositeKey: CompositeKey;
|
|
43
|
+
}): void;
|
|
44
|
+
/**
|
|
45
|
+
* Handles app-level navigation requested by an artifact viewer plugin.
|
|
46
|
+
* Opens the target nav item (switching apps if needed) then applies query params to the URL.
|
|
47
|
+
*/
|
|
48
|
+
onNavigationRequest(event: NavigationRequest): Promise<void>;
|
|
49
|
+
private resolveAppId;
|
|
35
50
|
GetResourceDisplayName(data: ResourceData): Promise<string>;
|
|
36
51
|
GetResourceIconClass(data: ResourceData): Promise<string>;
|
|
37
52
|
static ɵfac: i0.ɵɵFactoryDeclaration<ArtifactResource, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/artifact-resource.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"artifact-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/artifact-resource.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,YAAY,EAA+B,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAuD,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;;AAItH;;;;GAIG;AACH,qBAgCa,gBAAiB,SAAQ,qBAAqB;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkC;IACjE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuC;IAEpE;;;;OAIG;IACG,oBAAoB,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQhF,WAAW,EAAE,QAAQ,GAAG,IAAI,CAAQ;IACpC,UAAU,EAAE,MAAM,CAAM;IACxB,aAAa,EAAE,MAAM,CAAM;IAElC,QAAQ;IAoBR;;;;OAIG;IACG,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,YAAY,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB9F;;;OAGG;IACH,kBAAkB,CAAC,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,YAAY,CAAA;KAAE,GAAG,IAAI;IAInF;;;OAGG;IACG,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlE,OAAO,CAAC,YAAY;IAKd,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAe3D,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;yCAzGpD,gBAAgB;2CAAhB,gBAAgB;CA4G5B"}
|
|
@@ -15,7 +15,7 @@ import * as i1 from "@memberjunction/ng-artifacts";
|
|
|
15
15
|
function ArtifactResource_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
16
16
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
17
17
|
i0.ɵɵelementStart(0, "mj-artifact-viewer-panel", 2);
|
|
18
|
-
i0.ɵɵlistener("analyzeRequested", function ArtifactResource_Conditional_1_Template_mj_artifact_viewer_panel_analyzeRequested_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onAnalyzeRequested($event)); })("applyFormRequested", function ArtifactResource_Conditional_1_Template_mj_artifact_viewer_panel_applyFormRequested_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onApplyFormRequested($event)); });
|
|
18
|
+
i0.ɵɵlistener("analyzeRequested", function ArtifactResource_Conditional_1_Template_mj_artifact_viewer_panel_analyzeRequested_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onAnalyzeRequested($event)); })("applyFormRequested", function ArtifactResource_Conditional_1_Template_mj_artifact_viewer_panel_applyFormRequested_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onApplyFormRequested($event)); })("openEntityRecord", function ArtifactResource_Conditional_1_Template_mj_artifact_viewer_panel_openEntityRecord_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onOpenEntityRecord($event)); })("navigationRequest", function ArtifactResource_Conditional_1_Template_mj_artifact_viewer_panel_navigationRequest_0_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onNavigationRequest($event)); });
|
|
19
19
|
i0.ɵɵelementEnd();
|
|
20
20
|
} if (rf & 2) {
|
|
21
21
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -80,6 +80,27 @@ let ArtifactResource = class ArtifactResource extends BaseResourceComponent {
|
|
|
80
80
|
MJNotificationService.Instance.CreateSimpleNotification(message, 'error', 5000);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Opens an entity record requested by the artifact, e.g. an interactive component's
|
|
85
|
+
* OpenEntityRecord callback. Without this, record links in a standalone artifact tab do nothing.
|
|
86
|
+
*/
|
|
87
|
+
onOpenEntityRecord(event) {
|
|
88
|
+
this.navigationService.OpenEntityRecord(event.entityName, event.compositeKey);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Handles app-level navigation requested by an artifact viewer plugin.
|
|
92
|
+
* Opens the target nav item (switching apps if needed) then applies query params to the URL.
|
|
93
|
+
*/
|
|
94
|
+
async onNavigationRequest(event) {
|
|
95
|
+
const appId = event.appName ? this.resolveAppId(event.appName) : undefined;
|
|
96
|
+
await this.navigationService.OpenNavItemByName(event.navItemName, undefined, appId, {
|
|
97
|
+
queryParams: event.queryParams
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
resolveAppId(appName) {
|
|
101
|
+
const app = this.ProviderToUse.Applications.find(a => a.Name.toLowerCase() === appName.toLowerCase());
|
|
102
|
+
return app?.ID;
|
|
103
|
+
}
|
|
83
104
|
async GetResourceDisplayName(data) {
|
|
84
105
|
// Try to load artifact name from database
|
|
85
106
|
if (data.ResourceRecordID) {
|
|
@@ -99,7 +120,7 @@ let ArtifactResource = class ArtifactResource extends BaseResourceComponent {
|
|
|
99
120
|
return 'fa-solid fa-file-code';
|
|
100
121
|
}
|
|
101
122
|
static ɵfac = /*@__PURE__*/ (() => { let ɵArtifactResource_BaseFactory; return function ArtifactResource_Factory(__ngFactoryType__) { return (ɵArtifactResource_BaseFactory || (ɵArtifactResource_BaseFactory = i0.ɵɵgetInheritedFactory(ArtifactResource)))(__ngFactoryType__ || ArtifactResource); }; })();
|
|
102
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactResource, selectors: [["mj-artifact-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 1, consts: [[1, "artifact-container"], [3, "artifactId", "currentUser", "environmentId", "showSaveToCollection", "canShare", "canEdit"], [3, "analyzeRequested", "applyFormRequested", "artifactId", "currentUser", "environmentId", "showSaveToCollection", "canShare", "canEdit"]], template: function ArtifactResource_Template(rf, ctx) { if (rf & 1) {
|
|
123
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ArtifactResource, selectors: [["mj-artifact-resource"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 1, consts: [[1, "artifact-container"], [3, "artifactId", "currentUser", "environmentId", "showSaveToCollection", "canShare", "canEdit"], [3, "analyzeRequested", "applyFormRequested", "openEntityRecord", "navigationRequest", "artifactId", "currentUser", "environmentId", "showSaveToCollection", "canShare", "canEdit"]], template: function ArtifactResource_Template(rf, ctx) { if (rf & 1) {
|
|
103
124
|
i0.ɵɵelementStart(0, "div", 0);
|
|
104
125
|
i0.ɵɵconditionalCreate(1, ArtifactResource_Conditional_1_Template, 1, 6, "mj-artifact-viewer-panel", 1);
|
|
105
126
|
i0.ɵɵelementEnd();
|
|
@@ -125,11 +146,13 @@ export { ArtifactResource };
|
|
|
125
146
|
[canShare]="true"
|
|
126
147
|
[canEdit]="true"
|
|
127
148
|
(analyzeRequested)="onAnalyzeRequested($event)"
|
|
128
|
-
(applyFormRequested)="onApplyFormRequested($event)"
|
|
149
|
+
(applyFormRequested)="onApplyFormRequested($event)"
|
|
150
|
+
(openEntityRecord)="onOpenEntityRecord($event)"
|
|
151
|
+
(navigationRequest)="onNavigationRequest($event)">
|
|
129
152
|
</mj-artifact-viewer-panel>
|
|
130
153
|
}
|
|
131
154
|
</div>
|
|
132
155
|
`, encapsulation: ViewEncapsulation.None, styles: ["\n .artifact-container {\n display: flex;\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n "] }]
|
|
133
156
|
}], null, null); })();
|
|
134
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactResource, { className: "ArtifactResource", filePath: "src/lib/resource-wrappers/artifact-resource.component.ts", lineNumber:
|
|
157
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ArtifactResource, { className: "ArtifactResource", filePath: "src/lib/resource-wrappers/artifact-resource.component.ts", lineNumber: 47 }); })();
|
|
135
158
|
//# sourceMappingURL=artifact-resource.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/artifact-resource.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAgB,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,
|
|
1
|
+
{"version":3,"file":"artifact-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/artifact-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewEncapsulation, inject } from '@angular/core';\nimport { CompositeKey, DataSnapshot, Metadata, UserInfo } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData, MJEnvironmentEntityExtended } from '@memberjunction/core-entities';\nimport { AnalyzeArtifactService, InteractiveFormApplyService, NavigationRequest } from '@memberjunction/ng-artifacts';\nimport type { ComponentSpec } from '@memberjunction/interactive-component-types';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\n\n/**\n * Artifact Resource - displays versioned content artifacts\n * Wraps the artifact-viewer-panel component for tab-based display\n * Supports reports, dashboards, forms, and other artifact types\n */\n@RegisterClass(BaseResourceComponent, 'ArtifactResource')\n@Component({\n standalone: false,\n selector: 'mj-artifact-resource',\n template: `\n <div class=\"artifact-container\">\n @if (currentUser && artifactId) {\n <mj-artifact-viewer-panel\n [artifactId]=\"artifactId\"\n [currentUser]=\"currentUser\"\n [environmentId]=\"environmentId\"\n [showSaveToCollection]=\"true\"\n [canShare]=\"true\"\n [canEdit]=\"true\"\n (analyzeRequested)=\"onAnalyzeRequested($event)\"\n (applyFormRequested)=\"onApplyFormRequested($event)\"\n (openEntityRecord)=\"onOpenEntityRecord($event)\"\n (navigationRequest)=\"onNavigationRequest($event)\">\n </mj-artifact-viewer-panel>\n }\n </div>\n `,\n styles: [`\n .artifact-container {\n display: flex;\n width: 100%;\n height: 100%;\n overflow: hidden;\n }\n `],\n encapsulation: ViewEncapsulation.None\n})\nexport class ArtifactResource extends BaseResourceComponent {\n private readonly analyzeService = inject(AnalyzeArtifactService);\n private readonly applyService = inject(InteractiveFormApplyService);\n\n /**\n * Apply-to-my-form handler — see InteractiveFormApplyService.\n * Confirms with the user, then routes to Create or Modify depending on\n * whether an Active override already exists for this entity+user.\n */\n async onApplyFormRequested(event: { spec: unknown; entityName: string }): Promise<void> {\n await this.applyService.ConfirmAndApply(\n event.spec as ComponentSpec,\n event.entityName,\n this.ProviderToUse,\n );\n }\n\n public currentUser: UserInfo | null = null;\n public artifactId: string = '';\n public environmentId: string = '';\n\n ngOnInit() {\n super.ngOnInit();\n const md = this.ProviderToUse;\n this.currentUser = md.CurrentUser;\n\n // Get artifact ID from resource data\n if (this.Data && this.Data.ResourceRecordID) {\n this.artifactId = this.Data.ResourceRecordID;\n }\n\n // Environment ID — use the configured environment if present, otherwise\n // fall back to the default environment. Must be a valid UUID since\n // downstream saves (e.g. AnalyzeArtifactService creating artifacts)\n // require a non-empty EnvironmentID.\n this.environmentId = (this.Data?.Configuration?.['environmentId'] as string | undefined)\n || MJEnvironmentEntityExtended.DefaultEnvironmentID;\n\n setTimeout(() => this.NotifyLoadComplete(), 100);\n }\n\n /**\n * Handler for the Analyze button on the artifact viewer panel.\n * Creates a Data Snapshot artifact from the live viewer state, opens a\n * new conversation with it attached as input, and routes the user there.\n */\n async onAnalyzeRequested(event: { artifactId: string; snapshot: DataSnapshot }): Promise<void> {\n if (!this.currentUser) return;\n\n try {\n const result = await this.analyzeService.StartAnalysisConversation({\n snapshot: event.snapshot,\n currentUser: this.currentUser,\n environmentId: this.environmentId,\n });\n\n // Route to the new conversation in the Conversations nav item\n await this.navigationService.OpenNavItemByName('Conversations', {\n conversationId: result.conversationId,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to start analysis conversation';\n MJNotificationService.Instance.CreateSimpleNotification(message, 'error', 5000);\n }\n }\n\n /**\n * Opens an entity record requested by the artifact, e.g. an interactive component's\n * OpenEntityRecord callback. Without this, record links in a standalone artifact tab do nothing.\n */\n onOpenEntityRecord(event: { entityName: string; compositeKey: CompositeKey }): void {\n this.navigationService.OpenEntityRecord(event.entityName, event.compositeKey);\n }\n\n /**\n * Handles app-level navigation requested by an artifact viewer plugin.\n * Opens the target nav item (switching apps if needed) then applies query params to the URL.\n */\n async onNavigationRequest(event: NavigationRequest): Promise<void> {\n const appId = event.appName ? this.resolveAppId(event.appName) : undefined;\n await this.navigationService.OpenNavItemByName(event.navItemName, undefined, appId, {\n queryParams: event.queryParams\n });\n }\n\n private resolveAppId(appName: string): string | undefined {\n const app = this.ProviderToUse.Applications.find(a => a.Name.toLowerCase() === appName.toLowerCase());\n return app?.ID;\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n // Try to load artifact name from database\n if (data.ResourceRecordID) {\n try {\n const md = this.ProviderToUse;\n const artifact = await md.GetEntityObject<any>('MJ: Conversation Artifacts');\n await artifact.Load(data.ResourceRecordID);\n return artifact.Name || `Artifact - ${data.ResourceRecordID}`;\n } catch (error) {\n console.error('Error loading artifact name:', error);\n }\n }\n return 'Artifact';\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-file-code';\n }\n}\n"]}
|
|
@@ -78,7 +78,11 @@ export declare class UserViewResource extends BaseResourceComponent {
|
|
|
78
78
|
* so it's bounded and warns past the cap) and writes an Excel file.
|
|
79
79
|
*/
|
|
80
80
|
onExport(): Promise<void>;
|
|
81
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Columns to export — from grid state, else the view's columns, else the entity's real fields. Each
|
|
83
|
+
* column carries its field's export type, as the grid's export does, so a date-only field writes
|
|
84
|
+
* a date cell on its stored day rather than a timestamp.
|
|
85
|
+
*/
|
|
82
86
|
private buildExportColumns;
|
|
83
87
|
private buildExportFileName;
|
|
84
88
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/view-resource.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAqB,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAY,MAAM,+BAA+B,CAAC;AAEjG,OAAO,EAA0B,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,qBAAqB,EAAE,2BAA2B,
|
|
1
|
+
{"version":3,"file":"view-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/view-resource.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,UAAU,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,qBAAqB,EAAqB,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,wBAAwB,EAAY,MAAM,+BAA+B,CAAC;AAEjG,OAAO,EAA0B,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,qBAAqB,EAAE,2BAA2B,EAA8B,MAAM,kCAAkC,CAAC;AACpK,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAGlE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;;AAC/E;;;;;;;;;;;GAWG;AACH,qBAmHa,gBAAiB,SAAQ,qBAAqB;IAyBnD,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,aAAa;IAzBiB,gBAAgB,EAAG,UAAU,CAAC,cAAc,CAAC,CAAC;IAC7D,eAAe,CAAC,EAAE,qBAAqB,CAAC;IAE5D,SAAS,EAAE,OAAO,CAAS;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAQ;IACnC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAQ;IACrC,UAAU,EAAE,wBAAwB,GAAG,IAAI,CAAQ;IACnD,SAAS,EAAE,aAAa,GAAG,IAAI,CAAQ;IAMvC,WAAW,EAAE,OAAO,CAAS;IAC7B,wBAAwB,EAAE,OAAO,CAAS;IAG1C,uBAAuB,UAAS;IAChC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5C,cAAc,UAAS;IAE9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,KAAK,QAAQ,GAAiC;gBAEzC,GAAG,EAAE,iBAAiB,EACtB,aAAa,EAAE,aAAa;IAKxC,IAAa,IAAI,CAAC,KAAK,EAAE,YAAY,EAqBpC;IAED,IAAa,IAAI,IAAI,YAAY,CAEhC;IAED;;OAEG;YACW,QAAQ;IA+CtB;;OAEG;YACW,YAAY;IAuC1B;;OAEG;YACW,eAAe;IAiB7B;;OAEG;IACI,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAMrD;;;OAGG;IACI,mBAAmB,CAAC,GAAG,EAAE,2BAA2B,GAAG,IAAI;IASlE;;OAEG;IACI,YAAY,IAAI,IAAI;IAK3B,6FAA6F;IACtF,iBAAiB,IAAI,IAAI;IAIhC;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAQvC;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCtC;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAsB1B,OAAO,CAAC,mBAAmB;IAK3B;;OAEG;IACY,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAc1E;;OAEG;IACY,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAIzE;;OAEG;IACI,iBAAiB,IAAI,IAAI;IAOhC;;;;OAIG;IACI,YAAY,IAAI,IAAI;IAapB,qBAAqB,IAAI,IAAI;IAKvB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC7E;;OAEG;IACH,OAAO,CAAC,gBAAgB;yCAzYf,gBAAgB;2CAAhB,gBAAgB;CAqZ5B"}
|
|
@@ -9,6 +9,7 @@ import { BaseResourceComponent } from '@memberjunction/ng-shared';
|
|
|
9
9
|
import { ViewInfo } from '@memberjunction/core-entities';
|
|
10
10
|
import { RegisterClass, MJGlobal, MJEventType, UUIDsEqual } from '@memberjunction/global';
|
|
11
11
|
import { CompositeKey } from '@memberjunction/core';
|
|
12
|
+
import { ExportColumnTypeForSQLType } from '@memberjunction/ng-entity-viewer';
|
|
12
13
|
import { GraphQLListsClient } from '@memberjunction/graphql-dataprovider';
|
|
13
14
|
import * as i0 from "@angular/core";
|
|
14
15
|
import * as i1 from "@memberjunction/ng-export-service";
|
|
@@ -369,23 +370,32 @@ let UserViewResource = class UserViewResource extends BaseResourceComponent {
|
|
|
369
370
|
this.cdr.detectChanges();
|
|
370
371
|
}
|
|
371
372
|
}
|
|
372
|
-
/**
|
|
373
|
+
/**
|
|
374
|
+
* Columns to export — from grid state, else the view's columns, else the entity's real fields. Each
|
|
375
|
+
* column carries its field's export type, as the grid's export does, so a date-only field writes
|
|
376
|
+
* a date cell on its stored day rather than a timestamp.
|
|
377
|
+
*/
|
|
373
378
|
buildExportColumns() {
|
|
374
379
|
if (!this.entityInfo)
|
|
375
380
|
return [];
|
|
381
|
+
const entity = this.entityInfo;
|
|
382
|
+
const typed = (name, displayName) => {
|
|
383
|
+
const field = entity.Fields.find(f => f.Name.toLowerCase() === name.toLowerCase());
|
|
384
|
+
return { name, displayName, dataType: ExportColumnTypeForSQLType(field?.Type) };
|
|
385
|
+
};
|
|
376
386
|
if (this.gridState?.columnSettings && this.gridState.columnSettings.length > 0) {
|
|
377
387
|
return this.gridState.columnSettings
|
|
378
388
|
.filter(col => col.hidden !== true)
|
|
379
|
-
.map(col => (
|
|
389
|
+
.map(col => typed(col.Name, col.DisplayName || col.Name));
|
|
380
390
|
}
|
|
381
391
|
if (this.viewEntity?.Columns) {
|
|
382
392
|
return this.viewEntity.Columns
|
|
383
393
|
.filter(col => !col.hidden)
|
|
384
|
-
.map(col => (
|
|
394
|
+
.map(col => typed(col.Name, col.DisplayName || col.Name));
|
|
385
395
|
}
|
|
386
|
-
return
|
|
396
|
+
return entity.Fields
|
|
387
397
|
.filter(f => !f.IsVirtual)
|
|
388
|
-
.map(f => (
|
|
398
|
+
.map(f => typed(f.Name, f.DisplayNameOrName));
|
|
389
399
|
}
|
|
390
400
|
buildExportFileName() {
|
|
391
401
|
const viewName = this.viewEntity?.Name || 'Data';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/view-resource.component.ts","../../../src/lib/resource-wrappers/view-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { ResourceData, MJUserViewEntityExtended, ViewInfo } from '@memberjunction/core-entities';\nimport { RegisterClass, MJGlobal, MJEventType , UUIDsEqual } from '@memberjunction/global';\nimport { CompositeKey, Metadata, EntityInfo } from '@memberjunction/core';\nimport { RecordOpenedEvent, ViewGridState, EntityViewerComponent, ViewRelatedRecordNavigation } from '@memberjunction/ng-entity-viewer';\nimport { ExportService } from '@memberjunction/ng-export-service';\nimport { ExportColumn } from '@memberjunction/export-engine';\nimport { GraphQLDataProvider, GraphQLListsClient } from '@memberjunction/graphql-dataprovider';\nimport type { SaveViewAsListResult } from '@memberjunction/ng-list-management';\n/**\n * UserViewResource - Resource wrapper for displaying User Views in tabs\n *\n * This component wraps the EntityViewerComponent to display view data.\n * It loads the view configuration and entity, then renders the data grid/cards.\n *\n * Key features:\n * - Loads view by ID from ResourceRecordID\n * - Supports dynamic views by entity name + extra filter\n * - Applies view's WhereClause, GridState, and SortState\n * - Opens records in new tabs via NavigationService\n */\n@RegisterClass(BaseResourceComponent, 'ViewResource')\n@Component({\n standalone: false,\n selector: 'mj-userview-resource',\n templateUrl: './view-resource.component.html',\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n }\n .view-resource-container {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .view-header {\n padding: 16px 20px 8px 20px;\n flex-shrink: 0;\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 16px;\n }\n .header-left {\n flex: 1;\n min-width: 0;\n }\n .header-right {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n }\n .view-title {\n margin: 0 0 4px 0;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--text-primary, #1a1a1a);\n }\n .view-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--text-secondary, #666);\n }\n .action-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n }\n .action-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-default);\n }\n .action-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .action-button i {\n font-size: 0.875rem;\n }\n .create-button {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n }\n .create-button:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n }\n .export-button:hover:not(:disabled) {\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n }\n .view-loading-state,\n .view-error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n }\n .view-error-state {\n color: var(--danger-color, #dc3545);\n }\n .view-error-state i {\n font-size: 2rem;\n }\n .view-error-state p {\n margin: 0;\n font-size: 1rem;\n }\n mj-entity-viewer {\n flex: 1;\n min-height: 0;\n }\n `]\n})\nexport class UserViewResource extends BaseResourceComponent {\n @ViewChild('container', { static: true }) containerElement!: ElementRef<HTMLDivElement>;\n @ViewChild('entityViewer') entityViewerRef?: EntityViewerComponent;\n\n public isLoading: boolean = false;\n public errorMessage: string | null = null;\n public entityInfo: EntityInfo | null = null;\n public viewEntity: MJUserViewEntityExtended | null = null;\n public gridState: ViewGridState | null = null;\n\n // Export state. The header Export button is a FALLBACK shown only for view types that don't\n // provide their own export UI (Cards / Map / Timeline). The Grid renderer has its own in-toolbar\n // Export (full result set + format/sampling dialog), so we suppress this one there to avoid a\n // duplicate/confusing second button — while keeping export available for every other view type.\n public isExporting: boolean = false;\n public showFallbackExportButton: boolean = false;\n\n // Save-as-list dialog state\n public saveAsListDialogVisible = false;\n public saveAsListRecordCount: number | null = null;\n public isSavingAsList = false;\n\n private dataLoaded = false;\n private get metadata() { return this.ProviderToUse; }\n constructor(\n private cdr: ChangeDetectorRef,\n private exportService: ExportService\n ) {\n super();\n }\n\n override set Data(value: ResourceData) {\n const previousRecordId = super.Data?.ResourceRecordID;\n const previousEntity = super.Data?.Configuration?.Entity;\n super.Data = value;\n\n const newRecordId = value?.ResourceRecordID;\n const newEntity = value?.Configuration?.Entity;\n\n // View-type (grid/cards/timeline/map) and per-view-type config are now resolved\n // internally by mj-entity-viewer from the saved view's ViewTypeID — nothing to read here.\n\n // Load on first set, or when the view/entity has changed\n if (!this.dataLoaded || newRecordId !== previousRecordId || newEntity !== previousEntity) {\n this.dataLoaded = true;\n // Reset state before loading new view\n this.entityInfo = null;\n this.viewEntity = null;\n this.gridState = null;\n this.errorMessage = null;\n this.loadView();\n }\n }\n\n override get Data(): ResourceData {\n return super.Data;\n }\n\n /**\n * Load the view and entity based on ResourceData\n */\n private async loadView(): Promise<void> {\n const data = this.Data;\n\n if (!data) {\n this.NotifyLoadComplete();\n return;\n }\n\n this.isLoading = true;\n this.errorMessage = null;\n this.NotifyLoadStarted();\n this.cdr.detectChanges();\n\n try {\n // NavigationService.OpenDynamicView stamps the special marker 'dynamic' as the\n // record ID (tabs require ResourceRecordId) — that is NOT a saved-view ID.\n const recordId = data.ResourceRecordID;\n const isDynamicMarker = typeof recordId === 'string' && recordId.trim().toLowerCase() === 'dynamic';\n // Case 1: Load view by ID\n if (recordId && !isDynamicMarker) {\n await this.loadViewById(recordId);\n }\n // Case 2: Load dynamic view by entity name\n else if (data.Configuration?.Entity) {\n await this.loadDynamicView(\n data.Configuration.Entity as string,\n data.Configuration.ExtraFilter as string | undefined\n );\n }\n else {\n this.errorMessage = 'No view ID or entity specified';\n }\n } catch (error) {\n console.error('Error loading view:', error);\n this.errorMessage = error instanceof Error ? error.message : 'Failed to load view';\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n\n // If there was an error, notify load complete now\n if (this.errorMessage) {\n this.NotifyLoadComplete();\n }\n // Otherwise, wait for dataLoaded event from entity-viewer\n }\n }\n\n /**\n * Load a saved view by its ID\n */\n private async loadViewById(viewId: string): Promise<void> {\n // Load the view entity\n const view = await ViewInfo.GetViewEntity(viewId);\n\n if (!view) {\n throw new Error(`View with ID ${viewId} not found`);\n }\n\n this.viewEntity = view as MJUserViewEntityExtended;\n\n // Check permissions\n if (!this.viewEntity.UserCanView) {\n throw new Error('You do not have permission to view this view');\n }\n\n // Load the entity info\n const entity = this.metadata.Entities.find(e => UUIDsEqual(e.ID, this.viewEntity!.EntityID));\n\n if (!entity) {\n throw new Error(`Entity for view not found`);\n }\n\n this.entityInfo = entity;\n\n // Parse grid state if available\n if (this.viewEntity.GridState) {\n try {\n this.gridState = JSON.parse(this.viewEntity.GridState) as ViewGridState;\n } catch (e) {\n console.warn('Failed to parse GridState:', e);\n this.gridState = null;\n }\n }\n\n // View-type + per-view-type config persistence is fully owned by mj-entity-viewer\n // (it reads ViewTypeID + DisplayState.viewTypeConfigs off the [viewEntity] and, with\n // [AutoSaveView]=\"true\", saves changes back) — nothing to wire here.\n }\n\n /**\n * Load a dynamic view (no saved view, just entity + filter)\n */\n private async loadDynamicView(entityName: string, _extraFilter?: string): Promise<void> {\n const entity = this.metadata.Entities.find(\n e => e.Name.trim().toLowerCase() === entityName.trim().toLowerCase()\n );\n\n if (!entity) {\n throw new Error(`Entity '${entityName}' not found`);\n }\n\n this.entityInfo = entity;\n this.viewEntity = null;\n this.gridState = null;\n\n // For dynamic views, we could create a synthetic viewEntity with just the WhereClause\n // but for now, we'll rely on the entity-viewer's default behavior\n }\n\n /**\n * Handle record opened event - open in new tab\n */\n public onRecordOpened(event: RecordOpenedEvent): void {\n if (event && event.entity && event.compositeKey) {\n this.navigationService.OpenEntityRecord(event.entity.Name, event.compositeKey);\n }\n }\n\n /**\n * Handle a related-record navigation requested from within a view-type renderer\n * (e.g. a foreign-key cell) - open the target record in a new tab.\n */\n public onOpenRelatedRecord(nav: ViewRelatedRecordNavigation): void {\n if (nav?.entityName && nav.recordKey != null) {\n // The related entity is arbitrary, so its key column can have any name — resolve the key\n // against its metadata rather than hardcoding `ID` via FromID.\n const entityInfo = this.metadata.EntityByName(nav.entityName);\n this.navigationService.OpenEntityRecord(nav.entityName, CompositeKey.FromURLSegment(entityInfo, String(nav.recordKey)));\n }\n }\n\n /**\n * Handle data loaded event from entity-viewer\n */\n public onDataLoaded(): void {\n this.NotifyLoadComplete();\n this.refreshFallbackExportVisibility();\n }\n\n /** The active view type changed — recompute whether the fallback Export button is needed. */\n public onViewTypeChanged(): void {\n this.refreshFallbackExportVisibility();\n }\n\n /**\n * Show the wrapper's Export button only for view types that don't ship their own export UI. The\n * entity-viewer reports this via {@link EntityViewerComponent.ActiveViewTypeHasOwnExport} (true for\n * the Grid renderer, false for Cards / Map / Timeline). Uses a cached flag + explicit change\n * detection to avoid an ExpressionChanged error from reading child state during a CD pass.\n */\n private refreshFallbackExportVisibility(): void {\n const next = !!this.entityViewerRef && !this.entityViewerRef.ActiveViewTypeHasOwnExport;\n if (next !== this.showFallbackExportButton) {\n this.showFallbackExportButton = next;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Fallback export for view types without their own export UI (Cards / Map / Timeline). Pulls the\n * FULL result set via the entity-viewer's capped, filter/sort-aware fetch (same path the grid uses,\n * so it's bounded and warns past the cap) and writes an Excel file.\n */\n public async onExport(): Promise<void> {\n // Never fail silently — a \"nothing happens\" click is impossible to diagnose. Surface the\n // reason both in the UI and the console.\n if (!this.entityInfo || !this.entityViewerRef) {\n console.error('[ViewResource] Export: viewer not ready', {\n hasEntity: !!this.entityInfo, hasViewer: !!this.entityViewerRef\n });\n this.showNotification('Export is not ready yet — try again in a moment.', 'error', 5000);\n return;\n }\n this.isExporting = true;\n this.cdr.detectChanges();\n this.showNotification('Preparing your Excel export…', 'info', 2000);\n try {\n const rows = await this.entityViewerRef.FetchAllRowsForExport();\n if (!rows || rows.length === 0) {\n this.showNotification('Nothing to export — the view returned no records.', 'warning', 5000);\n return;\n }\n const result = await this.exportService.toExcel(rows, {\n fileName: this.buildExportFileName(),\n columns: this.buildExportColumns(),\n includeHeaders: true\n });\n if (result.success) {\n this.exportService.downloadResult(result);\n this.showNotification(`Exported ${rows.length.toLocaleString()} record(s) to Excel.`, 'success', 3000);\n } else {\n this.showNotification('Export failed while building the file.', 'error', 5000);\n console.error('[ViewResource] Export: toExcel returned failure', result);\n }\n } catch (e) {\n this.showNotification('Error exporting data — see console for details.', 'error', 5000);\n console.error('[ViewResource] Export error:', e);\n } finally {\n this.isExporting = false;\n this.cdr.detectChanges();\n }\n }\n\n /** Columns to export — from grid state, else the view's columns, else the entity's real fields. */\n private buildExportColumns(): ExportColumn[] {\n if (!this.entityInfo) return [];\n if (this.gridState?.columnSettings && this.gridState.columnSettings.length > 0) {\n return this.gridState.columnSettings\n .filter(col => col.hidden !== true)\n .map(col => ({ name: col.Name, displayName: col.DisplayName || col.Name }));\n }\n if (this.viewEntity?.Columns) {\n return this.viewEntity.Columns\n .filter(col => !col.hidden)\n .map(col => ({ name: col.Name, displayName: col.DisplayName || col.Name }));\n }\n return this.entityInfo.Fields\n .filter(f => !f.IsVirtual)\n .map(f => ({ name: f.Name, displayName: f.DisplayNameOrName }));\n }\n\n private buildExportFileName(): string {\n const viewName = this.viewEntity?.Name || 'Data';\n return `${this.entityInfo!.Name}_${viewName}_${new Date().toISOString().split('T')[0]}`;\n }\n\n /**\n * Get display name for the resource tab\n */\n override async GetResourceDisplayName(data: ResourceData): Promise<string> {\n if (data.ResourceRecordID) {\n const compositeKey = CompositeKey.FromID(data.ResourceRecordID); // first-pk-ok: ResourceRecordID of a User Views resource — core entity keyed by ID\n const name = await this.metadata.GetEntityRecordName('MJ: User Views', compositeKey);\n return name ? name : `View: ${data.ResourceRecordID}`;\n }\n else if (data.Configuration?.Entity) {\n const entityName = data.Configuration.Entity as string;\n const hasFilter = data.Configuration.ExtraFilter;\n return `${entityName} [Dynamic${hasFilter ? ' - Filtered' : ' - All'}]`;\n }\n return 'User Views [Error]';\n }\n\n /**\n * Get icon class for the resource tab\n */\n override async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-table-list';\n }\n\n /**\n * Handle creating a new record for the current entity\n */\n public onCreateNewRecord(): void {\n if (!this.entityInfo) return;\n\n // Use NavigationService to open a new record form\n this.navigationService.OpenNewEntityRecord(this.entityInfo.Name);\n }\n\n /**\n * Open the Save-as-List dialog. Only meaningful for saved views (a\n * ViewID is required to materialize). Dynamic views fall back to a\n * user-visible notification rather than silently doing nothing.\n */\n public onSaveAsList(): void {\n if (!this.viewEntity?.ID) {\n this.showNotification('Save as List requires a saved View. Save this view first.', 'info', 4000);\n return;\n }\n // Best-effort record-count hint — the entity-viewer exposes the\n // grid's row count on its gridState; we surface it so the dialog's\n // confirm button can say \"Save List (476 records)\".\n this.saveAsListRecordCount = this.entityViewerRef?.TotalRecordCount ?? null;\n this.saveAsListDialogVisible = true;\n this.cdr.detectChanges();\n }\n\n public onSaveAsListCancelled(): void {\n this.saveAsListDialogVisible = false;\n this.cdr.detectChanges();\n }\n\n public async onSaveAsListSubmit(payload: SaveViewAsListResult): Promise<void> {\n const viewId = this.viewEntity?.ID;\n if (!viewId) return;\n this.isSavingAsList = true;\n this.cdr.detectChanges();\n try {\n const provider = this.ProviderToUse as unknown as GraphQLDataProvider;\n const client = new GraphQLListsClient(provider);\n const result = await client.MaterializeFromView(viewId, {\n ListName: payload.ListName,\n Description: payload.Description,\n CategoryId: payload.CategoryId,\n RememberLineage: payload.RememberLineage,\n UseSnapshot: payload.UseSnapshot,\n RefreshMode: payload.RefreshMode,\n });\n if (result.Success && result.CreatedListId) {\n this.saveAsListDialogVisible = false;\n this.showNotification(\n `List created with ${result.Counts?.Added ?? 0} record(s).`,\n 'success',\n 3000,\n );\n this.navigationService.OpenEntityRecord('MJ: Lists', CompositeKey.FromID(result.CreatedListId));\n } else {\n this.showNotification(`Save failed: ${result.Message}`, 'error', 5000);\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n this.showNotification(`Save failed: ${message}`, 'error', 5000);\n } finally {\n this.isSavingAsList = false;\n this.cdr.detectChanges();\n }\n }\n\n\n /**\n * Show a notification to the user\n */\n private showNotification(message: string, style: 'info' | 'success' | 'error' | 'warning', duration: number): void {\n MJGlobal.Instance.RaiseEvent({\n component: this,\n event: MJEventType.DisplaySimpleNotificationRequest,\n eventCode: '',\n args: {\n message,\n style,\n DisplayDuration: duration\n }\n });\n }\n}\n","<div #container class=\"view-resource-container\">\n @if (isLoading) {\n <div class=\"view-loading-state\">\n <mj-loading text=\"Loading view...\" size=\"large\"></mj-loading>\n </div>\n } @else if (errorMessage) {\n <div class=\"view-error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ errorMessage }}</p>\n </div>\n } @else if (entityInfo) {\n <!-- Header with title and action buttons -->\n <div class=\"view-header\">\n <div class=\"header-left\">\n <h2 class=\"view-title\">{{ viewEntity?.Name || entityInfo.Name }}</h2>\n @if (viewEntity?.Description) {\n <p class=\"view-description\">{{ viewEntity!.Description }}</p>\n }\n </div>\n <div class=\"header-right\">\n <!-- Create New Record Button -->\n <button\n class=\"action-button create-button\"\n (click)=\"onCreateNewRecord()\"\n title=\"Create new {{ entityInfo.Name }} record\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New Record</span>\n </button>\n\n <!-- Save as List Button — only meaningful for saved (non-dynamic) views. -->\n @if (viewEntity?.ID) {\n <button\n class=\"action-button save-as-list-button\"\n (click)=\"onSaveAsList()\"\n [disabled]=\"isSavingAsList\"\n title=\"Materialize these results as a static List\">\n @if (isSavingAsList) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-floppy-disk\"></i>\n }\n <span>{{ isSavingAsList ? 'Saving...' : 'Save as List' }}</span>\n </button>\n }\n <!-- Fallback Export button. Shown ONLY for view types that lack their own export UI\n (Cards / Map / Timeline). The Grid renderer has its own in-toolbar Export (full\n result set + format/sampling dialog), so this is suppressed there to avoid a\n duplicate/confusing second button. -->\n @if (showFallbackExportButton) {\n <button\n class=\"action-button export-button\"\n (click)=\"onExport()\"\n [disabled]=\"isExporting\"\n title=\"Export\">\n @if (isExporting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-file-excel\"></i>\n }\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </button>\n }\n </div>\n </div>\n\n <!-- Entity Viewer -->\n <mj-entity-viewer\n #entityViewer\n [Entity]=\"entityInfo\"\n [Provider]=\"Provider\"\n [ViewEntity]=\"viewEntity\"\n [GridState]=\"gridState\"\n [AutoSaveView]=\"true\"\n (RecordOpened)=\"onRecordOpened($any($event))\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecord($event)\"\n (AfterViewTypeChange)=\"onViewTypeChanged()\"\n (DataLoaded)=\"onDataLoaded()\">\n </mj-entity-viewer>\n\n <!-- Save-as-List dialog -->\n <mj-save-view-as-list-dialog\n [Provider]=\"ProviderToUse\"\n [Visible]=\"saveAsListDialogVisible\"\n [ViewId]=\"viewEntity?.ID ?? null\"\n [ViewName]=\"viewEntity?.Name ?? null\"\n [RecordCount]=\"saveAsListRecordCount\"\n (Save)=\"onSaveAsListSubmit($event)\"\n (Cancel)=\"onSaveAsListCancelled()\">\n </mj-save-view-as-list-dialog>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"view-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/view-resource.component.ts","../../../src/lib/resource-wrappers/view-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { ResourceData, MJUserViewEntityExtended, ViewInfo } from '@memberjunction/core-entities';\nimport { RegisterClass, MJGlobal, MJEventType , UUIDsEqual } from '@memberjunction/global';\nimport { CompositeKey, Metadata, EntityInfo } from '@memberjunction/core';\nimport { RecordOpenedEvent, ViewGridState, EntityViewerComponent, ViewRelatedRecordNavigation, ExportColumnTypeForSQLType } from '@memberjunction/ng-entity-viewer';\nimport { ExportService } from '@memberjunction/ng-export-service';\nimport { ExportColumn } from '@memberjunction/export-engine';\nimport { GraphQLDataProvider, GraphQLListsClient } from '@memberjunction/graphql-dataprovider';\nimport type { SaveViewAsListResult } from '@memberjunction/ng-list-management';\n/**\n * UserViewResource - Resource wrapper for displaying User Views in tabs\n *\n * This component wraps the EntityViewerComponent to display view data.\n * It loads the view configuration and entity, then renders the data grid/cards.\n *\n * Key features:\n * - Loads view by ID from ResourceRecordID\n * - Supports dynamic views by entity name + extra filter\n * - Applies view's WhereClause, GridState, and SortState\n * - Opens records in new tabs via NavigationService\n */\n@RegisterClass(BaseResourceComponent, 'ViewResource')\n@Component({\n standalone: false,\n selector: 'mj-userview-resource',\n templateUrl: './view-resource.component.html',\n styles: [`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n }\n .view-resource-container {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .view-header {\n padding: 16px 20px 8px 20px;\n flex-shrink: 0;\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 16px;\n }\n .header-left {\n flex: 1;\n min-width: 0;\n }\n .header-right {\n display: flex;\n gap: 8px;\n flex-shrink: 0;\n }\n .view-title {\n margin: 0 0 4px 0;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--text-primary, #1a1a1a);\n }\n .view-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--text-secondary, #666);\n }\n .action-button {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-primary);\n font-size: 0.875rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n }\n .action-button:hover:not(:disabled) {\n background: var(--mj-bg-surface-sunken);\n border-color: var(--mj-border-default);\n }\n .action-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n .action-button i {\n font-size: 0.875rem;\n }\n .create-button {\n background: var(--mj-brand-primary);\n color: white;\n border-color: var(--mj-brand-primary);\n }\n .create-button:hover:not(:disabled) {\n background: var(--mj-brand-primary-hover);\n border-color: var(--mj-brand-primary-hover);\n }\n .export-button:hover:not(:disabled) {\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n }\n .view-loading-state,\n .view-error-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n gap: 16px;\n }\n .view-error-state {\n color: var(--danger-color, #dc3545);\n }\n .view-error-state i {\n font-size: 2rem;\n }\n .view-error-state p {\n margin: 0;\n font-size: 1rem;\n }\n mj-entity-viewer {\n flex: 1;\n min-height: 0;\n }\n `]\n})\nexport class UserViewResource extends BaseResourceComponent {\n @ViewChild('container', { static: true }) containerElement!: ElementRef<HTMLDivElement>;\n @ViewChild('entityViewer') entityViewerRef?: EntityViewerComponent;\n\n public isLoading: boolean = false;\n public errorMessage: string | null = null;\n public entityInfo: EntityInfo | null = null;\n public viewEntity: MJUserViewEntityExtended | null = null;\n public gridState: ViewGridState | null = null;\n\n // Export state. The header Export button is a FALLBACK shown only for view types that don't\n // provide their own export UI (Cards / Map / Timeline). The Grid renderer has its own in-toolbar\n // Export (full result set + format/sampling dialog), so we suppress this one there to avoid a\n // duplicate/confusing second button — while keeping export available for every other view type.\n public isExporting: boolean = false;\n public showFallbackExportButton: boolean = false;\n\n // Save-as-list dialog state\n public saveAsListDialogVisible = false;\n public saveAsListRecordCount: number | null = null;\n public isSavingAsList = false;\n\n private dataLoaded = false;\n private get metadata() { return this.ProviderToUse; }\n constructor(\n private cdr: ChangeDetectorRef,\n private exportService: ExportService\n ) {\n super();\n }\n\n override set Data(value: ResourceData) {\n const previousRecordId = super.Data?.ResourceRecordID;\n const previousEntity = super.Data?.Configuration?.Entity;\n super.Data = value;\n\n const newRecordId = value?.ResourceRecordID;\n const newEntity = value?.Configuration?.Entity;\n\n // View-type (grid/cards/timeline/map) and per-view-type config are now resolved\n // internally by mj-entity-viewer from the saved view's ViewTypeID — nothing to read here.\n\n // Load on first set, or when the view/entity has changed\n if (!this.dataLoaded || newRecordId !== previousRecordId || newEntity !== previousEntity) {\n this.dataLoaded = true;\n // Reset state before loading new view\n this.entityInfo = null;\n this.viewEntity = null;\n this.gridState = null;\n this.errorMessage = null;\n this.loadView();\n }\n }\n\n override get Data(): ResourceData {\n return super.Data;\n }\n\n /**\n * Load the view and entity based on ResourceData\n */\n private async loadView(): Promise<void> {\n const data = this.Data;\n\n if (!data) {\n this.NotifyLoadComplete();\n return;\n }\n\n this.isLoading = true;\n this.errorMessage = null;\n this.NotifyLoadStarted();\n this.cdr.detectChanges();\n\n try {\n // NavigationService.OpenDynamicView stamps the special marker 'dynamic' as the\n // record ID (tabs require ResourceRecordId) — that is NOT a saved-view ID.\n const recordId = data.ResourceRecordID;\n const isDynamicMarker = typeof recordId === 'string' && recordId.trim().toLowerCase() === 'dynamic';\n // Case 1: Load view by ID\n if (recordId && !isDynamicMarker) {\n await this.loadViewById(recordId);\n }\n // Case 2: Load dynamic view by entity name\n else if (data.Configuration?.Entity) {\n await this.loadDynamicView(\n data.Configuration.Entity as string,\n data.Configuration.ExtraFilter as string | undefined\n );\n }\n else {\n this.errorMessage = 'No view ID or entity specified';\n }\n } catch (error) {\n console.error('Error loading view:', error);\n this.errorMessage = error instanceof Error ? error.message : 'Failed to load view';\n } finally {\n this.isLoading = false;\n this.cdr.detectChanges();\n\n // If there was an error, notify load complete now\n if (this.errorMessage) {\n this.NotifyLoadComplete();\n }\n // Otherwise, wait for dataLoaded event from entity-viewer\n }\n }\n\n /**\n * Load a saved view by its ID\n */\n private async loadViewById(viewId: string): Promise<void> {\n // Load the view entity\n const view = await ViewInfo.GetViewEntity(viewId);\n\n if (!view) {\n throw new Error(`View with ID ${viewId} not found`);\n }\n\n this.viewEntity = view as MJUserViewEntityExtended;\n\n // Check permissions\n if (!this.viewEntity.UserCanView) {\n throw new Error('You do not have permission to view this view');\n }\n\n // Load the entity info\n const entity = this.metadata.Entities.find(e => UUIDsEqual(e.ID, this.viewEntity!.EntityID));\n\n if (!entity) {\n throw new Error(`Entity for view not found`);\n }\n\n this.entityInfo = entity;\n\n // Parse grid state if available\n if (this.viewEntity.GridState) {\n try {\n this.gridState = JSON.parse(this.viewEntity.GridState) as ViewGridState;\n } catch (e) {\n console.warn('Failed to parse GridState:', e);\n this.gridState = null;\n }\n }\n\n // View-type + per-view-type config persistence is fully owned by mj-entity-viewer\n // (it reads ViewTypeID + DisplayState.viewTypeConfigs off the [viewEntity] and, with\n // [AutoSaveView]=\"true\", saves changes back) — nothing to wire here.\n }\n\n /**\n * Load a dynamic view (no saved view, just entity + filter)\n */\n private async loadDynamicView(entityName: string, _extraFilter?: string): Promise<void> {\n const entity = this.metadata.Entities.find(\n e => e.Name.trim().toLowerCase() === entityName.trim().toLowerCase()\n );\n\n if (!entity) {\n throw new Error(`Entity '${entityName}' not found`);\n }\n\n this.entityInfo = entity;\n this.viewEntity = null;\n this.gridState = null;\n\n // For dynamic views, we could create a synthetic viewEntity with just the WhereClause\n // but for now, we'll rely on the entity-viewer's default behavior\n }\n\n /**\n * Handle record opened event - open in new tab\n */\n public onRecordOpened(event: RecordOpenedEvent): void {\n if (event && event.entity && event.compositeKey) {\n this.navigationService.OpenEntityRecord(event.entity.Name, event.compositeKey);\n }\n }\n\n /**\n * Handle a related-record navigation requested from within a view-type renderer\n * (e.g. a foreign-key cell) - open the target record in a new tab.\n */\n public onOpenRelatedRecord(nav: ViewRelatedRecordNavigation): void {\n if (nav?.entityName && nav.recordKey != null) {\n // The related entity is arbitrary, so its key column can have any name — resolve the key\n // against its metadata rather than hardcoding `ID` via FromID.\n const entityInfo = this.metadata.EntityByName(nav.entityName);\n this.navigationService.OpenEntityRecord(nav.entityName, CompositeKey.FromURLSegment(entityInfo, String(nav.recordKey)));\n }\n }\n\n /**\n * Handle data loaded event from entity-viewer\n */\n public onDataLoaded(): void {\n this.NotifyLoadComplete();\n this.refreshFallbackExportVisibility();\n }\n\n /** The active view type changed — recompute whether the fallback Export button is needed. */\n public onViewTypeChanged(): void {\n this.refreshFallbackExportVisibility();\n }\n\n /**\n * Show the wrapper's Export button only for view types that don't ship their own export UI. The\n * entity-viewer reports this via {@link EntityViewerComponent.ActiveViewTypeHasOwnExport} (true for\n * the Grid renderer, false for Cards / Map / Timeline). Uses a cached flag + explicit change\n * detection to avoid an ExpressionChanged error from reading child state during a CD pass.\n */\n private refreshFallbackExportVisibility(): void {\n const next = !!this.entityViewerRef && !this.entityViewerRef.ActiveViewTypeHasOwnExport;\n if (next !== this.showFallbackExportButton) {\n this.showFallbackExportButton = next;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Fallback export for view types without their own export UI (Cards / Map / Timeline). Pulls the\n * FULL result set via the entity-viewer's capped, filter/sort-aware fetch (same path the grid uses,\n * so it's bounded and warns past the cap) and writes an Excel file.\n */\n public async onExport(): Promise<void> {\n // Never fail silently — a \"nothing happens\" click is impossible to diagnose. Surface the\n // reason both in the UI and the console.\n if (!this.entityInfo || !this.entityViewerRef) {\n console.error('[ViewResource] Export: viewer not ready', {\n hasEntity: !!this.entityInfo, hasViewer: !!this.entityViewerRef\n });\n this.showNotification('Export is not ready yet — try again in a moment.', 'error', 5000);\n return;\n }\n this.isExporting = true;\n this.cdr.detectChanges();\n this.showNotification('Preparing your Excel export…', 'info', 2000);\n try {\n const rows = await this.entityViewerRef.FetchAllRowsForExport();\n if (!rows || rows.length === 0) {\n this.showNotification('Nothing to export — the view returned no records.', 'warning', 5000);\n return;\n }\n const result = await this.exportService.toExcel(rows, {\n fileName: this.buildExportFileName(),\n columns: this.buildExportColumns(),\n includeHeaders: true\n });\n if (result.success) {\n this.exportService.downloadResult(result);\n this.showNotification(`Exported ${rows.length.toLocaleString()} record(s) to Excel.`, 'success', 3000);\n } else {\n this.showNotification('Export failed while building the file.', 'error', 5000);\n console.error('[ViewResource] Export: toExcel returned failure', result);\n }\n } catch (e) {\n this.showNotification('Error exporting data — see console for details.', 'error', 5000);\n console.error('[ViewResource] Export error:', e);\n } finally {\n this.isExporting = false;\n this.cdr.detectChanges();\n }\n }\n\n /**\n * Columns to export — from grid state, else the view's columns, else the entity's real fields. Each\n * column carries its field's export type, as the grid's export does, so a date-only field writes\n * a date cell on its stored day rather than a timestamp.\n */\n private buildExportColumns(): ExportColumn[] {\n if (!this.entityInfo) return [];\n const entity = this.entityInfo;\n const typed = (name: string, displayName: string): ExportColumn => {\n const field = entity.Fields.find(f => f.Name.toLowerCase() === name.toLowerCase());\n return { name, displayName, dataType: ExportColumnTypeForSQLType(field?.Type) };\n };\n if (this.gridState?.columnSettings && this.gridState.columnSettings.length > 0) {\n return this.gridState.columnSettings\n .filter(col => col.hidden !== true)\n .map(col => typed(col.Name, col.DisplayName || col.Name));\n }\n if (this.viewEntity?.Columns) {\n return this.viewEntity.Columns\n .filter(col => !col.hidden)\n .map(col => typed(col.Name, col.DisplayName || col.Name));\n }\n return entity.Fields\n .filter(f => !f.IsVirtual)\n .map(f => typed(f.Name, f.DisplayNameOrName));\n }\n\n private buildExportFileName(): string {\n const viewName = this.viewEntity?.Name || 'Data';\n return `${this.entityInfo!.Name}_${viewName}_${new Date().toISOString().split('T')[0]}`;\n }\n\n /**\n * Get display name for the resource tab\n */\n override async GetResourceDisplayName(data: ResourceData): Promise<string> {\n if (data.ResourceRecordID) {\n const compositeKey = CompositeKey.FromID(data.ResourceRecordID); // first-pk-ok: ResourceRecordID of a User Views resource — core entity keyed by ID\n const name = await this.metadata.GetEntityRecordName('MJ: User Views', compositeKey);\n return name ? name : `View: ${data.ResourceRecordID}`;\n }\n else if (data.Configuration?.Entity) {\n const entityName = data.Configuration.Entity as string;\n const hasFilter = data.Configuration.ExtraFilter;\n return `${entityName} [Dynamic${hasFilter ? ' - Filtered' : ' - All'}]`;\n }\n return 'User Views [Error]';\n }\n\n /**\n * Get icon class for the resource tab\n */\n override async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-table-list';\n }\n\n /**\n * Handle creating a new record for the current entity\n */\n public onCreateNewRecord(): void {\n if (!this.entityInfo) return;\n\n // Use NavigationService to open a new record form\n this.navigationService.OpenNewEntityRecord(this.entityInfo.Name);\n }\n\n /**\n * Open the Save-as-List dialog. Only meaningful for saved views (a\n * ViewID is required to materialize). Dynamic views fall back to a\n * user-visible notification rather than silently doing nothing.\n */\n public onSaveAsList(): void {\n if (!this.viewEntity?.ID) {\n this.showNotification('Save as List requires a saved View. Save this view first.', 'info', 4000);\n return;\n }\n // Best-effort record-count hint — the entity-viewer exposes the\n // grid's row count on its gridState; we surface it so the dialog's\n // confirm button can say \"Save List (476 records)\".\n this.saveAsListRecordCount = this.entityViewerRef?.TotalRecordCount ?? null;\n this.saveAsListDialogVisible = true;\n this.cdr.detectChanges();\n }\n\n public onSaveAsListCancelled(): void {\n this.saveAsListDialogVisible = false;\n this.cdr.detectChanges();\n }\n\n public async onSaveAsListSubmit(payload: SaveViewAsListResult): Promise<void> {\n const viewId = this.viewEntity?.ID;\n if (!viewId) return;\n this.isSavingAsList = true;\n this.cdr.detectChanges();\n try {\n const provider = this.ProviderToUse as unknown as GraphQLDataProvider;\n const client = new GraphQLListsClient(provider);\n const result = await client.MaterializeFromView(viewId, {\n ListName: payload.ListName,\n Description: payload.Description,\n CategoryId: payload.CategoryId,\n RememberLineage: payload.RememberLineage,\n UseSnapshot: payload.UseSnapshot,\n RefreshMode: payload.RefreshMode,\n });\n if (result.Success && result.CreatedListId) {\n this.saveAsListDialogVisible = false;\n this.showNotification(\n `List created with ${result.Counts?.Added ?? 0} record(s).`,\n 'success',\n 3000,\n );\n this.navigationService.OpenEntityRecord('MJ: Lists', CompositeKey.FromID(result.CreatedListId));\n } else {\n this.showNotification(`Save failed: ${result.Message}`, 'error', 5000);\n }\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n this.showNotification(`Save failed: ${message}`, 'error', 5000);\n } finally {\n this.isSavingAsList = false;\n this.cdr.detectChanges();\n }\n }\n\n\n /**\n * Show a notification to the user\n */\n private showNotification(message: string, style: 'info' | 'success' | 'error' | 'warning', duration: number): void {\n MJGlobal.Instance.RaiseEvent({\n component: this,\n event: MJEventType.DisplaySimpleNotificationRequest,\n eventCode: '',\n args: {\n message,\n style,\n DisplayDuration: duration\n }\n });\n }\n}\n","<div #container class=\"view-resource-container\">\n @if (isLoading) {\n <div class=\"view-loading-state\">\n <mj-loading text=\"Loading view...\" size=\"large\"></mj-loading>\n </div>\n } @else if (errorMessage) {\n <div class=\"view-error-state\">\n <i class=\"fas fa-exclamation-triangle\"></i>\n <p>{{ errorMessage }}</p>\n </div>\n } @else if (entityInfo) {\n <!-- Header with title and action buttons -->\n <div class=\"view-header\">\n <div class=\"header-left\">\n <h2 class=\"view-title\">{{ viewEntity?.Name || entityInfo.Name }}</h2>\n @if (viewEntity?.Description) {\n <p class=\"view-description\">{{ viewEntity!.Description }}</p>\n }\n </div>\n <div class=\"header-right\">\n <!-- Create New Record Button -->\n <button\n class=\"action-button create-button\"\n (click)=\"onCreateNewRecord()\"\n title=\"Create new {{ entityInfo.Name }} record\">\n <i class=\"fa-solid fa-plus\"></i>\n <span>New Record</span>\n </button>\n\n <!-- Save as List Button — only meaningful for saved (non-dynamic) views. -->\n @if (viewEntity?.ID) {\n <button\n class=\"action-button save-as-list-button\"\n (click)=\"onSaveAsList()\"\n [disabled]=\"isSavingAsList\"\n title=\"Materialize these results as a static List\">\n @if (isSavingAsList) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-floppy-disk\"></i>\n }\n <span>{{ isSavingAsList ? 'Saving...' : 'Save as List' }}</span>\n </button>\n }\n <!-- Fallback Export button. Shown ONLY for view types that lack their own export UI\n (Cards / Map / Timeline). The Grid renderer has its own in-toolbar Export (full\n result set + format/sampling dialog), so this is suppressed there to avoid a\n duplicate/confusing second button. -->\n @if (showFallbackExportButton) {\n <button\n class=\"action-button export-button\"\n (click)=\"onExport()\"\n [disabled]=\"isExporting\"\n title=\"Export\">\n @if (isExporting) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-file-excel\"></i>\n }\n <span>{{ isExporting ? 'Exporting...' : 'Export' }}</span>\n </button>\n }\n </div>\n </div>\n\n <!-- Entity Viewer -->\n <mj-entity-viewer\n #entityViewer\n [Entity]=\"entityInfo\"\n [Provider]=\"Provider\"\n [ViewEntity]=\"viewEntity\"\n [GridState]=\"gridState\"\n [AutoSaveView]=\"true\"\n (RecordOpened)=\"onRecordOpened($any($event))\"\n (OpenRelatedRecordRequested)=\"onOpenRelatedRecord($event)\"\n (AfterViewTypeChange)=\"onViewTypeChanged()\"\n (DataLoaded)=\"onDataLoaded()\">\n </mj-entity-viewer>\n\n <!-- Save-as-List dialog -->\n <mj-save-view-as-list-dialog\n [Provider]=\"ProviderToUse\"\n [Visible]=\"saveAsListDialogVisible\"\n [ViewId]=\"viewEntity?.ID ?? null\"\n [ViewName]=\"viewEntity?.Name ?? null\"\n [RecordCount]=\"saveAsListRecordCount\"\n (Save)=\"onSaveAsListSubmit($event)\"\n (Cancel)=\"onSaveAsListCancelled()\">\n </mj-save-view-as-list-dialog>\n }\n</div>\n"]}
|
|
@@ -64,13 +64,28 @@ export declare class ComponentCacheManager {
|
|
|
64
64
|
* Generate a unique cache key from resource identity.
|
|
65
65
|
* This is the ONE canonical key format used by ALL cache operations.
|
|
66
66
|
*
|
|
67
|
-
* `discriminator` is appended into the recordId slot
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* would otherwise both cache at `appId::RecordResource::__no_record__`
|
|
71
|
-
* each other.
|
|
67
|
+
* `discriminator` is appended into the recordId slot when the recordId alone does not
|
|
68
|
+
* identify the resource:
|
|
69
|
+
* - **Empty recordId** — distinct "new record" tabs, e.g. a new MJ:Companies form and a new
|
|
70
|
+
* MJ:Employees form, would otherwise both cache at `appId::RecordResource::__no_record__`
|
|
71
|
+
* and clobber each other.
|
|
72
|
+
* - **The `'dynamic'` view marker** — `NavigationService.OpenDynamicView` stamps every
|
|
73
|
+
* dynamic view with that same recordId, so without the entity every dynamic view in an app
|
|
74
|
+
* shares one key. A reload from `#Accounts` to `#Contacts` would then get a cache hit on the
|
|
75
|
+
* Accounts component, which never has its `Data` rebound, so the tab keeps showing Accounts
|
|
76
|
+
* and the tab-container's entity check fires again on every emission.
|
|
77
|
+
*
|
|
78
|
+
* Passing the entity name as discriminator keeps them separate. Whatever the tab-container's
|
|
79
|
+
* reload check compares has to be part of this key, or a reload is handed back the component
|
|
80
|
+
* it just detached.
|
|
72
81
|
*/
|
|
73
82
|
private getCacheKey;
|
|
83
|
+
/**
|
|
84
|
+
* Whether a recordId is the `'dynamic'` marker `NavigationService.OpenDynamicView` stamps on a
|
|
85
|
+
* dynamic view, which is not a saved-view ID. Matched the way `ViewResourceComponent` matches it
|
|
86
|
+
* (trimmed, case-insensitive), so the cache and the view agree on what counts as dynamic.
|
|
87
|
+
*/
|
|
88
|
+
static IsDynamicViewMarker(recordId: string | null | undefined): boolean;
|
|
74
89
|
/**
|
|
75
90
|
* Check if a component exists in cache and is available for reuse.
|
|
76
91
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-cache-manager.d.ts","sourceRoot":"","sources":["../../../../../src/lib/shell/components/tabs/component-cache-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAElC,YAAY,EAAE,YAAY,CAAC,qBAAqB,CAAC,CAAC;IAGlD,cAAc,EAAE,WAAW,CAAC;IAG5B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IAMtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAG1B,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAG/B,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;IAGhB,YAAY,EAAE,YAAY,CAAC;IAK3B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI1C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAIvC,gBAAgB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,EAAE,CAAC;CACtK;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,qBAAqB;IAiBpB,OAAO,CAAC,MAAM;IAAkB,OAAO,CAAC,iBAAiB,CAAC;IAhBtE,OAAO,CAAC,KAAK,CAA0C;IAEvD;;;;OAIG;IACH,OAAc,qBAAqB,EAAE,MAAM,CAAM;IAEjD;;;;;;OAMG;gBACiB,MAAM,EAAE,cAAc,EAAU,iBAAiB,CAAC,EAAE,iBAAiB,YAAA;IAEzF
|
|
1
|
+
{"version":3,"file":"component-cache-manager.d.ts","sourceRoot":"","sources":["../../../../../src/lib/shell/components/tabs/component-cache-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,17 +40,42 @@ export class ComponentCacheManager {
|
|
|
40
40
|
* Generate a unique cache key from resource identity.
|
|
41
41
|
* This is the ONE canonical key format used by ALL cache operations.
|
|
42
42
|
*
|
|
43
|
-
* `discriminator` is appended into the recordId slot
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* would otherwise both cache at `appId::RecordResource::__no_record__`
|
|
47
|
-
* each other.
|
|
43
|
+
* `discriminator` is appended into the recordId slot when the recordId alone does not
|
|
44
|
+
* identify the resource:
|
|
45
|
+
* - **Empty recordId** — distinct "new record" tabs, e.g. a new MJ:Companies form and a new
|
|
46
|
+
* MJ:Employees form, would otherwise both cache at `appId::RecordResource::__no_record__`
|
|
47
|
+
* and clobber each other.
|
|
48
|
+
* - **The `'dynamic'` view marker** — `NavigationService.OpenDynamicView` stamps every
|
|
49
|
+
* dynamic view with that same recordId, so without the entity every dynamic view in an app
|
|
50
|
+
* shares one key. A reload from `#Accounts` to `#Contacts` would then get a cache hit on the
|
|
51
|
+
* Accounts component, which never has its `Data` rebound, so the tab keeps showing Accounts
|
|
52
|
+
* and the tab-container's entity check fires again on every emission.
|
|
53
|
+
*
|
|
54
|
+
* Passing the entity name as discriminator keeps them separate. Whatever the tab-container's
|
|
55
|
+
* reload check compares has to be part of this key, or a reload is handed back the component
|
|
56
|
+
* it just detached.
|
|
48
57
|
*/
|
|
49
58
|
getCacheKey(resourceType, recordId, appId, discriminator) {
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
let normalizedRecordId;
|
|
60
|
+
if (!recordId) {
|
|
61
|
+
normalizedRecordId = discriminator ? `__new__::${discriminator}` : '__no_record__';
|
|
62
|
+
}
|
|
63
|
+
else if (discriminator && ComponentCacheManager.IsDynamicViewMarker(recordId)) {
|
|
64
|
+
normalizedRecordId = `dynamic::${discriminator}`;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
normalizedRecordId = recordId;
|
|
68
|
+
}
|
|
52
69
|
return `${appId}::${resourceType}::${normalizedRecordId}`;
|
|
53
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Whether a recordId is the `'dynamic'` marker `NavigationService.OpenDynamicView` stamps on a
|
|
73
|
+
* dynamic view, which is not a saved-view ID. Matched the way `ViewResourceComponent` matches it
|
|
74
|
+
* (trimmed, case-insensitive), so the cache and the view agree on what counts as dynamic.
|
|
75
|
+
*/
|
|
76
|
+
static IsDynamicViewMarker(recordId) {
|
|
77
|
+
return typeof recordId === 'string' && recordId.trim().toLowerCase() === 'dynamic';
|
|
78
|
+
}
|
|
54
79
|
/**
|
|
55
80
|
* Check if a component exists in cache and is available for reuse.
|
|
56
81
|
*/
|