@memberjunction/ng-shared 5.32.0 → 5.34.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.
@@ -127,9 +127,24 @@ export declare class NavigationService implements OnDestroy {
127
127
  */
128
128
  private shouldForceNewTab;
129
129
  /**
130
- * Handle temporary tab preservation when forcing new tabs
131
- * Rule: Only ONE tab should be temporary at a time
132
- * When shift+clicking to force a new tab, pin the current active tab if it's temporary
130
+ * Returns whether the caller should use OpenTabForced (force-new path) or
131
+ * OpenTab (replace-temp path).
132
+ *
133
+ * Rule: only honor an explicit force-new request — from the user via
134
+ * shift+click, or from the caller via `options.forceNewTab`. We deliberately
135
+ * do NOT apply heuristics that auto-switch the workspace out of
136
+ * single-resource mode on cross-resource navigation. A previous version of
137
+ * this method tried to do that ("force new if single-resource + different
138
+ * resource") and it caused a regression: every plain hyperlink click on a
139
+ * record opened a new tab and dropped the user into multi-tab mode, even
140
+ * though they didn't ask for it. That violated the principle that mode
141
+ * transitions are user-driven (shift) or explicitly requested (options).
142
+ *
143
+ * If a particular caller really needs the parent context preserved when
144
+ * creating/navigating to a child resource (e.g. "+New" on a related-entity
145
+ * grid inside an open record), the caller should pass `forceNewTab: true`
146
+ * in `NavigationOptions`. That keeps intent explicit at the call site
147
+ * instead of buried in a global heuristic.
133
148
  */
134
149
  private handleSingleResourceModeTransition;
135
150
  /**
@@ -189,11 +204,12 @@ export declare class NavigationService implements OnDestroy {
189
204
  * This is the primary way to open search results from anywhere in the application.
190
205
  *
191
206
  * @param query The search query text
192
- * @param searchOptions Optional search-specific options (e.g., minRelevance)
207
+ * @param searchOptions Optional search-specific options (e.g., minRelevance, scopeIDs)
193
208
  * @param options Navigation options
194
209
  */
195
210
  OpenSearch(query: string, searchOptions?: {
196
211
  minRelevance?: number;
212
+ scopeIDs?: string[];
197
213
  }, options?: NavigationOptions): string;
198
214
  /**
199
215
  * Navigate to a nav item by name within the current or specified application.
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.service.d.ts","sourceRoot":"","sources":["../../src/lib/navigation.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"navigation.service.d.ts","sourceRoot":"","sources":["../../src/lib/navigation.service.ts"],"names":[],"mappings":"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"}
@@ -177,28 +177,27 @@ export class NavigationService {
177
177
  return this.isShiftPressed();
178
178
  }
179
179
  /**
180
- * Handle temporary tab preservation when forcing new tabs
181
- * Rule: Only ONE tab should be temporary at a time
182
- * When shift+clicking to force a new tab, pin the current active tab if it's temporary
180
+ * Returns whether the caller should use OpenTabForced (force-new path) or
181
+ * OpenTab (replace-temp path).
182
+ *
183
+ * Rule: only honor an explicit force-new request — from the user via
184
+ * shift+click, or from the caller via `options.forceNewTab`. We deliberately
185
+ * do NOT apply heuristics that auto-switch the workspace out of
186
+ * single-resource mode on cross-resource navigation. A previous version of
187
+ * this method tried to do that ("force new if single-resource + different
188
+ * resource") and it caused a regression: every plain hyperlink click on a
189
+ * record opened a new tab and dropped the user into multi-tab mode, even
190
+ * though they didn't ask for it. That violated the principle that mode
191
+ * transitions are user-driven (shift) or explicitly requested (options).
192
+ *
193
+ * If a particular caller really needs the parent context preserved when
194
+ * creating/navigating to a child resource (e.g. "+New" on a related-entity
195
+ * grid inside an open record), the caller should pass `forceNewTab: true`
196
+ * in `NavigationOptions`. That keeps intent explicit at the call site
197
+ * instead of buried in a global heuristic.
183
198
  */
184
- handleSingleResourceModeTransition(forceNew, newRequest) {
185
- if (!forceNew) {
186
- return; // Normal navigation, not forcing new tab
187
- }
188
- const config = this.workspaceManager.GetConfiguration();
189
- if (!config || !config.tabs || config.tabs.length === 0) {
190
- return; // No tabs to preserve
191
- }
192
- // Find the currently active tab
193
- const activeTab = config.tabs.find(tab => tab.id === config.activeTabId);
194
- if (!activeTab) {
195
- return; // No active tab
196
- }
197
- // If the active tab is NOT pinned (i.e., it's temporary), pin it to preserve it
198
- // This maintains the "only one temporary tab" rule
199
- if (!activeTab.isPinned) {
200
- this.workspaceManager.TogglePin(activeTab.id);
201
- }
199
+ handleSingleResourceModeTransition(forceNew, _newRequest) {
200
+ return forceNew;
202
201
  }
203
202
  /**
204
203
  * Check if a tab request matches an existing tab's resource
@@ -227,7 +226,7 @@ export class NavigationService {
227
226
  * Open a navigation item within an app
228
227
  */
229
228
  OpenNavItem(appId, navItem, appColor, options) {
230
- const forceNew = this.shouldForceNewTab(options);
229
+ let forceNew = this.shouldForceNewTab(options);
231
230
  // Get the app to find its name
232
231
  const app = this.appManager.GetAppById(appId);
233
232
  const appName = app?.Name || '';
@@ -253,7 +252,7 @@ export class NavigationService {
253
252
  IsPinned: options?.pinTab || false
254
253
  };
255
254
  // Handle transition from single-resource mode
256
- this.handleSingleResourceModeTransition(forceNew, request);
255
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
257
256
  let tabId;
258
257
  if (forceNew) {
259
258
  // Always create a new tab
@@ -276,7 +275,7 @@ export class NavigationService {
276
275
  OpenEntityRecord(entityName, recordPkey, options) {
277
276
  const appId = this.getDefaultApplicationId();
278
277
  const appColor = this.getDefaultAppColor();
279
- const forceNew = this.shouldForceNewTab(options);
278
+ let forceNew = this.shouldForceNewTab(options);
280
279
  const recordId = recordPkey.ToURLSegment();
281
280
  const request = {
282
281
  ApplicationId: appId,
@@ -290,7 +289,7 @@ export class NavigationService {
290
289
  IsPinned: options?.pinTab || false
291
290
  };
292
291
  // Handle transition from single-resource mode
293
- this.handleSingleResourceModeTransition(forceNew, request);
292
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
294
293
  let tabId;
295
294
  if (forceNew) {
296
295
  tabId = this.workspaceManager.OpenTabForced(request, appColor);
@@ -307,7 +306,7 @@ export class NavigationService {
307
306
  OpenView(viewId, viewName, options) {
308
307
  const appId = this.getDefaultApplicationId();
309
308
  const appColor = this.getDefaultAppColor();
310
- const forceNew = this.shouldForceNewTab(options);
309
+ let forceNew = this.shouldForceNewTab(options);
311
310
  const request = {
312
311
  ApplicationId: appId,
313
312
  Title: viewName,
@@ -320,7 +319,7 @@ export class NavigationService {
320
319
  IsPinned: options?.pinTab || false
321
320
  };
322
321
  // Handle transition from single-resource mode
323
- this.handleSingleResourceModeTransition(forceNew, request);
322
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
324
323
  if (forceNew) {
325
324
  return this.workspaceManager.OpenTabForced(request, appColor);
326
325
  }
@@ -335,7 +334,7 @@ export class NavigationService {
335
334
  OpenDashboard(dashboardId, dashboardName, options) {
336
335
  const appId = this.getDefaultApplicationId();
337
336
  const appColor = this.getDefaultAppColor();
338
- const forceNew = this.shouldForceNewTab(options);
337
+ let forceNew = this.shouldForceNewTab(options);
339
338
  const request = {
340
339
  ApplicationId: appId,
341
340
  Title: dashboardName,
@@ -348,7 +347,7 @@ export class NavigationService {
348
347
  IsPinned: options?.pinTab || false
349
348
  };
350
349
  // Handle transition from single-resource mode
351
- this.handleSingleResourceModeTransition(forceNew, request);
350
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
352
351
  if (forceNew) {
353
352
  return this.workspaceManager.OpenTabForced(request, appColor);
354
353
  }
@@ -363,7 +362,7 @@ export class NavigationService {
363
362
  OpenReport(reportId, reportName, options) {
364
363
  const appId = this.getDefaultApplicationId();
365
364
  const appColor = this.getDefaultAppColor();
366
- const forceNew = this.shouldForceNewTab(options);
365
+ let forceNew = this.shouldForceNewTab(options);
367
366
  const request = {
368
367
  ApplicationId: appId,
369
368
  Title: reportName,
@@ -376,7 +375,7 @@ export class NavigationService {
376
375
  IsPinned: options?.pinTab || false
377
376
  };
378
377
  // Handle transition from single-resource mode
379
- this.handleSingleResourceModeTransition(forceNew, request);
378
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
380
379
  if (forceNew) {
381
380
  return this.workspaceManager.OpenTabForced(request, appColor);
382
381
  }
@@ -392,7 +391,7 @@ export class NavigationService {
392
391
  OpenArtifact(artifactId, artifactName, options) {
393
392
  const appId = this.getDefaultApplicationId();
394
393
  const appColor = this.getDefaultAppColor();
395
- const forceNew = this.shouldForceNewTab(options);
394
+ let forceNew = this.shouldForceNewTab(options);
396
395
  const request = {
397
396
  ApplicationId: appId,
398
397
  Title: artifactName || `Artifact - ${artifactId}`,
@@ -405,7 +404,7 @@ export class NavigationService {
405
404
  IsPinned: options?.pinTab || false
406
405
  };
407
406
  // Handle transition from single-resource mode
408
- this.handleSingleResourceModeTransition(forceNew, request);
407
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
409
408
  if (forceNew) {
410
409
  return this.workspaceManager.OpenTabForced(request, appColor);
411
410
  }
@@ -421,7 +420,7 @@ export class NavigationService {
421
420
  OpenDynamicView(entityName, extraFilter, options) {
422
421
  const appId = this.getDefaultApplicationId();
423
422
  const appColor = this.getDefaultAppColor();
424
- const forceNew = this.shouldForceNewTab(options);
423
+ let forceNew = this.shouldForceNewTab(options);
425
424
  const filterSuffix = extraFilter ? ' (Filtered)' : '';
426
425
  const request = {
427
426
  ApplicationId: appId,
@@ -437,7 +436,7 @@ export class NavigationService {
437
436
  IsPinned: options?.pinTab || false
438
437
  };
439
438
  // Handle transition from single-resource mode
440
- this.handleSingleResourceModeTransition(forceNew, request);
439
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
441
440
  if (forceNew) {
442
441
  return this.workspaceManager.OpenTabForced(request, appColor);
443
442
  }
@@ -452,7 +451,7 @@ export class NavigationService {
452
451
  OpenQuery(queryId, queryName, options) {
453
452
  const appId = this.getDefaultApplicationId();
454
453
  const appColor = this.getDefaultAppColor();
455
- const forceNew = this.shouldForceNewTab(options);
454
+ let forceNew = this.shouldForceNewTab(options);
456
455
  const request = {
457
456
  ApplicationId: appId,
458
457
  Title: queryName,
@@ -465,7 +464,7 @@ export class NavigationService {
465
464
  IsPinned: options?.pinTab || false
466
465
  };
467
466
  // Handle transition from single-resource mode
468
- this.handleSingleResourceModeTransition(forceNew, request);
467
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
469
468
  if (forceNew) {
470
469
  return this.workspaceManager.OpenTabForced(request, appColor);
471
470
  }
@@ -482,7 +481,7 @@ export class NavigationService {
482
481
  OpenNewEntityRecord(entityName, options) {
483
482
  const appId = this.getDefaultApplicationId();
484
483
  const appColor = this.getDefaultAppColor();
485
- const forceNew = this.shouldForceNewTab(options);
484
+ let forceNew = this.shouldForceNewTab(options);
486
485
  const request = {
487
486
  ApplicationId: appId,
488
487
  Title: `New ${entityName}`,
@@ -497,7 +496,7 @@ export class NavigationService {
497
496
  IsPinned: options?.pinTab || false
498
497
  };
499
498
  // Handle transition from single-resource mode
500
- this.handleSingleResourceModeTransition(forceNew, request);
499
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
501
500
  if (forceNew) {
502
501
  return this.workspaceManager.OpenTabForced(request, appColor);
503
502
  }
@@ -510,13 +509,13 @@ export class NavigationService {
510
509
  * This is the primary way to open search results from anywhere in the application.
511
510
  *
512
511
  * @param query The search query text
513
- * @param searchOptions Optional search-specific options (e.g., minRelevance)
512
+ * @param searchOptions Optional search-specific options (e.g., minRelevance, scopeIDs)
514
513
  * @param options Navigation options
515
514
  */
516
515
  OpenSearch(query, searchOptions, options) {
517
516
  const appId = this.getDefaultApplicationId();
518
517
  const appColor = this.getDefaultAppColor();
519
- const forceNew = this.shouldForceNewTab(options);
518
+ let forceNew = this.shouldForceNewTab(options);
520
519
  const config = {
521
520
  resourceType: 'Search Results',
522
521
  Query: query,
@@ -526,6 +525,9 @@ export class NavigationService {
526
525
  if (searchOptions?.minRelevance != null) {
527
526
  config['MinRelevance'] = searchOptions.minRelevance;
528
527
  }
528
+ if (searchOptions?.scopeIDs && searchOptions.scopeIDs.length > 0) {
529
+ config['ScopeIDs'] = searchOptions.scopeIDs;
530
+ }
529
531
  const request = {
530
532
  ApplicationId: appId,
531
533
  Title: `Search: ${query}`,
@@ -534,7 +536,7 @@ export class NavigationService {
534
536
  IsPinned: false
535
537
  };
536
538
  // Handle transition from single-resource mode
537
- this.handleSingleResourceModeTransition(forceNew, request);
539
+ forceNew = this.handleSingleResourceModeTransition(forceNew, request);
538
540
  if (forceNew) {
539
541
  return this.workspaceManager.OpenTabForced(request, appColor);
540
542
  }
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.service.js","sourceRoot":"","sources":["../../src/lib/navigation.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, OnDestroy } from '@angular/core';\nimport { WorkspaceStateManager, NavItem, DynamicNavItem, TabRequest, ApplicationManager } from '@memberjunction/ng-base-application';\nimport { NavigationOptions } from './navigation.interfaces';\nimport { CompositeKey } from '@memberjunction/core';\nimport { fromEvent, Subject, Subscription } from 'rxjs';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent } from './base-resource-component';\n\n/**\n * Event emitted when query params change on a tab (e.g., from browser back/forward).\n * Includes the tab ID so that only the component in the affected tab reacts,\n * preventing cross-tab leakage in multi-tab scenarios.\n */\nexport interface QueryParamChangeEvent {\n TabId: string;\n Params: Record<string, string>;\n}\n\n/**\n * Event emitted when a resource component reports its agent context or tools.\n * The shell (which owns the ComponentCacheManager) subscribes to these events\n * and updates the cache + active AppContextSnapshot accordingly.\n */\nexport interface AgentContextUpdate {\n /** The component instance that reported the update */\n Caller: BaseResourceComponent;\n /** Dashboard-specific context for the agent (undefined = no change) */\n AgentContext?: Record<string, unknown>;\n /** Client tools available from this dashboard (undefined = no change) */\n AgentClientTools?: Array<{\n Name: string;\n Description: string;\n ParameterSchema: Record<string, unknown>;\n Handler: (params: Record<string, unknown>) => Promise<unknown>;\n }>;\n}\n\n/**\n * System application ID for non-app-specific resources (fallback only)\n * Uses double underscore prefix to indicate system-level resource\n * @deprecated Prefer using NavigationService.getDefaultApplicationId() instead\n */\nexport const SYSTEM_APP_ID = '__explorer';\n\n/**\n * Neutral color for fallback when no app is available\n */\nconst NEUTRAL_APP_COLOR = '#9E9E9E'; // Material Design Gray 500\n\n/**\n * Centralized navigation service that handles all navigation operations\n * with automatic shift-key detection for power user workflows\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class NavigationService implements OnDestroy {\n private shiftKeyPressed = false;\n private subscriptions: Subscription[] = [];\n\n private queryParamChanged$ = new Subject<QueryParamChangeEvent>();\n /** Observable that emits when query params change on a tab (back/forward navigation). */\n public QueryParamChanged$ = this.queryParamChanged$.asObservable();\n\n /** Cached Home app ID (null means not found, undefined means not checked) */\n private _homeAppId: string | null | undefined = undefined;\n /** Cached Home app color */\n private _homeAppColor: string | null = null;\n\n constructor(\n private workspaceManager: WorkspaceStateManager,\n private appManager: ApplicationManager\n ) {\n this.setupGlobalShiftKeyDetection();\n }\n\n /**\n * Get the neutral color used for system-wide resources (entities, views, dashboards)\n * Returns a light neutral gray\n * @deprecated Use getDefaultAppColor() for better UX with Home app integration\n */\n get ExplorerAppColor(): string {\n return NEUTRAL_APP_COLOR;\n }\n\n /**\n * Gets the default application ID for orphan resources.\n * Priority: Home app > Active app > SYSTEM_APP_ID\n *\n * This ensures orphan resources (entity records, dashboards, views opened directly)\n * are grouped under the Home app instead of being orphaned in the tab system.\n */\n private getDefaultApplicationId(): string {\n // Check cache first\n if (this._homeAppId !== undefined) {\n if (this._homeAppId !== null) {\n return this._homeAppId;\n }\n // Home app not found, check active app\n const activeApp = this.appManager.GetActiveApp();\n if (activeApp) {\n return activeApp.ID;\n }\n return SYSTEM_APP_ID;\n }\n\n // First time - look for Home app\n const homeApp = this.appManager.GetAppByName('Home');\n if (homeApp) {\n this._homeAppId = homeApp.ID;\n this._homeAppColor = homeApp.GetColor();\n return homeApp.ID;\n }\n\n // Cache that Home app doesn't exist\n this._homeAppId = null;\n\n // Fall back to currently active app\n const activeApp = this.appManager.GetActiveApp();\n if (activeApp) {\n return activeApp.ID;\n }\n\n // Last resort - system app ID\n return SYSTEM_APP_ID;\n }\n\n /**\n * Gets the default app color for orphan resources.\n * Returns Home app color if available, otherwise neutral gray.\n */\n private getDefaultAppColor(): string {\n // Ensure cache is populated\n this.getDefaultApplicationId();\n\n // If Home app exists, use its color\n if (this._homeAppColor) {\n return this._homeAppColor;\n }\n\n // Check active app\n const activeApp = this.appManager.GetActiveApp();\n if (activeApp) {\n return activeApp.GetColor();\n }\n\n // Fall back to neutral color\n return NEUTRAL_APP_COLOR;\n }\n\n /**\n * Clears the cached Home app info.\n * Call this if apps are reloaded or user logs out.\n */\n public clearHomeAppCache(): void {\n this._homeAppId = undefined;\n this._homeAppColor = null;\n }\n\n // ════════════════════════════════════════════\n // Agent Context & Client Tools\n // ════════════════════════════════════════════\n\n /**\n * Observable stream of agent context updates from resource components.\n * The shell subscribes to this to update the ComponentCacheManager and\n * push changes to the chat overlay's AppContextSnapshot.DashboardContext.\n */\n public readonly AgentContextUpdated$ = new Subject<AgentContextUpdate>();\n\n /**\n * Report the current agent-visible state from a resource component.\n * Call this whenever the dashboard's internal state changes (tab switch,\n * filter change, pipeline status change, drill-down, etc.).\n *\n * @param caller - Pass `this` from the calling component. Used to match\n * against the ComponentCacheManager to identify which cached component\n * this update belongs to.\n * @param context - Key-value pairs representing dashboard state the agent\n * should know about. Each dashboard defines its own shape.\n */\n public SetAgentContext(caller: BaseResourceComponent, context: Record<string, unknown>): void {\n this.AgentContextUpdated$.next({ Caller: caller, AgentContext: context });\n }\n\n /**\n * Register the client tools available from a resource component.\n * Call this on component init and whenever the available tools change.\n * Tools are automatically unregistered when the component becomes inactive\n * (tab switch) and re-registered when it becomes active again.\n *\n * @param caller - Pass `this` from the calling component.\n * @param tools - Array of tool definitions with Name, Description,\n * ParameterSchema (JSON Schema), and Handler function.\n */\n public SetAgentClientTools(caller: BaseResourceComponent, tools: Array<{\n Name: string;\n Description: string;\n ParameterSchema: Record<string, unknown>;\n Handler: (params: Record<string, unknown>) => Promise<unknown>;\n }>): void {\n this.AgentContextUpdated$.next({ Caller: caller, AgentClientTools: tools });\n }\n\n ngOnDestroy(): void {\n this.subscriptions.forEach(sub => sub.unsubscribe());\n }\n\n /**\n * Set up global keyboard event listeners to track shift key state\n */\n private setupGlobalShiftKeyDetection(): void {\n // Track shift key via mousedown events (capture phase) instead of keydown/keyup.\n // This is more reliable because:\n // 1. MouseEvent.shiftKey always reflects the actual modifier state at click time\n // 2. No risk of \"stuck\" state from missed keyup events (focus loss, tab switch, etc.)\n // 3. Navigation is always triggered by a click, so the shift state is read\n // at exactly the right moment\n this.subscriptions.push(\n fromEvent<MouseEvent>(document, 'mousedown', { capture: true }).subscribe(event => {\n this.shiftKeyPressed = event.shiftKey;\n })\n );\n }\n\n /**\n * Get current shift key state\n */\n private isShiftPressed(): boolean {\n return this.shiftKeyPressed;\n }\n\n /**\n * Determine if a new tab should be forced based on options and shift key state\n */\n private shouldForceNewTab(options?: NavigationOptions): boolean {\n // If forceNewTab is explicitly set, use that\n if (options?.forceNewTab !== undefined) {\n return options.forceNewTab;\n }\n\n // Otherwise, use global shift key detection\n return this.isShiftPressed();\n }\n\n /**\n * Handle temporary tab preservation when forcing new tabs\n * Rule: Only ONE tab should be temporary at a time\n * When shift+clicking to force a new tab, pin the current active tab if it's temporary\n */\n private handleSingleResourceModeTransition(forceNew: boolean, newRequest: TabRequest): void {\n if (!forceNew) {\n return; // Normal navigation, not forcing new tab\n }\n\n const config = this.workspaceManager.GetConfiguration();\n\n if (!config || !config.tabs || config.tabs.length === 0) {\n return; // No tabs to preserve\n }\n\n // Find the currently active tab\n const activeTab = config.tabs.find(tab => tab.id === config.activeTabId);\n if (!activeTab) {\n return; // No active tab\n }\n\n // If the active tab is NOT pinned (i.e., it's temporary), pin it to preserve it\n // This maintains the \"only one temporary tab\" rule\n if (!activeTab.isPinned) {\n this.workspaceManager.TogglePin(activeTab.id);\n }\n }\n\n /**\n * Check if a tab request matches an existing tab's resource\n */\n private isSameResource(tab: any, request: TabRequest): boolean {\n // Different apps = different resources\n if (tab.applicationId !== request.ApplicationId) {\n return false;\n }\n\n // For resource-based tabs, compare resourceType and recordId\n if (request.Configuration?.resourceType) {\n const requestRecordId = request.ResourceRecordId || '';\n const tabRecordId = tab.resourceRecordId || '';\n return tab.configuration?.resourceType === request.Configuration.resourceType &&\n tabRecordId === requestRecordId;\n }\n\n // For app nav items, compare appName and navItemName\n if (request.Configuration?.appName && request.Configuration?.navItemName) {\n return tab.configuration?.appName === request.Configuration.appName &&\n tab.configuration?.navItemName === request.Configuration.navItemName;\n }\n\n // Fallback to basic comparison\n return false;\n }\n\n /**\n * Open a navigation item within an app\n */\n public OpenNavItem(appId: string, navItem: NavItem, appColor: string, options?: NavigationOptions): string {\n const forceNew = this.shouldForceNewTab(options);\n\n // Get the app to find its name\n const app = this.appManager.GetAppById(appId);\n const appName = app?.Name || '';\n\n // Dynamic nav items (e.g. orphan entity records) carry their original tab Configuration\n // and should NOT get navItemName stamped on them — that would cause buildResourceUrl\n // to produce a nav-item-style URL like /app/home/<label> instead of the correct\n // resource-type URL like /app/home/record/Entity/ID|...\n const isDynamic = (navItem as DynamicNavItem).isDynamic === true;\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: navItem.Label,\n ResourceRecordId: navItem.RecordID || '', // Also store at top level for consistent tab matching\n Configuration: {\n route: navItem.Route,\n resourceType: navItem.ResourceType,\n driverClass: navItem.DriverClass, // Pass through DriverClass for Custom resource type\n recordId: navItem.RecordID,\n appName: appName, // Store app name for URL building\n appId: appId,\n ...(isDynamic ? {} : { navItemName: navItem.Label }), // Only set for static nav items\n ...(navItem.Configuration || {})\n },\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n let tabId: string;\n if (forceNew) {\n // Always create a new tab\n tabId = this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n // Use existing OpenTab logic (may replace temporary tab)\n tabId = this.workspaceManager.OpenTab(request, appColor);\n }\n\n // Apply query params to the newly opened/activated tab if provided\n if (options?.queryParams) {\n this.applyQueryParamsToTab(tabId, options.queryParams);\n }\n\n return tabId;\n }\n\n /**\n * Open an entity record view\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenEntityRecord(\n entityName: string,\n recordPkey: CompositeKey,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n\n const forceNew = this.shouldForceNewTab(options);\n\n const recordId = recordPkey.ToURLSegment();\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `${entityName} - ${recordId}`,\n Configuration: {\n resourceType: 'Records',\n Entity: entityName, // Must use 'Entity' (capital E) - expected by record-resource.component\n recordId: recordId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: recordId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n let tabId: string;\n if (forceNew) {\n tabId = this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n tabId = this.workspaceManager.OpenTab(request, appColor);\n }\n\n return tabId;\n }\n\n /**\n * Open a view\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenView(\n viewId: string,\n viewName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n const forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: viewName,\n Configuration: {\n resourceType: 'MJ: User Views',\n viewId,\n recordId: viewId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: viewId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a dashboard\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenDashboard(\n dashboardId: string,\n dashboardName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n const forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: dashboardName,\n Configuration: {\n resourceType: 'Dashboards',\n dashboardId,\n recordId: dashboardId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: dashboardId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a report\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenReport(\n reportId: string,\n reportName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n const forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: reportName,\n Configuration: {\n resourceType: 'Reports',\n reportId,\n recordId: reportId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: reportId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open an artifact\n * Artifacts are versioned content containers (reports, dashboards, UI components, etc.)\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenArtifact(\n artifactId: string,\n artifactName?: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n const forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: artifactName || `Artifact - ${artifactId}`,\n Configuration: {\n resourceType: 'Artifacts',\n artifactId,\n recordId: artifactId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: artifactId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a dynamic view\n * Dynamic views are entity-based views with custom filters, not saved views\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenDynamicView(\n entityName: string,\n extraFilter?: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n const forceNew = this.shouldForceNewTab(options);\n\n const filterSuffix = extraFilter ? ' (Filtered)' : '';\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `${entityName}${filterSuffix}`,\n Configuration: {\n resourceType: 'MJ: User Views',\n Entity: entityName,\n ExtraFilter: extraFilter,\n isDynamic: true,\n recordId: 'dynamic' // Special marker for dynamic views\n },\n ResourceRecordId: 'dynamic',\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a query\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenQuery(\n queryId: string,\n queryName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n const forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: queryName,\n Configuration: {\n resourceType: 'Queries',\n queryId,\n recordId: queryId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: queryId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a new entity record creation form\n * Uses Home app if available, otherwise falls back to active app or system app\n * @param entityName The name of the entity to create a new record for\n * @param options Navigation options including optional newRecordValues for pre-populating fields\n */\n public OpenNewEntityRecord(\n entityName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n\n const forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `New ${entityName}`,\n Configuration: {\n resourceType: 'Records',\n Entity: entityName, // Must use 'Entity' (capital E) - expected by record-resource.component\n recordId: '', // Empty recordId indicates new record\n isNew: true, // Flag to indicate this is a new record\n NewRecordValues: options?.newRecordValues // Pass through initial values if provided\n },\n ResourceRecordId: '', // Empty for new records\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a universal search results tab for the given query.\n * This is the primary way to open search results from anywhere in the application.\n *\n * @param query The search query text\n * @param searchOptions Optional search-specific options (e.g., minRelevance)\n * @param options Navigation options\n */\n public OpenSearch(\n query: string,\n searchOptions?: { minRelevance?: number },\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n const forceNew = this.shouldForceNewTab(options);\n\n const config: Record<string, unknown> = {\n resourceType: 'Search Results',\n Query: query,\n SearchInput: query,\n recordId: `search-${query}`\n };\n if (searchOptions?.minRelevance != null) {\n config['MinRelevance'] = searchOptions.minRelevance;\n }\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `Search: ${query}`,\n Configuration: config,\n ResourceRecordId: `search-${query}`,\n IsPinned: false\n };\n\n // Handle transition from single-resource mode\n this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Navigate to a nav item by name within the current or specified application.\n * Allows passing additional configuration parameters to merge with the nav item's config.\n * This is useful for cross-resource navigation where a component needs to navigate\n * to another nav item with specific parameters (e.g., navigate to Conversations with a specific conversationId).\n *\n * @param navItemName The label/name of the nav item to navigate to\n * @param configuration Additional configuration to merge (e.g., conversationId, artifactId)\n * @param appId Optional app ID (defaults to current active app)\n * @param options Navigation options\n * @returns The tab ID if successful, null if nav item not found\n */\n public async OpenNavItemByName(\n navItemName: string,\n configuration?: Record<string, unknown>,\n appId?: string,\n options?: NavigationOptions\n ): Promise<string | null> {\n // Get app (use provided or current active)\n const targetAppId = appId || this.appManager.GetActiveApp()?.ID;\n if (!targetAppId) {\n return null;\n }\n\n const app = this.appManager.GetAppById(targetAppId);\n if (!app) {\n return null;\n }\n\n // Find the nav item by name\n const navItems = await app.GetNavItems();\n const navItem = navItems.find(item => item.Label === navItemName);\n if (!navItem) {\n return null;\n }\n\n // Create a merged nav item with additional configuration\n const mergedNavItem: NavItem = {\n ...navItem,\n Configuration: {\n ...(navItem.Configuration || {}),\n ...(configuration || {})\n }\n };\n\n // Use existing OpenNavItem\n return this.OpenNavItem(targetAppId, mergedNavItem, app.GetColor(), options);\n }\n\n /**\n * Switch to an application by ID.\n * This sets the app as active and either opens a specific nav item or creates a default tab.\n * If the requested nav item already has an open tab, switches to that tab instead of creating a new one.\n * @param appId The application ID to switch to\n * @param navItemName Optional name of a nav item to open within the app. If provided, opens that nav item.\n */\n async SwitchToApp(appId: string, navItemName?: string): Promise<void> {\n await this.appManager.SetActiveApp(appId);\n\n const app = this.appManager.GetAllApps().find(a => UUIDsEqual(a.ID, appId));\n if (!app) {\n return;\n }\n\n const appTabs = this.workspaceManager.GetAppTabs(appId);\n\n // If a specific nav item is requested\n if (navItemName) {\n const navItems = await app.GetNavItems();\n const navItem = navItems.find(item => item.Label === navItemName);\n if (navItem) {\n // Check if there's already a tab for this nav item\n const existingTab = appTabs.find(tab =>\n tab.title === navItem.Label ||\n (tab.configuration?.['route'] === navItem.Route && navItem.Route)\n );\n\n if (existingTab) {\n // Switch to existing tab\n this.workspaceManager.SetActiveTab(existingTab.id);\n } else {\n // Open new tab for this nav item\n this.OpenNavItem(appId, navItem, app.GetColor());\n }\n return;\n }\n // Nav item not found, fall through to default behavior\n }\n\n // No specific nav item requested - check if app has any tabs\n if (appTabs.length === 0) {\n // Create default tab\n const tabRequest = await app.CreateDefaultTab();\n if (tabRequest) {\n this.workspaceManager.OpenTab(tabRequest, app.GetColor());\n }\n } else {\n // App has tabs - switch to the first one (or active one if exists)\n const config = this.workspaceManager.GetConfiguration();\n const activeAppTab = appTabs.find(t => t.id === config?.activeTabId);\n if (!activeAppTab) {\n // No active tab for this app, switch to first tab\n this.workspaceManager.SetActiveTab(appTabs[0].id);\n }\n }\n }\n\n /**\n * Update the query params for the currently active tab.\n * This updates the tab's configuration and triggers a URL sync via the shell's\n * workspace configuration subscription.\n *\n * Use this instead of directly calling router.navigate() to ensure proper\n * URL management that respects app-scoped routes.\n *\n * @param queryParams Object containing query param key-value pairs.\n * Use null values to remove a query param.\n * @example\n * // Add or update query params\n * navigationService.UpdateActiveTabQueryParams({ category: 'abc123', dashboard: 'xyz789' });\n *\n * // Remove a query param\n * navigationService.UpdateActiveTabQueryParams({ category: null });\n */\n UpdateActiveTabQueryParams(queryParams: Record<string, string | null>): void {\n const activeTabId = this.workspaceManager.GetActiveTabId();\n if (!activeTabId) {\n console.warn('NavigationService.UpdateActiveTabQueryParams: No active tab');\n return;\n }\n\n this.applyQueryParamsToTab(activeTabId, queryParams);\n }\n\n /**\n * Notify subscribers that query params changed on a specific tab.\n * Called by the shell when back/forward navigation changes query params on the active tab.\n * The notification includes the tab ID so only the component in that tab reacts.\n */\n NotifyQueryParamsChanged(tabId: string, params: Record<string, string>): void {\n this.queryParamChanged$.next({ TabId: tabId, Params: params });\n }\n\n /**\n * Apply query params to a specific tab by ID.\n * Merges with any existing query params on the tab. Use null values to remove params.\n */\n private applyQueryParamsToTab(tabId: string, queryParams: Record<string, string | null>): void {\n const tab = this.workspaceManager.GetTab(tabId);\n if (!tab) {\n console.warn('NavigationService.applyQueryParamsToTab: Tab not found:', tabId);\n return;\n }\n\n // Get existing queryParams from tab configuration\n const existingQueryParams = (tab.configuration?.['queryParams'] || {}) as Record<string, string | null>;\n\n // Merge with new query params\n const mergedQueryParams: Record<string, string> = {};\n\n // Start with existing params (excluding nulls)\n for (const [key, value] of Object.entries(existingQueryParams)) {\n if (value !== null) {\n mergedQueryParams[key] = value;\n }\n }\n\n // Apply new params (null means remove)\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === null) {\n delete mergedQueryParams[key];\n } else {\n mergedQueryParams[key] = value;\n }\n }\n\n // Update the tab configuration\n this.workspaceManager.UpdateTabConfiguration(tabId, {\n queryParams: Object.keys(mergedQueryParams).length > 0 ? mergedQueryParams : undefined\n });\n }\n}\n"]}
1
+ {"version":3,"file":"navigation.service.js","sourceRoot":"","sources":["../../src/lib/navigation.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, OnDestroy } from '@angular/core';\nimport { WorkspaceStateManager, NavItem, DynamicNavItem, TabRequest, ApplicationManager } from '@memberjunction/ng-base-application';\nimport { NavigationOptions } from './navigation.interfaces';\nimport { CompositeKey } from '@memberjunction/core';\nimport { fromEvent, Subject, Subscription } from 'rxjs';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { BaseResourceComponent } from './base-resource-component';\n\n/**\n * Event emitted when query params change on a tab (e.g., from browser back/forward).\n * Includes the tab ID so that only the component in the affected tab reacts,\n * preventing cross-tab leakage in multi-tab scenarios.\n */\nexport interface QueryParamChangeEvent {\n TabId: string;\n Params: Record<string, string>;\n}\n\n/**\n * Event emitted when a resource component reports its agent context or tools.\n * The shell (which owns the ComponentCacheManager) subscribes to these events\n * and updates the cache + active AppContextSnapshot accordingly.\n */\nexport interface AgentContextUpdate {\n /** The component instance that reported the update */\n Caller: BaseResourceComponent;\n /** Dashboard-specific context for the agent (undefined = no change) */\n AgentContext?: Record<string, unknown>;\n /** Client tools available from this dashboard (undefined = no change) */\n AgentClientTools?: Array<{\n Name: string;\n Description: string;\n ParameterSchema: Record<string, unknown>;\n Handler: (params: Record<string, unknown>) => Promise<unknown>;\n }>;\n}\n\n/**\n * System application ID for non-app-specific resources (fallback only)\n * Uses double underscore prefix to indicate system-level resource\n * @deprecated Prefer using NavigationService.getDefaultApplicationId() instead\n */\nexport const SYSTEM_APP_ID = '__explorer';\n\n/**\n * Neutral color for fallback when no app is available\n */\nconst NEUTRAL_APP_COLOR = '#9E9E9E'; // Material Design Gray 500\n\n/**\n * Centralized navigation service that handles all navigation operations\n * with automatic shift-key detection for power user workflows\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class NavigationService implements OnDestroy {\n private shiftKeyPressed = false;\n private subscriptions: Subscription[] = [];\n\n private queryParamChanged$ = new Subject<QueryParamChangeEvent>();\n /** Observable that emits when query params change on a tab (back/forward navigation). */\n public QueryParamChanged$ = this.queryParamChanged$.asObservable();\n\n /** Cached Home app ID (null means not found, undefined means not checked) */\n private _homeAppId: string | null | undefined = undefined;\n /** Cached Home app color */\n private _homeAppColor: string | null = null;\n\n constructor(\n private workspaceManager: WorkspaceStateManager,\n private appManager: ApplicationManager\n ) {\n this.setupGlobalShiftKeyDetection();\n }\n\n /**\n * Get the neutral color used for system-wide resources (entities, views, dashboards)\n * Returns a light neutral gray\n * @deprecated Use getDefaultAppColor() for better UX with Home app integration\n */\n get ExplorerAppColor(): string {\n return NEUTRAL_APP_COLOR;\n }\n\n /**\n * Gets the default application ID for orphan resources.\n * Priority: Home app > Active app > SYSTEM_APP_ID\n *\n * This ensures orphan resources (entity records, dashboards, views opened directly)\n * are grouped under the Home app instead of being orphaned in the tab system.\n */\n private getDefaultApplicationId(): string {\n // Check cache first\n if (this._homeAppId !== undefined) {\n if (this._homeAppId !== null) {\n return this._homeAppId;\n }\n // Home app not found, check active app\n const activeApp = this.appManager.GetActiveApp();\n if (activeApp) {\n return activeApp.ID;\n }\n return SYSTEM_APP_ID;\n }\n\n // First time - look for Home app\n const homeApp = this.appManager.GetAppByName('Home');\n if (homeApp) {\n this._homeAppId = homeApp.ID;\n this._homeAppColor = homeApp.GetColor();\n return homeApp.ID;\n }\n\n // Cache that Home app doesn't exist\n this._homeAppId = null;\n\n // Fall back to currently active app\n const activeApp = this.appManager.GetActiveApp();\n if (activeApp) {\n return activeApp.ID;\n }\n\n // Last resort - system app ID\n return SYSTEM_APP_ID;\n }\n\n /**\n * Gets the default app color for orphan resources.\n * Returns Home app color if available, otherwise neutral gray.\n */\n private getDefaultAppColor(): string {\n // Ensure cache is populated\n this.getDefaultApplicationId();\n\n // If Home app exists, use its color\n if (this._homeAppColor) {\n return this._homeAppColor;\n }\n\n // Check active app\n const activeApp = this.appManager.GetActiveApp();\n if (activeApp) {\n return activeApp.GetColor();\n }\n\n // Fall back to neutral color\n return NEUTRAL_APP_COLOR;\n }\n\n /**\n * Clears the cached Home app info.\n * Call this if apps are reloaded or user logs out.\n */\n public clearHomeAppCache(): void {\n this._homeAppId = undefined;\n this._homeAppColor = null;\n }\n\n // ════════════════════════════════════════════\n // Agent Context & Client Tools\n // ════════════════════════════════════════════\n\n /**\n * Observable stream of agent context updates from resource components.\n * The shell subscribes to this to update the ComponentCacheManager and\n * push changes to the chat overlay's AppContextSnapshot.DashboardContext.\n */\n public readonly AgentContextUpdated$ = new Subject<AgentContextUpdate>();\n\n /**\n * Report the current agent-visible state from a resource component.\n * Call this whenever the dashboard's internal state changes (tab switch,\n * filter change, pipeline status change, drill-down, etc.).\n *\n * @param caller - Pass `this` from the calling component. Used to match\n * against the ComponentCacheManager to identify which cached component\n * this update belongs to.\n * @param context - Key-value pairs representing dashboard state the agent\n * should know about. Each dashboard defines its own shape.\n */\n public SetAgentContext(caller: BaseResourceComponent, context: Record<string, unknown>): void {\n this.AgentContextUpdated$.next({ Caller: caller, AgentContext: context });\n }\n\n /**\n * Register the client tools available from a resource component.\n * Call this on component init and whenever the available tools change.\n * Tools are automatically unregistered when the component becomes inactive\n * (tab switch) and re-registered when it becomes active again.\n *\n * @param caller - Pass `this` from the calling component.\n * @param tools - Array of tool definitions with Name, Description,\n * ParameterSchema (JSON Schema), and Handler function.\n */\n public SetAgentClientTools(caller: BaseResourceComponent, tools: Array<{\n Name: string;\n Description: string;\n ParameterSchema: Record<string, unknown>;\n Handler: (params: Record<string, unknown>) => Promise<unknown>;\n }>): void {\n this.AgentContextUpdated$.next({ Caller: caller, AgentClientTools: tools });\n }\n\n ngOnDestroy(): void {\n this.subscriptions.forEach(sub => sub.unsubscribe());\n }\n\n /**\n * Set up global keyboard event listeners to track shift key state\n */\n private setupGlobalShiftKeyDetection(): void {\n // Track shift key via mousedown events (capture phase) instead of keydown/keyup.\n // This is more reliable because:\n // 1. MouseEvent.shiftKey always reflects the actual modifier state at click time\n // 2. No risk of \"stuck\" state from missed keyup events (focus loss, tab switch, etc.)\n // 3. Navigation is always triggered by a click, so the shift state is read\n // at exactly the right moment\n this.subscriptions.push(\n fromEvent<MouseEvent>(document, 'mousedown', { capture: true }).subscribe(event => {\n this.shiftKeyPressed = event.shiftKey;\n })\n );\n }\n\n /**\n * Get current shift key state\n */\n private isShiftPressed(): boolean {\n return this.shiftKeyPressed;\n }\n\n /**\n * Determine if a new tab should be forced based on options and shift key state\n */\n private shouldForceNewTab(options?: NavigationOptions): boolean {\n // If forceNewTab is explicitly set, use that\n if (options?.forceNewTab !== undefined) {\n return options.forceNewTab;\n }\n\n // Otherwise, use global shift key detection\n return this.isShiftPressed();\n }\n\n /**\n * Returns whether the caller should use OpenTabForced (force-new path) or\n * OpenTab (replace-temp path).\n *\n * Rule: only honor an explicit force-new request — from the user via\n * shift+click, or from the caller via `options.forceNewTab`. We deliberately\n * do NOT apply heuristics that auto-switch the workspace out of\n * single-resource mode on cross-resource navigation. A previous version of\n * this method tried to do that (\"force new if single-resource + different\n * resource\") and it caused a regression: every plain hyperlink click on a\n * record opened a new tab and dropped the user into multi-tab mode, even\n * though they didn't ask for it. That violated the principle that mode\n * transitions are user-driven (shift) or explicitly requested (options).\n *\n * If a particular caller really needs the parent context preserved when\n * creating/navigating to a child resource (e.g. \"+New\" on a related-entity\n * grid inside an open record), the caller should pass `forceNewTab: true`\n * in `NavigationOptions`. That keeps intent explicit at the call site\n * instead of buried in a global heuristic.\n */\n private handleSingleResourceModeTransition(forceNew: boolean, _newRequest: TabRequest): boolean {\n return forceNew;\n }\n\n /**\n * Check if a tab request matches an existing tab's resource\n */\n private isSameResource(tab: any, request: TabRequest): boolean {\n // Different apps = different resources\n if (tab.applicationId !== request.ApplicationId) {\n return false;\n }\n\n // For resource-based tabs, compare resourceType and recordId\n if (request.Configuration?.resourceType) {\n const requestRecordId = request.ResourceRecordId || '';\n const tabRecordId = tab.resourceRecordId || '';\n return tab.configuration?.resourceType === request.Configuration.resourceType &&\n tabRecordId === requestRecordId;\n }\n\n // For app nav items, compare appName and navItemName\n if (request.Configuration?.appName && request.Configuration?.navItemName) {\n return tab.configuration?.appName === request.Configuration.appName &&\n tab.configuration?.navItemName === request.Configuration.navItemName;\n }\n\n // Fallback to basic comparison\n return false;\n }\n\n /**\n * Open a navigation item within an app\n */\n public OpenNavItem(appId: string, navItem: NavItem, appColor: string, options?: NavigationOptions): string {\n let forceNew = this.shouldForceNewTab(options);\n\n // Get the app to find its name\n const app = this.appManager.GetAppById(appId);\n const appName = app?.Name || '';\n\n // Dynamic nav items (e.g. orphan entity records) carry their original tab Configuration\n // and should NOT get navItemName stamped on them — that would cause buildResourceUrl\n // to produce a nav-item-style URL like /app/home/<label> instead of the correct\n // resource-type URL like /app/home/record/Entity/ID|...\n const isDynamic = (navItem as DynamicNavItem).isDynamic === true;\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: navItem.Label,\n ResourceRecordId: navItem.RecordID || '', // Also store at top level for consistent tab matching\n Configuration: {\n route: navItem.Route,\n resourceType: navItem.ResourceType,\n driverClass: navItem.DriverClass, // Pass through DriverClass for Custom resource type\n recordId: navItem.RecordID,\n appName: appName, // Store app name for URL building\n appId: appId,\n ...(isDynamic ? {} : { navItemName: navItem.Label }), // Only set for static nav items\n ...(navItem.Configuration || {})\n },\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n let tabId: string;\n if (forceNew) {\n // Always create a new tab\n tabId = this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n // Use existing OpenTab logic (may replace temporary tab)\n tabId = this.workspaceManager.OpenTab(request, appColor);\n }\n\n // Apply query params to the newly opened/activated tab if provided\n if (options?.queryParams) {\n this.applyQueryParamsToTab(tabId, options.queryParams);\n }\n\n return tabId;\n }\n\n /**\n * Open an entity record view\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenEntityRecord(\n entityName: string,\n recordPkey: CompositeKey,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n\n let forceNew = this.shouldForceNewTab(options);\n\n const recordId = recordPkey.ToURLSegment();\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `${entityName} - ${recordId}`,\n Configuration: {\n resourceType: 'Records',\n Entity: entityName, // Must use 'Entity' (capital E) - expected by record-resource.component\n recordId: recordId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: recordId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n let tabId: string;\n if (forceNew) {\n tabId = this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n tabId = this.workspaceManager.OpenTab(request, appColor);\n }\n\n return tabId;\n }\n\n /**\n * Open a view\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenView(\n viewId: string,\n viewName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n let forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: viewName,\n Configuration: {\n resourceType: 'MJ: User Views',\n viewId,\n recordId: viewId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: viewId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a dashboard\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenDashboard(\n dashboardId: string,\n dashboardName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n let forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: dashboardName,\n Configuration: {\n resourceType: 'Dashboards',\n dashboardId,\n recordId: dashboardId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: dashboardId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a report\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenReport(\n reportId: string,\n reportName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n let forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: reportName,\n Configuration: {\n resourceType: 'Reports',\n reportId,\n recordId: reportId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: reportId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open an artifact\n * Artifacts are versioned content containers (reports, dashboards, UI components, etc.)\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenArtifact(\n artifactId: string,\n artifactName?: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n let forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: artifactName || `Artifact - ${artifactId}`,\n Configuration: {\n resourceType: 'Artifacts',\n artifactId,\n recordId: artifactId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: artifactId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a dynamic view\n * Dynamic views are entity-based views with custom filters, not saved views\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenDynamicView(\n entityName: string,\n extraFilter?: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n let forceNew = this.shouldForceNewTab(options);\n\n const filterSuffix = extraFilter ? ' (Filtered)' : '';\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `${entityName}${filterSuffix}`,\n Configuration: {\n resourceType: 'MJ: User Views',\n Entity: entityName,\n ExtraFilter: extraFilter,\n isDynamic: true,\n recordId: 'dynamic' // Special marker for dynamic views\n },\n ResourceRecordId: 'dynamic',\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a query\n * Uses Home app if available, otherwise falls back to active app or system app\n */\n public OpenQuery(\n queryId: string,\n queryName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n let forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: queryName,\n Configuration: {\n resourceType: 'Queries',\n queryId,\n recordId: queryId // Also needed in Configuration for tab-container.component to populate ResourceRecordID\n },\n ResourceRecordId: queryId,\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a new entity record creation form\n * Uses Home app if available, otherwise falls back to active app or system app\n * @param entityName The name of the entity to create a new record for\n * @param options Navigation options including optional newRecordValues for pre-populating fields\n */\n public OpenNewEntityRecord(\n entityName: string,\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n\n let forceNew = this.shouldForceNewTab(options);\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `New ${entityName}`,\n Configuration: {\n resourceType: 'Records',\n Entity: entityName, // Must use 'Entity' (capital E) - expected by record-resource.component\n recordId: '', // Empty recordId indicates new record\n isNew: true, // Flag to indicate this is a new record\n NewRecordValues: options?.newRecordValues // Pass through initial values if provided\n },\n ResourceRecordId: '', // Empty for new records\n IsPinned: options?.pinTab || false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Open a universal search results tab for the given query.\n * This is the primary way to open search results from anywhere in the application.\n *\n * @param query The search query text\n * @param searchOptions Optional search-specific options (e.g., minRelevance, scopeIDs)\n * @param options Navigation options\n */\n public OpenSearch(\n query: string,\n searchOptions?: { minRelevance?: number; scopeIDs?: string[] },\n options?: NavigationOptions\n ): string {\n const appId = this.getDefaultApplicationId();\n const appColor = this.getDefaultAppColor();\n let forceNew = this.shouldForceNewTab(options);\n\n const config: Record<string, unknown> = {\n resourceType: 'Search Results',\n Query: query,\n SearchInput: query,\n recordId: `search-${query}`\n };\n if (searchOptions?.minRelevance != null) {\n config['MinRelevance'] = searchOptions.minRelevance;\n }\n if (searchOptions?.scopeIDs && searchOptions.scopeIDs.length > 0) {\n config['ScopeIDs'] = searchOptions.scopeIDs;\n }\n\n const request: TabRequest = {\n ApplicationId: appId,\n Title: `Search: ${query}`,\n Configuration: config,\n ResourceRecordId: `search-${query}`,\n IsPinned: false\n };\n\n // Handle transition from single-resource mode\n forceNew = this.handleSingleResourceModeTransition(forceNew, request);\n\n if (forceNew) {\n return this.workspaceManager.OpenTabForced(request, appColor);\n } else {\n return this.workspaceManager.OpenTab(request, appColor);\n }\n }\n\n /**\n * Navigate to a nav item by name within the current or specified application.\n * Allows passing additional configuration parameters to merge with the nav item's config.\n * This is useful for cross-resource navigation where a component needs to navigate\n * to another nav item with specific parameters (e.g., navigate to Conversations with a specific conversationId).\n *\n * @param navItemName The label/name of the nav item to navigate to\n * @param configuration Additional configuration to merge (e.g., conversationId, artifactId)\n * @param appId Optional app ID (defaults to current active app)\n * @param options Navigation options\n * @returns The tab ID if successful, null if nav item not found\n */\n public async OpenNavItemByName(\n navItemName: string,\n configuration?: Record<string, unknown>,\n appId?: string,\n options?: NavigationOptions\n ): Promise<string | null> {\n // Get app (use provided or current active)\n const targetAppId = appId || this.appManager.GetActiveApp()?.ID;\n if (!targetAppId) {\n return null;\n }\n\n const app = this.appManager.GetAppById(targetAppId);\n if (!app) {\n return null;\n }\n\n // Find the nav item by name\n const navItems = await app.GetNavItems();\n const navItem = navItems.find(item => item.Label === navItemName);\n if (!navItem) {\n return null;\n }\n\n // Create a merged nav item with additional configuration\n const mergedNavItem: NavItem = {\n ...navItem,\n Configuration: {\n ...(navItem.Configuration || {}),\n ...(configuration || {})\n }\n };\n\n // Use existing OpenNavItem\n return this.OpenNavItem(targetAppId, mergedNavItem, app.GetColor(), options);\n }\n\n /**\n * Switch to an application by ID.\n * This sets the app as active and either opens a specific nav item or creates a default tab.\n * If the requested nav item already has an open tab, switches to that tab instead of creating a new one.\n * @param appId The application ID to switch to\n * @param navItemName Optional name of a nav item to open within the app. If provided, opens that nav item.\n */\n async SwitchToApp(appId: string, navItemName?: string): Promise<void> {\n await this.appManager.SetActiveApp(appId);\n\n const app = this.appManager.GetAllApps().find(a => UUIDsEqual(a.ID, appId));\n if (!app) {\n return;\n }\n\n const appTabs = this.workspaceManager.GetAppTabs(appId);\n\n // If a specific nav item is requested\n if (navItemName) {\n const navItems = await app.GetNavItems();\n const navItem = navItems.find(item => item.Label === navItemName);\n if (navItem) {\n // Check if there's already a tab for this nav item\n const existingTab = appTabs.find(tab =>\n tab.title === navItem.Label ||\n (tab.configuration?.['route'] === navItem.Route && navItem.Route)\n );\n\n if (existingTab) {\n // Switch to existing tab\n this.workspaceManager.SetActiveTab(existingTab.id);\n } else {\n // Open new tab for this nav item\n this.OpenNavItem(appId, navItem, app.GetColor());\n }\n return;\n }\n // Nav item not found, fall through to default behavior\n }\n\n // No specific nav item requested - check if app has any tabs\n if (appTabs.length === 0) {\n // Create default tab\n const tabRequest = await app.CreateDefaultTab();\n if (tabRequest) {\n this.workspaceManager.OpenTab(tabRequest, app.GetColor());\n }\n } else {\n // App has tabs - switch to the first one (or active one if exists)\n const config = this.workspaceManager.GetConfiguration();\n const activeAppTab = appTabs.find(t => t.id === config?.activeTabId);\n if (!activeAppTab) {\n // No active tab for this app, switch to first tab\n this.workspaceManager.SetActiveTab(appTabs[0].id);\n }\n }\n }\n\n /**\n * Update the query params for the currently active tab.\n * This updates the tab's configuration and triggers a URL sync via the shell's\n * workspace configuration subscription.\n *\n * Use this instead of directly calling router.navigate() to ensure proper\n * URL management that respects app-scoped routes.\n *\n * @param queryParams Object containing query param key-value pairs.\n * Use null values to remove a query param.\n * @example\n * // Add or update query params\n * navigationService.UpdateActiveTabQueryParams({ category: 'abc123', dashboard: 'xyz789' });\n *\n * // Remove a query param\n * navigationService.UpdateActiveTabQueryParams({ category: null });\n */\n UpdateActiveTabQueryParams(queryParams: Record<string, string | null>): void {\n const activeTabId = this.workspaceManager.GetActiveTabId();\n if (!activeTabId) {\n console.warn('NavigationService.UpdateActiveTabQueryParams: No active tab');\n return;\n }\n\n this.applyQueryParamsToTab(activeTabId, queryParams);\n }\n\n /**\n * Notify subscribers that query params changed on a specific tab.\n * Called by the shell when back/forward navigation changes query params on the active tab.\n * The notification includes the tab ID so only the component in that tab reacts.\n */\n NotifyQueryParamsChanged(tabId: string, params: Record<string, string>): void {\n this.queryParamChanged$.next({ TabId: tabId, Params: params });\n }\n\n /**\n * Apply query params to a specific tab by ID.\n * Merges with any existing query params on the tab. Use null values to remove params.\n */\n private applyQueryParamsToTab(tabId: string, queryParams: Record<string, string | null>): void {\n const tab = this.workspaceManager.GetTab(tabId);\n if (!tab) {\n console.warn('NavigationService.applyQueryParamsToTab: Tab not found:', tabId);\n return;\n }\n\n // Get existing queryParams from tab configuration\n const existingQueryParams = (tab.configuration?.['queryParams'] || {}) as Record<string, string | null>;\n\n // Merge with new query params\n const mergedQueryParams: Record<string, string> = {};\n\n // Start with existing params (excluding nulls)\n for (const [key, value] of Object.entries(existingQueryParams)) {\n if (value !== null) {\n mergedQueryParams[key] = value;\n }\n }\n\n // Apply new params (null means remove)\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === null) {\n delete mergedQueryParams[key];\n } else {\n mergedQueryParams[key] = value;\n }\n }\n\n // Update the tab configuration\n this.workspaceManager.UpdateTabConfiguration(tabId, {\n queryParams: Object.keys(mergedQueryParams).length > 0 ? mergedQueryParams : undefined\n });\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-shared",
3
- "version": "5.32.0",
3
+ "version": "5.34.0",
4
4
  "description": "MemberJunction: MJ Explorer Angular Shared Package - utility functions and other reusable elements used across other MJ Angular packages within the MJ Explorer App - do not use outside of MJ Explorer.",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -29,16 +29,16 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@angular/platform-browser": "21.1.3",
32
- "@memberjunction/ai-engine-base": "5.32.0",
33
- "@memberjunction/core": "5.32.0",
34
- "@memberjunction/core-entities": "5.32.0",
35
- "@memberjunction/entity-communications-base": "5.32.0",
36
- "@memberjunction/global": "5.32.0",
37
- "@memberjunction/graphql-dataprovider": "5.32.0",
38
- "@memberjunction/ng-base-application": "5.32.0",
39
- "@memberjunction/ng-base-types": "5.32.0",
40
- "@memberjunction/ng-notifications": "5.32.0",
41
- "@memberjunction/ng-shared-generic": "5.32.0",
32
+ "@memberjunction/ai-engine-base": "5.34.0",
33
+ "@memberjunction/core": "5.34.0",
34
+ "@memberjunction/core-entities": "5.34.0",
35
+ "@memberjunction/entity-communications-base": "5.34.0",
36
+ "@memberjunction/global": "5.34.0",
37
+ "@memberjunction/graphql-dataprovider": "5.34.0",
38
+ "@memberjunction/ng-base-application": "5.34.0",
39
+ "@memberjunction/ng-base-types": "5.34.0",
40
+ "@memberjunction/ng-notifications": "5.34.0",
41
+ "@memberjunction/ng-shared-generic": "5.34.0",
42
42
  "html-to-image": "^1.11.11",
43
43
  "tslib": "^2.8.1"
44
44
  },