@memberjunction/ng-dashboards 5.51.0 → 6.1.0-edge.1

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 (98) hide show
  1. package/LICENSE +7 -0
  2. package/dist/AI/components/agents/agent-configuration.component.d.ts.map +1 -1
  3. package/dist/AI/components/agents/agent-configuration.component.js +59 -63
  4. package/dist/AI/components/agents/agent-configuration.component.js.map +1 -1
  5. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts +7 -7
  6. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.d.ts.map +1 -1
  7. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js +21 -21
  8. package/dist/AI/components/autotagging/autotagging-pipeline-resource.component.js.map +1 -1
  9. package/dist/AI/components/autotagging/shared/classify.types.d.ts +4 -4
  10. package/dist/AI/components/autotagging/shared/classify.types.d.ts.map +1 -1
  11. package/dist/AI/components/autotagging/shared/classify.types.js.map +1 -1
  12. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +14 -19
  13. package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
  14. package/dist/AI/components/autotagging/tabs/sources-tab.component.js +53 -77
  15. package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
  16. package/dist/AI/components/models/model-management.component.d.ts.map +1 -1
  17. package/dist/AI/components/models/model-management.component.js +67 -70
  18. package/dist/AI/components/models/model-management.component.js.map +1 -1
  19. package/dist/AI/components/prompts/prompt-management.component.d.ts.map +1 -1
  20. package/dist/AI/components/prompts/prompt-management.component.js +55 -59
  21. package/dist/AI/components/prompts/prompt-management.component.js.map +1 -1
  22. package/dist/AI/components/system/system-configuration.component.d.ts.map +1 -1
  23. package/dist/AI/components/system/system-configuration.component.js +59 -63
  24. package/dist/AI/components/system/system-configuration.component.js.map +1 -1
  25. package/dist/AI/components/tags/tags-resource.component.d.ts +15 -20
  26. package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
  27. package/dist/AI/components/tags/tags-resource.component.js +51 -77
  28. package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
  29. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +1 -3
  30. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  31. package/dist/AI/components/vectors/vector-management-resource.component.js +22 -43
  32. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  33. package/dist/Actions/components/explorer/action-card.component.js +6 -6
  34. package/dist/Actions/components/explorer/action-card.component.js.map +1 -1
  35. package/dist/Actions/components/explorer/action-list-item.component.js +3 -3
  36. package/dist/Actions/components/explorer/action-list-item.component.js.map +1 -1
  37. package/dist/Actions/index.d.ts +0 -1
  38. package/dist/Actions/index.d.ts.map +1 -1
  39. package/dist/Actions/index.js +0 -1
  40. package/dist/Actions/index.js.map +1 -1
  41. package/dist/Admin/admin-dev-tools-resource.component.d.ts.map +1 -1
  42. package/dist/Admin/admin-dev-tools-resource.component.js +14 -0
  43. package/dist/Admin/admin-dev-tools-resource.component.js.map +1 -1
  44. package/dist/Admin/base-admin-container.component.d.ts.map +1 -1
  45. package/dist/Admin/base-admin-container.component.js +15 -0
  46. package/dist/Admin/base-admin-container.component.js.map +1 -1
  47. package/dist/DevTools/grid-width-lab.component.d.ts +78 -0
  48. package/dist/DevTools/grid-width-lab.component.d.ts.map +1 -0
  49. package/dist/DevTools/grid-width-lab.component.js +248 -0
  50. package/dist/DevTools/grid-width-lab.component.js.map +1 -0
  51. package/dist/DevTools/index.d.ts +2 -0
  52. package/dist/DevTools/index.d.ts.map +1 -1
  53. package/dist/DevTools/index.js +2 -0
  54. package/dist/DevTools/index.js.map +1 -1
  55. package/dist/DevTools/tab-strip-lab.component.d.ts +76 -0
  56. package/dist/DevTools/tab-strip-lab.component.d.ts.map +1 -0
  57. package/dist/DevTools/tab-strip-lab.component.js +247 -0
  58. package/dist/DevTools/tab-strip-lab.component.js.map +1 -0
  59. package/dist/Home/home-application.d.ts +5 -0
  60. package/dist/Home/home-application.d.ts.map +1 -1
  61. package/dist/Home/home-application.js +9 -0
  62. package/dist/Home/home-application.js.map +1 -1
  63. package/dist/Home/home-dashboard.component.d.ts.map +1 -1
  64. package/dist/Home/home-dashboard.component.js +0 -6
  65. package/dist/Home/home-dashboard.component.js.map +1 -1
  66. package/dist/SystemDiagnostics/system-diagnostics.component.d.ts +7 -3
  67. package/dist/SystemDiagnostics/system-diagnostics.component.d.ts.map +1 -1
  68. package/dist/SystemDiagnostics/system-diagnostics.component.js +22 -21
  69. package/dist/SystemDiagnostics/system-diagnostics.component.js.map +1 -1
  70. package/dist/Testing/components/testing-explorer.component.d.ts +9 -0
  71. package/dist/Testing/components/testing-explorer.component.d.ts.map +1 -1
  72. package/dist/Testing/components/testing-explorer.component.js +28 -5
  73. package/dist/Testing/components/testing-explorer.component.js.map +1 -1
  74. package/dist/actions-dashboards.module.d.ts +23 -24
  75. package/dist/actions-dashboards.module.d.ts.map +1 -1
  76. package/dist/actions-dashboards.module.js +0 -5
  77. package/dist/actions-dashboards.module.js.map +1 -1
  78. package/dist/ai-dashboards.module.d.ts +1 -1
  79. package/dist/ai-dashboards.module.d.ts.map +1 -1
  80. package/dist/ai-dashboards.module.js +4 -1
  81. package/dist/ai-dashboards.module.js.map +1 -1
  82. package/dist/core-dashboards.module.d.ts +46 -42
  83. package/dist/core-dashboards.module.d.ts.map +1 -1
  84. package/dist/core-dashboards.module.js +22 -0
  85. package/dist/core-dashboards.module.js.map +1 -1
  86. package/dist/public-api.d.ts +1 -1
  87. package/dist/public-api.d.ts.map +1 -1
  88. package/dist/public-api.js +1 -1
  89. package/dist/public-api.js.map +1 -1
  90. package/dist/shared/action-scheduled-job.d.ts +58 -0
  91. package/dist/shared/action-scheduled-job.d.ts.map +1 -0
  92. package/dist/shared/action-scheduled-job.js +77 -0
  93. package/dist/shared/action-scheduled-job.js.map +1 -0
  94. package/package.json +73 -70
  95. package/dist/Actions/components/scheduled-actions.component.d.ts +0 -16
  96. package/dist/Actions/components/scheduled-actions.component.d.ts.map +0 -1
  97. package/dist/Actions/components/scheduled-actions.component.js +0 -57
  98. package/dist/Actions/components/scheduled-actions.component.js.map +0 -1
@@ -0,0 +1,247 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Component } from '@angular/core';
8
+ import { BaseResourceComponent } from '@memberjunction/ng-shared';
9
+ import { RegisterClass } from '@memberjunction/global';
10
+ import { MJWorkspaceTabStore } from '@memberjunction/ng-ui-components';
11
+ import * as i0 from "@angular/core";
12
+ import * as i1 from "@memberjunction/ng-tabstrip";
13
+ import * as i2 from "@memberjunction/ng-ui-components";
14
+ function TabStripLabComponent_For_43_Template(rf, ctx) { if (rf & 1) {
15
+ i0.ɵɵelementStart(0, "mj-tab", 14);
16
+ i0.ɵɵtext(1);
17
+ i0.ɵɵelementEnd();
18
+ } if (rf & 2) {
19
+ const label_r1 = ctx.$implicit;
20
+ i0.ɵɵproperty("TabCloseable", true);
21
+ i0.ɵɵadvance();
22
+ i0.ɵɵtextInterpolate(label_r1);
23
+ } }
24
+ function TabStripLabComponent_For_45_Template(rf, ctx) { if (rf & 1) {
25
+ i0.ɵɵelementStart(0, "mj-tab-body")(1, "div", 16);
26
+ i0.ɵɵtext(2, "Body for ");
27
+ i0.ɵɵelementStart(3, "strong");
28
+ i0.ɵɵtext(4);
29
+ i0.ɵɵelementEnd()()();
30
+ } if (rf & 2) {
31
+ const label_r2 = ctx.$implicit;
32
+ i0.ɵɵadvance(4);
33
+ i0.ɵɵtextInterpolate(label_r2);
34
+ } }
35
+ function TabStripLabComponent_Conditional_55_Template(rf, ctx) { if (rf & 1) {
36
+ i0.ɵɵtext(0, " Body for ");
37
+ i0.ɵɵelementStart(1, "strong");
38
+ i0.ɵɵtext(2);
39
+ i0.ɵɵelementEnd();
40
+ i0.ɵɵelementStart(3, "span", 17);
41
+ i0.ɵɵtext(4);
42
+ i0.ɵɵelementEnd();
43
+ } if (rf & 2) {
44
+ const ctx_r2 = i0.ɵɵnextContext();
45
+ i0.ɵɵadvance(2);
46
+ i0.ɵɵtextInterpolate(ctx_r2.Store.ActiveTab.Label);
47
+ i0.ɵɵadvance(2);
48
+ i0.ɵɵtextInterpolate2("status: ", ctx_r2.Store.ActiveTab.Status, "", ctx_r2.Store.ActiveTab.Dirty ? " \u00B7 unsaved" : "");
49
+ } }
50
+ function TabStripLabComponent_Conditional_56_Template(rf, ctx) { if (rf & 1) {
51
+ i0.ɵɵelementStart(0, "em");
52
+ i0.ɵɵtext(1, "No tab selected \u2014 close them all to see the empty state.");
53
+ i0.ɵɵelementEnd();
54
+ } }
55
+ /**
56
+ * Tab Strip Lab — MJ's two tab strips, rendered side by side over the SAME labels.
57
+ *
58
+ * They are two components on purpose: `mj-tabstrip` takes tabs as projected children and addresses
59
+ * them by position (it owns their bodies), while `mj-workspace-tab-strip` takes a data array and
60
+ * addresses it by stable id (it projects nothing). Those are genuinely different API contracts.
61
+ * What they must NEVER differ on is how a tab looks or how it responds to a keyboard — and that is
62
+ * exactly the kind of drift no unit test catches and nobody notices until two screens sit side by
63
+ * side. Hence this page: the same four labels through both, so any divergence is immediate.
64
+ *
65
+ * Both get their chrome from the one global `.mj-tabs*` stylesheet and their keyboard behaviour
66
+ * from the one `mjTabList` directive, so a difference visible here is a bug in that sharing.
67
+ *
68
+ * 🚨 SAFETY BOUNDARY: deliberately unwired from agent context and client tools, as a developer
69
+ * fixture rather than a data surface (the GraphQL Console precedent). It reads and writes nothing.
70
+ */
71
+ let TabStripLabComponent = class TabStripLabComponent extends BaseResourceComponent {
72
+ cdr;
73
+ /** One source of labels for both strips — the comparison is worthless if they differ. */
74
+ Labels = ['Overview', 'Line items', 'A deliberately long tab label that must ellipsize', 'Audit'];
75
+ /**
76
+ * The projected strip's tabs, as mutable state: `mj-tabstrip` owns no tab array, so CLOSING a
77
+ * tab means the host removing it from the list it renders — a close with no `(BeforeTabClosed)`
78
+ * handler waits forever on the strip's cancelable-close contract and silently does nothing.
79
+ */
80
+ ProjectedLabels = [...this.Labels];
81
+ /** Drives the projected strip. */
82
+ ProjectedIndex = 0;
83
+ /**
84
+ * Drives the data-driven strip. Uses the real store rather than a hand-rolled array so the
85
+ * fixture also exercises open/close/reorder/neighbour-activation as shipped.
86
+ */
87
+ Store = new MJWorkspaceTabStore();
88
+ constructor(cdr) {
89
+ super();
90
+ this.cdr = cdr;
91
+ }
92
+ async GetResourceDisplayName() { return 'Tab Strip Lab'; }
93
+ async GetResourceIconClass() { return 'fa-solid fa-folder-tree'; }
94
+ /**
95
+ * Snapshot of `Store.Tabs`, reassigned by every handler. A getter delegating to the store
96
+ * returns a FRESH array per read, which both defeats the strip's OnPush change detection and
97
+ * trips dev-mode `ExpressionChanged` under default CD — the classic unstable-binding bug.
98
+ */
99
+ DraftTabs = [];
100
+ ngOnInit() {
101
+ this.ResetDraftTabs();
102
+ this.NotifyLoadComplete();
103
+ }
104
+ /**
105
+ * Seeded so every per-tab state the chrome can express is on screen at once — a plain tab, one
106
+ * with unsaved edits (dot), one rejected (warning tint + icon), one complete. Otherwise the
107
+ * states that only appear mid-workflow are the ones that quietly drift.
108
+ */
109
+ ResetDraftTabs() {
110
+ this.ProjectedLabels = [...this.Labels];
111
+ this.Store.Clear();
112
+ this.Labels.forEach((label, i) => {
113
+ this.Store.Open({
114
+ Id: `t${i}`,
115
+ Label: label,
116
+ Status: i === 2 ? 'rejected' : i === 3 ? 'complete' : 'draft',
117
+ Dirty: i === 1,
118
+ State: { Note: label },
119
+ });
120
+ });
121
+ this.Store.Activate('t0');
122
+ this.DraftTabs = this.Store.Tabs;
123
+ this.cdr.detectChanges();
124
+ }
125
+ OnDraftSelected(id) {
126
+ this.Store.Activate(id);
127
+ this.DraftTabs = this.Store.Tabs;
128
+ this.cdr.detectChanges();
129
+ }
130
+ OnDraftClosed(id) {
131
+ this.Store.Close(id);
132
+ this.DraftTabs = this.Store.Tabs;
133
+ this.cdr.detectChanges();
134
+ }
135
+ OnDraftReordered(move) {
136
+ this.Store.Reorder(move.previousIndex, move.currentIndex);
137
+ this.DraftTabs = this.Store.Tabs;
138
+ this.cdr.detectChanges();
139
+ }
140
+ OnDraftNew() {
141
+ const n = this.Store.Count + 1;
142
+ this.Store.Open({ Id: `new-${n}-${this.Labels.length}`, Label: `Draft ${n}`, Status: 'draft', State: { Note: '' } });
143
+ this.DraftTabs = this.Store.Tabs;
144
+ this.cdr.detectChanges();
145
+ }
146
+ OnProjectedTabSelect(event) {
147
+ this.ProjectedIndex = event.index;
148
+ this.cdr.detectChanges();
149
+ }
150
+ /**
151
+ * Complete the strip's close contract: `(TabClosed)` hands the host a `done` callback and the
152
+ * strip's `CloseTab` awaits it — the host removes the tab from ITS list (the strip owns no tab
153
+ * array) and signals done. Without a handler the promise never settles and the close button
154
+ * (and the Delete key) silently do nothing — the exact contract this page exists to demonstrate.
155
+ */
156
+ OnProjectedTabClosed(props) {
157
+ this.ProjectedLabels = this.ProjectedLabels.filter((_, i) => i !== props.index);
158
+ this.cdr.detectChanges();
159
+ props.done();
160
+ }
161
+ static ɵfac = function TabStripLabComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TabStripLabComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
162
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TabStripLabComponent, selectors: [["mj-tab-strip-lab"]], standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 57, vars: 3, consts: [[1, "mj-inspector", "mj-inspector--solo"], ["Role", "region", "AriaLabel", "Tab strip lab", "Title", "Tab Strip Lab", "Subtitle", "MJ's two tab strips over the same labels \u2014 they must be indistinguishable"], ["actions", ""], ["mjButton", "", "variant", "secondary", "size", "sm", "title", "Restore the seeded tabs", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-rotate-left"], [1, "mj-action-label"], [1, "mj-inspector__content"], [1, "tsl-note"], [1, "tsl-case"], [1, "tsl-case__head"], [1, "tsl-case__title"], [1, "tsl-case__meta"], [1, "tsl-case__stage"], [3, "TabSelected", "TabClosed"], [3, "TabCloseable"], ["NewTabLabel", "New draft", 3, "TabSelected", "TabClosed", "TabReordered", "NewTabRequested", "Tabs", "ActiveId"], [1, "tsl-body"], [1, "tsl-state"]], template: function TabStripLabComponent_Template(rf, ctx) { if (rf & 1) {
163
+ i0.ɵɵelementStart(0, "div", 0)(1, "mj-page-header-interior", 1)(2, "div", 2)(3, "button", 3);
164
+ i0.ɵɵlistener("click", function TabStripLabComponent_Template_button_click_3_listener() { return ctx.ResetDraftTabs(); });
165
+ i0.ɵɵelement(4, "i", 4);
166
+ i0.ɵɵelementStart(5, "span", 5);
167
+ i0.ɵɵtext(6, "Reset");
168
+ i0.ɵɵelementEnd()()()();
169
+ i0.ɵɵelementStart(7, "div", 6)(8, "p", 7);
170
+ i0.ɵɵtext(9, " Both strips draw from the one global ");
171
+ i0.ɵɵelementStart(10, "code");
172
+ i0.ɵɵtext(11, ".mj-tabs*");
173
+ i0.ɵɵelementEnd();
174
+ i0.ɵɵtext(12, " stylesheet and get their keyboard behaviour from the one ");
175
+ i0.ɵɵelementStart(13, "code");
176
+ i0.ɵɵtext(14, "mjTabList");
177
+ i0.ɵɵelementEnd();
178
+ i0.ɵɵtext(15, " directive. Any visual or behavioural difference between the two below is a bug in that sharing, not a styling choice. ");
179
+ i0.ɵɵelementStart(16, "strong");
180
+ i0.ɵɵtext(17, "Keyboard:");
181
+ i0.ɵɵelementEnd();
182
+ i0.ɵɵtext(18, " Tab into a strip (it is a single tab stop), then ");
183
+ i0.ɵɵelementStart(19, "kbd");
184
+ i0.ɵɵtext(20, "\u2190");
185
+ i0.ɵɵelementEnd();
186
+ i0.ɵɵtext(21, "/");
187
+ i0.ɵɵelementStart(22, "kbd");
188
+ i0.ɵɵtext(23, "\u2192");
189
+ i0.ɵɵelementEnd();
190
+ i0.ɵɵtext(24, " to move, ");
191
+ i0.ɵɵelementStart(25, "kbd");
192
+ i0.ɵɵtext(26, "Home");
193
+ i0.ɵɵelementEnd();
194
+ i0.ɵɵtext(27, "/");
195
+ i0.ɵɵelementStart(28, "kbd");
196
+ i0.ɵɵtext(29, "End");
197
+ i0.ɵɵelementEnd();
198
+ i0.ɵɵtext(30, " for the ends, ");
199
+ i0.ɵɵelementStart(31, "kbd");
200
+ i0.ɵɵtext(32, "Delete");
201
+ i0.ɵɵelementEnd();
202
+ i0.ɵɵtext(33, " to close a closeable tab. ");
203
+ i0.ɵɵelementEnd();
204
+ i0.ɵɵelementStart(34, "section", 8)(35, "header", 9)(36, "h4", 10);
205
+ i0.ɵɵtext(37, "<mj-tabstrip>");
206
+ i0.ɵɵelementEnd();
207
+ i0.ɵɵelementStart(38, "span", 11);
208
+ i0.ɵɵtext(39, "projected children \u00B7 addressed by index \u00B7 owns its bodies");
209
+ i0.ɵɵelementEnd()();
210
+ i0.ɵɵelementStart(40, "div", 12)(41, "mj-tabstrip", 13);
211
+ i0.ɵɵlistener("TabSelected", function TabStripLabComponent_Template_mj_tabstrip_TabSelected_41_listener($event) { return ctx.OnProjectedTabSelect($event); })("TabClosed", function TabStripLabComponent_Template_mj_tabstrip_TabClosed_41_listener($event) { return ctx.OnProjectedTabClosed($event); });
212
+ i0.ɵɵrepeaterCreate(42, TabStripLabComponent_For_43_Template, 2, 2, "mj-tab", 14, i0.ɵɵrepeaterTrackByIdentity);
213
+ i0.ɵɵrepeaterCreate(44, TabStripLabComponent_For_45_Template, 5, 1, "mj-tab-body", null, i0.ɵɵrepeaterTrackByIdentity);
214
+ i0.ɵɵelementEnd()()();
215
+ i0.ɵɵelementStart(46, "section", 8)(47, "header", 9)(48, "h4", 10);
216
+ i0.ɵɵtext(49, "<mj-workspace-tab-strip>");
217
+ i0.ɵɵelementEnd();
218
+ i0.ɵɵelementStart(50, "span", 11);
219
+ i0.ɵɵtext(51, "data array \u00B7 addressed by id \u00B7 projects nothing \u00B7 drag to reorder");
220
+ i0.ɵɵelementEnd()();
221
+ i0.ɵɵelementStart(52, "div", 12)(53, "mj-workspace-tab-strip", 15);
222
+ i0.ɵɵlistener("TabSelected", function TabStripLabComponent_Template_mj_workspace_tab_strip_TabSelected_53_listener($event) { return ctx.OnDraftSelected($event); })("TabClosed", function TabStripLabComponent_Template_mj_workspace_tab_strip_TabClosed_53_listener($event) { return ctx.OnDraftClosed($event); })("TabReordered", function TabStripLabComponent_Template_mj_workspace_tab_strip_TabReordered_53_listener($event) { return ctx.OnDraftReordered($event); })("NewTabRequested", function TabStripLabComponent_Template_mj_workspace_tab_strip_NewTabRequested_53_listener() { return ctx.OnDraftNew(); });
223
+ i0.ɵɵelementEnd();
224
+ i0.ɵɵelementStart(54, "div", 16);
225
+ i0.ɵɵconditionalCreate(55, TabStripLabComponent_Conditional_55_Template, 5, 3)(56, TabStripLabComponent_Conditional_56_Template, 2, 0, "em");
226
+ i0.ɵɵelementEnd()()()()();
227
+ } if (rf & 2) {
228
+ i0.ɵɵadvance(42);
229
+ i0.ɵɵrepeater(ctx.ProjectedLabels);
230
+ i0.ɵɵadvance(2);
231
+ i0.ɵɵrepeater(ctx.ProjectedLabels);
232
+ i0.ɵɵadvance(9);
233
+ i0.ɵɵproperty("Tabs", ctx.DraftTabs)("ActiveId", ctx.Store.ActiveId);
234
+ i0.ɵɵadvance(2);
235
+ i0.ɵɵconditional(ctx.Store.ActiveTab ? 55 : 56);
236
+ } }, dependencies: [i1.MJTabStripComponent, i1.MJTabBodyComponent, i1.MJTabComponent, i2.MJWorkspaceTabStripComponent, i2.MJButtonDirective, i2.MJPageHeaderInteriorComponent], styles: ["[_nghost-%COMP%] { display: block; height: 100%; }\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n.mj-inspector[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n font-family: inherit;\n}\n\n\n\n.mj-inspector__content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-page);\n}\n.mj-inspector__content-head[_ngcontent-%COMP%] {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--mj-bg-surface-card);\n}\n.mj-inspector__content-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.mj-inspector__content-meta[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n.mj-inspector__editor[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n.mj-inspector__editor[_ngcontent-%COMP%] mj-code-editor[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n display: block;\n}\n\n\n\n.mj-inspector__empty[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}", "\n\n\n\n\n.tsl-note[_ngcontent-%COMP%] {\n margin: 0 0 16px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 12px;\n line-height: 1.6;\n color: var(--mj-text-secondary);\n}\n.tsl-note[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n padding: 1px 5px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n}\n.tsl-note[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\n padding: 1px 6px;\n border: 1px solid var(--mj-border-default);\n border-bottom-width: 2px;\n border-radius: 4px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n font-size: 11px;\n}\n\n.tsl-case[_ngcontent-%COMP%] {\n margin-bottom: 22px;\n}\n\n.tsl-case__head[_ngcontent-%COMP%] {\n display: flex;\n align-items: baseline;\n gap: 10px;\n flex-wrap: wrap;\n margin-bottom: 8px;\n}\n\n.tsl-case__title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.tsl-case__meta[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n\n\n\n.tsl-case__stage[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.tsl-body[_ngcontent-%COMP%] {\n padding: 14px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.tsl-state[_ngcontent-%COMP%] {\n margin-left: 10px;\n color: var(--mj-text-muted);\n}"] });
237
+ };
238
+ TabStripLabComponent = __decorate([
239
+ RegisterClass(BaseResourceComponent, 'TabStripLabInspector')
240
+ ], TabStripLabComponent);
241
+ export { TabStripLabComponent };
242
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TabStripLabComponent, [{
243
+ type: Component,
244
+ args: [{ standalone: false, selector: 'mj-tab-strip-lab', template: "<div class=\"mj-inspector mj-inspector--solo\">\n <mj-page-header-interior\n Role=\"region\"\n AriaLabel=\"Tab strip lab\"\n Title=\"Tab Strip Lab\"\n Subtitle=\"MJ's two tab strips over the same labels \u2014 they must be indistinguishable\">\n <div actions>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"ResetDraftTabs()\" title=\"Restore the seeded tabs\">\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n <span class=\"mj-action-label\">Reset</span>\n </button>\n </div>\n </mj-page-header-interior>\n\n <div class=\"mj-inspector__content\">\n <p class=\"tsl-note\">\n Both strips draw from the one global <code>.mj-tabs*</code> stylesheet and get their keyboard\n behaviour from the one <code>mjTabList</code> directive. Any visual or behavioural difference\n between the two below is a bug in that sharing, not a styling choice.\n <strong>Keyboard:</strong> Tab into a strip (it is a single tab stop), then\n <kbd>\u2190</kbd>/<kbd>\u2192</kbd> to move, <kbd>Home</kbd>/<kbd>End</kbd> for the ends,\n <kbd>Delete</kbd> to close a closeable tab.\n </p>\n\n <!-- 1. Projected-children strip ------------------------------------------------------ -->\n <section class=\"tsl-case\">\n <header class=\"tsl-case__head\">\n <h4 class=\"tsl-case__title\">&lt;mj-tabstrip&gt;</h4>\n <span class=\"tsl-case__meta\">projected children \u00B7 addressed by index \u00B7 owns its bodies</span>\n </header>\n <div class=\"tsl-case__stage\">\n <mj-tabstrip (TabSelected)=\"OnProjectedTabSelect($event)\" (TabClosed)=\"OnProjectedTabClosed($event)\">\n @for (label of ProjectedLabels; track label) {\n <mj-tab [TabCloseable]=\"true\">{{ label }}</mj-tab>\n }\n @for (label of ProjectedLabels; track label) {\n <mj-tab-body>\n <div class=\"tsl-body\">Body for <strong>{{ label }}</strong></div>\n </mj-tab-body>\n }\n </mj-tabstrip>\n </div>\n </section>\n\n <!-- 2. Data-driven strip -------------------------------------------------------------- -->\n <section class=\"tsl-case\">\n <header class=\"tsl-case__head\">\n <h4 class=\"tsl-case__title\">&lt;mj-workspace-tab-strip&gt;</h4>\n <span class=\"tsl-case__meta\">data array \u00B7 addressed by id \u00B7 projects nothing \u00B7 drag to reorder</span>\n </header>\n <div class=\"tsl-case__stage\">\n <mj-workspace-tab-strip\n [Tabs]=\"DraftTabs\"\n [ActiveId]=\"Store.ActiveId\"\n NewTabLabel=\"New draft\"\n (TabSelected)=\"OnDraftSelected($event)\"\n (TabClosed)=\"OnDraftClosed($event)\"\n (TabReordered)=\"OnDraftReordered($event)\"\n (NewTabRequested)=\"OnDraftNew()\">\n </mj-workspace-tab-strip>\n <!-- This strip projects no bodies: the host renders whatever the active tab means.\n Shown here so the two cases are visually comparable end to end. -->\n <div class=\"tsl-body\">\n @if (Store.ActiveTab) {\n Body for <strong>{{ Store.ActiveTab.Label }}</strong>\n <span class=\"tsl-state\">status: {{ Store.ActiveTab.Status }}{{ Store.ActiveTab.Dirty ? ' \u00B7 unsaved' : '' }}</span>\n } @else {\n <em>No tab selected \u2014 close them all to see the empty state.</em>\n }\n </div>\n </div>\n </section>\n </div>\n</div>\n", styles: [":host { display: block; height: 100%; }\n\n/*\n Inspector shell \u2014 each Dev Tools sub-page wraps its body in .mj-inspector. The\n chrome (title icon, title, subtitle, action buttons) was previously rendered\n via .mj-inspector__header*, but that's been replaced by <mj-page-header-interior>\n in every inspector template. Action buttons now use the mjButton directive\n (variant=\"secondary\" / \"success\") so they inherit global button styling. App\n State + Layout inspectors used to carry an inner left rail (.mj-inspector__body\n + __sidebar + __nav-item) for L2 sections; that rail was retired 2026-05-19 in\n favor of <mj-tab-nav> projected into the chrome's [toolbar] slot, matching\n SystemDiagnostics and the API Keys tab strip. All inspectors are now \"solo\"\n mode (no sidebar).\n*/\n.mj-inspector {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n font-family: inherit;\n}\n\n/* Content area */\n.mj-inspector__content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-page);\n}\n.mj-inspector__content-head {\n padding: 12px 20px;\n border-bottom: 1px solid var(--mj-border-subtle);\n display: flex;\n align-items: center;\n justify-content: space-between;\n background: var(--mj-bg-surface-card);\n}\n.mj-inspector__content-title {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n.mj-inspector__content-meta {\n font-size: 11px;\n color: var(--mj-text-muted);\n}\n.mj-inspector__editor {\n flex: 1;\n min-height: 0;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n.mj-inspector__editor mj-code-editor {\n flex: 1;\n min-height: 0;\n display: block;\n}\n\n/* Empty state */\n.mj-inspector__empty {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: 13px;\n}\n\n", "/* Fixture chrome only. Nothing here may style a tab \u2014 the whole point of the page is that tabs get\n their appearance from the shared global `.mj-tabs*` sheet, so a local override would hide exactly\n the drift this page exists to expose. */\n\n.tsl-note {\n margin: 0 0 16px;\n padding: 10px 14px;\n background: var(--mj-bg-surface-card);\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n font-size: 12px;\n line-height: 1.6;\n color: var(--mj-text-secondary);\n}\n.tsl-note code {\n padding: 1px 5px;\n border-radius: 3px;\n background: var(--mj-bg-surface-sunken);\n}\n.tsl-note kbd {\n padding: 1px 6px;\n border: 1px solid var(--mj-border-default);\n border-bottom-width: 2px;\n border-radius: 4px;\n background: var(--mj-bg-surface);\n font-family: inherit;\n font-size: 11px;\n}\n\n.tsl-case {\n margin-bottom: 22px;\n}\n\n.tsl-case__head {\n display: flex;\n align-items: baseline;\n gap: 10px;\n flex-wrap: wrap;\n margin-bottom: 8px;\n}\n\n.tsl-case__title {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.tsl-case__meta {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n/* The stage deliberately mimics a card, because that is the context the tab chrome is drawn for \u2014\n the bar's bottom rule and the active tab's surface only read correctly against one. */\n.tsl-case__stage {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 12px;\n overflow: hidden;\n}\n\n.tsl-body {\n padding: 14px;\n font-size: 13px;\n color: var(--mj-text-secondary);\n}\n\n.tsl-state {\n margin-left: 10px;\n color: var(--mj-text-muted);\n}\n"] }]
245
+ }], () => [{ type: i0.ChangeDetectorRef }], null); })();
246
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TabStripLabComponent, { className: "TabStripLabComponent", filePath: "src/DevTools/tab-strip-lab.component.ts", lineNumber: 30 }); })();
247
+ //# sourceMappingURL=tab-strip-lab.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-strip-lab.component.js","sourceRoot":"","sources":["../../src/DevTools/tab-strip-lab.component.ts","../../src/DevTools/tab-strip-lab.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, OnInit, ChangeDetectorRef } from '@angular/core';\nimport { BaseResourceComponent } from '@memberjunction/ng-shared';\nimport { RegisterClass } from '@memberjunction/global';\nimport { MJWorkspaceTab, MJWorkspaceTabStore, MJTabReorder } from '@memberjunction/ng-ui-components';\nimport { TabClosedEvent } from '@memberjunction/ng-tabstrip';\n\n/**\n * Tab Strip Lab — MJ's two tab strips, rendered side by side over the SAME labels.\n *\n * They are two components on purpose: `mj-tabstrip` takes tabs as projected children and addresses\n * them by position (it owns their bodies), while `mj-workspace-tab-strip` takes a data array and\n * addresses it by stable id (it projects nothing). Those are genuinely different API contracts.\n * What they must NEVER differ on is how a tab looks or how it responds to a keyboard — and that is\n * exactly the kind of drift no unit test catches and nobody notices until two screens sit side by\n * side. Hence this page: the same four labels through both, so any divergence is immediate.\n *\n * Both get their chrome from the one global `.mj-tabs*` stylesheet and their keyboard behaviour\n * from the one `mjTabList` directive, so a difference visible here is a bug in that sharing.\n *\n * 🚨 SAFETY BOUNDARY: deliberately unwired from agent context and client tools, as a developer\n * fixture rather than a data surface (the GraphQL Console precedent). It reads and writes nothing.\n */\n@RegisterClass(BaseResourceComponent, 'TabStripLabInspector')\n@Component({\n standalone: false,\n selector: 'mj-tab-strip-lab',\n templateUrl: './tab-strip-lab.component.html',\n styleUrls: ['./inspector-shared.css', './tab-strip-lab.component.css']\n})\nexport class TabStripLabComponent extends BaseResourceComponent implements OnInit {\n /** One source of labels for both strips — the comparison is worthless if they differ. */\n public readonly Labels: string[] = ['Overview', 'Line items', 'A deliberately long tab label that must ellipsize', 'Audit'];\n\n /**\n * The projected strip's tabs, as mutable state: `mj-tabstrip` owns no tab array, so CLOSING a\n * tab means the host removing it from the list it renders — a close with no `(BeforeTabClosed)`\n * handler waits forever on the strip's cancelable-close contract and silently does nothing.\n */\n public ProjectedLabels: string[] = [...this.Labels];\n\n /** Drives the projected strip. */\n public ProjectedIndex = 0;\n\n /**\n * Drives the data-driven strip. Uses the real store rather than a hand-rolled array so the\n * fixture also exercises open/close/reorder/neighbour-activation as shipped.\n */\n public readonly Store = new MJWorkspaceTabStore<{ Note: string }>();\n\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n\n public override async GetResourceDisplayName(): Promise<string> { return 'Tab Strip Lab'; }\n public override async GetResourceIconClass(): Promise<string> { return 'fa-solid fa-folder-tree'; }\n\n /**\n * Snapshot of `Store.Tabs`, reassigned by every handler. A getter delegating to the store\n * returns a FRESH array per read, which both defeats the strip's OnPush change detection and\n * trips dev-mode `ExpressionChanged` under default CD — the classic unstable-binding bug.\n */\n public DraftTabs: MJWorkspaceTab<{ Note: string }>[] = [];\n\n public ngOnInit(): void {\n this.ResetDraftTabs();\n this.NotifyLoadComplete();\n }\n\n /**\n * Seeded so every per-tab state the chrome can express is on screen at once — a plain tab, one\n * with unsaved edits (dot), one rejected (warning tint + icon), one complete. Otherwise the\n * states that only appear mid-workflow are the ones that quietly drift.\n */\n public ResetDraftTabs(): void {\n this.ProjectedLabels = [...this.Labels];\n this.Store.Clear();\n this.Labels.forEach((label, i) => {\n this.Store.Open({\n Id: `t${i}`,\n Label: label,\n Status: i === 2 ? 'rejected' : i === 3 ? 'complete' : 'draft',\n Dirty: i === 1,\n State: { Note: label },\n });\n });\n this.Store.Activate('t0');\n this.DraftTabs = this.Store.Tabs;\n this.cdr.detectChanges();\n }\n\n public OnDraftSelected(id: string): void {\n this.Store.Activate(id);\n this.DraftTabs = this.Store.Tabs;\n this.cdr.detectChanges();\n }\n\n public OnDraftClosed(id: string): void {\n this.Store.Close(id);\n this.DraftTabs = this.Store.Tabs;\n this.cdr.detectChanges();\n }\n\n public OnDraftReordered(move: MJTabReorder): void {\n this.Store.Reorder(move.previousIndex, move.currentIndex);\n this.DraftTabs = this.Store.Tabs;\n this.cdr.detectChanges();\n }\n\n public OnDraftNew(): void {\n const n = this.Store.Count + 1;\n this.Store.Open({ Id: `new-${n}-${this.Labels.length}`, Label: `Draft ${n}`, Status: 'draft', State: { Note: '' } });\n this.DraftTabs = this.Store.Tabs;\n this.cdr.detectChanges();\n }\n\n public OnProjectedTabSelect(event: { index: number }): void {\n this.ProjectedIndex = event.index;\n this.cdr.detectChanges();\n }\n\n /**\n * Complete the strip's close contract: `(TabClosed)` hands the host a `done` callback and the\n * strip's `CloseTab` awaits it — the host removes the tab from ITS list (the strip owns no tab\n * array) and signals done. Without a handler the promise never settles and the close button\n * (and the Delete key) silently do nothing — the exact contract this page exists to demonstrate.\n */\n public OnProjectedTabClosed(props: TabClosedEvent): void {\n this.ProjectedLabels = this.ProjectedLabels.filter((_, i) => i !== props.index);\n this.cdr.detectChanges();\n props.done();\n }\n}\n","<div class=\"mj-inspector mj-inspector--solo\">\n <mj-page-header-interior\n Role=\"region\"\n AriaLabel=\"Tab strip lab\"\n Title=\"Tab Strip Lab\"\n Subtitle=\"MJ's two tab strips over the same labels — they must be indistinguishable\">\n <div actions>\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"ResetDraftTabs()\" title=\"Restore the seeded tabs\">\n <i class=\"fa-solid fa-rotate-left\" aria-hidden=\"true\"></i>\n <span class=\"mj-action-label\">Reset</span>\n </button>\n </div>\n </mj-page-header-interior>\n\n <div class=\"mj-inspector__content\">\n <p class=\"tsl-note\">\n Both strips draw from the one global <code>.mj-tabs*</code> stylesheet and get their keyboard\n behaviour from the one <code>mjTabList</code> directive. Any visual or behavioural difference\n between the two below is a bug in that sharing, not a styling choice.\n <strong>Keyboard:</strong> Tab into a strip (it is a single tab stop), then\n <kbd>←</kbd>/<kbd>→</kbd> to move, <kbd>Home</kbd>/<kbd>End</kbd> for the ends,\n <kbd>Delete</kbd> to close a closeable tab.\n </p>\n\n <!-- 1. Projected-children strip ------------------------------------------------------ -->\n <section class=\"tsl-case\">\n <header class=\"tsl-case__head\">\n <h4 class=\"tsl-case__title\">&lt;mj-tabstrip&gt;</h4>\n <span class=\"tsl-case__meta\">projected children · addressed by index · owns its bodies</span>\n </header>\n <div class=\"tsl-case__stage\">\n <mj-tabstrip (TabSelected)=\"OnProjectedTabSelect($event)\" (TabClosed)=\"OnProjectedTabClosed($event)\">\n @for (label of ProjectedLabels; track label) {\n <mj-tab [TabCloseable]=\"true\">{{ label }}</mj-tab>\n }\n @for (label of ProjectedLabels; track label) {\n <mj-tab-body>\n <div class=\"tsl-body\">Body for <strong>{{ label }}</strong></div>\n </mj-tab-body>\n }\n </mj-tabstrip>\n </div>\n </section>\n\n <!-- 2. Data-driven strip -------------------------------------------------------------- -->\n <section class=\"tsl-case\">\n <header class=\"tsl-case__head\">\n <h4 class=\"tsl-case__title\">&lt;mj-workspace-tab-strip&gt;</h4>\n <span class=\"tsl-case__meta\">data array · addressed by id · projects nothing · drag to reorder</span>\n </header>\n <div class=\"tsl-case__stage\">\n <mj-workspace-tab-strip\n [Tabs]=\"DraftTabs\"\n [ActiveId]=\"Store.ActiveId\"\n NewTabLabel=\"New draft\"\n (TabSelected)=\"OnDraftSelected($event)\"\n (TabClosed)=\"OnDraftClosed($event)\"\n (TabReordered)=\"OnDraftReordered($event)\"\n (NewTabRequested)=\"OnDraftNew()\">\n </mj-workspace-tab-strip>\n <!-- This strip projects no bodies: the host renders whatever the active tab means.\n Shown here so the two cases are visually comparable end to end. -->\n <div class=\"tsl-body\">\n @if (Store.ActiveTab) {\n Body for <strong>{{ Store.ActiveTab.Label }}</strong>\n <span class=\"tsl-state\">status: {{ Store.ActiveTab.Status }}{{ Store.ActiveTab.Dirty ? ' · unsaved' : '' }}</span>\n } @else {\n <em>No tab selected — close them all to see the empty state.</em>\n }\n </div>\n </div>\n </section>\n </div>\n</div>\n"]}
@@ -50,6 +50,11 @@ export declare class HomeApplication extends BaseApplication {
50
50
  * Returns navigation items including dynamic items for recently visited orphan resources.
51
51
  * Static items come from DefaultNavItems in metadata.
52
52
  * Dynamic items are generated from the recent orphan stack (up to 3).
53
+ *
54
+ * Records style (Shell.RecordOpen.Style = 'records', the default): dynamic
55
+ * items are SKIPPED — the shell's Records pill + strip represent open
56
+ * records globally, and Home's own stack would double-represent records
57
+ * opened from Home. Classic style keeps this behavior as-is.
53
58
  */
54
59
  GetNavItems(): Promise<NavItem[]>;
55
60
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"home-application.d.ts","sourceRoot":"","sources":["../../src/Home/home-application.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAkB,OAAO,EAAE,qBAAqB,EAAgB,MAAM,qCAAqC,CAAC;AACpI,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAiC1D;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,eAAgB,SAAQ,eAAe;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAK;IAE7C,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,iBAAiB,CAAgC;IACzD,OAAO,CAAC,mBAAmB,CAA8B;IAEzD;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB,CAAuB;IAEtD;;;OAGG;IACI,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAOhE;;OAEG;IACI,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAIrD;;;;OAIG;IACY,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAwBhD;;;;OAIG;IACI,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAiBhD;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAe7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAuBnB;;;;;;OAMG;YACW,iBAAiB;IAqE/B;;;;;;;;;;;;;OAaG;YACW,4BAA4B;IAsB1C;;;;OAIG;YACW,sBAAsB;IAgCpC;;OAEG;YACW,oBAAoB;IAoBlC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAsB5B;;;;;;;;;;OAUG;YACW,kBAAkB;IAwBhC;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;;OAGG;IACH,OAAO,CAAC,SAAS;IAiBjB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA4B1B;;;OAGG;YACW,oBAAoB;CAsBnC"}
1
+ {"version":3,"file":"home-application.d.ts","sourceRoot":"","sources":["../../src/Home/home-application.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAkB,OAAO,EAAE,qBAAqB,EAAgB,MAAM,qCAAqC,CAAC;AACpI,OAAO,EAAE,aAAa,EAAqB,MAAM,2BAA2B,CAAC;AAiC7E;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,eAAgB,SAAQ,eAAe;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAK;IAE7C,OAAO,CAAC,gBAAgB,CAAsC;IAC9D,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,iBAAiB,CAAgC;IACzD,OAAO,CAAC,mBAAmB,CAA8B;IAEzD;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB,CAAuB;IAEtD;;;OAGG;IACI,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAOhE;;OAEG;IACI,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAIrD;;;;;;;;;OASG;IACY,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IA4BhD;;;;OAIG;IACI,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAiBhD;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAe7B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAezB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAuBnB;;;;;;OAMG;YACW,iBAAiB;IAqE/B;;;;;;;;;;;;;OAaG;YACW,4BAA4B;IAsB1C;;;;OAIG;YACW,sBAAsB;IAgCpC;;OAEG;YACW,oBAAoB;IAoBlC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAsB5B;;;;;;;;;;OAUG;YACW,kBAAkB;IAwBhC;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;;OAGG;IACH,OAAO,CAAC,SAAS;IAiBjB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA4B1B;;;OAGG;YACW,oBAAoB;CAsBnC"}
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var HomeApplication_1;
8
8
  import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
9
9
  import { BaseApplication } from '@memberjunction/ng-base-application';
10
+ import { IsRecordTabsStyle } from '@memberjunction/ng-shared';
10
11
  import { CompositeKey, FieldValueCollection } from '@memberjunction/core';
11
12
  /** Storage key and category for persisting the recent orphan stack */
12
13
  const STORAGE_KEY = 'HomeApp_RecentOrphanStack';
@@ -71,8 +72,16 @@ let HomeApplication = class HomeApplication extends BaseApplication {
71
72
  * Returns navigation items including dynamic items for recently visited orphan resources.
72
73
  * Static items come from DefaultNavItems in metadata.
73
74
  * Dynamic items are generated from the recent orphan stack (up to 3).
75
+ *
76
+ * Records style (Shell.RecordOpen.Style = 'records', the default): dynamic
77
+ * items are SKIPPED — the shell's Records pill + strip represent open
78
+ * records globally, and Home's own stack would double-represent records
79
+ * opened from Home. Classic style keeps this behavior as-is.
74
80
  */
75
81
  async GetNavItems() {
82
+ if (IsRecordTabsStyle()) {
83
+ return super.GetNavItems();
84
+ }
76
85
  // Ensure persisted stack is loaded before building nav items.
77
86
  // On first call after page load, this awaits the IndexedDB read;
78
87
  // on subsequent calls the promise is already resolved (no-op await).
@@ -1 +1 @@
1
- {"version":3,"file":"home-application.js","sourceRoot":"","sources":["../../src/Home/home-application.ts"],"names":[],"mappings":"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","sourcesContent":["import { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { BaseApplication, DynamicNavItem, NavItem, WorkspaceStateManager, WorkspaceTab } from '@memberjunction/ng-base-application';\nimport { SharedService } from '@memberjunction/ng-shared';\nimport { Metadata, CompositeKey, FieldValueCollection } from '@memberjunction/core';\n\n/** Storage key and category for persisting the recent orphan stack */\nconst STORAGE_KEY = 'HomeApp_RecentOrphanStack';\nconst STORAGE_CATEGORY = 'HomeApplication';\n\n/**\n * Snapshot of an orphan resource tab for the recent navigation stack.\n * Persisted to localStorage (via Provider) so it survives page reloads.\n */\ninterface OrphanResourceSnapshot {\n /** URL-encoded composite key segment — primary dedup key */\n resourceRecordId: string;\n /** Resource type name (e.g., 'record', 'Dashboards') */\n resourceType: string;\n /** Entity name from tab configuration (for record name resolution) */\n entityName?: string;\n /** Tab title at time of capture (fallback label) */\n title: string;\n /** Resolved display label (cached record name). Persisted to avoid async lookups on reload. */\n resolvedLabel: string;\n /** Full tab configuration (passed to DynamicNavItem for re-opening) */\n configuration: Record<string, unknown>;\n /** Tab ID for fallback matching when no resourceRecordId */\n tabId: string;\n /** Timestamp (ms since epoch) when this snapshot was created or last promoted */\n timestamp: number;\n}\n\n/** Max age for persisted snapshots — 7 days */\nconst MAX_SNAPSHOT_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * Home Application - Provides dynamic navigation items for orphan resources.\n *\n * Maintains a recency-ordered stack of up to 3 recently visited orphan resources.\n * When the user opens a record/view/dashboard from within the Home app, the resource\n * appears as a dynamic nav item. When they navigate away (e.g., click Home), the\n * nav item persists so they can quickly jump back. Older items drop off as new ones\n * are added.\n *\n * The stack is persisted to localStorage (via Metadata.Provider.LocalStorageProvider)\n * so it survives page reloads. Resolved record labels are stored alongside each\n * snapshot to avoid async lookups when restoring from storage.\n *\n * @example\n * User opens \"John Smith\" contact, then \"Acme Corp\" company:\n * - Nav shows: [Home] [Favorites] | [person] \"Acme Corp\" [building] \"John Smith\"\n * - Clicking \"John Smith\" re-opens that record\n */\n@RegisterClass(BaseApplication, 'HomeApplication')\nexport class HomeApplication extends BaseApplication {\n private static readonly MAX_RECENT_ITEMS = 3;\n\n private workspaceManager: WorkspaceStateManager | null = null;\n private sharedService: SharedService | null = null;\n private recentOrphanStack: OrphanResourceSnapshot[] = [];\n private _storageLoadPromise: Promise<void> | null = null;\n\n /**\n * Fingerprint of the last-processed active tab state (tabId::resourceRecordId::title).\n * Guards against redundant stack mutations while still detecting content changes.\n * In single-resource mode the tab ID stays constant when navigating between records\n * (OpenTab replaces the temp tab's content but keeps its ID), so we must also\n * include the resourceRecordId to detect when the tab shows a different record.\n *\n * Title is also included so an in-place display-name change (e.g. user edits a\n * record's Name field and saves — tabId and resourceRecordId stay the same but the\n * title changes) triggers a re-evaluation. Without this, the dynamic nav item keeps\n * showing the pre-edit name forever.\n */\n private _lastSeenTabFingerprint: string | null = null;\n\n /**\n * Inject WorkspaceStateManager for accessing current tab state.\n * Also triggers loading the persisted stack from storage on first call.\n */\n public SetWorkspaceManager(manager: WorkspaceStateManager): void {\n this.workspaceManager = manager;\n if (!this._storageLoadPromise) {\n this._storageLoadPromise = this.loadStackFromStorage();\n }\n }\n\n /**\n * Inject SharedService for accessing ResourceTypes metadata\n */\n public SetSharedService(service: SharedService): void {\n this.sharedService = service;\n }\n\n /**\n * Returns navigation items including dynamic items for recently visited orphan resources.\n * Static items come from DefaultNavItems in metadata.\n * Dynamic items are generated from the recent orphan stack (up to 3).\n */\n override async GetNavItems(): Promise<NavItem[]> {\n // Ensure persisted stack is loaded before building nav items.\n // On first call after page load, this awaits the IndexedDB read;\n // on subsequent calls the promise is already resolved (no-op await).\n if (this._storageLoadPromise) {\n await this._storageLoadPromise;\n }\n\n const staticItems = await super.GetNavItems();\n\n // Update the recent stack based on current active tab\n // Must await — updateRecentStack is async (calls matchesStaticNavItem → super.GetNavItems())\n // and buildDynamicNavItems reads recentOrphanStack, so the stack must be fully updated first.\n await this.updateRecentStack();\n\n // Build dynamic nav items from the stack\n const dynamicItems = this.buildDynamicNavItems();\n if (dynamicItems.length > 0) {\n return [...staticItems, ...dynamicItems];\n }\n\n return staticItems;\n }\n\n /**\n * Removes a dynamic nav item from the recent stack by RecordID.\n * Called by AppNavComponent when the user clicks the dismiss X button.\n * If the dismissed item is currently active, navigates back to the app's default tab.\n */\n public RemoveDynamicNavItem(item: NavItem): void {\n const index = this.recentOrphanStack.findIndex(\n s => s.resourceRecordId === item.RecordID\n );\n if (index < 0) {\n return;\n }\n\n const wasActive = this.isDismissedItemActive(item);\n this.recentOrphanStack.splice(index, 1);\n this.saveStackToStorage();\n\n if (wasActive) {\n this.navigateToDefault();\n }\n }\n\n /**\n * Checks whether the dismissed nav item matches the currently active tab.\n */\n private isDismissedItemActive(item: NavItem): boolean {\n if (!this.workspaceManager) {\n return false;\n }\n const config = this.workspaceManager.GetConfiguration();\n if (!config?.activeTabId) {\n return false;\n }\n const activeTab = config.tabs.find(t => t.id === config.activeTabId);\n if (!activeTab) {\n return false;\n }\n return activeTab.resourceRecordId === item.RecordID;\n }\n\n /**\n * Navigates back to the app's default tab (first static nav item / Home dashboard).\n */\n private navigateToDefault(): void {\n if (!this.workspaceManager) {\n return;\n }\n this.CreateDefaultTab().then(tabRequest => {\n if (tabRequest && this.workspaceManager) {\n this.workspaceManager.OpenTab(tabRequest, this.GetColor());\n }\n });\n }\n\n // ========================================\n // Icon Resolution\n // ========================================\n\n /**\n * Resolves the best icon for a dynamic nav item.\n * Priority: entity-specific icon from metadata → resource type icon → generic fallback.\n */\n private resolveIcon(entityName: string | undefined, resourceTypeName: string): string {\n if (entityName) {\n const md = this.Provider;\n const entityIcon = md.EntityByName(entityName)?.Icon;\n if (entityIcon) {\n return entityIcon;\n }\n }\n\n if (this.sharedService) {\n const resourceType = this.sharedService.ResourceTypeByName(resourceTypeName);\n if (resourceType?.Icon) {\n return resourceType.Icon;\n }\n }\n\n return 'fa-solid fa-file';\n }\n\n // ========================================\n // Recent Stack Management\n // ========================================\n\n /**\n * Updates the recent orphan stack based on the currently active tab.\n * If the active tab is a new orphan resource (not already in the stack and not\n * matching any static nav item), it gets added to the front. Items already in the\n * stack keep their position to avoid visually jarring reordering when users click\n * between existing dynamic nav items.\n */\n private async updateRecentStack(): Promise<void> {\n if (!this.workspaceManager) {\n return;\n }\n\n const config = this.workspaceManager.GetConfiguration();\n if (!config?.activeTabId) {\n return;\n }\n\n const activeTab = config.tabs.find(t => t.id === config.activeTabId);\n if (!activeTab || !UUIDsEqual(activeTab.applicationId, this.ID)) {\n return;\n }\n\n // ALWAYS refresh the matching snapshot's label first — BEFORE the fingerprint\n // bail. A burst of configuration$ emissions (typical on save) causes multiple\n // concurrent updateCachedData calls; the first one proceeds past the fingerprint\n // check and gets stuck awaiting createSnapshotIfOrphan, while the rest bail at\n // fingerprint and race ahead with the *stale* snapshot. By the time the first\n // call's async work completes and updates the snapshot, the gen-check in\n // AppNav.updateCachedData has already discarded its results. The user is left\n // with the right data in memory but rendered against the wrong label.\n //\n // Refreshing here is cheap (cache hit after my save-handler's pre-warm) and\n // ensures every call — even fast bailers — produces fresh dynamic nav items.\n await this.refreshExistingSnapshotLabel(activeTab);\n\n // Build a fingerprint from tab ID + record content + title. In single-resource\n // mode, OpenTab replaces the temp tab's content but keeps the same tab ID, so we\n // need the resourceRecordId to detect when a different record is shown. Title is\n // included so an in-place rename (record's Name field edited and saved — tabId\n // and resourceRecordId stay the same but title changes) also triggers a refresh.\n const fingerprint = `${activeTab.id}::${activeTab.resourceRecordId ?? ''}::${activeTab.title ?? ''}`;\n if (fingerprint === this._lastSeenTabFingerprint) {\n return;\n }\n this._lastSeenTabFingerprint = fingerprint;\n\n // Check if active tab qualifies as an orphan resource\n const snapshot = await this.createSnapshotIfOrphan(activeTab);\n if (!snapshot) {\n // Active tab is a static resource (Home dashboard, etc.) — leave stack as-is\n return;\n }\n\n // If this item is already in the stack, leave the ORDER unchanged (reordering\n // on every click is visually jarring) — but DO refresh its `resolvedLabel` if the\n // underlying display name has changed. Without this, editing a record's Name\n // field would leave the dynamic nav item showing the pre-edit name forever.\n // Already-tracked snapshots are kept in their existing position (no jarring\n // reorder) and have their label kept fresh by refreshExistingSnapshotLabel\n // above — so here we only need to handle the NEW-snapshot case.\n const alreadyTracked = this.recentOrphanStack.some(\n s => s.resourceRecordId === snapshot.resourceRecordId\n );\n if (alreadyTracked) {\n return;\n }\n\n // New orphan — push to front (most recent first) and trim oldest if needed\n this.recentOrphanStack.unshift(snapshot);\n if (this.recentOrphanStack.length > HomeApplication.MAX_RECENT_ITEMS) {\n this.recentOrphanStack.length = HomeApplication.MAX_RECENT_ITEMS;\n }\n\n this.saveStackToStorage();\n }\n\n /**\n * Refreshes an already-tracked snapshot's `resolvedLabel` against the latest cached\n * record name. Called unconditionally at the top of `updateRecentStack` (BEFORE the\n * fingerprint bail), so even no-op-fingerprint calls don't render stale labels.\n *\n * Why this matters: when a record is saved, `configuration$` typically emits multiple\n * times in quick succession (UpdateTabTitle, UpdateConfiguration, etc.). AppNav's\n * subscription kicks off a `updateCachedData` for each. The first call wins the\n * fingerprint race and starts the slow async `createSnapshotIfOrphan` chain;\n * subsequent calls bail at fingerprint and race ahead with the still-unrefreshed\n * snapshot. AppNav's `_updateGeneration` then discards the slow call's results.\n * Without this method, the freshly-saved label lands in the snapshot — but never\n * makes it to the rendered nav until some unrelated event triggers another cycle.\n */\n private async refreshExistingSnapshotLabel(activeTab: WorkspaceTab): Promise<void> {\n if (!activeTab.resourceRecordId) {\n return;\n }\n const existing = this.recentOrphanStack.find(\n s => s.resourceRecordId === activeTab.resourceRecordId\n );\n if (!existing || !existing.entityName) {\n return;\n }\n const newLabel = await this.resolveRecordLabel(\n existing.entityName,\n activeTab.resourceRecordId,\n activeTab.title\n );\n if (newLabel && newLabel !== existing.resolvedLabel) {\n existing.resolvedLabel = newLabel;\n existing.title = activeTab.title;\n this.saveStackToStorage();\n }\n }\n\n /**\n * Creates an OrphanResourceSnapshot from a tab if it qualifies as an orphan resource.\n * Returns null if the tab is a static nav item, has no resource type, or is an\n * app-level custom dashboard (no record ID).\n */\n private async createSnapshotIfOrphan(tab: WorkspaceTab): Promise<OrphanResourceSnapshot | null> {\n const resourceType = tab.configuration?.['resourceType'] as string | undefined;\n if (!resourceType) {\n return null;\n }\n\n // Skip 'custom' resource type without a specific record (app-level dashboards)\n if (resourceType.toLowerCase() === 'custom' && !tab.resourceRecordId) {\n return null;\n }\n\n // Skip if it matches a static nav item\n if (await this.matchesStaticNavItem(tab)) {\n return null;\n }\n\n // Resolve the label now so it's stored with the snapshot\n const entityName = tab.configuration?.['Entity'] as string | undefined;\n const resolvedLabel = await this.resolveRecordLabel(entityName, tab.resourceRecordId, tab.title);\n\n return {\n resourceRecordId: tab.resourceRecordId,\n resourceType,\n entityName,\n title: tab.title,\n resolvedLabel,\n configuration: tab.configuration as Record<string, unknown>,\n tabId: tab.id,\n timestamp: Date.now()\n };\n }\n\n /**\n * Checks whether a tab matches any static nav item (by label, route, or driver class).\n */\n private async matchesStaticNavItem(tab: WorkspaceTab): Promise<boolean> {\n const staticItems = await super.GetNavItems();\n return staticItems.some(item => {\n if (item.Label === tab.title) {\n return true;\n }\n if (item.Route && tab.configuration?.['route'] === item.Route) {\n return true;\n }\n if (item.DriverClass && tab.configuration?.['driverClass'] === item.DriverClass) {\n return true;\n }\n return false;\n });\n }\n\n // ========================================\n // Dynamic NavItem Building\n // ========================================\n\n /**\n * Creates DynamicNavItem entries for each item in the recent orphan stack.\n * Uses the pre-resolved label from the snapshot (no async needed).\n */\n private buildDynamicNavItems(): DynamicNavItem[] {\n return this.recentOrphanStack.map(snapshot => this.createDynamicNavItem(snapshot));\n }\n\n /**\n * Creates a single DynamicNavItem from an OrphanResourceSnapshot.\n * Uses the snapshot's resolvedLabel directly — no async lookup needed.\n */\n private createDynamicNavItem(snapshot: OrphanResourceSnapshot): DynamicNavItem {\n return {\n Label: snapshot.resolvedLabel,\n Icon: this.resolveIcon(snapshot.entityName, snapshot.resourceType),\n ResourceType: snapshot.resourceType,\n RecordID: snapshot.resourceRecordId,\n Configuration: snapshot.configuration,\n isDynamic: true,\n isActiveMatch: (tab: unknown) => {\n const wsTab = tab as WorkspaceTab;\n if (snapshot.resourceRecordId) {\n return wsTab.resourceRecordId === snapshot.resourceRecordId;\n }\n return wsTab.id === snapshot.tabId;\n }\n };\n }\n\n // ========================================\n // Label Resolution\n // ========================================\n\n /**\n * Resolves the best available display label for an entity record nav item.\n * Priority order:\n * 1. Cached record name (from EntityRecordNameCache, populated by entity Load/Save)\n * 2. Tab title (whatever the workspace assigned when the tab was opened)\n * 3. Generated default (entity name + truncated primary key values)\n *\n * @param entityName - Entity name from tab configuration, may be undefined for non-entity resources\n * @param tabRecordId - URL-encoded composite key segment (e.g. \"ID|abc-123\" or \"Field1|val1||Field2|val2\")\n * @param tabTitle - Fallback title assigned by the workspace when the tab was opened\n */\n private async resolveRecordLabel(entityName: string | undefined, tabRecordId: string | undefined, tabTitle: string): Promise<string> {\n if (!entityName || !tabRecordId) {\n return tabTitle || '';\n }\n\n // Parse the URL segment into a CompositeKey\n const fvCollection = new FieldValueCollection();\n fvCollection.SimpleLoadFromURLSegment(tabRecordId);\n const compositeKey = new CompositeKey(fvCollection.KeyValuePairs);\n\n // Check the cache first\n try {\n const cachedName = await this.Provider.GetCachedRecordName(entityName, compositeKey, true);\n if (cachedName) {\n return cachedName;\n }\n } catch (error) {\n console.warn('Failed to look up cached record name:', error);\n }\n\n // Fall back generated default from the key values, then tabTitle if we have no default label(unlikely)\n return this.createDefaultLabel(entityName, compositeKey) || tabTitle;\n }\n\n /**\n * Generates a fallback label when no cached record name or tab title is available.\n * Format: \"EntityName: <truncated key value(s)>\"\n *\n * @example\n * // Single key: \"Contacts: abc1234...\"\n * // Multi key: \"Order Details: abc1..., 42\"\n * // No key: \"Contacts record\"\n */\n private createDefaultLabel(entityName: string, key: CompositeKey): string {\n if (!key || key.KeyValuePairs.length === 0) {\n return `${entityName} record`;\n }\n\n if (key.KeyValuePairs.length === 1) {\n return `${entityName}: ${this.trimValue(key.KeyValuePairs[0].Value)}`;\n }\n\n // Multiple keys - show each value trimmed, comma-separated\n const values = key.KeyValuePairs.map(kv => this.trimValue(kv.Value)).join(', ');\n return `${entityName}: ${values}`;\n }\n\n /**\n * Truncates a primary key value for display, appending \"...\" if it exceeds maxLength.\n * Returns the value as-is if it's short enough or empty.\n */\n private trimValue(value: string, maxLength: number = 8): string {\n if (!value || value.trim().length === 0) {\n return value;\n }\n\n const trimmed = value.trim();\n if (trimmed.length <= maxLength) {\n return trimmed;\n }\n\n return trimmed.substring(0, maxLength) + '...';\n }\n\n // ========================================\n // Storage Persistence\n // ========================================\n\n /**\n * Persists the current recentOrphanStack to localStorage via Provider.\n * Fire-and-forget — errors are logged but don't affect the UX.\n */\n private saveStackToStorage(): void {\n try {\n const provider = this.Provider.LocalStorageProvider;\n if (!provider) {\n return;\n }\n\n // Strip non-serializable fields (isActiveMatch closures are rebuilt on load)\n const serializable = this.recentOrphanStack.map(s => ({\n resourceRecordId: s.resourceRecordId,\n resourceType: s.resourceType,\n entityName: s.entityName,\n title: s.title,\n resolvedLabel: s.resolvedLabel,\n configuration: s.configuration,\n tabId: s.tabId,\n timestamp: s.timestamp\n }));\n\n // Native object storage — provider handles any required serialization internally.\n provider.SetItem<OrphanResourceSnapshot[]>(STORAGE_KEY, serializable, STORAGE_CATEGORY).catch(err => {\n console.warn('Failed to persist recent nav stack:', err);\n });\n } catch (err) {\n console.warn('Failed to persist recent nav stack:', err);\n }\n }\n\n /**\n * Loads the recent orphan stack from localStorage via Provider.\n * Filters out stale entries (older than MAX_SNAPSHOT_AGE_MS).\n */\n private async loadStackFromStorage(): Promise<void> {\n try {\n const provider = this.Provider.LocalStorageProvider;\n if (!provider) {\n return;\n }\n\n // Native object read — IDB returns the array directly; localStorage / Redis JSON-decode internally.\n const parsed = await provider.GetItem<OrphanResourceSnapshot[]>(STORAGE_KEY, STORAGE_CATEGORY);\n if (!parsed || !Array.isArray(parsed)) {\n return;\n }\n\n // Filter out stale snapshots\n const now = Date.now();\n this.recentOrphanStack = parsed\n .filter(s => s.resourceRecordId && s.timestamp && (now - s.timestamp) < MAX_SNAPSHOT_AGE_MS)\n .slice(0, HomeApplication.MAX_RECENT_ITEMS);\n } catch (err) {\n console.warn('Failed to load recent nav stack from storage:', err);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"home-application.js","sourceRoot":"","sources":["../../src/Home/home-application.ts"],"names":[],"mappings":"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","sourcesContent":["import { RegisterClass, UUIDsEqual } from '@memberjunction/global';\nimport { BaseApplication, DynamicNavItem, NavItem, WorkspaceStateManager, WorkspaceTab } from '@memberjunction/ng-base-application';\nimport { SharedService, IsRecordTabsStyle } from '@memberjunction/ng-shared';\nimport { Metadata, CompositeKey, FieldValueCollection } from '@memberjunction/core';\n\n/** Storage key and category for persisting the recent orphan stack */\nconst STORAGE_KEY = 'HomeApp_RecentOrphanStack';\nconst STORAGE_CATEGORY = 'HomeApplication';\n\n/**\n * Snapshot of an orphan resource tab for the recent navigation stack.\n * Persisted to localStorage (via Provider) so it survives page reloads.\n */\ninterface OrphanResourceSnapshot {\n /** URL-encoded composite key segment — primary dedup key */\n resourceRecordId: string;\n /** Resource type name (e.g., 'record', 'Dashboards') */\n resourceType: string;\n /** Entity name from tab configuration (for record name resolution) */\n entityName?: string;\n /** Tab title at time of capture (fallback label) */\n title: string;\n /** Resolved display label (cached record name). Persisted to avoid async lookups on reload. */\n resolvedLabel: string;\n /** Full tab configuration (passed to DynamicNavItem for re-opening) */\n configuration: Record<string, unknown>;\n /** Tab ID for fallback matching when no resourceRecordId */\n tabId: string;\n /** Timestamp (ms since epoch) when this snapshot was created or last promoted */\n timestamp: number;\n}\n\n/** Max age for persisted snapshots — 7 days */\nconst MAX_SNAPSHOT_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n\n/**\n * Home Application - Provides dynamic navigation items for orphan resources.\n *\n * Maintains a recency-ordered stack of up to 3 recently visited orphan resources.\n * When the user opens a record/view/dashboard from within the Home app, the resource\n * appears as a dynamic nav item. When they navigate away (e.g., click Home), the\n * nav item persists so they can quickly jump back. Older items drop off as new ones\n * are added.\n *\n * The stack is persisted to localStorage (via Metadata.Provider.LocalStorageProvider)\n * so it survives page reloads. Resolved record labels are stored alongside each\n * snapshot to avoid async lookups when restoring from storage.\n *\n * @example\n * User opens \"John Smith\" contact, then \"Acme Corp\" company:\n * - Nav shows: [Home] [Favorites] | [person] \"Acme Corp\" [building] \"John Smith\"\n * - Clicking \"John Smith\" re-opens that record\n */\n@RegisterClass(BaseApplication, 'HomeApplication')\nexport class HomeApplication extends BaseApplication {\n private static readonly MAX_RECENT_ITEMS = 3;\n\n private workspaceManager: WorkspaceStateManager | null = null;\n private sharedService: SharedService | null = null;\n private recentOrphanStack: OrphanResourceSnapshot[] = [];\n private _storageLoadPromise: Promise<void> | null = null;\n\n /**\n * Fingerprint of the last-processed active tab state (tabId::resourceRecordId::title).\n * Guards against redundant stack mutations while still detecting content changes.\n * In single-resource mode the tab ID stays constant when navigating between records\n * (OpenTab replaces the temp tab's content but keeps its ID), so we must also\n * include the resourceRecordId to detect when the tab shows a different record.\n *\n * Title is also included so an in-place display-name change (e.g. user edits a\n * record's Name field and saves — tabId and resourceRecordId stay the same but the\n * title changes) triggers a re-evaluation. Without this, the dynamic nav item keeps\n * showing the pre-edit name forever.\n */\n private _lastSeenTabFingerprint: string | null = null;\n\n /**\n * Inject WorkspaceStateManager for accessing current tab state.\n * Also triggers loading the persisted stack from storage on first call.\n */\n public SetWorkspaceManager(manager: WorkspaceStateManager): void {\n this.workspaceManager = manager;\n if (!this._storageLoadPromise) {\n this._storageLoadPromise = this.loadStackFromStorage();\n }\n }\n\n /**\n * Inject SharedService for accessing ResourceTypes metadata\n */\n public SetSharedService(service: SharedService): void {\n this.sharedService = service;\n }\n\n /**\n * Returns navigation items including dynamic items for recently visited orphan resources.\n * Static items come from DefaultNavItems in metadata.\n * Dynamic items are generated from the recent orphan stack (up to 3).\n *\n * Records style (Shell.RecordOpen.Style = 'records', the default): dynamic\n * items are SKIPPED — the shell's Records pill + strip represent open\n * records globally, and Home's own stack would double-represent records\n * opened from Home. Classic style keeps this behavior as-is.\n */\n override async GetNavItems(): Promise<NavItem[]> {\n if (IsRecordTabsStyle()) {\n return super.GetNavItems();\n }\n\n // Ensure persisted stack is loaded before building nav items.\n // On first call after page load, this awaits the IndexedDB read;\n // on subsequent calls the promise is already resolved (no-op await).\n if (this._storageLoadPromise) {\n await this._storageLoadPromise;\n }\n\n const staticItems = await super.GetNavItems();\n\n // Update the recent stack based on current active tab\n // Must await — updateRecentStack is async (calls matchesStaticNavItem → super.GetNavItems())\n // and buildDynamicNavItems reads recentOrphanStack, so the stack must be fully updated first.\n await this.updateRecentStack();\n\n // Build dynamic nav items from the stack\n const dynamicItems = this.buildDynamicNavItems();\n if (dynamicItems.length > 0) {\n return [...staticItems, ...dynamicItems];\n }\n\n return staticItems;\n }\n\n /**\n * Removes a dynamic nav item from the recent stack by RecordID.\n * Called by AppNavComponent when the user clicks the dismiss X button.\n * If the dismissed item is currently active, navigates back to the app's default tab.\n */\n public RemoveDynamicNavItem(item: NavItem): void {\n const index = this.recentOrphanStack.findIndex(\n s => s.resourceRecordId === item.RecordID\n );\n if (index < 0) {\n return;\n }\n\n const wasActive = this.isDismissedItemActive(item);\n this.recentOrphanStack.splice(index, 1);\n this.saveStackToStorage();\n\n if (wasActive) {\n this.navigateToDefault();\n }\n }\n\n /**\n * Checks whether the dismissed nav item matches the currently active tab.\n */\n private isDismissedItemActive(item: NavItem): boolean {\n if (!this.workspaceManager) {\n return false;\n }\n const config = this.workspaceManager.GetConfiguration();\n if (!config?.activeTabId) {\n return false;\n }\n const activeTab = config.tabs.find(t => t.id === config.activeTabId);\n if (!activeTab) {\n return false;\n }\n return activeTab.resourceRecordId === item.RecordID;\n }\n\n /**\n * Navigates back to the app's default tab (first static nav item / Home dashboard).\n */\n private navigateToDefault(): void {\n if (!this.workspaceManager) {\n return;\n }\n this.CreateDefaultTab().then(tabRequest => {\n if (tabRequest && this.workspaceManager) {\n this.workspaceManager.OpenTab(tabRequest, this.GetColor());\n }\n });\n }\n\n // ========================================\n // Icon Resolution\n // ========================================\n\n /**\n * Resolves the best icon for a dynamic nav item.\n * Priority: entity-specific icon from metadata → resource type icon → generic fallback.\n */\n private resolveIcon(entityName: string | undefined, resourceTypeName: string): string {\n if (entityName) {\n const md = this.Provider;\n const entityIcon = md.EntityByName(entityName)?.Icon;\n if (entityIcon) {\n return entityIcon;\n }\n }\n\n if (this.sharedService) {\n const resourceType = this.sharedService.ResourceTypeByName(resourceTypeName);\n if (resourceType?.Icon) {\n return resourceType.Icon;\n }\n }\n\n return 'fa-solid fa-file';\n }\n\n // ========================================\n // Recent Stack Management\n // ========================================\n\n /**\n * Updates the recent orphan stack based on the currently active tab.\n * If the active tab is a new orphan resource (not already in the stack and not\n * matching any static nav item), it gets added to the front. Items already in the\n * stack keep their position to avoid visually jarring reordering when users click\n * between existing dynamic nav items.\n */\n private async updateRecentStack(): Promise<void> {\n if (!this.workspaceManager) {\n return;\n }\n\n const config = this.workspaceManager.GetConfiguration();\n if (!config?.activeTabId) {\n return;\n }\n\n const activeTab = config.tabs.find(t => t.id === config.activeTabId);\n if (!activeTab || !UUIDsEqual(activeTab.applicationId, this.ID)) {\n return;\n }\n\n // ALWAYS refresh the matching snapshot's label first — BEFORE the fingerprint\n // bail. A burst of configuration$ emissions (typical on save) causes multiple\n // concurrent updateCachedData calls; the first one proceeds past the fingerprint\n // check and gets stuck awaiting createSnapshotIfOrphan, while the rest bail at\n // fingerprint and race ahead with the *stale* snapshot. By the time the first\n // call's async work completes and updates the snapshot, the gen-check in\n // AppNav.updateCachedData has already discarded its results. The user is left\n // with the right data in memory but rendered against the wrong label.\n //\n // Refreshing here is cheap (cache hit after my save-handler's pre-warm) and\n // ensures every call — even fast bailers — produces fresh dynamic nav items.\n await this.refreshExistingSnapshotLabel(activeTab);\n\n // Build a fingerprint from tab ID + record content + title. In single-resource\n // mode, OpenTab replaces the temp tab's content but keeps the same tab ID, so we\n // need the resourceRecordId to detect when a different record is shown. Title is\n // included so an in-place rename (record's Name field edited and saved — tabId\n // and resourceRecordId stay the same but title changes) also triggers a refresh.\n const fingerprint = `${activeTab.id}::${activeTab.resourceRecordId ?? ''}::${activeTab.title ?? ''}`;\n if (fingerprint === this._lastSeenTabFingerprint) {\n return;\n }\n this._lastSeenTabFingerprint = fingerprint;\n\n // Check if active tab qualifies as an orphan resource\n const snapshot = await this.createSnapshotIfOrphan(activeTab);\n if (!snapshot) {\n // Active tab is a static resource (Home dashboard, etc.) — leave stack as-is\n return;\n }\n\n // If this item is already in the stack, leave the ORDER unchanged (reordering\n // on every click is visually jarring) — but DO refresh its `resolvedLabel` if the\n // underlying display name has changed. Without this, editing a record's Name\n // field would leave the dynamic nav item showing the pre-edit name forever.\n // Already-tracked snapshots are kept in their existing position (no jarring\n // reorder) and have their label kept fresh by refreshExistingSnapshotLabel\n // above — so here we only need to handle the NEW-snapshot case.\n const alreadyTracked = this.recentOrphanStack.some(\n s => s.resourceRecordId === snapshot.resourceRecordId\n );\n if (alreadyTracked) {\n return;\n }\n\n // New orphan — push to front (most recent first) and trim oldest if needed\n this.recentOrphanStack.unshift(snapshot);\n if (this.recentOrphanStack.length > HomeApplication.MAX_RECENT_ITEMS) {\n this.recentOrphanStack.length = HomeApplication.MAX_RECENT_ITEMS;\n }\n\n this.saveStackToStorage();\n }\n\n /**\n * Refreshes an already-tracked snapshot's `resolvedLabel` against the latest cached\n * record name. Called unconditionally at the top of `updateRecentStack` (BEFORE the\n * fingerprint bail), so even no-op-fingerprint calls don't render stale labels.\n *\n * Why this matters: when a record is saved, `configuration$` typically emits multiple\n * times in quick succession (UpdateTabTitle, UpdateConfiguration, etc.). AppNav's\n * subscription kicks off a `updateCachedData` for each. The first call wins the\n * fingerprint race and starts the slow async `createSnapshotIfOrphan` chain;\n * subsequent calls bail at fingerprint and race ahead with the still-unrefreshed\n * snapshot. AppNav's `_updateGeneration` then discards the slow call's results.\n * Without this method, the freshly-saved label lands in the snapshot — but never\n * makes it to the rendered nav until some unrelated event triggers another cycle.\n */\n private async refreshExistingSnapshotLabel(activeTab: WorkspaceTab): Promise<void> {\n if (!activeTab.resourceRecordId) {\n return;\n }\n const existing = this.recentOrphanStack.find(\n s => s.resourceRecordId === activeTab.resourceRecordId\n );\n if (!existing || !existing.entityName) {\n return;\n }\n const newLabel = await this.resolveRecordLabel(\n existing.entityName,\n activeTab.resourceRecordId,\n activeTab.title\n );\n if (newLabel && newLabel !== existing.resolvedLabel) {\n existing.resolvedLabel = newLabel;\n existing.title = activeTab.title;\n this.saveStackToStorage();\n }\n }\n\n /**\n * Creates an OrphanResourceSnapshot from a tab if it qualifies as an orphan resource.\n * Returns null if the tab is a static nav item, has no resource type, or is an\n * app-level custom dashboard (no record ID).\n */\n private async createSnapshotIfOrphan(tab: WorkspaceTab): Promise<OrphanResourceSnapshot | null> {\n const resourceType = tab.configuration?.['resourceType'] as string | undefined;\n if (!resourceType) {\n return null;\n }\n\n // Skip 'custom' resource type without a specific record (app-level dashboards)\n if (resourceType.toLowerCase() === 'custom' && !tab.resourceRecordId) {\n return null;\n }\n\n // Skip if it matches a static nav item\n if (await this.matchesStaticNavItem(tab)) {\n return null;\n }\n\n // Resolve the label now so it's stored with the snapshot\n const entityName = tab.configuration?.['Entity'] as string | undefined;\n const resolvedLabel = await this.resolveRecordLabel(entityName, tab.resourceRecordId, tab.title);\n\n return {\n resourceRecordId: tab.resourceRecordId,\n resourceType,\n entityName,\n title: tab.title,\n resolvedLabel,\n configuration: tab.configuration as Record<string, unknown>,\n tabId: tab.id,\n timestamp: Date.now()\n };\n }\n\n /**\n * Checks whether a tab matches any static nav item (by label, route, or driver class).\n */\n private async matchesStaticNavItem(tab: WorkspaceTab): Promise<boolean> {\n const staticItems = await super.GetNavItems();\n return staticItems.some(item => {\n if (item.Label === tab.title) {\n return true;\n }\n if (item.Route && tab.configuration?.['route'] === item.Route) {\n return true;\n }\n if (item.DriverClass && tab.configuration?.['driverClass'] === item.DriverClass) {\n return true;\n }\n return false;\n });\n }\n\n // ========================================\n // Dynamic NavItem Building\n // ========================================\n\n /**\n * Creates DynamicNavItem entries for each item in the recent orphan stack.\n * Uses the pre-resolved label from the snapshot (no async needed).\n */\n private buildDynamicNavItems(): DynamicNavItem[] {\n return this.recentOrphanStack.map(snapshot => this.createDynamicNavItem(snapshot));\n }\n\n /**\n * Creates a single DynamicNavItem from an OrphanResourceSnapshot.\n * Uses the snapshot's resolvedLabel directly — no async lookup needed.\n */\n private createDynamicNavItem(snapshot: OrphanResourceSnapshot): DynamicNavItem {\n return {\n Label: snapshot.resolvedLabel,\n Icon: this.resolveIcon(snapshot.entityName, snapshot.resourceType),\n ResourceType: snapshot.resourceType,\n RecordID: snapshot.resourceRecordId,\n Configuration: snapshot.configuration,\n isDynamic: true,\n isActiveMatch: (tab: unknown) => {\n const wsTab = tab as WorkspaceTab;\n if (snapshot.resourceRecordId) {\n return wsTab.resourceRecordId === snapshot.resourceRecordId;\n }\n return wsTab.id === snapshot.tabId;\n }\n };\n }\n\n // ========================================\n // Label Resolution\n // ========================================\n\n /**\n * Resolves the best available display label for an entity record nav item.\n * Priority order:\n * 1. Cached record name (from EntityRecordNameCache, populated by entity Load/Save)\n * 2. Tab title (whatever the workspace assigned when the tab was opened)\n * 3. Generated default (entity name + truncated primary key values)\n *\n * @param entityName - Entity name from tab configuration, may be undefined for non-entity resources\n * @param tabRecordId - URL-encoded composite key segment (e.g. \"ID|abc-123\" or \"Field1|val1||Field2|val2\")\n * @param tabTitle - Fallback title assigned by the workspace when the tab was opened\n */\n private async resolveRecordLabel(entityName: string | undefined, tabRecordId: string | undefined, tabTitle: string): Promise<string> {\n if (!entityName || !tabRecordId) {\n return tabTitle || '';\n }\n\n // Parse the URL segment into a CompositeKey\n const fvCollection = new FieldValueCollection();\n fvCollection.SimpleLoadFromURLSegment(tabRecordId);\n const compositeKey = new CompositeKey(fvCollection.KeyValuePairs);\n\n // Check the cache first\n try {\n const cachedName = await this.Provider.GetCachedRecordName(entityName, compositeKey, true);\n if (cachedName) {\n return cachedName;\n }\n } catch (error) {\n console.warn('Failed to look up cached record name:', error);\n }\n\n // Fall back generated default from the key values, then tabTitle if we have no default label(unlikely)\n return this.createDefaultLabel(entityName, compositeKey) || tabTitle;\n }\n\n /**\n * Generates a fallback label when no cached record name or tab title is available.\n * Format: \"EntityName: <truncated key value(s)>\"\n *\n * @example\n * // Single key: \"Contacts: abc1234...\"\n * // Multi key: \"Order Details: abc1..., 42\"\n * // No key: \"Contacts record\"\n */\n private createDefaultLabel(entityName: string, key: CompositeKey): string {\n if (!key || key.KeyValuePairs.length === 0) {\n return `${entityName} record`;\n }\n\n if (key.KeyValuePairs.length === 1) {\n return `${entityName}: ${this.trimValue(key.KeyValuePairs[0].Value)}`;\n }\n\n // Multiple keys - show each value trimmed, comma-separated\n const values = key.KeyValuePairs.map(kv => this.trimValue(kv.Value)).join(', ');\n return `${entityName}: ${values}`;\n }\n\n /**\n * Truncates a primary key value for display, appending \"...\" if it exceeds maxLength.\n * Returns the value as-is if it's short enough or empty.\n */\n private trimValue(value: string, maxLength: number = 8): string {\n if (!value || value.trim().length === 0) {\n return value;\n }\n\n const trimmed = value.trim();\n if (trimmed.length <= maxLength) {\n return trimmed;\n }\n\n return trimmed.substring(0, maxLength) + '...';\n }\n\n // ========================================\n // Storage Persistence\n // ========================================\n\n /**\n * Persists the current recentOrphanStack to localStorage via Provider.\n * Fire-and-forget — errors are logged but don't affect the UX.\n */\n private saveStackToStorage(): void {\n try {\n const provider = this.Provider.LocalStorageProvider;\n if (!provider) {\n return;\n }\n\n // Strip non-serializable fields (isActiveMatch closures are rebuilt on load)\n const serializable = this.recentOrphanStack.map(s => ({\n resourceRecordId: s.resourceRecordId,\n resourceType: s.resourceType,\n entityName: s.entityName,\n title: s.title,\n resolvedLabel: s.resolvedLabel,\n configuration: s.configuration,\n tabId: s.tabId,\n timestamp: s.timestamp\n }));\n\n // Native object storage — provider handles any required serialization internally.\n provider.SetItem<OrphanResourceSnapshot[]>(STORAGE_KEY, serializable, STORAGE_CATEGORY).catch(err => {\n console.warn('Failed to persist recent nav stack:', err);\n });\n } catch (err) {\n console.warn('Failed to persist recent nav stack:', err);\n }\n }\n\n /**\n * Loads the recent orphan stack from localStorage via Provider.\n * Filters out stale entries (older than MAX_SNAPSHOT_AGE_MS).\n */\n private async loadStackFromStorage(): Promise<void> {\n try {\n const provider = this.Provider.LocalStorageProvider;\n if (!provider) {\n return;\n }\n\n // Native object read — IDB returns the array directly; localStorage / Redis JSON-decode internally.\n const parsed = await provider.GetItem<OrphanResourceSnapshot[]>(STORAGE_KEY, STORAGE_CATEGORY);\n if (!parsed || !Array.isArray(parsed)) {\n return;\n }\n\n // Filter out stale snapshots\n const now = Date.now();\n this.recentOrphanStack = parsed\n .filter(s => s.resourceRecordId && s.timestamp && (now - s.timestamp) < MAX_SNAPSHOT_AGE_MS)\n .slice(0, HomeApplication.MAX_RECENT_ITEMS);\n } catch (err) {\n console.warn('Failed to load recent nav stack from storage:', err);\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"home-dashboard.component.d.ts","sourceRoot":"","sources":["../../src/Home/home-dashboard.component.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"home-dashboard.component.d.ts","sourceRoot":"","sources":["../../src/Home/home-dashboard.component.ts"],"names":[],"mappings":"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"}
@@ -1898,9 +1898,6 @@ let HomeDashboardComponent = class HomeDashboardComponent extends BaseResourceCo
1898
1898
  else if (entityName === 'user views') {
1899
1899
  this.navigationService.OpenView(recordId, 'View');
1900
1900
  }
1901
- else if (entityName === 'reports') {
1902
- this.navigationService.OpenReport(recordId, 'Report');
1903
- }
1904
1901
  else if (entityName?.includes('artifact')) {
1905
1902
  this.navigationService.OpenArtifact(recordId, 'Artifact');
1906
1903
  }
@@ -1928,9 +1925,6 @@ let HomeDashboardComponent = class HomeDashboardComponent extends BaseResourceCo
1928
1925
  case 'artifact':
1929
1926
  this.navigationService.OpenArtifact(item.recordId, name || 'Artifact');
1930
1927
  break;
1931
- case 'report':
1932
- this.navigationService.OpenReport(item.recordId, name || 'Report');
1933
- break;
1934
1928
  default: {
1935
1929
  // Regular record
1936
1930
  const compositeKey = this.buildCompositeKeyForRecord(item.entityName, item.recordId);