@memberjunction/ng-explorer-core 6.2.0-edge.4 → 6.2.0-edge.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +7 -2
  2. package/dist/app-routing.module.d.ts.map +1 -1
  3. package/dist/app-routing.module.js +20 -10
  4. package/dist/app-routing.module.js.map +1 -1
  5. package/dist/generated/lazy-feature-config.d.ts +1 -1
  6. package/dist/generated/lazy-feature-config.d.ts.map +1 -1
  7. package/dist/generated/lazy-feature-config.js +6 -3
  8. package/dist/generated/lazy-feature-config.js.map +1 -1
  9. package/dist/lib/oauth/oauth-callback.component.d.ts +2 -0
  10. package/dist/lib/oauth/oauth-callback.component.d.ts.map +1 -1
  11. package/dist/lib/oauth/oauth-callback.component.js +10 -10
  12. package/dist/lib/oauth/oauth-callback.component.js.map +1 -1
  13. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +17 -3
  14. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
  15. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +211 -13
  16. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
  17. package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts +12 -3
  18. package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts.map +1 -1
  19. package/dist/lib/resource-wrappers/chat-tasks-resource.component.js +18 -3
  20. package/dist/lib/resource-wrappers/chat-tasks-resource.component.js.map +1 -1
  21. package/dist/lib/resource-wrappers/record-form-mode.d.ts +44 -0
  22. package/dist/lib/resource-wrappers/record-form-mode.d.ts.map +1 -0
  23. package/dist/lib/resource-wrappers/record-form-mode.js +47 -0
  24. package/dist/lib/resource-wrappers/record-form-mode.js.map +1 -0
  25. package/dist/lib/resource-wrappers/record-resource.component.d.ts +56 -1
  26. package/dist/lib/resource-wrappers/record-resource.component.d.ts.map +1 -1
  27. package/dist/lib/resource-wrappers/record-resource.component.js +124 -9
  28. package/dist/lib/resource-wrappers/record-resource.component.js.map +1 -1
  29. package/dist/lib/resource-wrappers/search-results-resource.component.d.ts +3 -3
  30. package/dist/lib/resource-wrappers/search-results-resource.component.d.ts.map +1 -1
  31. package/dist/lib/resource-wrappers/search-results-resource.component.js +5 -10
  32. package/dist/lib/resource-wrappers/search-results-resource.component.js.map +1 -1
  33. package/dist/lib/resource-wrappers/standard-form-create.d.ts +4 -0
  34. package/dist/lib/resource-wrappers/standard-form-create.d.ts.map +1 -0
  35. package/dist/lib/resource-wrappers/standard-form-create.js +6 -0
  36. package/dist/lib/resource-wrappers/standard-form-create.js.map +1 -0
  37. package/dist/lib/resource-wrappers/view-resource.component.d.ts +18 -1
  38. package/dist/lib/resource-wrappers/view-resource.component.d.ts.map +1 -1
  39. package/dist/lib/resource-wrappers/view-resource.component.js +105 -39
  40. package/dist/lib/resource-wrappers/view-resource.component.js.map +1 -1
  41. package/dist/lib/server-connectivity/server-connectivity-banner.component.d.ts +16 -3
  42. package/dist/lib/server-connectivity/server-connectivity-banner.component.d.ts.map +1 -1
  43. package/dist/lib/server-connectivity/server-connectivity-banner.component.js +17 -3
  44. package/dist/lib/server-connectivity/server-connectivity-banner.component.js.map +1 -1
  45. package/dist/lib/shell/components/record-open/record-origin-crumb.component.d.ts.map +1 -1
  46. package/dist/lib/shell/components/record-open/record-origin-crumb.component.js +12 -8
  47. package/dist/lib/shell/components/record-open/record-origin-crumb.component.js.map +1 -1
  48. package/dist/lib/shell/components/tabs/component-cache-manager.d.ts +6 -0
  49. package/dist/lib/shell/components/tabs/component-cache-manager.d.ts.map +1 -1
  50. package/dist/lib/shell/components/tabs/component-cache-manager.js +18 -3
  51. package/dist/lib/shell/components/tabs/component-cache-manager.js.map +1 -1
  52. package/dist/lib/shell/components/tabs/tab-container.component.d.ts +36 -0
  53. package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
  54. package/dist/lib/shell/components/tabs/tab-container.component.js +188 -47
  55. package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
  56. package/dist/lib/shell/deep-link-workspace.d.ts +25 -0
  57. package/dist/lib/shell/deep-link-workspace.d.ts.map +1 -0
  58. package/dist/lib/shell/deep-link-workspace.js +49 -0
  59. package/dist/lib/shell/deep-link-workspace.js.map +1 -0
  60. package/dist/lib/shell/shell-chrome-policy.d.ts +6 -0
  61. package/dist/lib/shell/shell-chrome-policy.d.ts.map +1 -1
  62. package/dist/lib/shell/shell-chrome-policy.js +1 -0
  63. package/dist/lib/shell/shell-chrome-policy.js.map +1 -1
  64. package/dist/lib/shell/shell.component.d.ts +35 -0
  65. package/dist/lib/shell/shell.component.d.ts.map +1 -1
  66. package/dist/lib/shell/shell.component.js +348 -78
  67. package/dist/lib/shell/shell.component.js.map +1 -1
  68. package/dist/lib/single-record/single-record.component.d.ts +39 -2
  69. package/dist/lib/single-record/single-record.component.d.ts.map +1 -1
  70. package/dist/lib/single-record/single-record.component.js +99 -12
  71. package/dist/lib/single-record/single-record.component.js.map +1 -1
  72. package/dist/lib/user-notifications/user-notifications.component.d.ts +10 -2
  73. package/dist/lib/user-notifications/user-notifications.component.d.ts.map +1 -1
  74. package/dist/lib/user-notifications/user-notifications.component.js +77 -22
  75. package/dist/lib/user-notifications/user-notifications.component.js.map +1 -1
  76. package/package.json +57 -57
@@ -1 +1 @@
1
- {"version":3,"file":"chat-tasks-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/chat-tasks-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewEncapsulation, OnDestroy, ViewChild } from '@angular/core';\nimport { Metadata } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport { MJEnvironmentEntityExtended } from '@memberjunction/core-entities';\nimport { TasksFullViewComponent } from '@memberjunction/ng-conversations';\nimport { Subject } from 'rxjs';\n/**\n * Chat Tasks Resource - displays the tasks full view for tab-based display\n * Extends BaseResourceComponent to work with the resource type system\n * Shows all tasks associated with conversations and artifacts\n * Supports URL deep-linking via taskId query parameter\n */\n@RegisterClass(BaseResourceComponent, 'ChatTasksResource')\n@Component({\n standalone: false,\n selector: 'mj-chat-tasks-resource',\n template: `\n <div class=\"chat-tasks-container\">\n @if (currentUser) {\n <mj-tasks-full-view\n #tasksView\n [environmentId]=\"environmentId\"\n [currentUser]=\"currentUser\"\n [baseFilter]=\"'1=1'\"\n [activeTaskId]=\"activeTaskId\"\n (taskSelected)=\"onTaskSelected($any($event))\"\n style=\"height: 100%;\">\n </mj-tasks-full-view>\n }\n </div>\n `,\n styles: [`\n :host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n }\n\n .chat-tasks-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n flex: 1;\n overflow: hidden;\n }\n `],\n encapsulation: ViewEncapsulation.None\n})\nexport class ChatTasksResource extends BaseResourceComponent implements OnDestroy {\n @ViewChild('tasksView') TasksView?: TasksFullViewComponent;\n\n /** @deprecated Use {@link TasksView}. */\n get tasksView(): TasksFullViewComponent | undefined {\n return this.TasksView;\n }\n /** @deprecated Use {@link TasksView}. */\n set tasksView(value: TasksFullViewComponent | undefined) {\n this.TasksView = value;\n }\n\n public CurrentUser: any = null;\n\n /** @deprecated Use {@link CurrentUser}. */\n public get currentUser(): any {\n return this.CurrentUser;\n }\n /** @deprecated Use {@link CurrentUser}. */\n public set currentUser(value: any) {\n this.CurrentUser = value;\n }\n public activeTaskId?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member\n\n ngOnInit() {\n super.ngOnInit();\n const md = this.ProviderToUse;\n this.CurrentUser = md.CurrentUser;\n\n // Apply initial state from query params or tab config\n const params = this.GetQueryParams();\n const config = this.Data?.Configuration;\n const taskId = params['taskId'] || (config?.taskId as string);\n if (taskId) {\n this.activeTaskId = taskId;\n }\n\n // Push initial state to URL\n this.UpdateQueryParams({ taskId: this.activeTaskId ?? null });\n\n // Notify load complete after user is set\n setTimeout(() => {\n this.NotifyLoadComplete();\n }, 100);\n }\n\n ngOnDestroy() {\n super.ngOnDestroy();\n }\n\n protected override OnQueryParamsChanged(params: Record<string, string>, source: 'popstate' | 'deeplink'): void {\n this.activeTaskId = params['taskId'] || undefined;\n }\n\n /**\n * Handle task selection from the tasks view.\n */\n OnTaskSelected(taskId: string | null): void {\n this.activeTaskId = taskId || undefined;\n this.UpdateQueryParams({ taskId: this.activeTaskId ?? null });\n }\n\n /** @deprecated Use {@link OnTaskSelected}. */\n onTaskSelected(taskId: string | null): void {\n return this.OnTaskSelected(taskId);\n }\n\n\n /**\n * Get the environment ID from configuration or use default\n */\n get EnvironmentId(): string {\n return this.Data?.Configuration?.environmentId || MJEnvironmentEntityExtended.DefaultEnvironmentID;\n }\n\n /** @deprecated Use {@link EnvironmentId}. */\n get environmentId(): string {\n return this.EnvironmentId;\n }\n\n /**\n * Get the display name for chat tasks\n */\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Tasks';\n }\n\n /**\n * Get the icon class for chat tasks\n */\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-tasks';\n }\n}\n"]}
1
+ {"version":3,"file":"chat-tasks-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/chat-tasks-resource.component.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAa,SAAS,EAAE,MAAM,eAAe,CAAC;AACnF,OAAO,EAAE,YAAY,EAAY,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;;;;;;IAepE,gDAQwB;IADtB,AADA,qNAAgB,6BAAsB,KAAC,gNACnB,iCAA0B,KAAC;IAEjD,iBAAqB;;;IAJnB,AADA,AADA,AADA,oDAA+B,mCACJ,qBACP,qCACS;;AAlBvC;;;;;GAKG;AAwCI,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,qBAAqB;IAClC,SAAS,CAA0B;IAE3D,yCAAyC;IACzC,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IACD,yCAAyC;IACzC,IAAI,SAAS,CAAC,KAAyC;QACrD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAEM,WAAW,GAAoB,IAAI,CAAC;IAE3C,2CAA2C;IAC3C,IAAW,WAAW;QACpB,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IACD,2CAA2C;IAC3C,IAAW,WAAW,CAAC,KAAsB;QAC3C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IACM,YAAY,CAAU,CAAE,yHAAyH;IAExJ,QAAQ;QACN,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjB,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,WAAW,CAAC;QAElC,sDAAsD;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAK,MAAM,EAAE,MAAiB,CAAC;QAC9D,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAC7B,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC,CAAC;QAE9D,yCAAyC;QACzC,UAAU,CAAC,GAAG,EAAE;YACd,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAED,WAAW;QACT,KAAK,CAAC,WAAW,EAAE,CAAC;IACtB,CAAC;IAEkB,oBAAoB,CAAC,MAA8B,EAAE,MAA+B;QACrG,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,MAAqB;QAClC,IAAI,CAAC,YAAY,GAAG,MAAM,IAAI,SAAS,CAAC;QACxC,IAAI,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,8CAA8C;IAC9C,cAAc,CAAC,MAAqB;QAClC,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,kBAAkB,CAAC,KAA+C;QAChE,IAAI,CAAC,KAAK,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;YAC3C,OAAO;QACT,CAAC;QACD,qFAAqF;QACrF,0DAA0D;QAC1D,MAAM,GAAG,GAAG,YAAY,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3G,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACjE,CAAC;IAGD;;OAEG;IACH,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,aAAa,IAAI,2BAA2B,CAAC,oBAAoB,CAAC;IACrG,CAAC;IAED,6CAA6C;IAC7C,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,sBAAsB,CAAC,IAAkB;QAC7C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB,CAAC,IAAkB;QAC3C,OAAO,mBAAmB,CAAC;IAC7B,CAAC;iPA1GU,iBAAiB,yBAAjB,iBAAiB;6DAAjB,iBAAiB;;;;;;YAlC1B,8BAAkC;YAChC,kGAAmB;YAYrB,iBAAM;;YAZJ,cAWC;YAXD,0CAWC;;;AAsBM,iBAAiB;IAvC7B,aAAa,CAAC,qBAAqB,EAAE,mBAAmB,CAAC;GAuC7C,iBAAiB,CA2G7B;;iFA3GY,iBAAiB;cAtC7B,SAAS;6BACI,KAAK,YACP,wBAAwB,YACxB;;;;;;;;;;;;;;;KAeP,iBAkBY,iBAAiB,CAAC,IAAI;;kBAGpC,SAAS;mBAAC,WAAW;;kFADX,iBAAiB","sourcesContent":["import { Component, ViewEncapsulation, OnDestroy, ViewChild } from '@angular/core';\nimport { CompositeKey, UserInfo } from '@memberjunction/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport { MJEnvironmentEntityExtended } from '@memberjunction/core-entities';\nimport { TasksFullViewComponent } from '@memberjunction/ng-conversations';\n/**\n * Chat Tasks Resource - displays the tasks full view for tab-based display\n * Extends BaseResourceComponent to work with the resource type system\n * Shows all tasks associated with conversations and artifacts\n * Supports URL deep-linking via taskId query parameter\n */\n@RegisterClass(BaseResourceComponent, 'ChatTasksResource')\n@Component({\n standalone: false,\n selector: 'mj-chat-tasks-resource',\n template: `\n <div class=\"chat-tasks-container\">\n @if (currentUser) {\n <mj-tasks-full-view\n #tasksView\n [environmentId]=\"environmentId\"\n [currentUser]=\"currentUser\"\n [baseFilter]=\"'1=1'\"\n [activeTaskId]=\"activeTaskId\"\n (taskSelected)=\"onTaskSelected($event)\"\n (openEntityRecord)=\"OnOpenEntityRecord($event)\"\n style=\"height: 100%;\">\n </mj-tasks-full-view>\n }\n </div>\n `,\n styles: [`\n :host {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n }\n\n .chat-tasks-container {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n flex: 1;\n overflow: hidden;\n }\n `],\n encapsulation: ViewEncapsulation.None\n})\nexport class ChatTasksResource extends BaseResourceComponent implements OnDestroy {\n @ViewChild('tasksView') TasksView?: TasksFullViewComponent;\n\n /** @deprecated Use {@link TasksView}. */\n get tasksView(): TasksFullViewComponent | undefined {\n return this.TasksView;\n }\n /** @deprecated Use {@link TasksView}. */\n set tasksView(value: TasksFullViewComponent | undefined) {\n this.TasksView = value;\n }\n\n public CurrentUser: UserInfo | null = null;\n\n /** @deprecated Use {@link CurrentUser}. */\n public get currentUser(): UserInfo | null {\n return this.CurrentUser;\n }\n /** @deprecated Use {@link CurrentUser}. */\n public set currentUser(value: UserInfo | null) {\n this.CurrentUser = value;\n }\n public activeTaskId?: string; // case-violation-ok-legacy-back-compat: an accessor cannot be optional, so a stub would turn this into a required member\n\n ngOnInit() {\n super.ngOnInit();\n const md = this.ProviderToUse;\n this.CurrentUser = md.CurrentUser;\n\n // Apply initial state from query params or tab config\n const params = this.GetQueryParams();\n const config = this.Data?.Configuration;\n const taskId = params['taskId'] || (config?.taskId as string);\n if (taskId) {\n this.activeTaskId = taskId;\n }\n\n // Push initial state to URL\n this.UpdateQueryParams({ taskId: this.activeTaskId ?? null });\n\n // Notify load complete after user is set\n setTimeout(() => {\n this.NotifyLoadComplete();\n }, 100);\n }\n\n ngOnDestroy() {\n super.ngOnDestroy();\n }\n\n protected override OnQueryParamsChanged(params: Record<string, string>, source: 'popstate' | 'deeplink'): void {\n this.activeTaskId = params['taskId'] || undefined;\n }\n\n /**\n * Handle task selection from the tasks view.\n */\n OnTaskSelected(taskId: string | null): void {\n this.activeTaskId = taskId || undefined;\n this.UpdateQueryParams({ taskId: this.activeTaskId ?? null });\n }\n\n /** @deprecated Use {@link OnTaskSelected}. */\n onTaskSelected(taskId: string | null): void {\n return this.OnTaskSelected(taskId);\n }\n\n /**\n * Handle entity record navigation requests from the AI Agent Workflows & Tasks Command Center\n * (e.g. opening an AI Agent or AI Agent Run record in Explorer).\n */\n OnOpenEntityRecord(event: { entityName: string; recordId: string }): void {\n if (!event?.entityName || !event?.recordId) {\n return;\n }\n // The entity arrives at runtime, so the key is built against its real primary key; a\n // composite key's \"F1|v1||F2|v2\" segment round-trips too.\n const key = CompositeKey.FromURLSegment(this.ProviderToUse.EntityByName(event.entityName), event.recordId);\n this.navigationService.OpenEntityRecord(event.entityName, key);\n }\n\n\n /**\n * Get the environment ID from configuration or use default\n */\n get EnvironmentId(): string {\n return this.Data?.Configuration?.environmentId || MJEnvironmentEntityExtended.DefaultEnvironmentID;\n }\n\n /** @deprecated Use {@link EnvironmentId}. */\n get environmentId(): string {\n return this.EnvironmentId;\n }\n\n /**\n * Get the display name for chat tasks\n */\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n return 'Tasks';\n }\n\n /**\n * Get the icon class for chat tasks\n */\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n return 'fa-solid fa-tasks';\n }\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import type { EntityFormMode } from '@memberjunction/ng-base-forms';
2
+ /**
3
+ * A record tab's form mode (MJ#4755) lives in its `form` query param, so the
4
+ * URL, back/forward, re-focus and a cached component all see one value.
5
+ * These are the decisions EntityRecordResource makes about it, kept pure so
6
+ * the component stays a thin caller.
7
+ */
8
+ /** The form mode a tab's query params ask for: `'standard'` only for `form=standard`. */
9
+ export declare function FormModeFromQueryParams(params: Record<string, string>): EntityFormMode;
10
+ /** The query-param patch that records `mode` on the tab (`null` removes the param). */
11
+ export declare function FormModeQueryParams(mode: EntityFormMode): Record<string, string | null>;
12
+ /** The record a tab hosts, or that a record component was opened for. */
13
+ export interface RecordTabIdentity {
14
+ Entity: string | undefined;
15
+ RecordId: string;
16
+ }
17
+ /**
18
+ * Whether a record component still owns its tab: the live tab hosts the same
19
+ * record (entity compared case- and whitespace-insensitively; record id via
20
+ * UUIDsEqual, like the tab identity guard — a save rewrites the component's id
21
+ * in the server's casing). False for a closed tab. A cached
22
+ * component whose tab id was reused for another record is not the owner, so
23
+ * that tab's `form` param is not addressed to it.
24
+ */
25
+ export declare function IsRecordTabOwner(liveTab: RecordTabIdentity | null, own: RecordTabIdentity): boolean;
26
+ /** Whatever can switch a mounted form (SingleRecordComponent → the form host). */
27
+ export interface FormModeSwitcher {
28
+ SwitchFormMode(mode: EntityFormMode): boolean;
29
+ }
30
+ /** Outcome of following a query-param change. */
31
+ export interface FormModeReconciliation {
32
+ /** The mode now in effect. */
33
+ Mode: EntityFormMode;
34
+ /** Params to write back when the switch was refused, so the URL matches the screen; else null. */
35
+ WriteBack: Record<string, string | null> | null;
36
+ }
37
+ /**
38
+ * Follow the tab's query params. With a mounted form, switches through the
39
+ * host's guarded `SwitchFormMode`; a refusal (unsaved work) keeps the live
40
+ * mode and asks for a write-back. Without one (`switcher` null), the requested
41
+ * mode is simply adopted — the input binding carries it to the host at mount.
42
+ */
43
+ export declare function ReconcileFormMode(params: Record<string, string>, current: EntityFormMode, switcher: FormModeSwitcher | null): FormModeReconciliation;
44
+ //# sourceMappingURL=record-form-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-form-mode.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-form-mode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAIpE;;;;;GAKG;AAEH,yFAAyF;AACzF,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,cAAc,CAEtF;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAEvF;AAED,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAInG;AAED,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC;CAC/C;AAED,iDAAiD;AACjD,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,IAAI,EAAE,cAAc,CAAC;IACrB,kGAAkG;IAClG,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;CACjD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAChC,sBAAsB,CAOxB"}
@@ -0,0 +1,47 @@
1
+ import { FORM_MODE_QUERY_PARAM, ReadStandardFormQuery } from '@memberjunction/ng-shared';
2
+ import { UUIDsEqual } from '@memberjunction/global';
3
+ /**
4
+ * A record tab's form mode (MJ#4755) lives in its `form` query param, so the
5
+ * URL, back/forward, re-focus and a cached component all see one value.
6
+ * These are the decisions EntityRecordResource makes about it, kept pure so
7
+ * the component stays a thin caller.
8
+ */
9
+ /** The form mode a tab's query params ask for: `'standard'` only for `form=standard`. */
10
+ export function FormModeFromQueryParams(params) {
11
+ return ReadStandardFormQuery(params) ?? 'default';
12
+ }
13
+ /** The query-param patch that records `mode` on the tab (`null` removes the param). */
14
+ export function FormModeQueryParams(mode) {
15
+ return { [FORM_MODE_QUERY_PARAM]: mode === 'standard' ? 'standard' : null };
16
+ }
17
+ /**
18
+ * Whether a record component still owns its tab: the live tab hosts the same
19
+ * record (entity compared case- and whitespace-insensitively; record id via
20
+ * UUIDsEqual, like the tab identity guard — a save rewrites the component's id
21
+ * in the server's casing). False for a closed tab. A cached
22
+ * component whose tab id was reused for another record is not the owner, so
23
+ * that tab's `form` param is not addressed to it.
24
+ */
25
+ export function IsRecordTabOwner(liveTab, own) {
26
+ if (!liveTab)
27
+ return false;
28
+ const entityKey = (entity) => (entity ?? '').trim().toLowerCase();
29
+ return entityKey(liveTab.Entity) === entityKey(own.Entity) && UUIDsEqual(liveTab.RecordId, own.RecordId);
30
+ }
31
+ /**
32
+ * Follow the tab's query params. With a mounted form, switches through the
33
+ * host's guarded `SwitchFormMode`; a refusal (unsaved work) keeps the live
34
+ * mode and asks for a write-back. Without one (`switcher` null), the requested
35
+ * mode is simply adopted — the input binding carries it to the host at mount.
36
+ */
37
+ export function ReconcileFormMode(params, current, switcher) {
38
+ const desired = FormModeFromQueryParams(params);
39
+ if (desired === current)
40
+ return { Mode: current, WriteBack: null };
41
+ if (!switcher)
42
+ return { Mode: desired, WriteBack: null };
43
+ return switcher.SwitchFormMode(desired)
44
+ ? { Mode: desired, WriteBack: null }
45
+ : { Mode: current, WriteBack: FormModeQueryParams(current) };
46
+ }
47
+ //# sourceMappingURL=record-form-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record-form-mode.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-form-mode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD;;;;;GAKG;AAEH,yFAAyF;AACzF,MAAM,UAAU,uBAAuB,CAAC,MAA8B;IACpE,OAAO,qBAAqB,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;AACpD,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,mBAAmB,CAAC,IAAoB;IACtD,OAAO,EAAE,CAAC,qBAAqB,CAAC,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC9E,CAAC;AAQD;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAiC,EAAE,GAAsB;IACxF,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,SAAS,GAAG,CAAC,MAA0B,EAAU,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9F,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC3G,CAAC;AAeD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAA8B,EAC9B,OAAuB,EACvB,QAAiC;IAEjC,MAAM,OAAO,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,OAAO,KAAK,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACnE,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACzD,OAAO,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC;QACrC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE;QACpC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;AACjE,CAAC","sourcesContent":["import type { EntityFormMode } from '@memberjunction/ng-base-forms';\nimport { FORM_MODE_QUERY_PARAM, ReadStandardFormQuery } from '@memberjunction/ng-shared';\nimport { UUIDsEqual } from '@memberjunction/global';\n\n/**\n * A record tab's form mode (MJ#4755) lives in its `form` query param, so the\n * URL, back/forward, re-focus and a cached component all see one value.\n * These are the decisions EntityRecordResource makes about it, kept pure so\n * the component stays a thin caller.\n */\n\n/** The form mode a tab's query params ask for: `'standard'` only for `form=standard`. */\nexport function FormModeFromQueryParams(params: Record<string, string>): EntityFormMode {\n return ReadStandardFormQuery(params) ?? 'default';\n}\n\n/** The query-param patch that records `mode` on the tab (`null` removes the param). */\nexport function FormModeQueryParams(mode: EntityFormMode): Record<string, string | null> {\n return { [FORM_MODE_QUERY_PARAM]: mode === 'standard' ? 'standard' : null };\n}\n\n/** The record a tab hosts, or that a record component was opened for. */\nexport interface RecordTabIdentity {\n Entity: string | undefined;\n RecordId: string;\n}\n\n/**\n * Whether a record component still owns its tab: the live tab hosts the same\n * record (entity compared case- and whitespace-insensitively; record id via\n * UUIDsEqual, like the tab identity guard — a save rewrites the component's id\n * in the server's casing). False for a closed tab. A cached\n * component whose tab id was reused for another record is not the owner, so\n * that tab's `form` param is not addressed to it.\n */\nexport function IsRecordTabOwner(liveTab: RecordTabIdentity | null, own: RecordTabIdentity): boolean {\n if (!liveTab) return false;\n const entityKey = (entity: string | undefined): string => (entity ?? '').trim().toLowerCase();\n return entityKey(liveTab.Entity) === entityKey(own.Entity) && UUIDsEqual(liveTab.RecordId, own.RecordId);\n}\n\n/** Whatever can switch a mounted form (SingleRecordComponent → the form host). */\nexport interface FormModeSwitcher {\n SwitchFormMode(mode: EntityFormMode): boolean;\n}\n\n/** Outcome of following a query-param change. */\nexport interface FormModeReconciliation {\n /** The mode now in effect. */\n Mode: EntityFormMode;\n /** Params to write back when the switch was refused, so the URL matches the screen; else null. */\n WriteBack: Record<string, string | null> | null;\n}\n\n/**\n * Follow the tab's query params. With a mounted form, switches through the\n * host's guarded `SwitchFormMode`; a refusal (unsaved work) keeps the live\n * mode and asks for a write-back. Without one (`switcher` null), the requested\n * mode is simply adopted — the input binding carries it to the host at mount.\n */\nexport function ReconcileFormMode(\n params: Record<string, string>,\n current: EntityFormMode,\n switcher: FormModeSwitcher | null\n): FormModeReconciliation {\n const desired = FormModeFromQueryParams(params);\n if (desired === current) return { Mode: current, WriteBack: null };\n if (!switcher) return { Mode: desired, WriteBack: null };\n return switcher.SwitchFormMode(desired)\n ? { Mode: desired, WriteBack: null }\n : { Mode: current, WriteBack: FormModeQueryParams(current) };\n}\n"]}
@@ -2,7 +2,7 @@ import { OnInit } from '@angular/core';
2
2
  import { BaseResourceComponent } from '@memberjunction/ng-shared';
3
3
  import { ResourceData } from '@memberjunction/core-entities';
4
4
  import { CompositeKey, IMetadataProvider } from '@memberjunction/core';
5
- import { type FormCompositionSnapshot } from '@memberjunction/ng-base-forms';
5
+ import { EntityFormMode, type FormCompositionSnapshot } from '@memberjunction/ng-base-forms';
6
6
  import * as i0 from "@angular/core";
7
7
  export declare class EntityRecordResource extends BaseResourceComponent implements OnInit {
8
8
  private singleRecord?;
@@ -27,11 +27,66 @@ export declare class EntityRecordResource extends BaseResourceComponent implemen
27
27
  * the surface the user sees, and returning to this tab publishes it again.
28
28
  */
29
29
  OnCompositionChanged(snapshot: FormCompositionSnapshot): void;
30
+ /** Ensure the active form's agent context is published immediately when opening AI chat. */
31
+ OnAskAIRequested(): void;
30
32
  /** Publishes the kept context while this tab is on screen and the shell's context lacks it. */
31
33
  private publishAgentContext;
32
34
  /** True while the cache has this tab attached and it is the workspace's active tab. */
33
35
  private isOnScreen;
34
36
  get PrimaryKey(): CompositeKey;
37
+ /**
38
+ * Custom vs standard form (MJ#4755). The tab's `form` query param is the
39
+ * source of truth — the URL, back/forward, tab re-focus and a cached
40
+ * component all read it — and this tracks the mode actually on screen.
41
+ */
42
+ private _formMode;
43
+ /** The mode bound to the form host: seeded from the tab's params, so a deep link mounts the standard form directly. */
44
+ get FormMode(): EntityFormMode;
45
+ set Data(value: ResourceData);
46
+ get Data(): ResourceData;
47
+ private destroyed;
48
+ ngOnDestroy(): void;
49
+ /**
50
+ * Follow the tab's `form` param — a standard-form open that dedup routed
51
+ * to this tab, a deep link, back/forward, or a plain URL clearing it.
52
+ */
53
+ protected OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void;
54
+ /**
55
+ * Re-home after a cache reattach. A reattach to a DIFFERENT tab id replays
56
+ * that tab's params in the base class. A same-id reattach does not — and
57
+ * a delivery this component skipped while its tab hosted another record
58
+ * (see {@link applyFormModeParams}) is recorded as delivered, so it would
59
+ * never come again. Re-read the live params in that case.
60
+ */
61
+ RebindTabId(tabId: string): void;
62
+ /**
63
+ * The host switched forms and told us: the strip, a programmatic
64
+ * {@link SingleRecordComponent.SwitchFormMode} (including our own, from
65
+ * {@link applyFormModeParams}), or an interactive-variant pick (back to
66
+ * default). Record it on the tab, and so the URL. For our own switch this
67
+ * runs inside a query-param delivery, where UpdateQueryParams is suppressed
68
+ * — correct, since the tab already says it, and it cannot loop.
69
+ */
70
+ OnFormModeChange(mode: EntityFormMode): void;
71
+ /**
72
+ * Reconcile the mounted form with a tab's `form` param. Ignored unless this
73
+ * component still owns its tab: a cached (detached) record stays subscribed
74
+ * to its birth tab id, which may now host another record — whose params
75
+ * would otherwise reload this form in the background or raise a spurious
76
+ * "save or discard" warning.
77
+ */
78
+ private applyFormModeParams;
79
+ /**
80
+ * The switch was refused (unsaved work; the host warned the user): put the
81
+ * URL back to what is on screen. Deferred a microtask because
82
+ * UpdateQueryParams is suppressed for the whole delivery that called us;
83
+ * re-checked then, since the component may be gone or its tab reused.
84
+ */
85
+ private writeBackRefusedMode;
86
+ /** Re-read the live tab's params and reconcile (same-id cache reattach). */
87
+ private resyncFormModeFromTab;
88
+ /** Whether the live tab still hosts this component's record. */
89
+ private ownsTab;
35
90
  static GetPrimaryKey(data: ResourceData, provider?: IMetadataProvider): CompositeKey;
36
91
  GetResourceDisplayName(data: ResourceData): Promise<string>;
37
92
  GetResourceIconClass(data: ResourceData): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"record-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAqB,MAAM,eAAe,CAAC;AAGrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAY,YAAY,EAAc,iBAAiB,EAA0B,MAAM,sBAAsB,CAAC;AAErH,OAAO,EAAgD,KAAK,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;;AAC3H,qBAOa,oBAAqB,SAAQ,qBAAsB,YAAW,MAAM;IAC3C,OAAO,CAAC,YAAY,CAAC,CAAwB;IAE/E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAE3D,kFAAkF;IAClF,OAAO,CAAC,YAAY,CAA2C;IAE/D,wGAAwG;IACxF,SAAS,IAAI,OAAO;IAIpC,uFAAuF;IAChF,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAItC,QAAQ,IAAI,IAAI;IAahC;;;;;;;;;;;OAWG;IACI,oBAAoB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAKpE,+FAA+F;IAC/F,OAAO,CAAC,mBAAmB;IAO3B,uFAAuF;IACvF,OAAO,CAAC,UAAU;IAMlB,IAAW,UAAU,IAAI,YAAY,CAEpC;WAEa,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,YAAY;IA4BrF,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA2B3D,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;yCA1HtD,oBAAoB;2CAApB,oBAAoB;CAuIhC"}
1
+ {"version":3,"file":"record-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,MAAM,EAAqB,MAAM,eAAe,CAAC;AAGrE,OAAO,EAAE,qBAAqB,EAAkC,MAAM,2BAA2B,CAAC;AAElG,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAY,YAAY,EAAc,iBAAiB,EAAoC,MAAM,sBAAsB,CAAC;AAG/H,OAAO,EAAyB,cAAc,EAAyB,KAAK,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;;AAC3I,qBAOa,oBAAqB,SAAQ,qBAAsB,YAAW,MAAM;IAC3C,OAAO,CAAC,YAAY,CAAC,CAAwB;IAE/E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiC;IAE3D,kFAAkF;IAClF,OAAO,CAAC,YAAY,CAA2C;IAE/D,wGAAwG;IACxF,SAAS,IAAI,OAAO;IAIpC,uFAAuF;IAChF,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAItC,QAAQ,IAAI,IAAI;IAahC;;;;;;;;;;;OAWG;IACI,oBAAoB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAKpE,4FAA4F;IACrF,gBAAgB,IAAI,IAAI;IAI/B,+FAA+F;IAC/F,OAAO,CAAC,mBAAmB;IAO3B,uFAAuF;IACvF,OAAO,CAAC,UAAU;IAMlB,IAAW,UAAU,IAAI,YAAY,CAEpC;IAED;;;;OAIG;IACH,OAAO,CAAC,SAAS,CAA6B;IAE9C,uHAAuH;IACvH,IAAW,QAAQ,IAAI,cAAc,CAEpC;IAED,IAAoB,IAAI,CAAC,KAAK,EAAE,YAAY,EAQ3C;IACD,IAAoB,IAAI,IAAI,YAAY,CAEvC;IAED,OAAO,CAAC,SAAS,CAAS;IAEV,WAAW,IAAI,IAAI;IAKnC;;;OAGG;cACgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI;IAI/G;;;;;;OAMG;IACa,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQhD;;;;;;;OAOG;IACI,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAKnD;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB;IAS3B;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;IAY5B,4EAA4E;IAC5E,OAAO,CAAC,qBAAqB;IAS7B,gEAAgE;IAChE,OAAO,CAAC,OAAO;WASD,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,YAAY;IA4BrF,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IA2B3D,oBAAoB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;yCAzPtD,oBAAoB;2CAApB,oBAAoB;CAsQhC"}
@@ -7,11 +7,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var EntityRecordResource_1;
8
8
  import { Component, ViewChild, inject } from '@angular/core';
9
9
  import { asapScheduler, merge } from 'rxjs';
10
- import { filter, observeOn, takeUntil } from 'rxjs/operators';
11
- import { BaseResourceComponent } from '@memberjunction/ng-shared';
10
+ import { filter, observeOn, take, takeUntil } from 'rxjs/operators';
11
+ import { BaseResourceComponent, FormatEntityRecordDisplayTitle } from '@memberjunction/ng-shared';
12
12
  import { WorkspaceStateManager } from '@memberjunction/ng-base-application';
13
13
  import { RegisterClass } from '@memberjunction/global';
14
- import { Metadata, CompositeKey, IsNewEntityRecordUrlId } from '@memberjunction/core';
14
+ import { Metadata, CompositeKey, IsNewEntityRecordUrlId, LogError } from '@memberjunction/core';
15
+ import { FormModeFromQueryParams, FormModeQueryParams, IsRecordTabOwner, ReconcileFormMode } from './record-form-mode';
15
16
  import { SingleRecordComponent } from '../single-record/single-record.component';
16
17
  import { BuildFormAgentContext } from '@memberjunction/ng-base-forms';
17
18
  import * as i0 from "@angular/core";
@@ -55,6 +56,10 @@ let EntityRecordResource = class EntityRecordResource extends BaseResourceCompon
55
56
  this.agentContext = { Form: BuildFormAgentContext(snapshot) };
56
57
  this.publishAgentContext();
57
58
  }
59
+ /** Ensure the active form's agent context is published immediately when opening AI chat. */
60
+ OnAskAIRequested() {
61
+ this.publishAgentContext();
62
+ }
58
63
  /** Publishes the kept context while this tab is on screen and the shell's context lacks it. */
59
64
  publishAgentContext() {
60
65
  const context = this.agentContext;
@@ -74,6 +79,116 @@ let EntityRecordResource = class EntityRecordResource extends BaseResourceCompon
74
79
  get PrimaryKey() {
75
80
  return EntityRecordResource_1.GetPrimaryKey(this.Data, this.ProviderToUse);
76
81
  }
82
+ /**
83
+ * Custom vs standard form (MJ#4755). The tab's `form` query param is the
84
+ * source of truth — the URL, back/forward, tab re-focus and a cached
85
+ * component all read it — and this tracks the mode actually on screen.
86
+ */
87
+ _formMode = 'default';
88
+ /** The mode bound to the form host: seeded from the tab's params, so a deep link mounts the standard form directly. */
89
+ get FormMode() {
90
+ return this._formMode;
91
+ }
92
+ set Data(value) {
93
+ super.Data = value;
94
+ // Seed only before the form mounts: afterwards a changed input would
95
+ // remount the host WITHOUT its unsaved-work guard. Later changes arrive
96
+ // through OnQueryParamsChanged instead.
97
+ if (!this.singleRecord) {
98
+ this._formMode = FormModeFromQueryParams(this.GetQueryParams());
99
+ }
100
+ }
101
+ get Data() {
102
+ return super.Data;
103
+ }
104
+ destroyed = false;
105
+ ngOnDestroy() {
106
+ this.destroyed = true;
107
+ super.ngOnDestroy();
108
+ }
109
+ /**
110
+ * Follow the tab's `form` param — a standard-form open that dedup routed
111
+ * to this tab, a deep link, back/forward, or a plain URL clearing it.
112
+ */
113
+ OnQueryParamsChanged(params, _source) {
114
+ this.applyFormModeParams(params);
115
+ }
116
+ /**
117
+ * Re-home after a cache reattach. A reattach to a DIFFERENT tab id replays
118
+ * that tab's params in the base class. A same-id reattach does not — and
119
+ * a delivery this component skipped while its tab hosted another record
120
+ * (see {@link applyFormModeParams}) is recorded as delivered, so it would
121
+ * never come again. Re-read the live params in that case.
122
+ */
123
+ RebindTabId(tabId) {
124
+ const sameTab = this.getTabId() === tabId;
125
+ super.RebindTabId(tabId);
126
+ if (sameTab) {
127
+ this.resyncFormModeFromTab();
128
+ }
129
+ }
130
+ /**
131
+ * The host switched forms and told us: the strip, a programmatic
132
+ * {@link SingleRecordComponent.SwitchFormMode} (including our own, from
133
+ * {@link applyFormModeParams}), or an interactive-variant pick (back to
134
+ * default). Record it on the tab, and so the URL. For our own switch this
135
+ * runs inside a query-param delivery, where UpdateQueryParams is suppressed
136
+ * — correct, since the tab already says it, and it cannot loop.
137
+ */
138
+ OnFormModeChange(mode) {
139
+ this._formMode = mode;
140
+ this.UpdateQueryParams(FormModeQueryParams(mode));
141
+ }
142
+ /**
143
+ * Reconcile the mounted form with a tab's `form` param. Ignored unless this
144
+ * component still owns its tab: a cached (detached) record stays subscribed
145
+ * to its birth tab id, which may now host another record — whose params
146
+ * would otherwise reload this form in the background or raise a spurious
147
+ * "save or discard" warning.
148
+ */
149
+ applyFormModeParams(params) {
150
+ if (!this.ownsTab())
151
+ return;
152
+ const result = ReconcileFormMode(params, this._formMode, this.singleRecord ?? null);
153
+ this._formMode = result.Mode;
154
+ if (result.WriteBack) {
155
+ this.writeBackRefusedMode(result.WriteBack);
156
+ }
157
+ }
158
+ /**
159
+ * The switch was refused (unsaved work; the host warned the user): put the
160
+ * URL back to what is on screen. Deferred a microtask because
161
+ * UpdateQueryParams is suppressed for the whole delivery that called us;
162
+ * re-checked then, since the component may be gone or its tab reused.
163
+ */
164
+ writeBackRefusedMode(writeBack) {
165
+ Promise.resolve()
166
+ .then(() => {
167
+ if (!this.destroyed && this.ownsTab()) {
168
+ this.UpdateQueryParams(writeBack);
169
+ }
170
+ })
171
+ .catch((err) => {
172
+ LogError(`EntityRecordResource: could not restore the form-mode query param for "${this.Data?.Configuration?.Entity}" (tab ${this.getTabId()}): ${err instanceof Error ? err.message : String(err)}`);
173
+ });
174
+ }
175
+ /** Re-read the live tab's params and reconcile (same-id cache reattach). */
176
+ resyncFormModeFromTab() {
177
+ const tabId = this.getTabId();
178
+ if (!tabId)
179
+ return;
180
+ // The workspace stream replays its current value on subscribe, so take(1) is a synchronous read.
181
+ this.navigationService.ObserveTabQueryParams(tabId)
182
+ .pipe(take(1))
183
+ .subscribe(params => this.applyFormModeParams(params));
184
+ }
185
+ /** Whether the live tab still hosts this component's record. */
186
+ ownsTab() {
187
+ const tabId = this.getTabId();
188
+ if (!tabId)
189
+ return false;
190
+ return IsRecordTabOwner(this.navigationService.GetTabRecordIdentity(tabId), { Entity: this.Data?.Configuration?.Entity, RecordId: this.Data?.ResourceRecordID || this.Data?.Configuration?.recordId || '' });
191
+ }
77
192
  static GetPrimaryKey(data, provider) {
78
193
  // global-provider-ok: static helper has no component instance scope; falls back to default provider
79
194
  const md = (provider ?? Metadata.Provider);
@@ -116,7 +231,7 @@ let EntityRecordResource = class EntityRecordResource extends BaseResourceCompon
116
231
  const pk = EntityRecordResource_1.GetPrimaryKey(data, this.ProviderToUse);
117
232
  if (pk.HasValue) {
118
233
  const name = await md.GetEntityRecordName(data.Configuration.Entity, pk);
119
- return name ? name : e.DisplayNameOrName;
234
+ return FormatEntityRecordDisplayTitle(e, data.Configuration.Entity, pk, name);
120
235
  }
121
236
  else {
122
237
  return `New ${e.DisplayNameOrName} Record`;
@@ -141,12 +256,12 @@ let EntityRecordResource = class EntityRecordResource extends BaseResourceCompon
141
256
  } if (rf & 2) {
142
257
  let _t;
143
258
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.singleRecord = _t.first);
144
- } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 3, consts: [[3, "loadComplete", "recordSaved", "recordDismissed", "EditModeChanged", "CompositionChanged", "PrimaryKey", "entityName", "newRecordValues"]], template: function EntityRecordResource_Template(rf, ctx) { if (rf & 1) {
259
+ } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 4, consts: [[3, "FormModeChange", "loadComplete", "recordSaved", "recordDismissed", "EditModeChanged", "CompositionChanged", "AskAIRequested", "PrimaryKey", "entityName", "newRecordValues", "FormMode"]], template: function EntityRecordResource_Template(rf, ctx) { if (rf & 1) {
145
260
  i0.ɵɵelementStart(0, "mj-single-record", 0);
146
- i0.ɵɵlistener("loadComplete", function EntityRecordResource_Template_mj_single_record_loadComplete_0_listener() { return ctx.NotifyLoadComplete(); })("recordSaved", function EntityRecordResource_Template_mj_single_record_recordSaved_0_listener($event) { return ctx.ResourceRecordSaved($event); })("recordDismissed", function EntityRecordResource_Template_mj_single_record_recordDismissed_0_listener() { return ctx.NotifyCloseRequested(); })("EditModeChanged", function EntityRecordResource_Template_mj_single_record_EditModeChanged_0_listener($event) { return ctx.ResourceEditModeChanged($event); })("CompositionChanged", function EntityRecordResource_Template_mj_single_record_CompositionChanged_0_listener($event) { return ctx.OnCompositionChanged($event); });
261
+ i0.ɵɵlistener("FormModeChange", function EntityRecordResource_Template_mj_single_record_FormModeChange_0_listener($event) { return ctx.OnFormModeChange($event); })("loadComplete", function EntityRecordResource_Template_mj_single_record_loadComplete_0_listener() { return ctx.NotifyLoadComplete(); })("recordSaved", function EntityRecordResource_Template_mj_single_record_recordSaved_0_listener($event) { return ctx.ResourceRecordSaved($event); })("recordDismissed", function EntityRecordResource_Template_mj_single_record_recordDismissed_0_listener() { return ctx.NotifyCloseRequested(); })("EditModeChanged", function EntityRecordResource_Template_mj_single_record_EditModeChanged_0_listener($event) { return ctx.ResourceEditModeChanged($event); })("CompositionChanged", function EntityRecordResource_Template_mj_single_record_CompositionChanged_0_listener($event) { return ctx.OnCompositionChanged($event); })("AskAIRequested", function EntityRecordResource_Template_mj_single_record_AskAIRequested_0_listener() { return ctx.OnAskAIRequested(); });
147
262
  i0.ɵɵelementEnd();
148
263
  } if (rf & 2) {
149
- i0.ɵɵproperty("PrimaryKey", ctx.PrimaryKey)("entityName", ctx.Data.Configuration.Entity)("newRecordValues", ctx.Data.Configuration.NewRecordValues);
264
+ i0.ɵɵproperty("PrimaryKey", ctx.PrimaryKey)("entityName", ctx.Data.Configuration.Entity)("newRecordValues", ctx.Data.Configuration.NewRecordValues)("FormMode", ctx.FormMode);
150
265
  } }, dependencies: [i1.SingleRecordComponent], styles: ["[_nghost-%COMP%] { display: block; height: 100%; width: 100%; }"] });
151
266
  };
152
267
  EntityRecordResource = EntityRecordResource_1 = __decorate([
@@ -155,10 +270,10 @@ EntityRecordResource = EntityRecordResource_1 = __decorate([
155
270
  export { EntityRecordResource };
156
271
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityRecordResource, [{
157
272
  type: Component,
158
- args: [{ standalone: false, selector: 'mj-record-resource', template: `<mj-single-record [PrimaryKey]="this.PrimaryKey" [entityName]="Data.Configuration.Entity" [newRecordValues]="Data.Configuration.NewRecordValues" (loadComplete)="NotifyLoadComplete()" (recordSaved)="ResourceRecordSaved($event)" (recordDismissed)="NotifyCloseRequested()" (EditModeChanged)="ResourceEditModeChanged($event)" (CompositionChanged)="OnCompositionChanged($event)"></mj-single-record>`, styles: [":host { display: block; height: 100%; width: 100%; }"] }]
273
+ args: [{ standalone: false, selector: 'mj-record-resource', template: `<mj-single-record [PrimaryKey]="this.PrimaryKey" [entityName]="Data.Configuration.Entity" [newRecordValues]="Data.Configuration.NewRecordValues" [FormMode]="FormMode" (FormModeChange)="OnFormModeChange($event)" (loadComplete)="NotifyLoadComplete()" (recordSaved)="ResourceRecordSaved($event)" (recordDismissed)="NotifyCloseRequested()" (EditModeChanged)="ResourceEditModeChanged($event)" (CompositionChanged)="OnCompositionChanged($event)" (AskAIRequested)="OnAskAIRequested()"></mj-single-record>`, styles: [":host { display: block; height: 100%; width: 100%; }"] }]
159
274
  }], null, { singleRecord: [{
160
275
  type: ViewChild,
161
276
  args: [SingleRecordComponent]
162
277
  }] }); })();
163
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityRecordResource, { className: "EntityRecordResource", filePath: "src/lib/resource-wrappers/record-resource.component.ts", lineNumber: 18 }); })();
278
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EntityRecordResource, { className: "EntityRecordResource", filePath: "src/lib/resource-wrappers/record-resource.component.ts", lineNumber: 19 }); })();
164
279
  //# sourceMappingURL=record-resource.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"record-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ViewChild, inject } from '@angular/core';\nimport { asapScheduler, merge } from 'rxjs';\nimport { filter, observeOn, takeUntil } from 'rxjs/operators';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { WorkspaceStateManager } from '@memberjunction/ng-base-application';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { Metadata, CompositeKey, EntityInfo, IMetadataProvider, IsNewEntityRecordUrlId } from '@memberjunction/core';\nimport { SingleRecordComponent } from '../single-record/single-record.component';\nimport { BuildFormAgentContext, type FormAgentContext, type FormCompositionSnapshot } from '@memberjunction/ng-base-forms';\n@RegisterClass(BaseResourceComponent, 'RecordResource')\n@Component({\n standalone: false,\n selector: 'mj-record-resource',\n styles: [`:host { display: block; height: 100%; width: 100%; }`],\n template: `<mj-single-record [PrimaryKey]=\"this.PrimaryKey\" [entityName]=\"Data.Configuration.Entity\" [newRecordValues]=\"Data.Configuration.NewRecordValues\" (loadComplete)=\"NotifyLoadComplete()\" (recordSaved)=\"ResourceRecordSaved($event)\" (recordDismissed)=\"NotifyCloseRequested()\" (EditModeChanged)=\"ResourceEditModeChanged($event)\" (CompositionChanged)=\"OnCompositionChanged($event)\"></mj-single-record>`\n})\nexport class EntityRecordResource extends BaseResourceComponent implements OnInit {\n @ViewChild(SingleRecordComponent) private singleRecord?: SingleRecordComponent;\n\n private readonly workspace = inject(WorkspaceStateManager);\n\n /** The form context this tab last reported, kept so it can be published again. */\n private agentContext: { Form: FormAgentContext } | null = null;\n\n /** Fallback read for the pool predicate; promotion via ResourceEditModeChanged is the primary guard. */\n public override IsEditing(): boolean {\n return this.singleRecord?.IsEditing() === true;\n }\n\n /** The hosted form entered or left edit mode; the shell promotes the tab on `true`. */\n public ResourceEditModeChanged(editing: boolean): void {\n this.NotifyEditModeChanged(editing);\n }\n\n public override ngOnInit(): void {\n super.ngOnInit();\n // Publish the kept context again when the shell's app context lacks it, or when the cache\n // reattaches this tab. Deferred, so a publish never runs inside another subscriber's\n // AppContextSnapshot$ delivery.\n merge(\n this.navigationService.AppContextSnapshot$,\n this.navigationService.ResourceReattached$.pipe(filter((resource) => resource === this)),\n )\n .pipe(observeOn(asapScheduler), takeUntil(this.destroy$))\n .subscribe(() => this.publishAgentContext());\n }\n\n /**\n * Report the form to the agent context, so an agent asked to build a panel for this record\n * knows what the form shows. The agent gets the compact form ({@link BuildFormAgentContext}):\n * entity, record, which form, and the sections. The full snapshot stays in the browser, in\n * the `FormCompositionRegistry` the apply flow reads.\n *\n * The shell folds this into `AppContextSnapshot.AdditionalContext` and assigns that wholesale,\n * so the last publisher wins app-wide, and it rebuilds the app context without it on every tab\n * switch. So the context is kept here and published only while this tab is the one on screen\n * (attached and the active tab): a background tab's late resolve cannot replace the context of\n * the surface the user sees, and returning to this tab publishes it again.\n */\n public OnCompositionChanged(snapshot: FormCompositionSnapshot): void {\n this.agentContext = { Form: BuildFormAgentContext(snapshot) };\n this.publishAgentContext();\n }\n\n /** Publishes the kept context while this tab is on screen and the shell's context lacks it. */\n private publishAgentContext(): void {\n const context = this.agentContext;\n if (!context || !this.isOnScreen()) return;\n if (this.navigationService.AppContextSnapshot$.value?.AdditionalContext === context) return;\n this.navigationService.SetAgentContext(this, context);\n }\n\n /** True while the cache has this tab attached and it is the workspace's active tab. */\n private isOnScreen(): boolean {\n if (this.navigationService.IsResourceDetached(this)) return false;\n const tabId = this.getTabId();\n return !!tabId && this.workspace.GetActiveTabId() === tabId;\n }\n\n public get PrimaryKey(): CompositeKey {\n return EntityRecordResource.GetPrimaryKey(this.Data, this.ProviderToUse);\n }\n\n public static GetPrimaryKey(data: ResourceData, provider?: IMetadataProvider): CompositeKey {\n // global-provider-ok: static helper has no component instance scope; falls back to default provider\n const md = (provider ?? Metadata.Provider) as IMetadataProvider;\n const requested = (data.Configuration.Entity ?? '').trim();\n // Prefer EntityByName (project rule: never use Entities.find for\n // single-entity lookups — case/whitespace tolerant + O(1) map). Fall\n // back to DisplayName match for callers (AI agents, hand-typed URLs,\n // external CTAs) that pass the human-readable display name instead\n // of the canonical Name (e.g. \"Users\" for \"MJ: Users\").\n let e: EntityInfo | undefined = md.EntityByName(requested);\n if (!e) {\n const lowered = requested.toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e){\n throw new Error(`Entity ${data.Configuration.Entity} not found in metadata (tried Name and DisplayName)`);\n }\n\n if (IsNewEntityRecordUrlId(data.ResourceRecordID)) {\n return new CompositeKey();\n }\n\n let compositeKey: CompositeKey = new CompositeKey();\n compositeKey.LoadFromURLSegment(e, data.ResourceRecordID);\n return compositeKey;\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity) {\n return '';\n }\n\n const md = this.ProviderToUse;\n let e = md.EntityByName(data.Configuration.Entity);\n if (!e) {\n // Same DisplayName fallback as GetPrimaryKey — keeps the\n // breadcrumb/title in sync when a CTA used the display name.\n const lowered = (data.Configuration.Entity ?? '').trim().toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e) {\n return '';\n }\n\n const pk: CompositeKey = EntityRecordResource.GetPrimaryKey(data, this.ProviderToUse);\n if (pk.HasValue) {\n const name = await md.GetEntityRecordName(data.Configuration.Entity, pk);\n return name ? name : e.DisplayNameOrName;\n } else {\n return `New ${e.DisplayNameOrName} Record`;\n }\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity){\n return ''\n }\n else {\n const md = this.ProviderToUse;\n const e = md.Entities.find(e => e.Name.trim().toLowerCase() === data.Configuration.Entity.trim().toLowerCase());\n if (e)\n return e?.Icon;\n else\n return '';\n }\n }\n}\n"]}
1
+ {"version":3,"file":"record-resource.component.js","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/record-resource.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ViewChild, inject } from '@angular/core';\nimport { asapScheduler, merge } from 'rxjs';\nimport { filter, observeOn, take, takeUntil } from 'rxjs/operators';\nimport { BaseResourceComponent, FormatEntityRecordDisplayTitle } from '@memberjunction/ng-shared';\nimport { WorkspaceStateManager } from '@memberjunction/ng-base-application';\nimport { ResourceData } from '@memberjunction/core-entities';\nimport { RegisterClass } from '@memberjunction/global';\nimport { Metadata, CompositeKey, EntityInfo, IMetadataProvider, IsNewEntityRecordUrlId, LogError } from '@memberjunction/core';\nimport { FormModeFromQueryParams, FormModeQueryParams, IsRecordTabOwner, ReconcileFormMode } from './record-form-mode';\nimport { SingleRecordComponent } from '../single-record/single-record.component';\nimport { BuildFormAgentContext, EntityFormMode, type FormAgentContext, type FormCompositionSnapshot } from '@memberjunction/ng-base-forms';\n@RegisterClass(BaseResourceComponent, 'RecordResource')\n@Component({\n standalone: false,\n selector: 'mj-record-resource',\n styles: [`:host { display: block; height: 100%; width: 100%; }`],\n template: `<mj-single-record [PrimaryKey]=\"this.PrimaryKey\" [entityName]=\"Data.Configuration.Entity\" [newRecordValues]=\"Data.Configuration.NewRecordValues\" [FormMode]=\"FormMode\" (FormModeChange)=\"OnFormModeChange($event)\" (loadComplete)=\"NotifyLoadComplete()\" (recordSaved)=\"ResourceRecordSaved($event)\" (recordDismissed)=\"NotifyCloseRequested()\" (EditModeChanged)=\"ResourceEditModeChanged($event)\" (CompositionChanged)=\"OnCompositionChanged($event)\" (AskAIRequested)=\"OnAskAIRequested()\"></mj-single-record>`\n})\nexport class EntityRecordResource extends BaseResourceComponent implements OnInit {\n @ViewChild(SingleRecordComponent) private singleRecord?: SingleRecordComponent;\n\n private readonly workspace = inject(WorkspaceStateManager);\n\n /** The form context this tab last reported, kept so it can be published again. */\n private agentContext: { Form: FormAgentContext } | null = null;\n\n /** Fallback read for the pool predicate; promotion via ResourceEditModeChanged is the primary guard. */\n public override IsEditing(): boolean {\n return this.singleRecord?.IsEditing() === true;\n }\n\n /** The hosted form entered or left edit mode; the shell promotes the tab on `true`. */\n public ResourceEditModeChanged(editing: boolean): void {\n this.NotifyEditModeChanged(editing);\n }\n\n public override ngOnInit(): void {\n super.ngOnInit();\n // Publish the kept context again when the shell's app context lacks it, or when the cache\n // reattaches this tab. Deferred, so a publish never runs inside another subscriber's\n // AppContextSnapshot$ delivery.\n merge(\n this.navigationService.AppContextSnapshot$,\n this.navigationService.ResourceReattached$.pipe(filter((resource) => resource === this)),\n )\n .pipe(observeOn(asapScheduler), takeUntil(this.destroy$))\n .subscribe(() => this.publishAgentContext());\n }\n\n /**\n * Report the form to the agent context, so an agent asked to build a panel for this record\n * knows what the form shows. The agent gets the compact form ({@link BuildFormAgentContext}):\n * entity, record, which form, and the sections. The full snapshot stays in the browser, in\n * the `FormCompositionRegistry` the apply flow reads.\n *\n * The shell folds this into `AppContextSnapshot.AdditionalContext` and assigns that wholesale,\n * so the last publisher wins app-wide, and it rebuilds the app context without it on every tab\n * switch. So the context is kept here and published only while this tab is the one on screen\n * (attached and the active tab): a background tab's late resolve cannot replace the context of\n * the surface the user sees, and returning to this tab publishes it again.\n */\n public OnCompositionChanged(snapshot: FormCompositionSnapshot): void {\n this.agentContext = { Form: BuildFormAgentContext(snapshot) };\n this.publishAgentContext();\n }\n\n /** Ensure the active form's agent context is published immediately when opening AI chat. */\n public OnAskAIRequested(): void {\n this.publishAgentContext();\n }\n\n /** Publishes the kept context while this tab is on screen and the shell's context lacks it. */\n private publishAgentContext(): void {\n const context = this.agentContext;\n if (!context || !this.isOnScreen()) return;\n if (this.navigationService.AppContextSnapshot$.value?.AdditionalContext === context) return;\n this.navigationService.SetAgentContext(this, context);\n }\n\n /** True while the cache has this tab attached and it is the workspace's active tab. */\n private isOnScreen(): boolean {\n if (this.navigationService.IsResourceDetached(this)) return false;\n const tabId = this.getTabId();\n return !!tabId && this.workspace.GetActiveTabId() === tabId;\n }\n\n public get PrimaryKey(): CompositeKey {\n return EntityRecordResource.GetPrimaryKey(this.Data, this.ProviderToUse);\n }\n\n /**\n * Custom vs standard form (MJ#4755). The tab's `form` query param is the\n * source of truth — the URL, back/forward, tab re-focus and a cached\n * component all read it — and this tracks the mode actually on screen.\n */\n private _formMode: EntityFormMode = 'default';\n\n /** The mode bound to the form host: seeded from the tab's params, so a deep link mounts the standard form directly. */\n public get FormMode(): EntityFormMode {\n return this._formMode;\n }\n\n public override set Data(value: ResourceData) {\n super.Data = value;\n // Seed only before the form mounts: afterwards a changed input would\n // remount the host WITHOUT its unsaved-work guard. Later changes arrive\n // through OnQueryParamsChanged instead.\n if (!this.singleRecord) {\n this._formMode = FormModeFromQueryParams(this.GetQueryParams());\n }\n }\n public override get Data(): ResourceData {\n return super.Data;\n }\n\n private destroyed = false;\n\n public override ngOnDestroy(): void {\n this.destroyed = true;\n super.ngOnDestroy();\n }\n\n /**\n * Follow the tab's `form` param — a standard-form open that dedup routed\n * to this tab, a deep link, back/forward, or a plain URL clearing it.\n */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n this.applyFormModeParams(params);\n }\n\n /**\n * Re-home after a cache reattach. A reattach to a DIFFERENT tab id replays\n * that tab's params in the base class. A same-id reattach does not — and\n * a delivery this component skipped while its tab hosted another record\n * (see {@link applyFormModeParams}) is recorded as delivered, so it would\n * never come again. Re-read the live params in that case.\n */\n public override RebindTabId(tabId: string): void {\n const sameTab = this.getTabId() === tabId;\n super.RebindTabId(tabId);\n if (sameTab) {\n this.resyncFormModeFromTab();\n }\n }\n\n /**\n * The host switched forms and told us: the strip, a programmatic\n * {@link SingleRecordComponent.SwitchFormMode} (including our own, from\n * {@link applyFormModeParams}), or an interactive-variant pick (back to\n * default). Record it on the tab, and so the URL. For our own switch this\n * runs inside a query-param delivery, where UpdateQueryParams is suppressed\n * — correct, since the tab already says it, and it cannot loop.\n */\n public OnFormModeChange(mode: EntityFormMode): void {\n this._formMode = mode;\n this.UpdateQueryParams(FormModeQueryParams(mode));\n }\n\n /**\n * Reconcile the mounted form with a tab's `form` param. Ignored unless this\n * component still owns its tab: a cached (detached) record stays subscribed\n * to its birth tab id, which may now host another record — whose params\n * would otherwise reload this form in the background or raise a spurious\n * \"save or discard\" warning.\n */\n private applyFormModeParams(params: Record<string, string>): void {\n if (!this.ownsTab()) return;\n const result = ReconcileFormMode(params, this._formMode, this.singleRecord ?? null);\n this._formMode = result.Mode;\n if (result.WriteBack) {\n this.writeBackRefusedMode(result.WriteBack);\n }\n }\n\n /**\n * The switch was refused (unsaved work; the host warned the user): put the\n * URL back to what is on screen. Deferred a microtask because\n * UpdateQueryParams is suppressed for the whole delivery that called us;\n * re-checked then, since the component may be gone or its tab reused.\n */\n private writeBackRefusedMode(writeBack: Record<string, string | null>): void {\n Promise.resolve()\n .then(() => {\n if (!this.destroyed && this.ownsTab()) {\n this.UpdateQueryParams(writeBack);\n }\n })\n .catch((err: unknown) => {\n LogError(`EntityRecordResource: could not restore the form-mode query param for \"${this.Data?.Configuration?.Entity}\" (tab ${this.getTabId()}): ${err instanceof Error ? err.message : String(err)}`);\n });\n }\n\n /** Re-read the live tab's params and reconcile (same-id cache reattach). */\n private resyncFormModeFromTab(): void {\n const tabId = this.getTabId();\n if (!tabId) return;\n // The workspace stream replays its current value on subscribe, so take(1) is a synchronous read.\n this.navigationService.ObserveTabQueryParams(tabId)\n .pipe(take(1))\n .subscribe(params => this.applyFormModeParams(params));\n }\n\n /** Whether the live tab still hosts this component's record. */\n private ownsTab(): boolean {\n const tabId = this.getTabId();\n if (!tabId) return false;\n return IsRecordTabOwner(\n this.navigationService.GetTabRecordIdentity(tabId),\n { Entity: this.Data?.Configuration?.Entity, RecordId: this.Data?.ResourceRecordID || this.Data?.Configuration?.recordId || '' }\n );\n }\n\n public static GetPrimaryKey(data: ResourceData, provider?: IMetadataProvider): CompositeKey {\n // global-provider-ok: static helper has no component instance scope; falls back to default provider\n const md = (provider ?? Metadata.Provider) as IMetadataProvider;\n const requested = (data.Configuration.Entity ?? '').trim();\n // Prefer EntityByName (project rule: never use Entities.find for\n // single-entity lookups — case/whitespace tolerant + O(1) map). Fall\n // back to DisplayName match for callers (AI agents, hand-typed URLs,\n // external CTAs) that pass the human-readable display name instead\n // of the canonical Name (e.g. \"Users\" for \"MJ: Users\").\n let e: EntityInfo | undefined = md.EntityByName(requested);\n if (!e) {\n const lowered = requested.toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e){\n throw new Error(`Entity ${data.Configuration.Entity} not found in metadata (tried Name and DisplayName)`);\n }\n\n if (IsNewEntityRecordUrlId(data.ResourceRecordID)) {\n return new CompositeKey();\n }\n\n let compositeKey: CompositeKey = new CompositeKey();\n compositeKey.LoadFromURLSegment(e, data.ResourceRecordID);\n return compositeKey;\n }\n\n async GetResourceDisplayName(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity) {\n return '';\n }\n\n const md = this.ProviderToUse;\n let e = md.EntityByName(data.Configuration.Entity);\n if (!e) {\n // Same DisplayName fallback as GetPrimaryKey — keeps the\n // breadcrumb/title in sync when a CTA used the display name.\n const lowered = (data.Configuration.Entity ?? '').trim().toLowerCase();\n e = md.Entities.find((x: EntityInfo) =>\n (x.DisplayName ?? '').trim().toLowerCase() === lowered);\n }\n if (!e) {\n return '';\n }\n\n const pk: CompositeKey = EntityRecordResource.GetPrimaryKey(data, this.ProviderToUse);\n if (pk.HasValue) {\n const name = await md.GetEntityRecordName(data.Configuration.Entity, pk);\n return FormatEntityRecordDisplayTitle(e, data.Configuration.Entity, pk, name);\n } else {\n return `New ${e.DisplayNameOrName} Record`;\n }\n }\n\n async GetResourceIconClass(data: ResourceData): Promise<string> {\n if (!data.Configuration.Entity){\n return ''\n }\n else {\n const md = this.ProviderToUse;\n const e = md.Entities.find(e => e.Name.trim().toLowerCase() === data.Configuration.Entity.trim().toLowerCase());\n if (e)\n return e?.Icon;\n else\n return '';\n }\n }\n}\n"]}
@@ -80,9 +80,9 @@ export declare class SearchResultsResource extends BaseResourceComponent {
80
80
  private navigateToResult;
81
81
  private executeSearch;
82
82
  /**
83
- * Phase 2C streaming variant. Subscribes to `streamScopedSearch` and progressively
84
- * populates the result list as each provider reports back. The 'final' event carries
85
- * the canonical fused/reranked list, which replaces any partials the user already saw.
83
+ * Phase 2C streaming variant. Subscribes to `streamScopedSearch`, shows each provider's
84
+ * count in the chip strip as it reports back, and renders the result list from the 'final'
85
+ * event. A 'provider' event carries no rows: they arrive before the server's permission pass.
86
86
  *
87
87
  * Cancellation: a new query starts by tearing down the in-flight stream so events
88
88
  * from a stale search do not bleed into the current view.
@@ -1 +1 @@
1
- {"version":3,"file":"search-results-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/search-results-resource.component.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAqB,MAAM,2BAA2B,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAG7D,OAAO,EAEH,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EAGvB,yBAAyB,EACzB,uBAAuB,EAE1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;;AAElF,qBAgXa,qBAAsB,SAAQ,qBAAqB;IAC5D,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,eAAe,CAA2B;IAElD,YAAY,SAAM;IAClB,WAAW,UAAS;IACpB,WAAW,UAAS;IACpB,UAAU,SAAK;IACf,SAAS,SAAK;IACd,OAAO,EAAE,YAAY,EAAE,CAAM;IAC7B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAM;IAC7C,eAAe,EAAE,gBAAgB,EAAE,CAAM;IACzC,eAAe,SAAM;IACrB;iFAC6E;IAC7E,qBAAqB,SAAM;IAE3B,qDAAqD;IACrD,IAAI,qBAAqB,WAExB;IACD,qDAAqD;IACrD,IAAI,qBAAqB,CAAC,KAAK,QAAA,EAE9B;IACD,0EAA0E;IAC1E,iBAAiB,SAAK;IACtB,eAAe,UAAQ;IACvB,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAW;IAClD,gBAAgB,SAAM;IACtB,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAU;IACpC,UAAU,EAAE,aAAa,EAAE,CAAM;IACjC,cAAc,UAAS;IAEvB,sEAAsE;IACtE,OAAO,CAAC,UAAU,CAA0B;IAE5C,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAgB;IAEhC;;;;;OAKG;IACH,eAAe,UAAS;IAExB,sFAAsF;IACtF,kBAAkB,EAAE,uBAAuB,EAAE,CAAM;IAEnD,8EAA8E;IAC9E,OAAO,CAAC,aAAa,CAA6B;IAElD,OAAO,CAAC,UAAU,CAAS;IAI3B,IAAa,IAAI,CAAC,KAAK,EAAE,YAAY,EAMpC;IACD,IAAa,IAAI,IAAI,YAAY,CAEhC;YAEa,YAAY;IAsDjB,WAAW,IAAI,IAAI;IAMtB,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAK3D,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1D,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASlD,eAAe,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI;IAQrD,gBAAgB,IAAI,IAAI;IAOxB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAYxC;;;;OAIG;cACgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI;IAe/G,gBAAgB,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI;IAIxD,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAItC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAShC,iBAAiB,IAAI,IAAI;IAazB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKjC,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAK5C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IASzC,gBAAgB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAKlD;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;YAoBV,aAAa;IAqC3B;;;;;;;OAOG;IACH,OAAO,CAAC,sBAAsB;IA6D9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAkD1B,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,oBAAoB;IA4B5B;;;OAGG;IACH;;;;OAIG;YACW,eAAe;IAsE7B,kDAAkD;IAClD,OAAO,CAAC,gBAAgB;IAwBxB,uEAAuE;IACvE,OAAO,CAAC,kBAAkB;yCA3jBjB,qBAAqB;2CAArB,qBAAqB;CA8pBjC;AAED,wBAAgB,yBAAyB,SAExC"}
1
+ {"version":3,"file":"search-results-resource.component.d.ts","sourceRoot":"","sources":["../../../src/lib/resource-wrappers/search-results-resource.component.ts"],"names":[],"mappings":"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"}
@@ -509,9 +509,9 @@ let SearchResultsResource = class SearchResultsResource extends BaseResourceComp
509
509
  this.cdr.detectChanges();
510
510
  }
511
511
  /**
512
- * Phase 2C streaming variant. Subscribes to `streamScopedSearch` and progressively
513
- * populates the result list as each provider reports back. The 'final' event carries
514
- * the canonical fused/reranked list, which replaces any partials the user already saw.
512
+ * Phase 2C streaming variant. Subscribes to `streamScopedSearch`, shows each provider's
513
+ * count in the chip strip as it reports back, and renders the result list from the 'final'
514
+ * event. A 'provider' event carries no rows: they arrive before the server's permission pass.
515
515
  *
516
516
  * Cancellation: a new query starts by tearing down the in-flight stream so events
517
517
  * from a stale search do not bleed into the current view.
@@ -531,21 +531,16 @@ let SearchResultsResource = class SearchResultsResource extends BaseResourceComp
531
531
  this.currentStream = this.searchService.StreamSearch(request).subscribe({
532
532
  next: (event) => {
533
533
  if (event.Phase === 'provider' && event.ProviderName) {
534
- const count = event.Results?.length ?? 0;
534
+ // Progress only: the count, never the rows (they precede the permission pass).
535
535
  this.StreamingProviders = [
536
536
  ...this.StreamingProviders,
537
537
  {
538
538
  Name: event.ProviderName,
539
- Count: count,
539
+ Count: event.ResultCount ?? 0,
540
540
  ElapsedMs: event.ElapsedMs ?? 0,
541
541
  State: 'Completed',
542
542
  },
543
543
  ];
544
- if (event.Results && event.Results.length > 0) {
545
- this.allResults = [...this.allResults, ...event.Results].sort((a, b) => b.Score - a.Score);
546
- this.ServerResultCount = this.allResults.length;
547
- this.applyClientFilters();
548
- }
549
544
  }
550
545
  else if (event.Phase === 'final' && event.Results) {
551
546
  this.allResults = [...event.Results].sort((a, b) => b.Score - a.Score);