@memberjunction/ng-shared 5.43.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/base-resource-component.d.ts +1 -0
- package/dist/lib/base-resource-component.d.ts.map +1 -1
- package/dist/lib/base-resource-component.js +16 -1
- package/dist/lib/base-resource-component.js.map +1 -1
- package/dist/lib/navigation.service.d.ts +48 -0
- package/dist/lib/navigation.service.d.ts.map +1 -1
- package/dist/lib/navigation.service.js +99 -0
- package/dist/lib/navigation.service.js.map +1 -1
- package/package.json +12 -12
- package/dist/lib/__tests__/navigation-framework.test.d.ts +0 -2
- package/dist/lib/__tests__/navigation-framework.test.d.ts.map +0 -1
- package/dist/lib/__tests__/navigation-framework.test.js +0 -307
- package/dist/lib/__tests__/navigation-framework.test.js.map +0 -1
- package/dist/lib/__tests__/shared.test.d.ts +0 -2
- package/dist/lib/__tests__/shared.test.d.ts.map +0 -1
- package/dist/lib/__tests__/shared.test.js +0 -265
- package/dist/lib/__tests__/shared.test.js.map +0 -1
|
@@ -96,6 +96,7 @@ export declare abstract class BaseResourceComponent extends BaseNavigationCompon
|
|
|
96
96
|
* wrappers for child dashboards), then falls back to Data.Configuration.tabId.
|
|
97
97
|
*/
|
|
98
98
|
getTabId(): string;
|
|
99
|
+
private getQueryParamUpdateGuard;
|
|
99
100
|
protected NotifyLoadComplete(): void;
|
|
100
101
|
protected NotifyLoadStarted(): void;
|
|
101
102
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-resource-component.d.ts","sourceRoot":"","sources":["../../src/lib/base-resource-component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAE,SAAS,EAAiB,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"base-resource-component.d.ts","sourceRoot":"","sources":["../../src/lib/base-resource-component.ts"],"names":[],"mappings":"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"}
|
|
@@ -119,7 +119,12 @@ export class BaseResourceComponent extends BaseNavigationComponent {
|
|
|
119
119
|
UpdateQueryParams(params) {
|
|
120
120
|
if (this._suppressQueryParamSync)
|
|
121
121
|
return;
|
|
122
|
-
this.
|
|
122
|
+
const tabId = this.getTabId();
|
|
123
|
+
if (!tabId) {
|
|
124
|
+
this.navigationService.UpdateActiveTabQueryParams(params);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.navigationService.UpdateTabQueryParams(tabId, params, this.getQueryParamUpdateGuard());
|
|
123
128
|
}
|
|
124
129
|
/**
|
|
125
130
|
* Read current query params from tab configuration.
|
|
@@ -201,6 +206,16 @@ export class BaseResourceComponent extends BaseNavigationComponent {
|
|
|
201
206
|
getTabId() {
|
|
202
207
|
return this.ParentTabId || this.Data?.Configuration?.['tabId'] || '';
|
|
203
208
|
}
|
|
209
|
+
getQueryParamUpdateGuard() {
|
|
210
|
+
const config = this.Data?.Configuration || {};
|
|
211
|
+
return {
|
|
212
|
+
resourceType: config['resourceType'],
|
|
213
|
+
driverClass: (config['resourceTypeDriverClass'] || config['driverClass']),
|
|
214
|
+
recordId: (this.Data?.ResourceRecordID || config['recordId']),
|
|
215
|
+
navItemName: config['navItemName'],
|
|
216
|
+
entity: (config['Entity'] || config['entity'])
|
|
217
|
+
};
|
|
218
|
+
}
|
|
204
219
|
NotifyLoadComplete() {
|
|
205
220
|
this._loadComplete = true;
|
|
206
221
|
if (this._loadCompleteWatchdog) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-resource-component.js","sourceRoot":"","sources":["../../src/lib/base-resource-component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Directive, OnInit, OnDestroy, Input, inject } from \"@angular/core\";\nimport { Subject } from \"rxjs\";\nimport { filter, takeUntil } from \"rxjs/operators\";\nimport { BaseEntity } from \"@memberjunction/core\";\nimport { BaseNavigationComponent } from \"./base-navigation-component\";\nimport { ResourceData } from \"@memberjunction/core-entities\";\nimport { NavigationService } from \"./navigation.service\";\n\n@Directive()\nexport abstract class BaseResourceComponent extends BaseNavigationComponent implements OnInit, OnDestroy {\n private _data: ResourceData = new ResourceData();\n private _suppressQueryParamSync = false;\n /** Stable key of the most recently delivered query params, used to de-duplicate\n * delivery across the reactive (initial/deep-link) and popstate paths. */\n private _lastDeliveredParamsKey: string | null = null;\n protected destroy$ = new Subject<void>();\n protected navigationService = inject(NavigationService);\n\n /**\n * Tab ID for query param notification scoping. Set by resource wrappers\n * that render child dashboards, so the child knows which tab it belongs to.\n * If not set, falls back to Data.Configuration.tabId.\n */\n @Input() ParentTabId: string | null = null;\n\n public get Data(): ResourceData {\n return this._data;\n }\n public set Data(value: ResourceData) {\n this._data = value;\n }\n\n private _loadComplete: boolean = false;\n public get LoadComplete(): boolean {\n return this._loadComplete;\n }\n\n /**\n * Watchdog window: if a resource component hasn't called {@link NotifyLoadComplete} within this\n * time, we log a warning naming the offending class. The app loading screen waits on\n * NotifyLoadComplete, so a resource that never calls it hangs the screen forever — this makes the\n * culprit obvious in the console instead of leaving a mystery \"stuck loading\" state.\n */\n private static readonly LOAD_COMPLETE_WATCHDOG_MS = 15_000;\n private _loadCompleteWatchdog: ReturnType<typeof setTimeout> | null = null;\n\n private _loadStarted: boolean = false;\n public get LoadStarted(): boolean {\n return this._loadStarted;\n }\n\n\n private _loadCompleteEvent: any = null;\n public get LoadCompleteEvent(): any {\n return this._loadCompleteEvent\n }\n public set LoadCompleteEvent(value: any) {\n this._loadCompleteEvent = value;\n }\n\n private _loadStartedEvent: any = null;\n public get LoadStartedEvent(): any {\n return this._loadStartedEvent\n }\n public set LoadStartedEvent(value: any) {\n this._loadStartedEvent = value;\n }\n\n private _resourceRecordSavedEvent: any = null;\n public get ResourceRecordSavedEvent(): any {\n return this._resourceRecordSavedEvent\n }\n public set ResourceRecordSavedEvent(value: any) {\n this._resourceRecordSavedEvent = value;\n }\n\n private _resourceCloseRequestedEvent: (() => void) | null = null;\n public get ResourceCloseRequestedEvent(): (() => void) | null {\n return this._resourceCloseRequestedEvent;\n }\n public set ResourceCloseRequestedEvent(value: (() => void) | null) {\n this._resourceCloseRequestedEvent = value;\n }\n\n private _displayNameChangedEvent: ((newName: string) => void) | null = null;\n public get DisplayNameChangedEvent(): ((newName: string) => void) | null {\n return this._displayNameChangedEvent;\n }\n public set DisplayNameChangedEvent(value: ((newName: string) => void) | null) {\n this._displayNameChangedEvent = value;\n }\n\n ngOnInit(): void {\n // Order matters: set up the popstate subscription first (a plain Subject — emits\n // nothing on subscribe), then the reactive initial-delivery subscription (backed by\n // a BehaviorSubject — emits the current params synchronously). This lets the initial\n // emission claim the 'deeplink' source before any later popstate event.\n this.setupQueryParamSubscription();\n this.setupInitialParamDelivery();\n\n // Start the NotifyLoadComplete watchdog (no-op once it fires or load completes).\n this._loadCompleteWatchdog = setTimeout(() => {\n if (!this._loadComplete) {\n // eslint-disable-next-line no-console\n console.warn(\n `[LoadComplete WATCHDOG] ${this.constructor.name} has NOT called NotifyLoadComplete() ` +\n `within ${BaseResourceComponent.LOAD_COMPLETE_WATCHDOG_MS / 1000}s. The app loading screen ` +\n `waits on this signal — if the screen is stuck, this resource is the likely cause. ` +\n `(tabId=${this.getTabId() || 'n/a'})`\n );\n }\n }, BaseResourceComponent.LOAD_COMPLETE_WATCHDOG_MS);\n }\n\n ngOnDestroy(): void {\n if (this._loadCompleteWatchdog) {\n clearTimeout(this._loadCompleteWatchdog);\n this._loadCompleteWatchdog = null;\n }\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n /**\n * Called by the framework when query params change from an external source\n * (browser back/forward, deep link navigation).\n * Override in subclasses to react to query param changes.\n * @param params The new query params from the URL\n * @param source 'popstate' for back/forward, 'deeplink' for external URL entry\n */\n protected OnQueryParamsChanged(params: Record<string, string>, source: 'popstate' | 'deeplink'): void {\n // Default no-op — override in subclasses\n }\n\n /**\n * Push query param changes to the URL. Creates a browser history entry.\n * Safe to call during OnQueryParamsChanged — auto-suppressed to prevent loops.\n */\n protected UpdateQueryParams(params: Record<string, string | null>): void {\n if (this._suppressQueryParamSync) return;\n this.navigationService.UpdateActiveTabQueryParams(params);\n }\n\n /**\n * Read current query params from tab configuration.\n * Use in initDashboard() / ngOnInit() to get initial URL state.\n */\n protected GetQueryParams(): Record<string, string> {\n return (this.Data?.Configuration?.['queryParams'] as Record<string, string>) || {};\n }\n\n /**\n * Internal: subscribe to NavigationService query param notifications.\n * Filters to only this component's tab to prevent cross-tab leakage.\n * This is the explicit back/forward (popstate) path.\n */\n private setupQueryParamSubscription(): void {\n this.navigationService.QueryParamChanged$\n .pipe(\n filter(event => {\n const myTabId = this.getTabId();\n return !myTabId || event.TabId === myTabId;\n }),\n takeUntil(this.destroy$)\n )\n .subscribe(event => this.deliverQueryParams(event.Params));\n }\n\n /**\n * Internal: reactively deliver this tab's query params from the workspace\n * BehaviorSubject. Because the source replays the current value on subscribe and\n * emits future changes, this delivers initial deep-link params even when the\n * component mounts (e.g. from workspace restoration) before the URL params have\n * been merged into the tab configuration — closing the cold-load race that the\n * popstate-only path could not.\n */\n private setupInitialParamDelivery(): void {\n const tabId = this.getTabId();\n if (!tabId) {\n return; // No tab scope (e.g. embedded usage) — nothing to observe.\n }\n this.navigationService.ObserveTabQueryParams(tabId)\n .pipe(takeUntil(this.destroy$))\n .subscribe(params => this.deliverQueryParams(params));\n }\n\n /**\n * Internal: funnel point for both the reactive and popstate paths. De-duplicates\n * identical deliveries (the two paths overlap on back/forward) and labels the first\n * meaningful delivery as a 'deeplink', subsequent ones as 'popstate'.\n */\n private deliverQueryParams(params: Record<string, string>): void {\n const key = this.queryParamsKey(params);\n if (key === this._lastDeliveredParamsKey) {\n return; // Already delivered these exact params.\n }\n const isInitial = this._lastDeliveredParamsKey === null;\n // Don't fire an initial no-op: a component entered without deep-link params has\n // nothing to apply. Leave _lastDeliveredParamsKey null so the first real params\n // (whenever they arrive) are still treated as the deep-link entry.\n if (isInitial && Object.keys(params).length === 0) {\n return;\n }\n this._lastDeliveredParamsKey = key;\n const source: 'popstate' | 'deeplink' = isInitial ? 'deeplink' : 'popstate';\n // try/finally ensures the suppression flag is always cleared, even if\n // OnQueryParamsChanged throws.\n this._suppressQueryParamSync = true;\n try {\n this.OnQueryParamsChanged(params, source);\n } finally {\n this._suppressQueryParamSync = false;\n }\n }\n\n /** Stable, order-independent string key for a query param record. */\n private queryParamsKey(params: Record<string, string>): string {\n return Object.keys(params)\n .sort()\n .map(k => `${k}=${params[k]}`)\n .join('&');\n }\n\n /**\n * Get this component's tab ID. Checks ParentTabId input first (set by resource\n * wrappers for child dashboards), then falls back to Data.Configuration.tabId.\n */\n public getTabId(): string {\n return this.ParentTabId || this.Data?.Configuration?.['tabId'] as string || '';\n }\n\n protected NotifyLoadComplete() {\n this._loadComplete = true;\n if (this._loadCompleteWatchdog) {\n clearTimeout(this._loadCompleteWatchdog);\n this._loadCompleteWatchdog = null;\n }\n if (this._loadCompleteEvent) {\n this._loadCompleteEvent();\n }\n }\n\n protected NotifyLoadStarted() {\n this._loadStarted = true;\n if (this._loadStartedEvent) {\n this._loadStartedEvent();\n }\n }\n\n\n\n /**\n * Call this to notify the tab system that the resource's display name has changed.\n * The tab container will update the tab title and browser title accordingly.\n */\n protected NotifyDisplayNameChanged(newName: string): void {\n if (this._displayNameChangedEvent) {\n this._displayNameChangedEvent(newName);\n }\n }\n\n protected ResourceRecordSaved(resourceRecordEntity: BaseEntity) {\n // Use ToURLSegment, NOT ToString. ResourceRecordID is consumed by\n // EntityRecordResource.GetPrimaryKey → CompositeKey.LoadFromURLSegment, which\n // expects URL-segment format (e.g. \"ID|<uuid>\"). ToString produces \"ID=<uuid>\",\n // which LoadFromURLSegment treats as a raw value and double-prefixes —\n // breaking any code path that re-reads this field after save.\n this.Data.ResourceRecordID = resourceRecordEntity.PrimaryKey.ToURLSegment();\n if (this._resourceRecordSavedEvent) {\n this._resourceRecordSavedEvent(resourceRecordEntity);\n }\n }\n\n /**\n * Ask the host shell to close/dismiss this resource (typically: close the tab).\n * Called by subclasses that hosted a form that emitted a 'dismiss' navigation\n * event — most often, a brand-new record where the user clicked Discard. The\n * record was never saved, the form is empty, and leaving it open serves no\n * purpose. The tab-container listens for this and closes the workspace tab.\n */\n protected NotifyCloseRequested(): void {\n if (this._resourceCloseRequestedEvent) {\n this._resourceCloseRequestedEvent();\n }\n }\n\n abstract GetResourceDisplayName(data: ResourceData): Promise<string>\n\n abstract GetResourceIconClass(data: ResourceData): Promise<string>\n}\n"]}
|
|
1
|
+
{"version":3,"file":"base-resource-component.js","sourceRoot":"","sources":["../../src/lib/base-resource-component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Directive, OnInit, OnDestroy, Input, inject } from \"@angular/core\";\nimport { Subject } from \"rxjs\";\nimport { filter, takeUntil } from \"rxjs/operators\";\nimport { BaseEntity } from \"@memberjunction/core\";\nimport { BaseNavigationComponent } from \"./base-navigation-component\";\nimport { ResourceData } from \"@memberjunction/core-entities\";\nimport { NavigationService, TabQueryParamUpdateGuard } from \"./navigation.service\";\n\n@Directive()\nexport abstract class BaseResourceComponent extends BaseNavigationComponent implements OnInit, OnDestroy {\n private _data: ResourceData = new ResourceData();\n private _suppressQueryParamSync = false;\n /** Stable key of the most recently delivered query params, used to de-duplicate\n * delivery across the reactive (initial/deep-link) and popstate paths. */\n private _lastDeliveredParamsKey: string | null = null;\n protected destroy$ = new Subject<void>();\n protected navigationService = inject(NavigationService);\n\n /**\n * Tab ID for query param notification scoping. Set by resource wrappers\n * that render child dashboards, so the child knows which tab it belongs to.\n * If not set, falls back to Data.Configuration.tabId.\n */\n @Input() ParentTabId: string | null = null;\n\n public get Data(): ResourceData {\n return this._data;\n }\n public set Data(value: ResourceData) {\n this._data = value;\n }\n\n private _loadComplete: boolean = false;\n public get LoadComplete(): boolean {\n return this._loadComplete;\n }\n\n /**\n * Watchdog window: if a resource component hasn't called {@link NotifyLoadComplete} within this\n * time, we log a warning naming the offending class. The app loading screen waits on\n * NotifyLoadComplete, so a resource that never calls it hangs the screen forever — this makes the\n * culprit obvious in the console instead of leaving a mystery \"stuck loading\" state.\n */\n private static readonly LOAD_COMPLETE_WATCHDOG_MS = 15_000;\n private _loadCompleteWatchdog: ReturnType<typeof setTimeout> | null = null;\n\n private _loadStarted: boolean = false;\n public get LoadStarted(): boolean {\n return this._loadStarted;\n }\n\n\n private _loadCompleteEvent: any = null;\n public get LoadCompleteEvent(): any {\n return this._loadCompleteEvent\n }\n public set LoadCompleteEvent(value: any) {\n this._loadCompleteEvent = value;\n }\n\n private _loadStartedEvent: any = null;\n public get LoadStartedEvent(): any {\n return this._loadStartedEvent\n }\n public set LoadStartedEvent(value: any) {\n this._loadStartedEvent = value;\n }\n\n private _resourceRecordSavedEvent: any = null;\n public get ResourceRecordSavedEvent(): any {\n return this._resourceRecordSavedEvent\n }\n public set ResourceRecordSavedEvent(value: any) {\n this._resourceRecordSavedEvent = value;\n }\n\n private _resourceCloseRequestedEvent: (() => void) | null = null;\n public get ResourceCloseRequestedEvent(): (() => void) | null {\n return this._resourceCloseRequestedEvent;\n }\n public set ResourceCloseRequestedEvent(value: (() => void) | null) {\n this._resourceCloseRequestedEvent = value;\n }\n\n private _displayNameChangedEvent: ((newName: string) => void) | null = null;\n public get DisplayNameChangedEvent(): ((newName: string) => void) | null {\n return this._displayNameChangedEvent;\n }\n public set DisplayNameChangedEvent(value: ((newName: string) => void) | null) {\n this._displayNameChangedEvent = value;\n }\n\n ngOnInit(): void {\n // Order matters: set up the popstate subscription first (a plain Subject — emits\n // nothing on subscribe), then the reactive initial-delivery subscription (backed by\n // a BehaviorSubject — emits the current params synchronously). This lets the initial\n // emission claim the 'deeplink' source before any later popstate event.\n this.setupQueryParamSubscription();\n this.setupInitialParamDelivery();\n\n // Start the NotifyLoadComplete watchdog (no-op once it fires or load completes).\n this._loadCompleteWatchdog = setTimeout(() => {\n if (!this._loadComplete) {\n // eslint-disable-next-line no-console\n console.warn(\n `[LoadComplete WATCHDOG] ${this.constructor.name} has NOT called NotifyLoadComplete() ` +\n `within ${BaseResourceComponent.LOAD_COMPLETE_WATCHDOG_MS / 1000}s. The app loading screen ` +\n `waits on this signal — if the screen is stuck, this resource is the likely cause. ` +\n `(tabId=${this.getTabId() || 'n/a'})`\n );\n }\n }, BaseResourceComponent.LOAD_COMPLETE_WATCHDOG_MS);\n }\n\n ngOnDestroy(): void {\n if (this._loadCompleteWatchdog) {\n clearTimeout(this._loadCompleteWatchdog);\n this._loadCompleteWatchdog = null;\n }\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n /**\n * Called by the framework when query params change from an external source\n * (browser back/forward, deep link navigation).\n * Override in subclasses to react to query param changes.\n * @param params The new query params from the URL\n * @param source 'popstate' for back/forward, 'deeplink' for external URL entry\n */\n protected OnQueryParamsChanged(params: Record<string, string>, source: 'popstate' | 'deeplink'): void {\n // Default no-op — override in subclasses\n }\n\n /**\n * Push query param changes to the URL. Creates a browser history entry.\n * Safe to call during OnQueryParamsChanged — auto-suppressed to prevent loops.\n */\n protected UpdateQueryParams(params: Record<string, string | null>): void {\n if (this._suppressQueryParamSync) return;\n const tabId = this.getTabId();\n if (!tabId) {\n this.navigationService.UpdateActiveTabQueryParams(params);\n return;\n }\n\n this.navigationService.UpdateTabQueryParams(tabId, params, this.getQueryParamUpdateGuard());\n }\n\n /**\n * Read current query params from tab configuration.\n * Use in initDashboard() / ngOnInit() to get initial URL state.\n */\n protected GetQueryParams(): Record<string, string> {\n return (this.Data?.Configuration?.['queryParams'] as Record<string, string>) || {};\n }\n\n /**\n * Internal: subscribe to NavigationService query param notifications.\n * Filters to only this component's tab to prevent cross-tab leakage.\n * This is the explicit back/forward (popstate) path.\n */\n private setupQueryParamSubscription(): void {\n this.navigationService.QueryParamChanged$\n .pipe(\n filter(event => {\n const myTabId = this.getTabId();\n return !myTabId || event.TabId === myTabId;\n }),\n takeUntil(this.destroy$)\n )\n .subscribe(event => this.deliverQueryParams(event.Params));\n }\n\n /**\n * Internal: reactively deliver this tab's query params from the workspace\n * BehaviorSubject. Because the source replays the current value on subscribe and\n * emits future changes, this delivers initial deep-link params even when the\n * component mounts (e.g. from workspace restoration) before the URL params have\n * been merged into the tab configuration — closing the cold-load race that the\n * popstate-only path could not.\n */\n private setupInitialParamDelivery(): void {\n const tabId = this.getTabId();\n if (!tabId) {\n return; // No tab scope (e.g. embedded usage) — nothing to observe.\n }\n this.navigationService.ObserveTabQueryParams(tabId)\n .pipe(takeUntil(this.destroy$))\n .subscribe(params => this.deliverQueryParams(params));\n }\n\n /**\n * Internal: funnel point for both the reactive and popstate paths. De-duplicates\n * identical deliveries (the two paths overlap on back/forward) and labels the first\n * meaningful delivery as a 'deeplink', subsequent ones as 'popstate'.\n */\n private deliverQueryParams(params: Record<string, string>): void {\n const key = this.queryParamsKey(params);\n if (key === this._lastDeliveredParamsKey) {\n return; // Already delivered these exact params.\n }\n const isInitial = this._lastDeliveredParamsKey === null;\n // Don't fire an initial no-op: a component entered without deep-link params has\n // nothing to apply. Leave _lastDeliveredParamsKey null so the first real params\n // (whenever they arrive) are still treated as the deep-link entry.\n if (isInitial && Object.keys(params).length === 0) {\n return;\n }\n this._lastDeliveredParamsKey = key;\n const source: 'popstate' | 'deeplink' = isInitial ? 'deeplink' : 'popstate';\n // try/finally ensures the suppression flag is always cleared, even if\n // OnQueryParamsChanged throws.\n this._suppressQueryParamSync = true;\n try {\n this.OnQueryParamsChanged(params, source);\n } finally {\n this._suppressQueryParamSync = false;\n }\n }\n\n /** Stable, order-independent string key for a query param record. */\n private queryParamsKey(params: Record<string, string>): string {\n return Object.keys(params)\n .sort()\n .map(k => `${k}=${params[k]}`)\n .join('&');\n }\n\n /**\n * Get this component's tab ID. Checks ParentTabId input first (set by resource\n * wrappers for child dashboards), then falls back to Data.Configuration.tabId.\n */\n public getTabId(): string {\n return this.ParentTabId || this.Data?.Configuration?.['tabId'] as string || '';\n }\n\n private getQueryParamUpdateGuard(): TabQueryParamUpdateGuard {\n const config = this.Data?.Configuration || {};\n return {\n resourceType: config['resourceType'] as string | undefined,\n driverClass: (config['resourceTypeDriverClass'] || config['driverClass']) as string | undefined,\n recordId: (this.Data?.ResourceRecordID || config['recordId']) as string | undefined,\n navItemName: config['navItemName'] as string | undefined,\n entity: (config['Entity'] || config['entity']) as string | undefined\n };\n }\n\n protected NotifyLoadComplete() {\n this._loadComplete = true;\n if (this._loadCompleteWatchdog) {\n clearTimeout(this._loadCompleteWatchdog);\n this._loadCompleteWatchdog = null;\n }\n if (this._loadCompleteEvent) {\n this._loadCompleteEvent();\n }\n }\n\n protected NotifyLoadStarted() {\n this._loadStarted = true;\n if (this._loadStartedEvent) {\n this._loadStartedEvent();\n }\n }\n\n\n\n /**\n * Call this to notify the tab system that the resource's display name has changed.\n * The tab container will update the tab title and browser title accordingly.\n */\n protected NotifyDisplayNameChanged(newName: string): void {\n if (this._displayNameChangedEvent) {\n this._displayNameChangedEvent(newName);\n }\n }\n\n protected ResourceRecordSaved(resourceRecordEntity: BaseEntity) {\n // Use ToURLSegment, NOT ToString. ResourceRecordID is consumed by\n // EntityRecordResource.GetPrimaryKey → CompositeKey.LoadFromURLSegment, which\n // expects URL-segment format (e.g. \"ID|<uuid>\"). ToString produces \"ID=<uuid>\",\n // which LoadFromURLSegment treats as a raw value and double-prefixes —\n // breaking any code path that re-reads this field after save.\n this.Data.ResourceRecordID = resourceRecordEntity.PrimaryKey.ToURLSegment();\n if (this._resourceRecordSavedEvent) {\n this._resourceRecordSavedEvent(resourceRecordEntity);\n }\n }\n\n /**\n * Ask the host shell to close/dismiss this resource (typically: close the tab).\n * Called by subclasses that hosted a form that emitted a 'dismiss' navigation\n * event — most often, a brand-new record where the user clicked Discard. The\n * record was never saved, the form is empty, and leaving it open serves no\n * purpose. The tab-container listens for this and closes the workspace tab.\n */\n protected NotifyCloseRequested(): void {\n if (this._resourceCloseRequestedEvent) {\n this._resourceCloseRequestedEvent();\n }\n }\n\n abstract GetResourceDisplayName(data: ResourceData): Promise<string>\n\n abstract GetResourceIconClass(data: ResourceData): Promise<string>\n}\n"]}
|
|
@@ -33,6 +33,13 @@ export interface AgentContextUpdate {
|
|
|
33
33
|
Handler: (params: Record<string, unknown>) => Promise<unknown>;
|
|
34
34
|
}>;
|
|
35
35
|
}
|
|
36
|
+
export interface TabQueryParamUpdateGuard {
|
|
37
|
+
resourceType?: string | null;
|
|
38
|
+
driverClass?: string | null;
|
|
39
|
+
recordId?: string | null;
|
|
40
|
+
navItemName?: string | null;
|
|
41
|
+
entity?: string | null;
|
|
42
|
+
}
|
|
36
43
|
/**
|
|
37
44
|
* System application ID for non-app-specific resources (fallback only)
|
|
38
45
|
* Uses double underscore prefix to indicate system-level resource
|
|
@@ -86,6 +93,18 @@ export declare class NavigationService implements OnDestroy {
|
|
|
86
93
|
* push changes to the chat overlay's AppContextSnapshot.DashboardContext.
|
|
87
94
|
*/
|
|
88
95
|
readonly AgentContextUpdated$: Subject<AgentContextUpdate>;
|
|
96
|
+
/** The client tools currently surfaced to the agent (the most recent SetAgentClientTools set). */
|
|
97
|
+
private currentAgentTools;
|
|
98
|
+
/**
|
|
99
|
+
* Tools captured for each cached resource component at the moment it was DETACHED, keyed by that
|
|
100
|
+
* component (the one the cache manager tracks). Replayed on reattach. Captured at detach time (vs.
|
|
101
|
+
* keyed by the registering component) so it works even when a resource WRAPPER component is what's
|
|
102
|
+
* cached/reattached while an INNER child component is what actually called SetAgentClientTools
|
|
103
|
+
* (e.g. Data Explorer's resource wrapper hosting its dashboard) — keying by the registerer would
|
|
104
|
+
* miss on reattach. This keeps the agent's live tool set a function of the CURRENTLY attached
|
|
105
|
+
* surface, fixing the staleness where a previous app's tools lingered after navigation.
|
|
106
|
+
*/
|
|
107
|
+
private readonly agentToolsByDetachedResource;
|
|
89
108
|
/**
|
|
90
109
|
* Latest `AppContextSnapshot` published by the Explorer app shell.
|
|
91
110
|
*
|
|
@@ -143,6 +162,27 @@ export declare class NavigationService implements OnDestroy {
|
|
|
143
162
|
ParameterSchema: Record<string, unknown>;
|
|
144
163
|
Handler: (params: Record<string, unknown>) => Promise<unknown>;
|
|
145
164
|
}>): void;
|
|
165
|
+
/**
|
|
166
|
+
* Re-publish a cached resource component's tools when its tab is re-focused. Cached components keep
|
|
167
|
+
* their Angular instance but do NOT re-run `ngAfterViewInit`, so they never re-register on reattach
|
|
168
|
+
* — the shell calls this so the just-reactivated surface's tools become the agent's active set
|
|
169
|
+
* again. Replays the set captured for this component at its last detach; no-op (lets a fresh
|
|
170
|
+
* component register itself) when none was captured (e.g. a component's very first attach).
|
|
171
|
+
*/
|
|
172
|
+
NotifyResourceReattached(caller: BaseResourceComponent): void;
|
|
173
|
+
/**
|
|
174
|
+
* Capture + clear the active client tools when a resource component's tab is detached (navigated
|
|
175
|
+
* away from), so the previous surface's tools aren't offered to the agent on the next surface. We
|
|
176
|
+
* snapshot whatever tools are CURRENTLY active and key them by the detaching component, so
|
|
177
|
+
* {@link NotifyResourceReattached} can replay them — robust to a wrapper component being the one
|
|
178
|
+
* cached/reattached while an inner child actually registered the tools (e.g. Data Explorer).
|
|
179
|
+
*/
|
|
180
|
+
NotifyResourceDetached(caller: BaseResourceComponent): void;
|
|
181
|
+
/**
|
|
182
|
+
* Drop a destroyed component's captured tools (e.g. on LRU eviction), so the map doesn't retain
|
|
183
|
+
* references to dead component instances.
|
|
184
|
+
*/
|
|
185
|
+
ForgetResource(caller: BaseResourceComponent): void;
|
|
146
186
|
ngOnDestroy(): void;
|
|
147
187
|
/**
|
|
148
188
|
* Set up global keyboard event listeners to track shift key state
|
|
@@ -285,6 +325,13 @@ export declare class NavigationService implements OnDestroy {
|
|
|
285
325
|
* navigationService.UpdateActiveTabQueryParams({ category: null });
|
|
286
326
|
*/
|
|
287
327
|
UpdateActiveTabQueryParams(queryParams: Record<string, string | null>): void;
|
|
328
|
+
/**
|
|
329
|
+
* Update query params for a specific tab, optionally only if the tab still hosts
|
|
330
|
+
* the expected resource identity. This matters in single-resource mode where a
|
|
331
|
+
* tab ID can be reused for a different resource while the previous component is
|
|
332
|
+
* detached but still alive in the cache.
|
|
333
|
+
*/
|
|
334
|
+
UpdateTabQueryParams(tabId: string, queryParams: Record<string, string | null>, guard?: TabQueryParamUpdateGuard): boolean;
|
|
288
335
|
/**
|
|
289
336
|
* Notify subscribers that query params changed on a specific tab.
|
|
290
337
|
* Called by the shell when back/forward navigation changes query params on the active tab.
|
|
@@ -307,6 +354,7 @@ export declare class NavigationService implements OnDestroy {
|
|
|
307
354
|
*/
|
|
308
355
|
ObserveTabQueryParams(tabId: string): Observable<Record<string, string>>;
|
|
309
356
|
private shallowParamsEqual;
|
|
357
|
+
private tabMatchesQueryParamGuard;
|
|
310
358
|
/**
|
|
311
359
|
* Apply query params to a specific tab by ID.
|
|
312
360
|
* Merges with any existing query params on the tab. Use null values to remove params.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.service.d.ts","sourceRoot":"","sources":["../../src/lib/navigation.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,SAAS,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAA8B,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACrI,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAa,eAAe,EAAE,OAAO,EAAgB,UAAU,EAAE,MAAM,MAAM,CAAC;AACrF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;;AAElE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAC/B,sDAAsD;IACtD,MAAM,EAAE,qBAAqB,CAAC;IAC9B,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,KAAK,CAAC;QACrB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KAClE,CAAC,CAAC;CACN;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,eAAe,CAAC;AAO1C;;;GAGG;AACH,qBAGa,iBAAkB,YAAW,SAAS;IAc/C,OAAO,CAAC,gBAAgB;IACxB,OAAO,CAAC,UAAU;IAdpB,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,aAAa,CAAsB;IAE3C,OAAO,CAAC,kBAAkB,CAAwC;IAClE,yFAAyF;IAClF,kBAAkB,oCAA0C;IAEnE,6EAA6E;IAC7E,OAAO,CAAC,UAAU,CAAwC;IAC1D,4BAA4B;IAC5B,OAAO,CAAC,aAAa,CAAuB;gBAGlC,gBAAgB,EAAE,qBAAqB,EACvC,UAAU,EAAE,kBAAkB;IAKxC;;;;OAIG;IACH,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED;;;;;;OAMG;IACH,OAAO,CAAC,uBAAuB;IAmC/B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAmB1B;;;OAGG;IACI,iBAAiB,IAAI,IAAI;IAShC;;;;OAIG;IACH,SAAgB,oBAAoB,8BAAqC;IAEzE;;;;;;;;;;;;;;;;;;;OAmBG;IACH,SAAgB,mBAAmB,6CAAwD;IAE3F;;;;;;OAMG;IACI,yBAAyB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,IAAI,GAAG,IAAI;IAI3E;;;;;;;;;;OAUG;IACI,eAAe,CAAC,MAAM,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI7F;;;;;;;;;OASG;IACI,mBAAmB,CAAC,MAAM,EAAE,qBAAqB,EAAE,KAAK,EAAE,KAAK,CAAC;QACrE,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KAChE,CAAC,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"navigation.service.d.ts","sourceRoot":"","sources":["../../src/lib/navigation.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -116,6 +116,18 @@ export class NavigationService {
|
|
|
116
116
|
* push changes to the chat overlay's AppContextSnapshot.DashboardContext.
|
|
117
117
|
*/
|
|
118
118
|
AgentContextUpdated$ = new Subject();
|
|
119
|
+
/** The client tools currently surfaced to the agent (the most recent SetAgentClientTools set). */
|
|
120
|
+
currentAgentTools = [];
|
|
121
|
+
/**
|
|
122
|
+
* Tools captured for each cached resource component at the moment it was DETACHED, keyed by that
|
|
123
|
+
* component (the one the cache manager tracks). Replayed on reattach. Captured at detach time (vs.
|
|
124
|
+
* keyed by the registering component) so it works even when a resource WRAPPER component is what's
|
|
125
|
+
* cached/reattached while an INNER child component is what actually called SetAgentClientTools
|
|
126
|
+
* (e.g. Data Explorer's resource wrapper hosting its dashboard) — keying by the registerer would
|
|
127
|
+
* miss on reattach. This keeps the agent's live tool set a function of the CURRENTLY attached
|
|
128
|
+
* surface, fixing the staleness where a previous app's tools lingered after navigation.
|
|
129
|
+
*/
|
|
130
|
+
agentToolsByDetachedResource = new Map();
|
|
119
131
|
/**
|
|
120
132
|
* Latest `AppContextSnapshot` published by the Explorer app shell.
|
|
121
133
|
*
|
|
@@ -172,8 +184,43 @@ export class NavigationService {
|
|
|
172
184
|
* ParameterSchema (JSON Schema), and Handler function.
|
|
173
185
|
*/
|
|
174
186
|
SetAgentClientTools(caller, tools) {
|
|
187
|
+
this.currentAgentTools = tools;
|
|
188
|
+
this.AgentContextUpdated$.next({ Caller: caller, AgentClientTools: tools });
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Re-publish a cached resource component's tools when its tab is re-focused. Cached components keep
|
|
192
|
+
* their Angular instance but do NOT re-run `ngAfterViewInit`, so they never re-register on reattach
|
|
193
|
+
* — the shell calls this so the just-reactivated surface's tools become the agent's active set
|
|
194
|
+
* again. Replays the set captured for this component at its last detach; no-op (lets a fresh
|
|
195
|
+
* component register itself) when none was captured (e.g. a component's very first attach).
|
|
196
|
+
*/
|
|
197
|
+
NotifyResourceReattached(caller) {
|
|
198
|
+
const tools = this.agentToolsByDetachedResource.get(caller);
|
|
199
|
+
if (tools === undefined) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
this.currentAgentTools = tools;
|
|
175
203
|
this.AgentContextUpdated$.next({ Caller: caller, AgentClientTools: tools });
|
|
176
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Capture + clear the active client tools when a resource component's tab is detached (navigated
|
|
207
|
+
* away from), so the previous surface's tools aren't offered to the agent on the next surface. We
|
|
208
|
+
* snapshot whatever tools are CURRENTLY active and key them by the detaching component, so
|
|
209
|
+
* {@link NotifyResourceReattached} can replay them — robust to a wrapper component being the one
|
|
210
|
+
* cached/reattached while an inner child actually registered the tools (e.g. Data Explorer).
|
|
211
|
+
*/
|
|
212
|
+
NotifyResourceDetached(caller) {
|
|
213
|
+
this.agentToolsByDetachedResource.set(caller, this.currentAgentTools);
|
|
214
|
+
this.currentAgentTools = [];
|
|
215
|
+
this.AgentContextUpdated$.next({ Caller: caller, AgentClientTools: [] });
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Drop a destroyed component's captured tools (e.g. on LRU eviction), so the map doesn't retain
|
|
219
|
+
* references to dead component instances.
|
|
220
|
+
*/
|
|
221
|
+
ForgetResource(caller) {
|
|
222
|
+
this.agentToolsByDetachedResource.delete(caller);
|
|
223
|
+
}
|
|
177
224
|
ngOnDestroy() {
|
|
178
225
|
this.subscriptions.forEach(sub => sub.unsubscribe());
|
|
179
226
|
}
|
|
@@ -705,6 +752,35 @@ export class NavigationService {
|
|
|
705
752
|
}
|
|
706
753
|
this.applyQueryParamsToTab(activeTabId, queryParams);
|
|
707
754
|
}
|
|
755
|
+
/**
|
|
756
|
+
* Update query params for a specific tab, optionally only if the tab still hosts
|
|
757
|
+
* the expected resource identity. This matters in single-resource mode where a
|
|
758
|
+
* tab ID can be reused for a different resource while the previous component is
|
|
759
|
+
* detached but still alive in the cache.
|
|
760
|
+
*/
|
|
761
|
+
UpdateTabQueryParams(tabId, queryParams, guard) {
|
|
762
|
+
const tab = this.workspaceManager.GetTab(tabId);
|
|
763
|
+
if (!tab) {
|
|
764
|
+
console.debug('NavigationService.UpdateTabQueryParams: Tab not found; ignoring stale query-param update:', tabId);
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
if (guard && !this.tabMatchesQueryParamGuard(tab, guard)) {
|
|
768
|
+
console.debug('NavigationService.UpdateTabQueryParams: Tab identity changed; ignoring stale query-param update:', {
|
|
769
|
+
tabId,
|
|
770
|
+
guard,
|
|
771
|
+
current: {
|
|
772
|
+
resourceType: tab.configuration?.['resourceType'],
|
|
773
|
+
driverClass: tab.configuration?.['resourceTypeDriverClass'] || tab.configuration?.['driverClass'],
|
|
774
|
+
recordId: tab.resourceRecordId || tab.configuration?.['recordId'],
|
|
775
|
+
navItemName: tab.configuration?.['navItemName'],
|
|
776
|
+
entity: tab.configuration?.['Entity'] || tab.configuration?.['entity']
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
781
|
+
this.applyQueryParamsToTab(tabId, queryParams);
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
708
784
|
/**
|
|
709
785
|
* Notify subscribers that query params changed on a specific tab.
|
|
710
786
|
* Called by the shell when back/forward navigation changes query params on the active tab.
|
|
@@ -741,6 +817,29 @@ export class NavigationService {
|
|
|
741
817
|
}
|
|
742
818
|
return keysA.every(key => a[key] === b[key]);
|
|
743
819
|
}
|
|
820
|
+
tabMatchesQueryParamGuard(tab, guard) {
|
|
821
|
+
const config = tab.configuration || {};
|
|
822
|
+
const matches = (expected, actual, normalize = false) => {
|
|
823
|
+
if (expected === undefined || expected === null) {
|
|
824
|
+
return true;
|
|
825
|
+
}
|
|
826
|
+
const expectedText = String(expected);
|
|
827
|
+
const actualText = actual == null ? '' : String(actual);
|
|
828
|
+
return normalize
|
|
829
|
+
? expectedText.trim().toLowerCase() === actualText.trim().toLowerCase()
|
|
830
|
+
: expectedText === actualText;
|
|
831
|
+
};
|
|
832
|
+
const currentDriverClass = (config['resourceTypeDriverClass'] || config['driverClass']);
|
|
833
|
+
const currentRecordId = tab.resourceRecordId || config['recordId'] || '';
|
|
834
|
+
const currentEntity = (config['Entity'] || config['entity']);
|
|
835
|
+
// Resource type and entity names can vary by casing/metadata spelling; class names,
|
|
836
|
+
// record IDs, and nav labels are canonical tab identity fields and stay exact-match.
|
|
837
|
+
return matches(guard.resourceType, config['resourceType'], true) &&
|
|
838
|
+
matches(guard.driverClass, currentDriverClass) &&
|
|
839
|
+
matches(guard.recordId, currentRecordId) &&
|
|
840
|
+
matches(guard.navItemName, config['navItemName']) &&
|
|
841
|
+
matches(guard.entity, currentEntity, true);
|
|
842
|
+
}
|
|
744
843
|
/**
|
|
745
844
|
* Apply query params to a specific tab by ID.
|
|
746
845
|
* Merges with any existing query params on the tab. Use null values to remove params.
|