@memberjunction/ng-explorer-core 6.1.4 → 6.1.6
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/tab-container.component.d.ts +14 -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 +72 -12
- package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
- package/dist/lib/shell/shell.component.d.ts +33 -2
- package/dist/lib/shell/shell.component.d.ts.map +1 -1
- package/dist/lib/shell/shell.component.js +84 -6
- 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"]}
|
|
@@ -47,6 +47,7 @@ export declare class TabContainerComponent extends BaseAngularComponent implemen
|
|
|
47
47
|
/** Pane-level origin crumbs, one per record pane (see RecordOriginCrumbComponent) */
|
|
48
48
|
private originCrumbRefs;
|
|
49
49
|
private tabsCurrentlyLoading;
|
|
50
|
+
private pendingRecordShows;
|
|
50
51
|
private cacheManager;
|
|
51
52
|
useSingleResourceMode: boolean;
|
|
52
53
|
private singleResourceComponentRef;
|
|
@@ -188,6 +189,19 @@ export declare class TabContainerComponent extends BaseAngularComponent implemen
|
|
|
188
189
|
* `ensureRecordOriginCrumb` once the incoming record attaches.
|
|
189
190
|
*/
|
|
190
191
|
private reloadRecordsTabIfResourceChanged;
|
|
192
|
+
/**
|
|
193
|
+
* Load a record tab's content into its GL container and mark it loaded —
|
|
194
|
+
* the second half of the TabShown handler, split out so a show parked
|
|
195
|
+
* while the region was hidden can be replayed on reveal.
|
|
196
|
+
*/
|
|
197
|
+
private loadShownRecordTab;
|
|
198
|
+
/**
|
|
199
|
+
* Replay the shows parked while the records region was hidden (see the
|
|
200
|
+
* TabShown handler). Always against the LIVE container: a breakpoint
|
|
201
|
+
* rebuild between park and reveal replaces the one GL handed us (and its
|
|
202
|
+
* Destroy fires TabClosed, which drops the stale entry anyway).
|
|
203
|
+
*/
|
|
204
|
+
private flushPendingRecordShows;
|
|
191
205
|
/** Focus a records-region tab without feeding back into SetActiveTab loops */
|
|
192
206
|
private focusRecordsTab;
|
|
193
207
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tab-container.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/shell/components/tabs/tab-container.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,MAAM,EACN,SAAS,EACT,aAAa,EAEb,UAAU,EACV,cAAc,EACd,mBAAmB,EAKnB,iBAAiB,EAGjB,YAAY,EAEb,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAMnB,MAAM,qCAAqC,CAAC;AAM7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gDAAgD,CAAC;AAGrF,OAAO,EAAyB,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAIrE;;;;;;;;;GASG;AACH,qBAOa,qBAAsB,SAAQ,oBAAqB,YAAW,MAAM,EAAE,SAAS,EAAE,aAAa;
|
|
1
|
+
{"version":3,"file":"tab-container.component.d.ts","sourceRoot":"","sources":["../../../../../src/lib/shell/components/tabs/tab-container.component.ts"],"names":[],"mappings":"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"}
|
|
@@ -188,6 +188,15 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
188
188
|
// When a tab's content changes while active, both the reload path (workspace config subscription)
|
|
189
189
|
// and onTabShown can race to call loadTabContent, resulting in duplicate component rendering.
|
|
190
190
|
tabsCurrentlyLoading = new Set();
|
|
191
|
+
// Record-tab shows GL fired while the records region was HIDDEN, by tab id.
|
|
192
|
+
// Their content loads are deferred until the region is the visible surface —
|
|
193
|
+
// see the TabShown handler in wireRecordsLayoutEvents.
|
|
194
|
+
//
|
|
195
|
+
// A SET, not a map of containers: the replay deliberately re-resolves the live
|
|
196
|
+
// container via GetContainer(tabId), so a parked one would never be read — and
|
|
197
|
+
// holding it would retain a GL container, and its possibly-detached DOM, for as
|
|
198
|
+
// long as the region stays hidden. The type says the id is all that is kept.
|
|
199
|
+
pendingRecordShows = new Set();
|
|
191
200
|
// NEW: Smart component cache for preserving state across tab switches
|
|
192
201
|
cacheManager;
|
|
193
202
|
// Single-resource mode: render component directly without Golden Layout
|
|
@@ -420,6 +429,9 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
420
429
|
// Flush NOW — the visibility class must land in this pass, not
|
|
421
430
|
// whenever the next unrelated emission happens to run CD.
|
|
422
431
|
this.flushRegionCd();
|
|
432
|
+
if (showing) {
|
|
433
|
+
this.flushPendingRecordShows();
|
|
434
|
+
}
|
|
423
435
|
}
|
|
424
436
|
if (showing && activeTab && this.recordsLayoutInitialized) {
|
|
425
437
|
this.focusRecordsTab(activeTab.id);
|
|
@@ -536,6 +548,46 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
536
548
|
}
|
|
537
549
|
return true;
|
|
538
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* Load a record tab's content into its GL container and mark it loaded —
|
|
553
|
+
* the second half of the TabShown handler, split out so a show parked
|
|
554
|
+
* while the region was hidden can be replayed on reveal.
|
|
555
|
+
*/
|
|
556
|
+
async loadShownRecordTab(tabId, container) {
|
|
557
|
+
await this.loadTabContent(tabId, container);
|
|
558
|
+
// Mark loaded ONLY when content actually attached to the LIVE
|
|
559
|
+
// container. During layout restore, GL can re-render item elements
|
|
560
|
+
// while an async load is in flight — the load appends into a
|
|
561
|
+
// detached element and the visible pane stays blank. Leaving the
|
|
562
|
+
// tab unmarked lets the next show retry, which hits the component
|
|
563
|
+
// cache and reattaches instantly into the live element.
|
|
564
|
+
const live = this.recordsLayoutManager.GetContainer(tabId);
|
|
565
|
+
if (live?.element && live.element.childElementCount > 0) {
|
|
566
|
+
this.recordsLayoutManager.MarkTabLoaded(tabId);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Replay the shows parked while the records region was hidden (see the
|
|
571
|
+
* TabShown handler). Always against the LIVE container: a breakpoint
|
|
572
|
+
* rebuild between park and reveal replaces the one GL handed us (and its
|
|
573
|
+
* Destroy fires TabClosed, which drops the stale entry anyway).
|
|
574
|
+
*/
|
|
575
|
+
flushPendingRecordShows() {
|
|
576
|
+
if (this.pendingRecordShows.size === 0) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const parked = [...this.pendingRecordShows];
|
|
580
|
+
this.pendingRecordShows.clear();
|
|
581
|
+
for (const tabId of parked) {
|
|
582
|
+
if (this.recordsLayoutManager.IsTabLoaded(tabId)) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
const live = this.recordsLayoutManager.GetContainer(tabId);
|
|
586
|
+
if (live) {
|
|
587
|
+
this.loadShownRecordTab(tabId, live).catch(e => LogError(`Deferred record tab load failed for ${tabId}: ${e}`));
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
539
591
|
/** Focus a records-region tab without feeding back into SetActiveTab loops */
|
|
540
592
|
focusRecordsTab(tabId) {
|
|
541
593
|
if (this.recordsRegionActiveTabId !== tabId) {
|
|
@@ -781,20 +833,28 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
781
833
|
*/
|
|
782
834
|
wireRecordsLayoutEvents() {
|
|
783
835
|
this.subscriptions.push(this.recordsLayoutManager.TabShown.subscribe(async (event) => {
|
|
784
|
-
if (event.isFirstShow) {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
836
|
+
if (!event.isFirstShow) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
// LAZY content. The records GL initializes EAGERLY (see
|
|
840
|
+
// ensureRecordsLayoutInitialized) so the strip and the pill never
|
|
841
|
+
// drift from the workspace — and as it builds, GL fires 'show' for
|
|
842
|
+
// every stack's active tab while the region is still
|
|
843
|
+
// visibility-hidden behind the main surface. Loading content on
|
|
844
|
+
// those shows means every restored record hydrates at BOOT: an open
|
|
845
|
+
// AI Agent Run pulls its whole run tree (every prompt run, action
|
|
846
|
+
// log, step) before the user has looked at it, and client-side
|
|
847
|
+
// RunView coalescing folds the ACTIVE tab's own reads into the same
|
|
848
|
+
// requests, so the surface the user is looking at waits for records
|
|
849
|
+
// they are not. Park the show; it is replayed when the region shows.
|
|
850
|
+
if (!this.ShowRecordsRegion) {
|
|
851
|
+
this.pendingRecordShows.add(event.tabId);
|
|
852
|
+
return;
|
|
796
853
|
}
|
|
854
|
+
this.pendingRecordShows.delete(event.tabId);
|
|
855
|
+
await this.loadShownRecordTab(event.tabId, event.container);
|
|
797
856
|
}), this.recordsLayoutManager.TabClosed.subscribe(async (tabId) => {
|
|
857
|
+
this.pendingRecordShows.delete(tabId);
|
|
798
858
|
this.cleanupTabComponent(tabId);
|
|
799
859
|
// REBUILD guard (breakpoint crossing): Destroy() fires TabClosed for
|
|
800
860
|
// every pane. The tabs are NOT closing — the layout is being rebuilt
|