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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/app-routing.module.d.ts.map +1 -1
  2. package/dist/app-routing.module.js +8 -6
  3. package/dist/app-routing.module.js.map +1 -1
  4. package/dist/generated/lazy-feature-config.d.ts +1 -1
  5. package/dist/generated/lazy-feature-config.d.ts.map +1 -1
  6. package/dist/generated/lazy-feature-config.js +3 -2
  7. package/dist/generated/lazy-feature-config.js.map +1 -1
  8. package/dist/lib/oauth/oauth-callback.component.d.ts +2 -0
  9. package/dist/lib/oauth/oauth-callback.component.d.ts.map +1 -1
  10. package/dist/lib/oauth/oauth-callback.component.js +10 -10
  11. package/dist/lib/oauth/oauth-callback.component.js.map +1 -1
  12. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +17 -3
  13. package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
  14. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +211 -13
  15. package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
  16. package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts +12 -3
  17. package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts.map +1 -1
  18. package/dist/lib/resource-wrappers/chat-tasks-resource.component.js +18 -3
  19. package/dist/lib/resource-wrappers/chat-tasks-resource.component.js.map +1 -1
  20. package/dist/lib/resource-wrappers/search-results-resource.component.d.ts +3 -3
  21. package/dist/lib/resource-wrappers/search-results-resource.component.d.ts.map +1 -1
  22. package/dist/lib/resource-wrappers/search-results-resource.component.js +5 -10
  23. package/dist/lib/resource-wrappers/search-results-resource.component.js.map +1 -1
  24. package/dist/lib/server-connectivity/server-connectivity-banner.component.d.ts +16 -3
  25. package/dist/lib/server-connectivity/server-connectivity-banner.component.d.ts.map +1 -1
  26. package/dist/lib/server-connectivity/server-connectivity-banner.component.js +17 -3
  27. package/dist/lib/server-connectivity/server-connectivity-banner.component.js.map +1 -1
  28. package/dist/lib/shell/components/tabs/tab-container.component.d.ts +34 -0
  29. package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
  30. package/dist/lib/shell/components/tabs/tab-container.component.js +151 -38
  31. package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
  32. package/dist/lib/shell/deep-link-workspace.d.ts +25 -0
  33. package/dist/lib/shell/deep-link-workspace.d.ts.map +1 -0
  34. package/dist/lib/shell/deep-link-workspace.js +49 -0
  35. package/dist/lib/shell/deep-link-workspace.js.map +1 -0
  36. package/dist/lib/shell/shell.component.d.ts +12 -0
  37. package/dist/lib/shell/shell.component.d.ts.map +1 -1
  38. package/dist/lib/shell/shell.component.js +66 -8
  39. package/dist/lib/shell/shell.component.js.map +1 -1
  40. package/dist/lib/single-record/single-record.component.d.ts +12 -0
  41. package/dist/lib/single-record/single-record.component.d.ts.map +1 -1
  42. package/dist/lib/single-record/single-record.component.js +49 -8
  43. package/dist/lib/single-record/single-record.component.js.map +1 -1
  44. package/package.json +57 -57
@@ -82,6 +82,18 @@ export declare class SingleRecordComponent extends BaseAngularComponent implemen
82
82
  private sharedService;
83
83
  private formPresenter;
84
84
  private recentAccessService;
85
+ private cdr;
86
+ /**
87
+ * True once another user (another session) has deleted the record shown here.
88
+ * The tab is NOT closed under the user — they may be reading it — so a banner
89
+ * says so and offers to close it. Deletes in this session are handled by the
90
+ * shell, which closes the tab outright.
91
+ */
92
+ DeletedRemotely: boolean;
93
+ private remoteDeleteSub;
94
+ /** Close this record's tab (the remote-delete banner's Close button). */
95
+ OnCloseDeletedRecord(): void;
96
+ private onGlobalEvent;
85
97
  /** Unblock the shell's first-resource-load gate (success or error). */
86
98
  OnLoadComplete(): void;
87
99
  /** @deprecated Use {@link OnLoadComplete}. */
@@ -1 +1 @@
1
- {"version":3,"file":"single-record.component.d.ts","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,SAAS,EAAqB,MAAM,eAAe,CAAC;AACrG,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAqD,MAAM,+BAA+B,CAAC;AAC9I,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAGhG,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;;AAErE;;;;;;;;;;;;;GAaG;AACH,qBAMa,qBAAsB,SAAQ,oBAAqB,YAAW,SAAS;IAClE,UAAU,EAAE,YAAY,CAAsB;IAC9C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAM;IAC/B,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAM;IAE9E,+CAA+C;IAC/C,IAAoB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EAEjF;IACD,+CAA+C;IAC/C,IAAW,eAAe,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEpE;IAEgB,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,CAA4B;IAE7E;;;;;;OAMG;IACc,YAAY,qBAAqB;IACjC,WAAW,EAAE,YAAY,CAAC,UAAU,CAAC,CAAkC;IAExF;;;;;;OAMG;IACc,WAAW,oCAAoB;IAChD,wFAAwF;IACvE,eAAe,EAAE,YAAY,CAAC,IAAI,CAAC,CAA4B;IAEhF;;;;;;OAMG;IACc,eAAe,qBAAwB;IAExD;;;;OAIG;IACc,eAAe,EAAE,YAAY,CAAC,OAAO,CAAC,CAA+B;IAEtF;;;;;;OAMG;IACc,kBAAkB,EAAE,YAAY,CAAC,uBAAuB,CAAC,CAA+C;IAEnF,OAAO,CAAC,QAAQ,CAAC,CAA4B;IAEnF;;;;;;;OAOG;IACI,SAAS,IAAI,OAAO;IAI3B,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,mBAAmB,CAA6B;IAExD,uEAAuE;IACvE,cAAc,IAAI,IAAI;IAItB,8CAA8C;IAC9C,cAAc,IAAI,IAAI;IAItB,OAAO,CAAC,cAAc,CAA6B;IAEnD;;;;;;OAMG;IACH,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAU5C,WAAW,IAAI,IAAI;IAKnB,uEAAuE;IACvE,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAMvC,6CAA6C;IAC7C,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIvC,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIjC,uCAAuC;IACvC,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAIjC,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIzC,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI;IAIlD,8CAA8C;IAC9C,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI;IAIlD,4EAA4E;IAC5E,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAyClD,gDAAgD;IAChD,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;yCAhMvC,qBAAqB;2CAArB,qBAAqB;CAmMjC"}
1
+ {"version":3,"file":"single-record.component.d.ts","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,19 @@
1
- import { Component, EventEmitter, inject, Input, Output, ViewChild } from '@angular/core';
1
+ import { ChangeDetectorRef, Component, EventEmitter, inject, Input, Output, ViewChild } from '@angular/core';
2
2
  import { CompositeKey } from '@memberjunction/core';
3
3
  import { MJFormPresenterService, MjEntityFormHostComponent } from '@memberjunction/ng-base-forms';
4
- import { NavigationService, RecentAccessService, SharedService } from '@memberjunction/ng-shared';
4
+ import { GetDeletedRecordFromEvent, NavigationService, RecentAccessService, RecordIdentityMatches, SafeDetectChanges, SharedService } from '@memberjunction/ng-shared';
5
+ import { MJGlobal } from '@memberjunction/global';
5
6
  import { BaseAngularComponent } from '@memberjunction/ng-base-types';
6
7
  import * as i0 from "@angular/core";
7
8
  import * as i1 from "@memberjunction/ng-base-forms";
9
+ import * as i2 from "@memberjunction/ng-ui-components";
10
+ function SingleRecordComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
11
+ const _r1 = i0.ɵɵgetCurrentView();
12
+ i0.ɵɵelementStart(0, "mj-alert", 0)(1, "button", 2);
13
+ i0.ɵɵlistener("click", function SingleRecordComponent_Conditional_0_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnCloseDeletedRecord()); });
14
+ i0.ɵɵtext(2, "Close");
15
+ i0.ɵɵelementEnd()();
16
+ } }
8
17
  /**
9
18
  * Explorer-side host for a single entity record in the main tab area.
10
19
  *
@@ -89,6 +98,33 @@ export class SingleRecordComponent extends BaseAngularComponent {
89
98
  sharedService = inject(SharedService);
90
99
  formPresenter = inject(MJFormPresenterService);
91
100
  recentAccessService = new RecentAccessService();
101
+ cdr = inject(ChangeDetectorRef);
102
+ /**
103
+ * True once another user (another session) has deleted the record shown here.
104
+ * The tab is NOT closed under the user — they may be reading it — so a banner
105
+ * says so and offers to close it. Deletes in this session are handled by the
106
+ * shell, which closes the tab outright.
107
+ */
108
+ DeletedRemotely = false;
109
+ remoteDeleteSub = MJGlobal.Instance.GetEventListener()
110
+ .subscribe((event) => this.onGlobalEvent(event));
111
+ /** Close this record's tab (the remote-delete banner's Close button). */
112
+ OnCloseDeletedRecord() {
113
+ this.RecordDismissed.emit();
114
+ }
115
+ onGlobalEvent(event) {
116
+ if (this.DeletedRemotely) {
117
+ return;
118
+ }
119
+ const deleted = GetDeletedRecordFromEvent(event);
120
+ if (!deleted?.Remote || !this.PrimaryKey?.HasValue) {
121
+ return;
122
+ }
123
+ if (RecordIdentityMatches(this.entityName, this.PrimaryKey.ToURLSegment(), deleted)) {
124
+ this.DeletedRemotely = true;
125
+ SafeDetectChanges(this.cdr);
126
+ }
127
+ }
92
128
  /** Unblock the shell's first-resource-load gate (success or error). */
93
129
  OnLoadComplete() {
94
130
  this.LoadComplete.emit();
@@ -115,6 +151,8 @@ export class SingleRecordComponent extends BaseAngularComponent {
115
151
  ngOnDestroy() {
116
152
  this.compositionSub?.unsubscribe();
117
153
  this.compositionSub = null;
154
+ this.remoteDeleteSub?.unsubscribe();
155
+ this.remoteDeleteSub = null;
118
156
  }
119
157
  /** Log access for existing records once the form's record is ready. */
120
158
  OnRecordReady(record) {
@@ -194,17 +232,20 @@ export class SingleRecordComponent extends BaseAngularComponent {
194
232
  } if (rf & 2) {
195
233
  let _t;
196
234
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.formHost = _t.first);
197
- } }, inputs: { PrimaryKey: "PrimaryKey", entityName: "entityName", NewRecordValues: "NewRecordValues", newRecordValues: "newRecordValues" }, outputs: { LoadComplete: "LoadComplete", loadComplete: "loadComplete", RecordSaved: "RecordSaved", recordSaved: "recordSaved", RecordDismissed: "RecordDismissed", recordDismissed: "recordDismissed", EditModeChanged: "EditModeChanged", CompositionChanged: "CompositionChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 1, vars: 4, consts: [[3, "LoadComplete", "LoadError", "RecordReady", "Saved", "Navigate", "Notification", "EditModeChanged", "Dismissed", "FormCreated", "EntityName", "PrimaryKey", "NewRecordValues", "Provider"]], template: function SingleRecordComponent_Template(rf, ctx) { if (rf & 1) {
198
- i0.ɵɵelementStart(0, "mj-entity-form-host", 0);
199
- i0.ɵɵlistener("LoadComplete", function SingleRecordComponent_Template_mj_entity_form_host_LoadComplete_0_listener() { return ctx.onLoadComplete(); })("LoadError", function SingleRecordComponent_Template_mj_entity_form_host_LoadError_0_listener() { return ctx.onLoadComplete(); })("RecordReady", function SingleRecordComponent_Template_mj_entity_form_host_RecordReady_0_listener($event) { return ctx.onRecordReady($event); })("Saved", function SingleRecordComponent_Template_mj_entity_form_host_Saved_0_listener($event) { return ctx.onSaved($event); })("Navigate", function SingleRecordComponent_Template_mj_entity_form_host_Navigate_0_listener($event) { return ctx.handleNavigation($event); })("Notification", function SingleRecordComponent_Template_mj_entity_form_host_Notification_0_listener($event) { return ctx.onNotification($event); })("EditModeChanged", function SingleRecordComponent_Template_mj_entity_form_host_EditModeChanged_0_listener($event) { return ctx.OnEditModeChanged($event); })("Dismissed", function SingleRecordComponent_Template_mj_entity_form_host_Dismissed_0_listener() { return ctx.recordDismissed.emit(); })("FormCreated", function SingleRecordComponent_Template_mj_entity_form_host_FormCreated_0_listener($event) { return ctx.onFormCreated($event); });
235
+ } }, inputs: { PrimaryKey: "PrimaryKey", entityName: "entityName", NewRecordValues: "NewRecordValues", newRecordValues: "newRecordValues" }, outputs: { LoadComplete: "LoadComplete", loadComplete: "loadComplete", RecordSaved: "RecordSaved", recordSaved: "recordSaved", RecordDismissed: "RecordDismissed", recordDismissed: "recordDismissed", EditModeChanged: "EditModeChanged", CompositionChanged: "CompositionChanged" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 2, vars: 5, consts: [["Variant", "warning", "Title", "This record was deleted by another user", "Message", "It no longer exists. What you see here is the last copy that was loaded.", 1, "single-record-deleted-banner"], [3, "LoadComplete", "LoadError", "RecordReady", "Saved", "Navigate", "Notification", "EditModeChanged", "Dismissed", "FormCreated", "EntityName", "PrimaryKey", "NewRecordValues", "Provider"], ["actions", "", "mjButton", "", "Variant", "secondary", "Size", "sm", 3, "click"]], template: function SingleRecordComponent_Template(rf, ctx) { if (rf & 1) {
236
+ i0.ɵɵconditionalCreate(0, SingleRecordComponent_Conditional_0_Template, 3, 0, "mj-alert", 0);
237
+ i0.ɵɵelementStart(1, "mj-entity-form-host", 1);
238
+ i0.ɵɵlistener("LoadComplete", function SingleRecordComponent_Template_mj_entity_form_host_LoadComplete_1_listener() { return ctx.onLoadComplete(); })("LoadError", function SingleRecordComponent_Template_mj_entity_form_host_LoadError_1_listener() { return ctx.onLoadComplete(); })("RecordReady", function SingleRecordComponent_Template_mj_entity_form_host_RecordReady_1_listener($event) { return ctx.onRecordReady($event); })("Saved", function SingleRecordComponent_Template_mj_entity_form_host_Saved_1_listener($event) { return ctx.onSaved($event); })("Navigate", function SingleRecordComponent_Template_mj_entity_form_host_Navigate_1_listener($event) { return ctx.handleNavigation($event); })("Notification", function SingleRecordComponent_Template_mj_entity_form_host_Notification_1_listener($event) { return ctx.onNotification($event); })("EditModeChanged", function SingleRecordComponent_Template_mj_entity_form_host_EditModeChanged_1_listener($event) { return ctx.OnEditModeChanged($event); })("Dismissed", function SingleRecordComponent_Template_mj_entity_form_host_Dismissed_1_listener() { return ctx.recordDismissed.emit(); })("FormCreated", function SingleRecordComponent_Template_mj_entity_form_host_FormCreated_1_listener($event) { return ctx.onFormCreated($event); });
200
239
  i0.ɵɵelementEnd();
201
240
  } if (rf & 2) {
241
+ i0.ɵɵconditional(ctx.DeletedRemotely ? 0 : -1);
242
+ i0.ɵɵadvance();
202
243
  i0.ɵɵproperty("EntityName", ctx.entityName)("PrimaryKey", ctx.PrimaryKey)("NewRecordValues", ctx.newRecordValues)("Provider", ctx.Provider);
203
- } }, dependencies: [i1.MjEntityFormHostComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.single-record-error[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 32px;\n max-width: 720px;\n margin: 64px auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n color: var(--mj-text-primary);\n}\n\n.single-record-error__icon[_ngcontent-%COMP%] {\n font-size: 36px;\n color: var(--mj-status-error);\n margin-bottom: 16px;\n}\n\n.single-record-error__title[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 600;\n margin: 0 0 12px 0;\n color: var(--mj-status-error-text);\n}\n\n.single-record-error__detail[_ngcontent-%COMP%] {\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n margin: 0 0 16px 0;\n white-space: pre-wrap;\n}\n\n.single-record-error__hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin: 0;\n font-style: italic;\n}"] });
244
+ } }, dependencies: [i1.MjEntityFormHostComponent, i2.MJButtonDirective, i2.MJAlertComponent], styles: ["[_nghost-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n\nmj-entity-form-host[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.single-record-deleted-banner[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n margin: var(--mj-space-3) var(--mj-space-4) 0;\n}\n\n.single-record-error[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 32px;\n max-width: 720px;\n margin: 64px auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n color: var(--mj-text-primary);\n}\n\n.single-record-error__icon[_ngcontent-%COMP%] {\n font-size: 36px;\n color: var(--mj-status-error);\n margin-bottom: 16px;\n}\n\n.single-record-error__title[_ngcontent-%COMP%] {\n font-size: 18px;\n font-weight: 600;\n margin: 0 0 12px 0;\n color: var(--mj-status-error-text);\n}\n\n.single-record-error__detail[_ngcontent-%COMP%] {\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n margin: 0 0 16px 0;\n white-space: pre-wrap;\n}\n\n.single-record-error__hint[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin: 0;\n font-style: italic;\n}"] });
204
245
  }
205
246
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SingleRecordComponent, [{
206
247
  type: Component,
207
- args: [{ standalone: false, selector: 'mj-single-record', template: "<mj-entity-form-host\n [EntityName]=\"entityName\"\n [PrimaryKey]=\"PrimaryKey\"\n [NewRecordValues]=\"newRecordValues\"\n [Provider]=\"Provider\"\n (LoadComplete)=\"onLoadComplete()\"\n (LoadError)=\"onLoadComplete()\"\n (RecordReady)=\"onRecordReady($event)\"\n (Saved)=\"onSaved($event)\"\n (Navigate)=\"handleNavigation($event)\"\n (Notification)=\"onNotification($event)\"\n (EditModeChanged)=\"OnEditModeChanged($event)\"\n (Dismissed)=\"recordDismissed.emit()\"\n (FormCreated)=\"onFormCreated($event)\">\n</mj-entity-form-host>\n", styles: [":host {\n display: block;\n height: 100%;\n width: 100%;\n}\n\n.single-record-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 32px;\n max-width: 720px;\n margin: 64px auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n color: var(--mj-text-primary);\n}\n\n.single-record-error__icon {\n font-size: 36px;\n color: var(--mj-status-error);\n margin-bottom: 16px;\n}\n\n.single-record-error__title {\n font-size: 18px;\n font-weight: 600;\n margin: 0 0 12px 0;\n color: var(--mj-status-error-text);\n}\n\n.single-record-error__detail {\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n margin: 0 0 16px 0;\n white-space: pre-wrap;\n}\n\n.single-record-error__hint {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin: 0;\n font-style: italic;\n}\n"] }]
248
+ args: [{ standalone: false, selector: 'mj-single-record', template: "@if (DeletedRemotely) {\n <mj-alert\n class=\"single-record-deleted-banner\"\n Variant=\"warning\"\n Title=\"This record was deleted by another user\"\n Message=\"It no longer exists. What you see here is the last copy that was loaded.\">\n <button actions mjButton Variant=\"secondary\" Size=\"sm\" (click)=\"OnCloseDeletedRecord()\">Close</button>\n </mj-alert>\n}\n<mj-entity-form-host\n [EntityName]=\"entityName\"\n [PrimaryKey]=\"PrimaryKey\"\n [NewRecordValues]=\"newRecordValues\"\n [Provider]=\"Provider\"\n (LoadComplete)=\"onLoadComplete()\"\n (LoadError)=\"onLoadComplete()\"\n (RecordReady)=\"onRecordReady($event)\"\n (Saved)=\"onSaved($event)\"\n (Navigate)=\"handleNavigation($event)\"\n (Notification)=\"onNotification($event)\"\n (EditModeChanged)=\"OnEditModeChanged($event)\"\n (Dismissed)=\"recordDismissed.emit()\"\n (FormCreated)=\"onFormCreated($event)\">\n</mj-entity-form-host>\n", styles: [":host {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n}\n\n/* The form fills what the remote-delete banner leaves. */\nmj-entity-form-host {\n flex: 1 1 auto;\n min-height: 0;\n}\n\n.single-record-deleted-banner {\n flex: 0 0 auto;\n margin: var(--mj-space-3) var(--mj-space-4) 0;\n}\n\n.single-record-error {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 48px 32px;\n max-width: 720px;\n margin: 64px auto;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-status-error-border);\n border-radius: 8px;\n color: var(--mj-text-primary);\n}\n\n.single-record-error__icon {\n font-size: 36px;\n color: var(--mj-status-error);\n margin-bottom: 16px;\n}\n\n.single-record-error__title {\n font-size: 18px;\n font-weight: 600;\n margin: 0 0 12px 0;\n color: var(--mj-status-error-text);\n}\n\n.single-record-error__detail {\n font-size: 14px;\n line-height: 1.5;\n color: var(--mj-text-secondary);\n margin: 0 0 16px 0;\n white-space: pre-wrap;\n}\n\n.single-record-error__hint {\n font-size: 12px;\n color: var(--mj-text-muted);\n margin: 0;\n font-style: italic;\n}\n"] }]
208
249
  }], null, { PrimaryKey: [{
209
250
  type: Input
210
251
  }], entityName: [{
@@ -233,5 +274,5 @@ export class SingleRecordComponent extends BaseAngularComponent {
233
274
  type: ViewChild,
234
275
  args: [MjEntityFormHostComponent]
235
276
  }] }); })();
236
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SingleRecordComponent, { className: "SingleRecordComponent", filePath: "src/lib/single-record/single-record.component.ts", lineNumber: 29 }); })();
277
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SingleRecordComponent, { className: "SingleRecordComponent", filePath: "src/lib/single-record/single-record.component.ts", lineNumber: 30 }); })();
237
278
  //# sourceMappingURL=single-record.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"single-record.component.js","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts","../../../src/lib/single-record/single-record.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, inject, Input, OnDestroy, Output, ViewChild } from '@angular/core';\nimport { CompositeKey, BaseEntity } from '@memberjunction/core';\nimport { FormNavigationEvent, FormNotificationEvent, MJFormPresenterService, MjEntityFormHostComponent } from '@memberjunction/ng-base-forms';\nimport type { BaseFormComponent, FormCompositionSnapshot } from '@memberjunction/ng-base-forms';\nimport { Subscription } from 'rxjs';\nimport { NavigationService, RecentAccessService, SharedService } from '@memberjunction/ng-shared';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Explorer-side host for a single entity record in the main tab area.\n *\n * This is now a **thin wrapper** around the Generic `<mj-entity-form-host>`\n * (in `@memberjunction/ng-base-forms`), which owns all the mechanics: resolving\n * the form (class / custom / interactive override + variants), loading the\n * record, dynamically creating the form, binding it, and tearing it down.\n *\n * SingleRecordComponent's only remaining job is the **Explorer mapping**:\n * translating the host's framework-agnostic events into Explorer services —\n * `Navigate` → {@link NavigationService}, `Notification` → {@link SharedService},\n * record loads → {@link RecentAccessService} — none of which belong in a Generic\n * component.\n */\n@Component({\n standalone: false,\n selector: 'mj-single-record',\n templateUrl: './single-record.component.html',\n styleUrls: ['./single-record.component.css']\n})\nexport class SingleRecordComponent extends BaseAngularComponent implements OnDestroy {\n @Input() public PrimaryKey: CompositeKey = new CompositeKey();\n @Input() public entityName: string | null = '';\n @Input() public NewRecordValues: string | Record<string, unknown> | null = '';\n\n /** @deprecated Use {@link NewRecordValues}. */\n @Input() public set newRecordValues(value: string | Record<string, unknown> | null) {\n this.NewRecordValues = value;\n }\n /** @deprecated Use {@link NewRecordValues}. */\n public get newRecordValues(): string | Record<string, unknown> | null {\n return this.NewRecordValues;\n }\n\n @Output() public LoadComplete: EventEmitter<void> = new EventEmitter<void>();\n\n /**\n * @deprecated Use {@link LoadComplete}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (loadComplete) keeps working. Must stay AFTER LoadComplete: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() public loadComplete = this.LoadComplete;\n @Output() public RecordSaved: EventEmitter<BaseEntity> = new EventEmitter<BaseEntity>();\n\n /**\n * @deprecated Use {@link RecordSaved}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (recordSaved) keeps working. Must stay AFTER RecordSaved: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() public recordSaved = this.RecordSaved;\n /** Emitted when the hosted form asks to be dismissed (e.g. Discard on a new record). */\n @Output() public RecordDismissed: EventEmitter<void> = new EventEmitter<void>();\n\n /**\n * @deprecated Use {@link RecordDismissed}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (recordDismissed) keeps working. Must stay AFTER RecordDismissed: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() public recordDismissed = this.RecordDismissed;\n\n /**\n * Edit mode of the hosted form started (true) or ended (false). Relayed from\n * `<mj-entity-form-host>` so the resource wrapper can tell the shell to\n * promote this tab. {@link IsEditing} remains as the synchronous fallback.\n */\n @Output() public EditModeChanged: EventEmitter<boolean> = new EventEmitter<boolean>();\n\n /**\n * The live form's composition — sections, related grids, contributions, and the slots\n * the form actually emits. Re-emitted on every chrome resolve.\n *\n * The form is created dynamically inside `<mj-entity-form-host>`, so this relay is the\n * only route the snapshot has out to Explorer.\n */\n @Output() public CompositionChanged: EventEmitter<FormCompositionSnapshot> = new EventEmitter<FormCompositionSnapshot>();\n\n @ViewChild(MjEntityFormHostComponent) private formHost?: MjEntityFormHostComponent;\n\n /**\n * True while the hosted form is in edit mode. The host already exposes the\n * live form instance, so this is a read, not a new event pipeline.\n *\n * MJ forms are read-only until the user explicitly clicks Edit, so edit mode\n * is a deliberate gesture and a sound proxy for \"there is work in here worth\n * protecting\" — which is all the preview-tab replacement guard needs.\n */\n public IsEditing(): boolean {\n return this.formHost?.Form?.EditMode === true;\n }\n\n private navigationService = inject(NavigationService);\n private sharedService = inject(SharedService);\n private formPresenter = inject(MJFormPresenterService);\n private recentAccessService = new RecentAccessService();\n\n /** Unblock the shell's first-resource-load gate (success or error). */\n OnLoadComplete(): void {\n this.LoadComplete.emit();\n }\n\n /** @deprecated Use {@link OnLoadComplete}. */\n onLoadComplete(): void {\n return this.OnLoadComplete();\n }\n\n private compositionSub: Subscription | null = null;\n\n /**\n * Bind to the newly created form's composition stream.\n *\n * The previous subscription is dropped first: the host re-creates the form when the\n * user switches variants, and a retained subscription would let the replaced form\n * keep publishing over the live one.\n */\n onFormCreated(form: BaseFormComponent): void {\n this.compositionSub?.unsubscribe();\n this.compositionSub = form.CompositionChanged.subscribe((snapshot: FormCompositionSnapshot) =>\n this.CompositionChanged.emit(snapshot),\n );\n if (form.CompositionSnapshot) {\n this.CompositionChanged.emit(form.CompositionSnapshot);\n }\n }\n\n ngOnDestroy(): void {\n this.compositionSub?.unsubscribe();\n this.compositionSub = null;\n }\n\n /** Log access for existing records once the form's record is ready. */\n OnRecordReady(record: BaseEntity): void {\n if (record?.IsSaved) {\n this.recentAccessService.logAccess(record.EntityInfo.Name, record.PrimaryKey, 'record');\n }\n }\n\n /** @deprecated Use {@link OnRecordReady}. */\n onRecordReady(record: BaseEntity): void {\n return this.OnRecordReady(record);\n }\n\n OnSaved(record: BaseEntity): void {\n this.RecordSaved.emit(record);\n }\n\n /** @deprecated Use {@link OnSaved}. */\n onSaved(record: BaseEntity): void {\n return this.OnSaved(record);\n }\n\n OnEditModeChanged(editing: boolean): void {\n this.EditModeChanged.emit(editing);\n }\n\n OnNotification(event: FormNotificationEvent): void {\n this.sharedService.CreateSimpleNotification(event.Message, event.Type, event.Duration);\n }\n\n /** @deprecated Use {@link OnNotification}. */\n onNotification(event: FormNotificationEvent): void {\n return this.OnNotification(event);\n }\n\n /** Map the form's navigation requests onto Explorer's NavigationService. */\n HandleNavigation(event: FormNavigationEvent): void {\n switch (event.Kind) {\n case 'record':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey, { forceNewTab: event.OpenInNewTab });\n break;\n case 'new-record':\n // Creating a related record from inside an open form: force a new tab so the\n // parent record stays intact in single-resource mode.\n this.navigationService.OpenNewEntityRecord(event.EntityName, {\n newRecordValues: event.DefaultValues,\n forceNewTab: true,\n });\n break;\n case 'entity-hierarchy':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey);\n break;\n case 'external-link':\n window.open(event.Url, '_blank');\n break;\n case 'email':\n window.open(`mailto:${event.EmailAddress}`, '_self');\n break;\n case 'dismiss':\n this.RecordDismissed.emit();\n break;\n case 'create-related': {\n // A FK field wants a new related record created. Open the related entity's form\n // as a dialog/slide-in (prefilled), then hand the saved record back so the field\n // can select it.\n const ref = this.formPresenter.Open({\n EntityName: event.EntityName,\n Presentation: event.Presentation ?? 'dialog',\n NewRecordValues: event.NewRecordValues,\n Provider: event.Provider,\n });\n ref.AfterSaved().then(created => event.Complete(created));\n break;\n }\n }\n }\n\n /** @deprecated Use {@link HandleNavigation}. */\n handleNavigation(event: FormNavigationEvent): void {\n return this.HandleNavigation(event);\n }\n}\n","<mj-entity-form-host\n [EntityName]=\"entityName\"\n [PrimaryKey]=\"PrimaryKey\"\n [NewRecordValues]=\"newRecordValues\"\n [Provider]=\"Provider\"\n (LoadComplete)=\"onLoadComplete()\"\n (LoadError)=\"onLoadComplete()\"\n (RecordReady)=\"onRecordReady($event)\"\n (Saved)=\"onSaved($event)\"\n (Navigate)=\"handleNavigation($event)\"\n (Notification)=\"onNotification($event)\"\n (EditModeChanged)=\"OnEditModeChanged($event)\"\n (Dismissed)=\"recordDismissed.emit()\"\n (FormCreated)=\"onFormCreated($event)\">\n</mj-entity-form-host>\n"]}
1
+ {"version":3,"file":"single-record.component.js","sourceRoot":"","sources":["../../../src/lib/single-record/single-record.component.ts","../../../src/lib/single-record/single-record.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, EventEmitter, inject, Input, OnDestroy, Output, ViewChild } from '@angular/core';\nimport { CompositeKey, BaseEntity } from '@memberjunction/core';\nimport { FormNavigationEvent, FormNotificationEvent, MJFormPresenterService, MjEntityFormHostComponent } from '@memberjunction/ng-base-forms';\nimport type { BaseFormComponent, FormCompositionSnapshot } from '@memberjunction/ng-base-forms';\nimport { Subscription } from 'rxjs';\nimport { GetDeletedRecordFromEvent, NavigationService, RecentAccessService, RecordIdentityMatches, SafeDetectChanges, SharedService } from '@memberjunction/ng-shared';\nimport { MJEvent, MJGlobal } from '@memberjunction/global';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\n\n/**\n * Explorer-side host for a single entity record in the main tab area.\n *\n * This is now a **thin wrapper** around the Generic `<mj-entity-form-host>`\n * (in `@memberjunction/ng-base-forms`), which owns all the mechanics: resolving\n * the form (class / custom / interactive override + variants), loading the\n * record, dynamically creating the form, binding it, and tearing it down.\n *\n * SingleRecordComponent's only remaining job is the **Explorer mapping**:\n * translating the host's framework-agnostic events into Explorer services —\n * `Navigate` → {@link NavigationService}, `Notification` → {@link SharedService},\n * record loads → {@link RecentAccessService} — none of which belong in a Generic\n * component.\n */\n@Component({\n standalone: false,\n selector: 'mj-single-record',\n templateUrl: './single-record.component.html',\n styleUrls: ['./single-record.component.css']\n})\nexport class SingleRecordComponent extends BaseAngularComponent implements OnDestroy {\n @Input() public PrimaryKey: CompositeKey = new CompositeKey();\n @Input() public entityName: string | null = '';\n @Input() public NewRecordValues: string | Record<string, unknown> | null = '';\n\n /** @deprecated Use {@link NewRecordValues}. */\n @Input() public set newRecordValues(value: string | Record<string, unknown> | null) {\n this.NewRecordValues = value;\n }\n /** @deprecated Use {@link NewRecordValues}. */\n public get newRecordValues(): string | Record<string, unknown> | null {\n return this.NewRecordValues;\n }\n\n @Output() public LoadComplete: EventEmitter<void> = new EventEmitter<void>();\n\n /**\n * @deprecated Use {@link LoadComplete}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (loadComplete) keeps working. Must stay AFTER LoadComplete: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() public loadComplete = this.LoadComplete;\n @Output() public RecordSaved: EventEmitter<BaseEntity> = new EventEmitter<BaseEntity>();\n\n /**\n * @deprecated Use {@link RecordSaved}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (recordSaved) keeps working. Must stay AFTER RecordSaved: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() public recordSaved = this.RecordSaved;\n /** Emitted when the hosted form asks to be dismissed (e.g. Discard on a new record). */\n @Output() public RecordDismissed: EventEmitter<void> = new EventEmitter<void>();\n\n /**\n * @deprecated Use {@link RecordDismissed}.\n *\n * The same emitter under the old binding name, so a template still binding\n * (recordDismissed) keeps working. Must stay AFTER RecordDismissed: class fields\n * initialise in order, and the other way round this captures undefined.\n */\n @Output() public recordDismissed = this.RecordDismissed;\n\n /**\n * Edit mode of the hosted form started (true) or ended (false). Relayed from\n * `<mj-entity-form-host>` so the resource wrapper can tell the shell to\n * promote this tab. {@link IsEditing} remains as the synchronous fallback.\n */\n @Output() public EditModeChanged: EventEmitter<boolean> = new EventEmitter<boolean>();\n\n /**\n * The live form's composition — sections, related grids, contributions, and the slots\n * the form actually emits. Re-emitted on every chrome resolve.\n *\n * The form is created dynamically inside `<mj-entity-form-host>`, so this relay is the\n * only route the snapshot has out to Explorer.\n */\n @Output() public CompositionChanged: EventEmitter<FormCompositionSnapshot> = new EventEmitter<FormCompositionSnapshot>();\n\n @ViewChild(MjEntityFormHostComponent) private formHost?: MjEntityFormHostComponent;\n\n /**\n * True while the hosted form is in edit mode. The host already exposes the\n * live form instance, so this is a read, not a new event pipeline.\n *\n * MJ forms are read-only until the user explicitly clicks Edit, so edit mode\n * is a deliberate gesture and a sound proxy for \"there is work in here worth\n * protecting\" — which is all the preview-tab replacement guard needs.\n */\n public IsEditing(): boolean {\n return this.formHost?.Form?.EditMode === true;\n }\n\n private navigationService = inject(NavigationService);\n private sharedService = inject(SharedService);\n private formPresenter = inject(MJFormPresenterService);\n private recentAccessService = new RecentAccessService();\n private cdr = inject(ChangeDetectorRef);\n\n /**\n * True once another user (another session) has deleted the record shown here.\n * The tab is NOT closed under the user — they may be reading it — so a banner\n * says so and offers to close it. Deletes in this session are handled by the\n * shell, which closes the tab outright.\n */\n public DeletedRemotely = false;\n\n private remoteDeleteSub: Subscription | null = MJGlobal.Instance.GetEventListener()\n .subscribe((event: MJEvent) => this.onGlobalEvent(event));\n\n /** Close this record's tab (the remote-delete banner's Close button). */\n OnCloseDeletedRecord(): void {\n this.RecordDismissed.emit();\n }\n\n private onGlobalEvent(event: MJEvent): void {\n if (this.DeletedRemotely) {\n return;\n }\n const deleted = GetDeletedRecordFromEvent(event);\n if (!deleted?.Remote || !this.PrimaryKey?.HasValue) {\n return;\n }\n if (RecordIdentityMatches(this.entityName, this.PrimaryKey.ToURLSegment(), deleted)) {\n this.DeletedRemotely = true;\n SafeDetectChanges(this.cdr);\n }\n }\n\n /** Unblock the shell's first-resource-load gate (success or error). */\n OnLoadComplete(): void {\n this.LoadComplete.emit();\n }\n\n /** @deprecated Use {@link OnLoadComplete}. */\n onLoadComplete(): void {\n return this.OnLoadComplete();\n }\n\n private compositionSub: Subscription | null = null;\n\n /**\n * Bind to the newly created form's composition stream.\n *\n * The previous subscription is dropped first: the host re-creates the form when the\n * user switches variants, and a retained subscription would let the replaced form\n * keep publishing over the live one.\n */\n onFormCreated(form: BaseFormComponent): void {\n this.compositionSub?.unsubscribe();\n this.compositionSub = form.CompositionChanged.subscribe((snapshot: FormCompositionSnapshot) =>\n this.CompositionChanged.emit(snapshot),\n );\n if (form.CompositionSnapshot) {\n this.CompositionChanged.emit(form.CompositionSnapshot);\n }\n }\n\n ngOnDestroy(): void {\n this.compositionSub?.unsubscribe();\n this.compositionSub = null;\n this.remoteDeleteSub?.unsubscribe();\n this.remoteDeleteSub = null;\n }\n\n /** Log access for existing records once the form's record is ready. */\n OnRecordReady(record: BaseEntity): void {\n if (record?.IsSaved) {\n this.recentAccessService.logAccess(record.EntityInfo.Name, record.PrimaryKey, 'record');\n }\n }\n\n /** @deprecated Use {@link OnRecordReady}. */\n onRecordReady(record: BaseEntity): void {\n return this.OnRecordReady(record);\n }\n\n OnSaved(record: BaseEntity): void {\n this.RecordSaved.emit(record);\n }\n\n /** @deprecated Use {@link OnSaved}. */\n onSaved(record: BaseEntity): void {\n return this.OnSaved(record);\n }\n\n OnEditModeChanged(editing: boolean): void {\n this.EditModeChanged.emit(editing);\n }\n\n OnNotification(event: FormNotificationEvent): void {\n this.sharedService.CreateSimpleNotification(event.Message, event.Type, event.Duration);\n }\n\n /** @deprecated Use {@link OnNotification}. */\n onNotification(event: FormNotificationEvent): void {\n return this.OnNotification(event);\n }\n\n /** Map the form's navigation requests onto Explorer's NavigationService. */\n HandleNavigation(event: FormNavigationEvent): void {\n switch (event.Kind) {\n case 'record':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey, { forceNewTab: event.OpenInNewTab });\n break;\n case 'new-record':\n // Creating a related record from inside an open form: force a new tab so the\n // parent record stays intact in single-resource mode.\n this.navigationService.OpenNewEntityRecord(event.EntityName, {\n newRecordValues: event.DefaultValues,\n forceNewTab: true,\n });\n break;\n case 'entity-hierarchy':\n this.navigationService.OpenEntityRecord(event.EntityName, event.PrimaryKey);\n break;\n case 'external-link':\n window.open(event.Url, '_blank');\n break;\n case 'email':\n window.open(`mailto:${event.EmailAddress}`, '_self');\n break;\n case 'dismiss':\n this.RecordDismissed.emit();\n break;\n case 'create-related': {\n // A FK field wants a new related record created. Open the related entity's form\n // as a dialog/slide-in (prefilled), then hand the saved record back so the field\n // can select it.\n const ref = this.formPresenter.Open({\n EntityName: event.EntityName,\n Presentation: event.Presentation ?? 'dialog',\n NewRecordValues: event.NewRecordValues,\n Provider: event.Provider,\n });\n ref.AfterSaved().then(created => event.Complete(created));\n break;\n }\n }\n }\n\n /** @deprecated Use {@link HandleNavigation}. */\n handleNavigation(event: FormNavigationEvent): void {\n return this.HandleNavigation(event);\n }\n}\n","@if (DeletedRemotely) {\n <mj-alert\n class=\"single-record-deleted-banner\"\n Variant=\"warning\"\n Title=\"This record was deleted by another user\"\n Message=\"It no longer exists. What you see here is the last copy that was loaded.\">\n <button actions mjButton Variant=\"secondary\" Size=\"sm\" (click)=\"OnCloseDeletedRecord()\">Close</button>\n </mj-alert>\n}\n<mj-entity-form-host\n [EntityName]=\"entityName\"\n [PrimaryKey]=\"PrimaryKey\"\n [NewRecordValues]=\"newRecordValues\"\n [Provider]=\"Provider\"\n (LoadComplete)=\"onLoadComplete()\"\n (LoadError)=\"onLoadComplete()\"\n (RecordReady)=\"onRecordReady($event)\"\n (Saved)=\"onSaved($event)\"\n (Navigate)=\"handleNavigation($event)\"\n (Notification)=\"onNotification($event)\"\n (EditModeChanged)=\"OnEditModeChanged($event)\"\n (Dismissed)=\"recordDismissed.emit()\"\n (FormCreated)=\"onFormCreated($event)\">\n</mj-entity-form-host>\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/ng-explorer-core",
3
- "version": "6.2.0-edge.4",
3
+ "version": "6.2.0-edge.5",
4
4
  "description": "MemberJunction Explorer: Core Angular Components",
5
5
  "main": "./dist/public-api.js",
6
6
  "typings": "./dist/public-api.d.ts",
@@ -14,9 +14,9 @@
14
14
  "@angular/compiler": "21.2.22",
15
15
  "@angular/compiler-cli": "21.2.22",
16
16
  "sass": "^1.97.3",
17
- "@memberjunction/ng-test-utils": "6.2.0-edge.4",
18
- "@memberjunction/sql-dialect": "6.2.0-edge.4",
19
- "@memberjunction/sql-parser": "6.2.0-edge.4"
17
+ "@memberjunction/ng-test-utils": "6.2.0-edge.5",
18
+ "@memberjunction/sql-dialect": "6.2.0-edge.5",
19
+ "@memberjunction/sql-parser": "6.2.0-edge.5"
20
20
  },
21
21
  "peerDependencies": {
22
22
  "@angular/animations": "^21.2.22",
@@ -29,63 +29,63 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@auth0/auth0-angular": "^2.6.0",
32
- "@memberjunction/ai-core-plus": "6.2.0-edge.4",
33
- "@memberjunction/ai-engine-base": "6.2.0-edge.4",
34
- "@memberjunction/communication-types": "6.2.0-edge.4",
35
- "@memberjunction/conversations-runtime": "6.2.0-edge.4",
36
- "@memberjunction/core": "6.2.0-edge.4",
37
- "@memberjunction/core-entities": "6.2.0-edge.4",
38
- "@memberjunction/entity-communications-client": "6.2.0-edge.4",
39
- "@memberjunction/export-engine": "6.2.0-edge.4",
40
- "@memberjunction/global": "6.2.0-edge.4",
41
- "@memberjunction/graphql-dataprovider": "6.2.0-edge.4",
42
- "@memberjunction/interactive-component-types": "6.2.0-edge.4",
43
- "@memberjunction/lists-base": "6.2.0-edge.4",
44
- "@memberjunction/theme-engine": "6.2.0-edge.4",
45
- "@memberjunction/ng-ai-test-harness": "6.2.0-edge.4",
46
- "@memberjunction/ng-artifacts": "6.2.0-edge.4",
47
- "@memberjunction/ng-auth-services": "6.2.0-edge.4",
48
- "@memberjunction/ng-base-application": "6.2.0-edge.4",
49
- "@memberjunction/ng-base-forms": "6.2.0-edge.4",
50
- "@memberjunction/ng-base-types": "6.2.0-edge.4",
51
- "@memberjunction/ng-composer": "6.2.0-edge.4",
52
- "@memberjunction/ng-container-directives": "6.2.0-edge.4",
53
- "@memberjunction/ng-conversation-offers": "6.2.0-edge.4",
54
- "@memberjunction/ng-conversations": "6.2.0-edge.4",
55
- "@memberjunction/ng-dashboard-viewer": "6.2.0-edge.4",
56
- "@memberjunction/ng-dashboards": "6.2.0-edge.4",
57
- "@memberjunction/ng-entity-form-dialog": "6.2.0-edge.4",
58
- "@memberjunction/ng-entity-permissions": "6.2.0-edge.4",
59
- "@memberjunction/ng-entity-viewer": "6.2.0-edge.4",
60
- "@memberjunction/ng-explorer-settings": "6.2.0-edge.4",
61
- "@memberjunction/ng-export-service": "6.2.0-edge.4",
62
- "@memberjunction/ng-feedback": "6.2.0-edge.4",
63
- "@memberjunction/ng-file-storage": "6.2.0-edge.4",
64
- "@memberjunction/ng-generic-dialog": "6.2.0-edge.4",
65
- "@memberjunction/ng-list-detail-grid": "6.2.0-edge.4",
66
- "@memberjunction/ng-list-management": "6.2.0-edge.4",
67
- "@memberjunction/ng-markdown": "6.2.0-edge.4",
68
- "@memberjunction/ng-mj-livekit-room": "6.2.0-edge.4",
69
- "@memberjunction/ng-notifications": "6.2.0-edge.4",
70
- "@memberjunction/ng-pagination": "6.2.0-edge.4",
71
- "@memberjunction/ng-query-viewer": "6.2.0-edge.4",
72
- "@memberjunction/ng-realtime-media": "6.2.0-edge.4",
73
- "@memberjunction/ng-record-changes": "6.2.0-edge.4",
74
- "@memberjunction/ng-record-selector": "6.2.0-edge.4",
75
- "@memberjunction/ng-record-tags": "6.2.0-edge.4",
76
- "@memberjunction/ng-resource-permissions": "6.2.0-edge.4",
77
- "@memberjunction/ng-search": "6.2.0-edge.4",
78
- "@memberjunction/ng-shared": "6.2.0-edge.4",
79
- "@memberjunction/ng-shared-generic": "6.2.0-edge.4",
80
- "@memberjunction/ng-ui-components": "6.2.0-edge.4",
81
- "@memberjunction/ng-user-avatar": "6.2.0-edge.4",
82
- "@memberjunction/ng-word-cloud": "6.2.0-edge.4",
83
- "@memberjunction/templates-base-types": "6.2.0-edge.4",
32
+ "@memberjunction/ai-core-plus": "6.2.0-edge.5",
33
+ "@memberjunction/ai-engine-base": "6.2.0-edge.5",
34
+ "@memberjunction/communication-types": "6.2.0-edge.5",
35
+ "@memberjunction/conversations-runtime": "6.2.0-edge.5",
36
+ "@memberjunction/core": "6.2.0-edge.5",
37
+ "@memberjunction/core-entities": "6.2.0-edge.5",
38
+ "@memberjunction/entity-communications-client": "6.2.0-edge.5",
39
+ "@memberjunction/export-engine": "6.2.0-edge.5",
40
+ "@memberjunction/global": "6.2.0-edge.5",
41
+ "@memberjunction/graphql-dataprovider": "6.2.0-edge.5",
42
+ "@memberjunction/interactive-component-types": "6.2.0-edge.5",
43
+ "@memberjunction/lists-base": "6.2.0-edge.5",
44
+ "@memberjunction/theme-engine": "6.2.0-edge.5",
45
+ "@memberjunction/ng-ai-test-harness": "6.2.0-edge.5",
46
+ "@memberjunction/ng-artifacts": "6.2.0-edge.5",
47
+ "@memberjunction/ng-auth-services": "6.2.0-edge.5",
48
+ "@memberjunction/ng-base-application": "6.2.0-edge.5",
49
+ "@memberjunction/ng-base-forms": "6.2.0-edge.5",
50
+ "@memberjunction/ng-base-types": "6.2.0-edge.5",
51
+ "@memberjunction/ng-composer": "6.2.0-edge.5",
52
+ "@memberjunction/ng-container-directives": "6.2.0-edge.5",
53
+ "@memberjunction/ng-conversation-offers": "6.2.0-edge.5",
54
+ "@memberjunction/ng-conversations": "6.2.0-edge.5",
55
+ "@memberjunction/ng-dashboard-viewer": "6.2.0-edge.5",
56
+ "@memberjunction/ng-dashboards": "6.2.0-edge.5",
57
+ "@memberjunction/ng-entity-form-dialog": "6.2.0-edge.5",
58
+ "@memberjunction/ng-entity-permissions": "6.2.0-edge.5",
59
+ "@memberjunction/ng-entity-viewer": "6.2.0-edge.5",
60
+ "@memberjunction/ng-explorer-settings": "6.2.0-edge.5",
61
+ "@memberjunction/ng-export-service": "6.2.0-edge.5",
62
+ "@memberjunction/ng-feedback": "6.2.0-edge.5",
63
+ "@memberjunction/ng-file-storage": "6.2.0-edge.5",
64
+ "@memberjunction/ng-generic-dialog": "6.2.0-edge.5",
65
+ "@memberjunction/ng-list-detail-grid": "6.2.0-edge.5",
66
+ "@memberjunction/ng-list-management": "6.2.0-edge.5",
67
+ "@memberjunction/ng-markdown": "6.2.0-edge.5",
68
+ "@memberjunction/ng-mj-livekit-room": "6.2.0-edge.5",
69
+ "@memberjunction/ng-notifications": "6.2.0-edge.5",
70
+ "@memberjunction/ng-pagination": "6.2.0-edge.5",
71
+ "@memberjunction/ng-query-viewer": "6.2.0-edge.5",
72
+ "@memberjunction/ng-realtime-media": "6.2.0-edge.5",
73
+ "@memberjunction/ng-record-changes": "6.2.0-edge.5",
74
+ "@memberjunction/ng-record-selector": "6.2.0-edge.5",
75
+ "@memberjunction/ng-record-tags": "6.2.0-edge.5",
76
+ "@memberjunction/ng-resource-permissions": "6.2.0-edge.5",
77
+ "@memberjunction/ng-search": "6.2.0-edge.5",
78
+ "@memberjunction/ng-shared": "6.2.0-edge.5",
79
+ "@memberjunction/ng-shared-generic": "6.2.0-edge.5",
80
+ "@memberjunction/ng-ui-components": "6.2.0-edge.5",
81
+ "@memberjunction/ng-user-avatar": "6.2.0-edge.5",
82
+ "@memberjunction/ng-word-cloud": "6.2.0-edge.5",
83
+ "@memberjunction/templates-base-types": "6.2.0-edge.5",
84
84
  "angular-split": "^20.0.0",
85
85
  "golden-layout": "^2.6.0",
86
86
  "rxjs": "^7.8.2",
87
87
  "tslib": "^2.8.1",
88
- "@memberjunction/ng-react": "6.2.0-edge.4"
88
+ "@memberjunction/ng-react": "6.2.0-edge.5"
89
89
  },
90
90
  "sideEffects": false,
91
91
  "repository": {