@memberjunction/ng-explorer-core 6.1.4 → 6.2.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.
- package/dist/app-routing.module.d.ts +23 -1
- package/dist/app-routing.module.d.ts.map +1 -1
- package/dist/app-routing.module.js +73 -17
- package/dist/app-routing.module.js.map +1 -1
- package/dist/generated/lazy-feature-config.d.ts +1 -1
- package/dist/generated/lazy-feature-config.d.ts.map +1 -1
- package/dist/generated/lazy-feature-config.js +1 -8
- package/dist/generated/lazy-feature-config.js.map +1 -1
- package/dist/lib/command-palette/command-palette.component.d.ts +7 -1
- package/dist/lib/command-palette/command-palette.component.d.ts.map +1 -1
- package/dist/lib/command-palette/command-palette.component.js +28 -14
- package/dist/lib/command-palette/command-palette.component.js.map +1 -1
- package/dist/lib/conversation-feedback/conversation-feedback.d.ts +103 -13
- package/dist/lib/conversation-feedback/conversation-feedback.d.ts.map +1 -1
- package/dist/lib/conversation-feedback/conversation-feedback.js +219 -67
- package/dist/lib/conversation-feedback/conversation-feedback.js.map +1 -1
- package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.d.ts +64 -10
- package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.d.ts.map +1 -1
- package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js +172 -66
- package/dist/lib/dashboard-preferences-dialog/dashboard-preferences-dialog.component.js.map +1 -1
- package/dist/lib/generic/resource-container-component.d.ts +19 -5
- package/dist/lib/generic/resource-container-component.d.ts.map +1 -1
- package/dist/lib/generic/resource-container-component.js +43 -13
- package/dist/lib/generic/resource-container-component.js.map +1 -1
- package/dist/lib/guards/entities.guard.d.ts +4 -0
- package/dist/lib/guards/entities.guard.d.ts.map +1 -1
- package/dist/lib/guards/entities.guard.js +10 -2
- package/dist/lib/guards/entities.guard.js.map +1 -1
- package/dist/lib/identity-claims/claim-redeem.component.d.ts +4 -0
- package/dist/lib/identity-claims/claim-redeem.component.d.ts.map +1 -1
- package/dist/lib/identity-claims/claim-redeem.component.js +10 -2
- package/dist/lib/identity-claims/claim-redeem.component.js.map +1 -1
- package/dist/lib/oauth/oauth-callback.component.d.ts +4 -0
- package/dist/lib/oauth/oauth-callback.component.d.ts.map +1 -1
- package/dist/lib/oauth/oauth-callback.component.js +10 -2
- package/dist/lib/oauth/oauth-callback.component.js.map +1 -1
- package/dist/lib/profile/profile-dialog.component.d.ts.map +1 -1
- package/dist/lib/profile/profile-dialog.component.js +194 -191
- package/dist/lib/profile/profile-dialog.component.js.map +1 -1
- package/dist/lib/resource-wrappers/artifact-resource.component.d.ts +20 -2
- package/dist/lib/resource-wrappers/artifact-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/artifact-resource.component.js +33 -9
- package/dist/lib/resource-wrappers/artifact-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/chat-collections-resource.component.d.ts +80 -10
- package/dist/lib/resource-wrappers/chat-collections-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/chat-collections-resource.component.js +168 -56
- package/dist/lib/resource-wrappers/chat-collections-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts +186 -23
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.js +500 -177
- package/dist/lib/resource-wrappers/chat-conversations-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/chat-deeplink-params.d.ts +2 -0
- package/dist/lib/resource-wrappers/chat-deeplink-params.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/chat-deeplink-params.js +5 -1
- package/dist/lib/resource-wrappers/chat-deeplink-params.js.map +1 -1
- package/dist/lib/resource-wrappers/chat-search-routing.d.ts +25 -0
- package/dist/lib/resource-wrappers/chat-search-routing.d.ts.map +1 -0
- package/dist/lib/resource-wrappers/chat-search-routing.js +24 -0
- package/dist/lib/resource-wrappers/chat-search-routing.js.map +1 -0
- package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts +14 -2
- package/dist/lib/resource-wrappers/chat-tasks-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/chat-tasks-resource.component.js +32 -8
- package/dist/lib/resource-wrappers/chat-tasks-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts +54 -8
- package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/dashboard-resource.component.js +138 -46
- package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/livekit-room-resource.component.d.ts +223 -30
- package/dist/lib/resource-wrappers/livekit-room-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/livekit-room-resource.component.js +438 -118
- package/dist/lib/resource-wrappers/livekit-room-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/search-results-resource.component.d.ts +7 -3
- package/dist/lib/resource-wrappers/search-results-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/search-results-resource.component.js +23 -15
- package/dist/lib/resource-wrappers/search-results-resource.component.js.map +1 -1
- package/dist/lib/resource-wrappers/view-resource.component.d.ts +68 -10
- package/dist/lib/resource-wrappers/view-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/view-resource.component.js +178 -62
- package/dist/lib/resource-wrappers/view-resource.component.js.map +1 -1
- package/dist/lib/services/startup-validation.service.d.ts +4 -0
- package/dist/lib/services/startup-validation.service.d.ts.map +1 -1
- package/dist/lib/services/startup-validation.service.js +10 -2
- package/dist/lib/services/startup-validation.service.js.map +1 -1
- package/dist/lib/services/system-validation.service.d.ts +13 -1
- package/dist/lib/services/system-validation.service.d.ts.map +1 -1
- package/dist/lib/services/system-validation.service.js +29 -5
- package/dist/lib/services/system-validation.service.js.map +1 -1
- package/dist/lib/shell/components/dialogs/app-access-dialog.component.d.ts +54 -4
- package/dist/lib/shell/components/dialogs/app-access-dialog.component.d.ts.map +1 -1
- package/dist/lib/shell/components/dialogs/app-access-dialog.component.js +130 -40
- package/dist/lib/shell/components/dialogs/app-access-dialog.component.js.map +1 -1
- package/dist/lib/shell/components/header/app-nav.component.d.ts +29 -1
- package/dist/lib/shell/components/header/app-nav.component.d.ts.map +1 -1
- package/dist/lib/shell/components/header/app-nav.component.js +56 -12
- package/dist/lib/shell/components/header/app-nav.component.js.map +1 -1
- package/dist/lib/shell/components/header/app-switcher.component.d.ts +33 -5
- package/dist/lib/shell/components/header/app-switcher.component.d.ts.map +1 -1
- package/dist/lib/shell/components/header/app-switcher.component.js +85 -29
- package/dist/lib/shell/components/header/app-switcher.component.js.map +1 -1
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.d.ts +7 -1
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.d.ts.map +1 -1
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.js +63 -9
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.js.map +1 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.d.ts +30 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/component-cache-manager.js +63 -15
- package/dist/lib/shell/components/tabs/component-cache-manager.js.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts +99 -9
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.js +310 -110
- package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
- package/dist/lib/shell/loading-themes.d.ts +16 -12
- package/dist/lib/shell/loading-themes.d.ts.map +1 -1
- package/dist/lib/shell/loading-themes.js +145 -137
- package/dist/lib/shell/loading-themes.js.map +1 -1
- package/dist/lib/shell/readiness-beacon.d.ts +24 -0
- package/dist/lib/shell/readiness-beacon.d.ts.map +1 -0
- package/dist/lib/shell/readiness-beacon.js +40 -0
- package/dist/lib/shell/readiness-beacon.js.map +1 -0
- package/dist/lib/shell/services/about-dialog.service.d.ts +6 -0
- package/dist/lib/shell/services/about-dialog.service.d.ts.map +1 -1
- package/dist/lib/shell/services/about-dialog.service.js +16 -4
- package/dist/lib/shell/services/about-dialog.service.js.map +1 -1
- package/dist/lib/shell/services/profile-dialog.service.d.ts +6 -0
- package/dist/lib/shell/services/profile-dialog.service.d.ts.map +1 -1
- package/dist/lib/shell/services/profile-dialog.service.js +16 -4
- package/dist/lib/shell/services/profile-dialog.service.js.map +1 -1
- package/dist/lib/shell/services/user-sharing-center-dialog.service.d.ts +6 -0
- package/dist/lib/shell/services/user-sharing-center-dialog.service.d.ts.map +1 -1
- package/dist/lib/shell/services/user-sharing-center-dialog.service.js +15 -3
- package/dist/lib/shell/services/user-sharing-center-dialog.service.js.map +1 -1
- package/dist/lib/shell/shell.component.d.ts +275 -40
- package/dist/lib/shell/shell.component.d.ts.map +1 -1
- package/dist/lib/shell/shell.component.js +704 -290
- package/dist/lib/shell/shell.component.js.map +1 -1
- package/dist/lib/single-dashboard/Components/add-item/add-item.component.d.ts +64 -8
- package/dist/lib/single-dashboard/Components/add-item/add-item.component.d.ts.map +1 -1
- package/dist/lib/single-dashboard/Components/add-item/add-item.component.js +129 -37
- package/dist/lib/single-dashboard/Components/add-item/add-item.component.js.map +1 -1
- package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.d.ts +26 -2
- package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.d.ts.map +1 -1
- package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.js +48 -10
- package/dist/lib/single-dashboard/Components/delete-item/delete-item.component.js.map +1 -1
- package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.d.ts +84 -6
- package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.d.ts.map +1 -1
- package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.js +133 -29
- package/dist/lib/single-dashboard/Components/edit-dashboard/edit-dashboard.component.js.map +1 -1
- package/dist/lib/single-dashboard/single-dashboard.component.d.ts +173 -23
- package/dist/lib/single-dashboard/single-dashboard.component.d.ts.map +1 -1
- package/dist/lib/single-dashboard/single-dashboard.component.js +383 -109
- package/dist/lib/single-dashboard/single-dashboard.component.js.map +1 -1
- package/dist/lib/single-list-detail/single-list-detail.component.d.ts +383 -55
- package/dist/lib/single-list-detail/single-list-detail.component.d.ts.map +1 -1
- package/dist/lib/single-list-detail/single-list-detail.component.js +962 -326
- package/dist/lib/single-list-detail/single-list-detail.component.js.map +1 -1
- package/dist/lib/single-query/single-query.component.d.ts +22 -2
- package/dist/lib/single-query/single-query.component.d.ts.map +1 -1
- package/dist/lib/single-query/single-query.component.js +40 -10
- package/dist/lib/single-query/single-query.component.js.map +1 -1
- package/dist/lib/single-record/single-record.component.d.ts +41 -3
- package/dist/lib/single-record/single-record.component.d.ts.map +1 -1
- package/dist/lib/single-record/single-record.component.js +71 -11
- package/dist/lib/single-record/single-record.component.js.map +1 -1
- package/dist/lib/single-search-result/single-search-result.component.d.ts +23 -3
- package/dist/lib/single-search-result/single-search-result.component.d.ts.map +1 -1
- package/dist/lib/single-search-result/single-search-result.component.js +42 -12
- package/dist/lib/single-search-result/single-search-result.component.js.map +1 -1
- package/dist/lib/system-validation/system-validation-banner.component.d.ts +12 -2
- package/dist/lib/system-validation/system-validation-banner.component.d.ts.map +1 -1
- package/dist/lib/system-validation/system-validation-banner.component.js +25 -5
- package/dist/lib/system-validation/system-validation-banner.component.js.map +1 -1
- package/dist/lib/user-menu/user-menu.types.d.ts +4 -0
- package/dist/lib/user-menu/user-menu.types.d.ts.map +1 -1
- package/dist/lib/user-menu/user-menu.types.js +10 -2
- package/dist/lib/user-menu/user-menu.types.js.map +1 -1
- package/dist/lib/user-notifications/user-notifications.component.d.ts +59 -7
- package/dist/lib/user-notifications/user-notifications.component.d.ts.map +1 -1
- package/dist/lib/user-notifications/user-notifications.component.js +151 -47
- package/dist/lib/user-notifications/user-notifications.component.js.map +1 -1
- package/dist/lib/user-profile/user-profile.component.d.ts +3 -2
- package/dist/lib/user-profile/user-profile.component.d.ts.map +1 -1
- package/dist/lib/user-profile/user-profile.component.js +5 -4
- package/dist/lib/user-profile/user-profile.component.js.map +1 -1
- package/package.json +52 -52
|
@@ -158,20 +158,60 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
158
158
|
appRef;
|
|
159
159
|
environmentInjector;
|
|
160
160
|
cdr;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
GlContainer;
|
|
162
|
+
/** @deprecated Use {@link GlContainer}. */
|
|
163
|
+
get glContainer() {
|
|
164
|
+
return this.GlContainer;
|
|
165
|
+
}
|
|
166
|
+
/** @deprecated Use {@link GlContainer}. */
|
|
167
|
+
set glContainer(value) {
|
|
168
|
+
this.GlContainer = value;
|
|
169
|
+
}
|
|
170
|
+
DirectContentContainer;
|
|
171
|
+
/** @deprecated Use {@link DirectContentContainer}. */
|
|
172
|
+
get directContentContainer() {
|
|
173
|
+
return this.DirectContentContainer;
|
|
174
|
+
}
|
|
175
|
+
/** @deprecated Use {@link DirectContentContainer}. */
|
|
176
|
+
set directContentContainer(value) {
|
|
177
|
+
this.DirectContentContainer = value;
|
|
178
|
+
}
|
|
179
|
+
RecordsGlContainer;
|
|
180
|
+
/** @deprecated Use {@link RecordsGlContainer}. */
|
|
181
|
+
get recordsGlContainer() {
|
|
182
|
+
return this.RecordsGlContainer;
|
|
183
|
+
}
|
|
184
|
+
/** @deprecated Use {@link RecordsGlContainer}. */
|
|
185
|
+
set recordsGlContainer(value) {
|
|
186
|
+
this.RecordsGlContainer = value;
|
|
187
|
+
}
|
|
164
188
|
/**
|
|
165
189
|
* Emitted when the first resource component finishes loading.
|
|
166
190
|
* This allows the shell to keep showing its loading indicator until the first
|
|
167
191
|
* resource is ready, eliminating the visual gap between shell loading and resource loading.
|
|
168
192
|
*/
|
|
169
|
-
|
|
193
|
+
FirstResourceLoadComplete = new EventEmitter();
|
|
194
|
+
/**
|
|
195
|
+
* @deprecated Use {@link FirstResourceLoadComplete}.
|
|
196
|
+
*
|
|
197
|
+
* The same emitter under the old binding name, so a template still binding
|
|
198
|
+
* (firstResourceLoadComplete) keeps working. Must stay AFTER FirstResourceLoadComplete: class fields
|
|
199
|
+
* initialise in order, and the other way round this captures undefined.
|
|
200
|
+
*/
|
|
201
|
+
firstResourceLoadComplete = this.FirstResourceLoadComplete;
|
|
170
202
|
/**
|
|
171
203
|
* Emitted when Golden Layout fails to initialize after multiple retries.
|
|
172
204
|
* The shell can use this to show an error dialog and redirect.
|
|
173
205
|
*/
|
|
174
|
-
|
|
206
|
+
LayoutInitError = new EventEmitter();
|
|
207
|
+
/**
|
|
208
|
+
* @deprecated Use {@link LayoutInitError}.
|
|
209
|
+
*
|
|
210
|
+
* The same emitter under the old binding name, so a template still binding
|
|
211
|
+
* (layoutInitError) keeps working. Must stay AFTER LayoutInitError: class fields
|
|
212
|
+
* initialise in order, and the other way round this captures undefined.
|
|
213
|
+
*/
|
|
214
|
+
layoutInitError = this.LayoutInitError;
|
|
175
215
|
pinService = inject(HomeAppPinService);
|
|
176
216
|
navigationService = inject(NavigationService);
|
|
177
217
|
recordSwitcher = inject(RecordSwitcherService);
|
|
@@ -188,11 +228,28 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
188
228
|
// When a tab's content changes while active, both the reload path (workspace config subscription)
|
|
189
229
|
// and onTabShown can race to call loadTabContent, resulting in duplicate component rendering.
|
|
190
230
|
tabsCurrentlyLoading = new Set();
|
|
231
|
+
// Record-tab shows GL fired while the records region was HIDDEN, by tab id.
|
|
232
|
+
// Their content loads are deferred until the region is the visible surface —
|
|
233
|
+
// see the TabShown handler in wireRecordsLayoutEvents.
|
|
234
|
+
//
|
|
235
|
+
// A SET, not a map of containers: the replay deliberately re-resolves the live
|
|
236
|
+
// container via GetContainer(tabId), so a parked one would never be read — and
|
|
237
|
+
// holding it would retain a GL container, and its possibly-detached DOM, for as
|
|
238
|
+
// long as the region stays hidden. The type says the id is all that is kept.
|
|
239
|
+
pendingRecordShows = new Set();
|
|
191
240
|
// NEW: Smart component cache for preserving state across tab switches
|
|
192
241
|
cacheManager;
|
|
193
242
|
// Single-resource mode: render component directly without Golden Layout
|
|
194
243
|
// This avoids the 20px height issue when GL header is hidden
|
|
195
|
-
|
|
244
|
+
UseSingleResourceMode = false;
|
|
245
|
+
/** @deprecated Use {@link UseSingleResourceMode}. */
|
|
246
|
+
get useSingleResourceMode() {
|
|
247
|
+
return this.UseSingleResourceMode;
|
|
248
|
+
}
|
|
249
|
+
/** @deprecated Use {@link UseSingleResourceMode}. */
|
|
250
|
+
set useSingleResourceMode(value) {
|
|
251
|
+
this.UseSingleResourceMode = value;
|
|
252
|
+
}
|
|
196
253
|
singleResourceComponentRef = null;
|
|
197
254
|
/** Cache identity of the current single-resource component for detachment */
|
|
198
255
|
singleResourceCacheIdentity = null;
|
|
@@ -200,10 +257,42 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
200
257
|
currentSingleResourceSignature = null; // Track loaded content signature to avoid unnecessary reloads
|
|
201
258
|
isCreatingInitialTabs = false; // Flag to prevent syncTabsWithConfiguration during initial tab creation
|
|
202
259
|
// Context menu state
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
260
|
+
ContextMenuVisible = false;
|
|
261
|
+
/** @deprecated Use {@link ContextMenuVisible}. */
|
|
262
|
+
get contextMenuVisible() {
|
|
263
|
+
return this.ContextMenuVisible;
|
|
264
|
+
}
|
|
265
|
+
/** @deprecated Use {@link ContextMenuVisible}. */
|
|
266
|
+
set contextMenuVisible(value) {
|
|
267
|
+
this.ContextMenuVisible = value;
|
|
268
|
+
}
|
|
269
|
+
ContextMenuX = 0;
|
|
270
|
+
/** @deprecated Use {@link ContextMenuX}. */
|
|
271
|
+
get contextMenuX() {
|
|
272
|
+
return this.ContextMenuX;
|
|
273
|
+
}
|
|
274
|
+
/** @deprecated Use {@link ContextMenuX}. */
|
|
275
|
+
set contextMenuX(value) {
|
|
276
|
+
this.ContextMenuX = value;
|
|
277
|
+
}
|
|
278
|
+
ContextMenuY = 0;
|
|
279
|
+
/** @deprecated Use {@link ContextMenuY}. */
|
|
280
|
+
get contextMenuY() {
|
|
281
|
+
return this.ContextMenuY;
|
|
282
|
+
}
|
|
283
|
+
/** @deprecated Use {@link ContextMenuY}. */
|
|
284
|
+
set contextMenuY(value) {
|
|
285
|
+
this.ContextMenuY = value;
|
|
286
|
+
}
|
|
287
|
+
ContextMenuTabId = null;
|
|
288
|
+
/** @deprecated Use {@link ContextMenuTabId}. */
|
|
289
|
+
get contextMenuTabId() {
|
|
290
|
+
return this.ContextMenuTabId;
|
|
291
|
+
}
|
|
292
|
+
/** @deprecated Use {@link ContextMenuTabId}. */
|
|
293
|
+
set contextMenuTabId(value) {
|
|
294
|
+
this.ContextMenuTabId = value;
|
|
295
|
+
}
|
|
207
296
|
/** The control that opened the context menu — focus returns here on close */
|
|
208
297
|
contextMenuAnchor = null;
|
|
209
298
|
// ---- RECORDS region (records-style record opens) ----
|
|
@@ -420,6 +509,9 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
420
509
|
// Flush NOW — the visibility class must land in this pass, not
|
|
421
510
|
// whenever the next unrelated emission happens to run CD.
|
|
422
511
|
this.flushRegionCd();
|
|
512
|
+
if (showing) {
|
|
513
|
+
this.flushPendingRecordShows();
|
|
514
|
+
}
|
|
423
515
|
}
|
|
424
516
|
if (showing && activeTab && this.recordsLayoutInitialized) {
|
|
425
517
|
this.focusRecordsTab(activeTab.id);
|
|
@@ -536,6 +628,46 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
536
628
|
}
|
|
537
629
|
return true;
|
|
538
630
|
}
|
|
631
|
+
/**
|
|
632
|
+
* Load a record tab's content into its GL container and mark it loaded —
|
|
633
|
+
* the second half of the TabShown handler, split out so a show parked
|
|
634
|
+
* while the region was hidden can be replayed on reveal.
|
|
635
|
+
*/
|
|
636
|
+
async loadShownRecordTab(tabId, container) {
|
|
637
|
+
await this.loadTabContent(tabId, container);
|
|
638
|
+
// Mark loaded ONLY when content actually attached to the LIVE
|
|
639
|
+
// container. During layout restore, GL can re-render item elements
|
|
640
|
+
// while an async load is in flight — the load appends into a
|
|
641
|
+
// detached element and the visible pane stays blank. Leaving the
|
|
642
|
+
// tab unmarked lets the next show retry, which hits the component
|
|
643
|
+
// cache and reattaches instantly into the live element.
|
|
644
|
+
const live = this.recordsLayoutManager.GetContainer(tabId);
|
|
645
|
+
if (live?.element && live.element.childElementCount > 0) {
|
|
646
|
+
this.recordsLayoutManager.MarkTabLoaded(tabId);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Replay the shows parked while the records region was hidden (see the
|
|
651
|
+
* TabShown handler). Always against the LIVE container: a breakpoint
|
|
652
|
+
* rebuild between park and reveal replaces the one GL handed us (and its
|
|
653
|
+
* Destroy fires TabClosed, which drops the stale entry anyway).
|
|
654
|
+
*/
|
|
655
|
+
flushPendingRecordShows() {
|
|
656
|
+
if (this.pendingRecordShows.size === 0) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
const parked = [...this.pendingRecordShows];
|
|
660
|
+
this.pendingRecordShows.clear();
|
|
661
|
+
for (const tabId of parked) {
|
|
662
|
+
if (this.recordsLayoutManager.IsTabLoaded(tabId)) {
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
const live = this.recordsLayoutManager.GetContainer(tabId);
|
|
666
|
+
if (live) {
|
|
667
|
+
this.loadShownRecordTab(tabId, live).catch(e => LogError(`Deferred record tab load failed for ${tabId}: ${e}`));
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
539
671
|
/** Focus a records-region tab without feeding back into SetActiveTab loops */
|
|
540
672
|
focusRecordsTab(tabId) {
|
|
541
673
|
if (this.recordsRegionActiveTabId !== tabId) {
|
|
@@ -554,7 +686,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
554
686
|
if (this.recordsLayoutInitialized) {
|
|
555
687
|
return;
|
|
556
688
|
}
|
|
557
|
-
const container = this.
|
|
689
|
+
const container = this.RecordsGlContainer?.nativeElement;
|
|
558
690
|
if (!container) {
|
|
559
691
|
return; // Template not settled yet — the next sync pass retries
|
|
560
692
|
}
|
|
@@ -690,7 +822,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
690
822
|
}), this.layoutManager.TabDoubleClicked.subscribe(tabId => {
|
|
691
823
|
this.workspaceManager.TogglePin(tabId);
|
|
692
824
|
}), this.layoutManager.TabRightClicked.subscribe(event => {
|
|
693
|
-
this.
|
|
825
|
+
this.ShowContextMenu(event.x, event.y, event.tabId, event.anchorEl);
|
|
694
826
|
}));
|
|
695
827
|
this.wireRecordsLayoutEvents();
|
|
696
828
|
// Breakpoint crossings rebuild the records GL in the other chrome mode
|
|
@@ -728,7 +860,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
728
860
|
// the region is the visible surface for this configuration.
|
|
729
861
|
this.syncRecordsRegion(config);
|
|
730
862
|
this.updateRecordSurfaceState(config);
|
|
731
|
-
if (this.
|
|
863
|
+
if (this.UseSingleResourceMode) {
|
|
732
864
|
// In single-resource mode, reload content if the tab content changed
|
|
733
865
|
// The same tab ID can have different content (tab gets reused)
|
|
734
866
|
const activeTab = config.tabs.find(t => t.id === config.activeTabId) || config.tabs[0];
|
|
@@ -781,20 +913,28 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
781
913
|
*/
|
|
782
914
|
wireRecordsLayoutEvents() {
|
|
783
915
|
this.subscriptions.push(this.recordsLayoutManager.TabShown.subscribe(async (event) => {
|
|
784
|
-
if (event.isFirstShow) {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
916
|
+
if (!event.isFirstShow) {
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
// LAZY content. The records GL initializes EAGERLY (see
|
|
920
|
+
// ensureRecordsLayoutInitialized) so the strip and the pill never
|
|
921
|
+
// drift from the workspace — and as it builds, GL fires 'show' for
|
|
922
|
+
// every stack's active tab while the region is still
|
|
923
|
+
// visibility-hidden behind the main surface. Loading content on
|
|
924
|
+
// those shows means every restored record hydrates at BOOT: an open
|
|
925
|
+
// AI Agent Run pulls its whole run tree (every prompt run, action
|
|
926
|
+
// log, step) before the user has looked at it, and client-side
|
|
927
|
+
// RunView coalescing folds the ACTIVE tab's own reads into the same
|
|
928
|
+
// requests, so the surface the user is looking at waits for records
|
|
929
|
+
// they are not. Park the show; it is replayed when the region shows.
|
|
930
|
+
if (!this.ShowRecordsRegion) {
|
|
931
|
+
this.pendingRecordShows.add(event.tabId);
|
|
932
|
+
return;
|
|
796
933
|
}
|
|
934
|
+
this.pendingRecordShows.delete(event.tabId);
|
|
935
|
+
await this.loadShownRecordTab(event.tabId, event.container);
|
|
797
936
|
}), this.recordsLayoutManager.TabClosed.subscribe(async (tabId) => {
|
|
937
|
+
this.pendingRecordShows.delete(tabId);
|
|
798
938
|
this.cleanupTabComponent(tabId);
|
|
799
939
|
// REBUILD guard (breakpoint crossing): Destroy() fires TabClosed for
|
|
800
940
|
// every pane. The tabs are NOT closing — the layout is being rebuilt
|
|
@@ -843,12 +983,12 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
843
983
|
}), this.recordsLayoutManager.TabDoubleClicked.subscribe(tabId => {
|
|
844
984
|
this.workspaceManager.TogglePin(tabId);
|
|
845
985
|
}), this.recordsLayoutManager.TabRightClicked.subscribe(event => {
|
|
846
|
-
this.
|
|
986
|
+
this.ShowContextMenu(event.x, event.y, event.tabId, event.anchorEl);
|
|
847
987
|
}));
|
|
848
988
|
}
|
|
849
989
|
ngAfterViewInit() {
|
|
850
990
|
// Initialize Golden Layout only if we're not in single-resource mode
|
|
851
|
-
if (!this.
|
|
991
|
+
if (!this.UseSingleResourceMode) {
|
|
852
992
|
this.initializeGoldenLayout();
|
|
853
993
|
}
|
|
854
994
|
else {
|
|
@@ -862,13 +1002,13 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
862
1002
|
*/
|
|
863
1003
|
initializeGoldenLayout(forceCreateTabs = false) {
|
|
864
1004
|
// If we are in single resource mode we do NOT need to do this work as golden layout should not exist in that state
|
|
865
|
-
if (this.
|
|
1005
|
+
if (this.UseSingleResourceMode)
|
|
866
1006
|
return;
|
|
867
|
-
if (!this.
|
|
1007
|
+
if (!this.GlContainer?.nativeElement) {
|
|
868
1008
|
this.layoutInitRetryCount++;
|
|
869
1009
|
if (this.layoutInitRetryCount > this.MAX_LAYOUT_INIT_RETRIES) {
|
|
870
1010
|
console.error(`Golden Layout container not available after ${this.MAX_LAYOUT_INIT_RETRIES} retries, emitting error`);
|
|
871
|
-
this.
|
|
1011
|
+
this.LayoutInitError.emit();
|
|
872
1012
|
return;
|
|
873
1013
|
}
|
|
874
1014
|
console.warn(`Golden Layout container not available, retry ${this.layoutInitRetryCount}/${this.MAX_LAYOUT_INIT_RETRIES}...`);
|
|
@@ -902,7 +1042,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
902
1042
|
return;
|
|
903
1043
|
}
|
|
904
1044
|
// Initialize Golden Layout (we have config now)
|
|
905
|
-
this.layoutManager.Initialize(this.
|
|
1045
|
+
this.layoutManager.Initialize(this.GlContainer.nativeElement);
|
|
906
1046
|
// Mark layout as initialized
|
|
907
1047
|
this.layoutInitialized = true;
|
|
908
1048
|
// The MAIN layout hosts only non-record tabs — record tabs live in the
|
|
@@ -1002,7 +1142,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
1002
1142
|
async ReloadAllTabs() {
|
|
1003
1143
|
// Destroy all cached component instances
|
|
1004
1144
|
this.cacheManager.clearCache();
|
|
1005
|
-
if (this.
|
|
1145
|
+
if (this.UseSingleResourceMode) {
|
|
1006
1146
|
// Force reload by clearing the signature check
|
|
1007
1147
|
this.currentSingleResourceSignature = null;
|
|
1008
1148
|
this.singleResourceComponentRef = null;
|
|
@@ -1095,7 +1235,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
1095
1235
|
* ensures the layout is properly sized after browser window changes.
|
|
1096
1236
|
*/
|
|
1097
1237
|
onWindowResize() {
|
|
1098
|
-
if (this.layoutInitialized && !this.
|
|
1238
|
+
if (this.layoutInitialized && !this.UseSingleResourceMode) {
|
|
1099
1239
|
this.layoutManager.updateSize();
|
|
1100
1240
|
}
|
|
1101
1241
|
}
|
|
@@ -1110,12 +1250,12 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
1110
1250
|
this.previousTabBarVisible = tabBarVisible;
|
|
1111
1251
|
// Determine if we should use single-resource mode
|
|
1112
1252
|
const shouldUseSingleResourceMode = !tabBarVisible;
|
|
1113
|
-
if (shouldUseSingleResourceMode !== this.
|
|
1114
|
-
this.
|
|
1253
|
+
if (shouldUseSingleResourceMode !== this.UseSingleResourceMode) {
|
|
1254
|
+
this.UseSingleResourceMode = shouldUseSingleResourceMode;
|
|
1115
1255
|
// Defer detectChanges to next microtask to avoid ExpressionChangedAfterItHasBeenCheckedError
|
|
1116
1256
|
// when this handler fires during an already-running change detection cycle.
|
|
1117
1257
|
Promise.resolve().then(() => this.cdr.detectChanges());
|
|
1118
|
-
if (this.
|
|
1258
|
+
if (this.UseSingleResourceMode) {
|
|
1119
1259
|
// Transitioning to single-resource mode
|
|
1120
1260
|
// **CRITICAL FIX**: Wait for the template to render directContentContainer
|
|
1121
1261
|
// before trying to load content. detectChanges() only marks dirty, doesn't render immediately.
|
|
@@ -1217,7 +1357,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
1217
1357
|
}
|
|
1218
1358
|
this.currentSingleResourceSignature = newSignature;
|
|
1219
1359
|
// Get the container element
|
|
1220
|
-
const container = this.
|
|
1360
|
+
const container = this.DirectContentContainer?.nativeElement;
|
|
1221
1361
|
if (!container) {
|
|
1222
1362
|
// Retry after view is updated
|
|
1223
1363
|
setTimeout(() => this.loadSingleResourceContent(), 50);
|
|
@@ -1415,7 +1555,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
1415
1555
|
// Remove children from the container. This detaches the wrapper DOM element
|
|
1416
1556
|
// without destroying the Angular component — it lives on in the cache.
|
|
1417
1557
|
// Using removeChild (not innerHTML='') to avoid aggressive DOM cleanup.
|
|
1418
|
-
const container = this.
|
|
1558
|
+
const container = this.DirectContentContainer?.nativeElement;
|
|
1419
1559
|
if (container) {
|
|
1420
1560
|
while (container.firstChild) {
|
|
1421
1561
|
container.removeChild(container.firstChild);
|
|
@@ -1469,7 +1609,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
1469
1609
|
// Pre-compute and stamp the new signature so the configuration-subscription path
|
|
1470
1610
|
// in single-resource mode doesn't see a "content changed" delta and trigger a
|
|
1471
1611
|
// needless reload cycle (which would destroy the currently attached component).
|
|
1472
|
-
if (this.
|
|
1612
|
+
if (this.UseSingleResourceMode && this.currentSingleResourceSignature !== null) {
|
|
1473
1613
|
const updatedTab = {
|
|
1474
1614
|
...tab,
|
|
1475
1615
|
resourceRecordId: newRecordId,
|
|
@@ -1552,7 +1692,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
1552
1692
|
this.singleResourceCacheIdentity = null;
|
|
1553
1693
|
// Clear the host container's DOM so the user isn't briefly looking at the
|
|
1554
1694
|
// destroyed component's wrapper between CloseTab and the default-tab load.
|
|
1555
|
-
const directContainer = this.
|
|
1695
|
+
const directContainer = this.DirectContentContainer?.nativeElement;
|
|
1556
1696
|
if (directContainer) {
|
|
1557
1697
|
while (directContainer.firstChild)
|
|
1558
1698
|
directContainer.removeChild(directContainer.firstChild);
|
|
@@ -2242,11 +2382,11 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2242
2382
|
/**
|
|
2243
2383
|
* Show context menu
|
|
2244
2384
|
*/
|
|
2245
|
-
|
|
2246
|
-
this.
|
|
2247
|
-
this.
|
|
2248
|
-
this.
|
|
2249
|
-
this.
|
|
2385
|
+
ShowContextMenu(x, y, tabId, anchorEl) {
|
|
2386
|
+
this.ContextMenuX = x;
|
|
2387
|
+
this.ContextMenuY = y;
|
|
2388
|
+
this.ContextMenuTabId = tabId;
|
|
2389
|
+
this.ContextMenuVisible = true;
|
|
2250
2390
|
// Remember the invoking control so closing can hand focus back (the
|
|
2251
2391
|
// slot button passes itself; right-click falls back to whatever was
|
|
2252
2392
|
// focused). aria-expanded reflects the open menu on the anchor.
|
|
@@ -2273,14 +2413,14 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2273
2413
|
const clickHandler = (event) => {
|
|
2274
2414
|
const target = event.target;
|
|
2275
2415
|
if (!target.closest('.context-menu')) {
|
|
2276
|
-
this.
|
|
2416
|
+
this.HideContextMenu();
|
|
2277
2417
|
document.removeEventListener('click', clickHandler, true);
|
|
2278
2418
|
document.removeEventListener('keydown', keyHandler, true);
|
|
2279
2419
|
}
|
|
2280
2420
|
};
|
|
2281
2421
|
const keyHandler = (event) => {
|
|
2282
2422
|
if (event.key === 'Escape') {
|
|
2283
|
-
this.
|
|
2423
|
+
this.HideContextMenu();
|
|
2284
2424
|
document.removeEventListener('click', clickHandler, true);
|
|
2285
2425
|
document.removeEventListener('keydown', keyHandler, true);
|
|
2286
2426
|
}
|
|
@@ -2289,12 +2429,16 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2289
2429
|
document.addEventListener('keydown', keyHandler, true);
|
|
2290
2430
|
}, 0);
|
|
2291
2431
|
}
|
|
2432
|
+
/** @deprecated Use {@link ShowContextMenu}. */
|
|
2433
|
+
showContextMenu(x, y, tabId, anchorEl) {
|
|
2434
|
+
return this.ShowContextMenu(x, y, tabId, anchorEl);
|
|
2435
|
+
}
|
|
2292
2436
|
/**
|
|
2293
2437
|
* Hide context menu
|
|
2294
2438
|
*/
|
|
2295
|
-
|
|
2296
|
-
this.
|
|
2297
|
-
this.
|
|
2439
|
+
HideContextMenu(restoreFocus = true) {
|
|
2440
|
+
this.ContextMenuVisible = false;
|
|
2441
|
+
this.ContextMenuTabId = null;
|
|
2298
2442
|
const anchor = this.contextMenuAnchor;
|
|
2299
2443
|
this.contextMenuAnchor = null;
|
|
2300
2444
|
if (anchor?.classList.contains('mj-tab-type-slot')) {
|
|
@@ -2310,12 +2454,16 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2310
2454
|
requestAnimationFrame(() => anchor.focus());
|
|
2311
2455
|
}
|
|
2312
2456
|
}
|
|
2457
|
+
/** @deprecated Use {@link HideContextMenu}. */
|
|
2458
|
+
hideContextMenu(restoreFocus = true) {
|
|
2459
|
+
return this.HideContextMenu(restoreFocus);
|
|
2460
|
+
}
|
|
2313
2461
|
/**
|
|
2314
2462
|
* role="menu" keyboard model: ArrowUp/Down rove (wrapping) over enabled
|
|
2315
2463
|
* items, Home/End jump, Escape closes with focus return, Tab dismisses
|
|
2316
2464
|
* (native menus don't trap Tab).
|
|
2317
2465
|
*/
|
|
2318
|
-
|
|
2466
|
+
OnMenuKeydown(event) {
|
|
2319
2467
|
const items = Array.from(document.querySelectorAll('.context-menu [role="menuitem"]:not([disabled])'));
|
|
2320
2468
|
if (items.length === 0) {
|
|
2321
2469
|
return;
|
|
@@ -2343,37 +2491,53 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2343
2491
|
// deferred document-level teardown listener attaches.
|
|
2344
2492
|
event.preventDefault();
|
|
2345
2493
|
event.stopPropagation();
|
|
2346
|
-
this.
|
|
2494
|
+
this.HideContextMenu();
|
|
2347
2495
|
break;
|
|
2348
2496
|
case 'Tab':
|
|
2349
|
-
this.
|
|
2497
|
+
this.HideContextMenu(false);
|
|
2350
2498
|
break;
|
|
2351
2499
|
}
|
|
2352
2500
|
}
|
|
2501
|
+
/** @deprecated Use {@link OnMenuKeydown}. */
|
|
2502
|
+
onMenuKeydown(event) {
|
|
2503
|
+
return this.OnMenuKeydown(event);
|
|
2504
|
+
}
|
|
2353
2505
|
/**
|
|
2354
2506
|
* Check if context menu tab is pinned
|
|
2355
2507
|
*/
|
|
2356
|
-
get
|
|
2357
|
-
if (!this.
|
|
2508
|
+
get IsContextTabPinned() {
|
|
2509
|
+
if (!this.ContextMenuTabId)
|
|
2358
2510
|
return false;
|
|
2359
|
-
const tab = this.workspaceManager.GetTab(this.
|
|
2511
|
+
const tab = this.workspaceManager.GetTab(this.ContextMenuTabId);
|
|
2360
2512
|
return tab?.isPinned || false;
|
|
2361
2513
|
}
|
|
2514
|
+
/** @deprecated Use {@link IsContextTabPinned}. */
|
|
2515
|
+
get isContextTabPinned() {
|
|
2516
|
+
return this.IsContextTabPinned;
|
|
2517
|
+
}
|
|
2362
2518
|
/** Context tab is a records-REGION record — eligible for "Move to Workspace" */
|
|
2363
|
-
get
|
|
2519
|
+
get CanContextMoveToWorkspace() {
|
|
2364
2520
|
// Docked/region composition is a DESKTOP concept — no move actions on mobile
|
|
2365
|
-
if (!this.
|
|
2521
|
+
if (!this.ContextMenuTabId || !this.RecordsStyleActive || this.mobileRecordsActive)
|
|
2366
2522
|
return false;
|
|
2367
|
-
const tab = this.workspaceManager.GetTab(this.
|
|
2523
|
+
const tab = this.workspaceManager.GetTab(this.ContextMenuTabId);
|
|
2368
2524
|
return !!tab && IsRecordsRegionTab(tab.configuration);
|
|
2369
2525
|
}
|
|
2526
|
+
/** @deprecated Use {@link CanContextMoveToWorkspace}. */
|
|
2527
|
+
get canContextMoveToWorkspace() {
|
|
2528
|
+
return this.CanContextMoveToWorkspace;
|
|
2529
|
+
}
|
|
2370
2530
|
/** Context tab is a DOCKED record — eligible for "Move to Records" */
|
|
2371
|
-
get
|
|
2372
|
-
if (!this.
|
|
2531
|
+
get CanContextMoveToRecords() {
|
|
2532
|
+
if (!this.ContextMenuTabId || !this.RecordsStyleActive || this.mobileRecordsActive)
|
|
2373
2533
|
return false;
|
|
2374
|
-
const tab = this.workspaceManager.GetTab(this.
|
|
2534
|
+
const tab = this.workspaceManager.GetTab(this.ContextMenuTabId);
|
|
2375
2535
|
return !!tab && IsRecordsTabConfiguration(tab.configuration) && IsRecordDockedToWorkspace(tab.configuration);
|
|
2376
2536
|
}
|
|
2537
|
+
/** @deprecated Use {@link CanContextMoveToRecords}. */
|
|
2538
|
+
get canContextMoveToRecords() {
|
|
2539
|
+
return this.CanContextMoveToRecords;
|
|
2540
|
+
}
|
|
2377
2541
|
/**
|
|
2378
2542
|
* Promote: records region → main workspace layout ("Move to Workspace").
|
|
2379
2543
|
* ORDER MATTERS: activate FIRST, then flip the flag. With the tab already
|
|
@@ -2382,15 +2546,19 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2382
2546
|
* (b) a single-resource→multi-tab transition triggered by the flip exempts
|
|
2383
2547
|
* it from the force-pin sweep (it IS the activeTabId).
|
|
2384
2548
|
*/
|
|
2385
|
-
|
|
2386
|
-
const tabId = this.
|
|
2387
|
-
this.
|
|
2549
|
+
OnContextMoveToWorkspace() {
|
|
2550
|
+
const tabId = this.ContextMenuTabId;
|
|
2551
|
+
this.HideContextMenu(false);
|
|
2388
2552
|
if (!tabId)
|
|
2389
2553
|
return;
|
|
2390
2554
|
this.workspaceManager.SetActiveTab(tabId);
|
|
2391
2555
|
this.workspaceManager.UpdateTabConfiguration(tabId, { [RECORD_DOCKED_TO_WORKSPACE_KEY]: true });
|
|
2392
2556
|
this.assertMovedTabActivation(tabId);
|
|
2393
2557
|
}
|
|
2558
|
+
/** @deprecated Use {@link OnContextMoveToWorkspace}. */
|
|
2559
|
+
onContextMoveToWorkspace() {
|
|
2560
|
+
return this.OnContextMoveToWorkspace();
|
|
2561
|
+
}
|
|
2394
2562
|
/**
|
|
2395
2563
|
* Demote: main workspace layout → records region ("Move to Records").
|
|
2396
2564
|
* Same activate-first ordering: the flip's emission then computes
|
|
@@ -2398,15 +2566,19 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2398
2566
|
* the returned tab. `false` (not undefined) so the choice is explicit in
|
|
2399
2567
|
* the persisted configuration.
|
|
2400
2568
|
*/
|
|
2401
|
-
|
|
2402
|
-
const tabId = this.
|
|
2403
|
-
this.
|
|
2569
|
+
OnContextMoveToRecords() {
|
|
2570
|
+
const tabId = this.ContextMenuTabId;
|
|
2571
|
+
this.HideContextMenu(false);
|
|
2404
2572
|
if (!tabId)
|
|
2405
2573
|
return;
|
|
2406
2574
|
this.workspaceManager.SetActiveTab(tabId);
|
|
2407
2575
|
this.workspaceManager.UpdateTabConfiguration(tabId, { [RECORD_DOCKED_TO_WORKSPACE_KEY]: false });
|
|
2408
2576
|
this.assertMovedTabActivation(tabId);
|
|
2409
2577
|
}
|
|
2578
|
+
/** @deprecated Use {@link OnContextMoveToRecords}. */
|
|
2579
|
+
onContextMoveToRecords() {
|
|
2580
|
+
return this.OnContextMoveToRecords();
|
|
2581
|
+
}
|
|
2410
2582
|
/**
|
|
2411
2583
|
* A move's SOURCE layout auto-activates its next tab when the moved tab is
|
|
2412
2584
|
* removed, and that GL activation WRITES BACK into the workspace — stomping
|
|
@@ -2425,69 +2597,89 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2425
2597
|
/**
|
|
2426
2598
|
* Toggle pin from context menu
|
|
2427
2599
|
*/
|
|
2428
|
-
|
|
2429
|
-
if (this.
|
|
2430
|
-
this.workspaceManager.TogglePin(this.
|
|
2600
|
+
OnContextPin() {
|
|
2601
|
+
if (this.ContextMenuTabId) {
|
|
2602
|
+
this.workspaceManager.TogglePin(this.ContextMenuTabId);
|
|
2431
2603
|
}
|
|
2432
|
-
this.
|
|
2604
|
+
this.HideContextMenu();
|
|
2605
|
+
}
|
|
2606
|
+
/** @deprecated Use {@link OnContextPin}. */
|
|
2607
|
+
onContextPin() {
|
|
2608
|
+
return this.OnContextPin();
|
|
2433
2609
|
}
|
|
2434
2610
|
/**
|
|
2435
2611
|
* Close tab from context menu
|
|
2436
2612
|
*/
|
|
2437
|
-
|
|
2438
|
-
if (this.
|
|
2439
|
-
const tab = this.workspaceManager.GetTab(this.
|
|
2613
|
+
OnContextClose() {
|
|
2614
|
+
if (this.ContextMenuTabId) {
|
|
2615
|
+
const tab = this.workspaceManager.GetTab(this.ContextMenuTabId);
|
|
2440
2616
|
const manager = tab && this.isRecordTab(tab) ? this.recordsLayoutManager : this.layoutManager;
|
|
2441
|
-
manager.RemoveTab(this.
|
|
2617
|
+
manager.RemoveTab(this.ContextMenuTabId);
|
|
2442
2618
|
}
|
|
2443
2619
|
// The anchor lives on the closed tab — nothing to return focus to.
|
|
2444
|
-
this.
|
|
2620
|
+
this.HideContextMenu(false);
|
|
2621
|
+
}
|
|
2622
|
+
/** @deprecated Use {@link OnContextClose}. */
|
|
2623
|
+
onContextClose() {
|
|
2624
|
+
return this.OnContextClose();
|
|
2445
2625
|
}
|
|
2446
2626
|
/**
|
|
2447
2627
|
* Close all other tabs from context menu
|
|
2448
2628
|
*/
|
|
2449
|
-
|
|
2450
|
-
if (this.
|
|
2451
|
-
this.workspaceManager.CloseOtherTabs(this.
|
|
2629
|
+
OnContextCloseOthers() {
|
|
2630
|
+
if (this.ContextMenuTabId) {
|
|
2631
|
+
this.workspaceManager.CloseOtherTabs(this.ContextMenuTabId);
|
|
2452
2632
|
}
|
|
2453
|
-
this.
|
|
2633
|
+
this.HideContextMenu();
|
|
2634
|
+
}
|
|
2635
|
+
/** @deprecated Use {@link OnContextCloseOthers}. */
|
|
2636
|
+
onContextCloseOthers() {
|
|
2637
|
+
return this.OnContextCloseOthers();
|
|
2454
2638
|
}
|
|
2455
2639
|
/**
|
|
2456
2640
|
* Close tabs to the right from context menu
|
|
2457
2641
|
*/
|
|
2458
|
-
|
|
2459
|
-
if (this.
|
|
2460
|
-
this.workspaceManager.CloseTabsToRight(this.
|
|
2642
|
+
OnContextCloseToRight() {
|
|
2643
|
+
if (this.ContextMenuTabId) {
|
|
2644
|
+
this.workspaceManager.CloseTabsToRight(this.ContextMenuTabId);
|
|
2461
2645
|
}
|
|
2462
|
-
this.
|
|
2646
|
+
this.HideContextMenu();
|
|
2647
|
+
}
|
|
2648
|
+
/** @deprecated Use {@link OnContextCloseToRight}. */
|
|
2649
|
+
onContextCloseToRight() {
|
|
2650
|
+
return this.OnContextCloseToRight();
|
|
2463
2651
|
}
|
|
2464
2652
|
/**
|
|
2465
2653
|
* Check if context menu tab is pinned to Home dashboard
|
|
2466
2654
|
*/
|
|
2467
|
-
get
|
|
2468
|
-
if (!this.
|
|
2655
|
+
get IsContextTabPinnedToHome() {
|
|
2656
|
+
if (!this.ContextMenuTabId)
|
|
2469
2657
|
return false;
|
|
2470
|
-
const tab = this.workspaceManager.GetTab(this.
|
|
2658
|
+
const tab = this.workspaceManager.GetTab(this.ContextMenuTabId);
|
|
2471
2659
|
if (!tab)
|
|
2472
2660
|
return false;
|
|
2473
2661
|
const resourceType = this.resolveResourceType(tab);
|
|
2474
2662
|
return this.pinService.IsPinned(resourceType, tab.configuration);
|
|
2475
2663
|
}
|
|
2664
|
+
/** @deprecated Use {@link IsContextTabPinnedToHome}. */
|
|
2665
|
+
get isContextTabPinnedToHome() {
|
|
2666
|
+
return this.IsContextTabPinnedToHome;
|
|
2667
|
+
}
|
|
2476
2668
|
/**
|
|
2477
2669
|
* Pin current context menu tab to Home dashboard
|
|
2478
2670
|
*/
|
|
2479
|
-
async
|
|
2480
|
-
if (this.
|
|
2481
|
-
this.
|
|
2671
|
+
async OnContextPinToHome() {
|
|
2672
|
+
if (this.IsContextTabPinnedToHome) {
|
|
2673
|
+
this.HideContextMenu();
|
|
2482
2674
|
return;
|
|
2483
2675
|
}
|
|
2484
|
-
if (!this.
|
|
2485
|
-
this.
|
|
2676
|
+
if (!this.ContextMenuTabId) {
|
|
2677
|
+
this.HideContextMenu();
|
|
2486
2678
|
return;
|
|
2487
2679
|
}
|
|
2488
|
-
const tab = this.workspaceManager.GetTab(this.
|
|
2680
|
+
const tab = this.workspaceManager.GetTab(this.ContextMenuTabId);
|
|
2489
2681
|
if (!tab) {
|
|
2490
|
-
this.
|
|
2682
|
+
this.HideContextMenu();
|
|
2491
2683
|
return;
|
|
2492
2684
|
}
|
|
2493
2685
|
const resourceType = this.resolveResourceType(tab);
|
|
@@ -2518,7 +2710,11 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2518
2710
|
else {
|
|
2519
2711
|
MJNotificationService.Instance.CreateSimpleNotification(`"${tab.title}" is already pinned to Home`, 'info', 3000);
|
|
2520
2712
|
}
|
|
2521
|
-
this.
|
|
2713
|
+
this.HideContextMenu();
|
|
2714
|
+
}
|
|
2715
|
+
/** @deprecated Use {@link OnContextPinToHome}. */
|
|
2716
|
+
async onContextPinToHome() {
|
|
2717
|
+
return this.OnContextPinToHome();
|
|
2522
2718
|
}
|
|
2523
2719
|
/**
|
|
2524
2720
|
* Resolve a WorkspaceTab's resource type string for pin matching
|
|
@@ -2545,12 +2741,12 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2545
2741
|
try {
|
|
2546
2742
|
// Find the active content element — differs by mode
|
|
2547
2743
|
let contentEl = null;
|
|
2548
|
-
if (this.
|
|
2549
|
-
contentEl = this.
|
|
2744
|
+
if (this.UseSingleResourceMode) {
|
|
2745
|
+
contentEl = this.DirectContentContainer?.nativeElement ?? null;
|
|
2550
2746
|
}
|
|
2551
2747
|
else {
|
|
2552
2748
|
// In Golden Layout mode, find the active tab's content pane
|
|
2553
|
-
contentEl = this.
|
|
2749
|
+
contentEl = this.GlContainer?.nativeElement?.querySelector('.lm_item_container .lm_content');
|
|
2554
2750
|
}
|
|
2555
2751
|
if (!contentEl)
|
|
2556
2752
|
return;
|
|
@@ -2574,11 +2770,11 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2574
2770
|
async CaptureActiveThumbnail() {
|
|
2575
2771
|
try {
|
|
2576
2772
|
let contentEl = null;
|
|
2577
|
-
if (this.
|
|
2578
|
-
contentEl = this.
|
|
2773
|
+
if (this.UseSingleResourceMode) {
|
|
2774
|
+
contentEl = this.DirectContentContainer?.nativeElement ?? null;
|
|
2579
2775
|
}
|
|
2580
2776
|
else {
|
|
2581
|
-
contentEl = this.
|
|
2777
|
+
contentEl = this.GlContainer?.nativeElement?.querySelector('.lm_item_container .lm_content');
|
|
2582
2778
|
}
|
|
2583
2779
|
if (!contentEl)
|
|
2584
2780
|
return undefined;
|
|
@@ -2594,7 +2790,7 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2594
2790
|
* forever we emit all events upstream
|
|
2595
2791
|
*/
|
|
2596
2792
|
emitFirstLoadCompleteOnce() {
|
|
2597
|
-
this.
|
|
2793
|
+
this.FirstResourceLoadComplete.emit(); // do this each time to be sure we don't suppress messages
|
|
2598
2794
|
}
|
|
2599
2795
|
/**
|
|
2600
2796
|
* Render an inline "missing resource component" error into a host element when
|
|
@@ -2655,12 +2851,12 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2655
2851
|
i0.ɵɵviewQuery(_c0, 5)(_c1, 5)(_c2, 5);
|
|
2656
2852
|
} if (rf & 2) {
|
|
2657
2853
|
let _t;
|
|
2658
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.
|
|
2659
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.
|
|
2660
|
-
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.
|
|
2854
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.GlContainer = _t.first);
|
|
2855
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.DirectContentContainer = _t.first);
|
|
2856
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.RecordsGlContainer = _t.first);
|
|
2661
2857
|
} }, hostBindings: function TabContainerComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
2662
2858
|
i0.ɵɵlistener("resize", function TabContainerComponent_resize_HostBindingHandler() { return ctx.onWindowResize(); }, i0.ɵɵresolveWindow);
|
|
2663
|
-
} }, outputs: { firstResourceLoadComplete: "firstResourceLoadComplete", layoutInitError: "layoutInitError" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 6, vars: 5, consts: [["directContentContainer", ""], ["glContainer", ""], ["recordsGlContainer", ""], [1, "tab-container"], [1, "main-region"], [1, "direct-content-container"], [1, "gl-container"], ["role", "menu", "aria-label", "Tab actions", 1, "context-menu", 3, "left", "top"], [1, "records-region"], [3, "Title", "Icon", "Color", "Count"], [1, "records-gl-container"], [3, "VisibleChange", "ActivateRequested", "CloseRequested", "Entries", "Visible"], [3, "SwitcherRequested", "Title", "Icon", "Color", "Count"], ["role", "menu", "aria-label", "Tab actions", 1, "context-menu", 3, "keydown"], ["type", "button", "role", "menuitem", 1, "context-menu-item", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-thumbtack"], [1, "context-menu-divider"], ["type", "button", "role", "menuitem", 1, "context-menu-item", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-house-chimney"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], ["aria-hidden", "true", 1, "fa-solid", "fa-layer-group"], ["aria-hidden", "true", 1, "fa-solid", "fa-angles-right"], [1, "check"], ["aria-hidden", "true", 1, "fa-solid", "fa-check"], ["type", "button", "role", "menuitem", 1, "context-menu-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-up-right-from-square"], ["aria-hidden", "true", 1, "fa-solid", "fa-file-lines"]], template: function TabContainerComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2859
|
+
} }, outputs: { FirstResourceLoadComplete: "FirstResourceLoadComplete", firstResourceLoadComplete: "firstResourceLoadComplete", LayoutInitError: "LayoutInitError", layoutInitError: "layoutInitError" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 6, vars: 5, consts: [["directContentContainer", ""], ["glContainer", ""], ["recordsGlContainer", ""], [1, "tab-container"], [1, "main-region"], [1, "direct-content-container"], [1, "gl-container"], ["role", "menu", "aria-label", "Tab actions", 1, "context-menu", 3, "left", "top"], [1, "records-region"], [3, "Title", "Icon", "Color", "Count"], [1, "records-gl-container"], [3, "VisibleChange", "ActivateRequested", "CloseRequested", "Entries", "Visible"], [3, "SwitcherRequested", "Title", "Icon", "Color", "Count"], ["role", "menu", "aria-label", "Tab actions", 1, "context-menu", 3, "keydown"], ["type", "button", "role", "menuitem", 1, "context-menu-item", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-thumbtack"], [1, "context-menu-divider"], ["type", "button", "role", "menuitem", 1, "context-menu-item", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-house-chimney"], ["aria-hidden", "true", 1, "fa-solid", "fa-xmark"], ["aria-hidden", "true", 1, "fa-solid", "fa-layer-group"], ["aria-hidden", "true", 1, "fa-solid", "fa-angles-right"], [1, "check"], ["aria-hidden", "true", 1, "fa-solid", "fa-check"], ["type", "button", "role", "menuitem", 1, "context-menu-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-up-right-from-square"], ["aria-hidden", "true", 1, "fa-solid", "fa-file-lines"]], template: function TabContainerComponent_Template(rf, ctx) { if (rf & 1) {
|
|
2664
2860
|
i0.ɵɵelementStart(0, "div", 3)(1, "div", 4);
|
|
2665
2861
|
i0.ɵɵconditionalCreate(2, TabContainerComponent_Conditional_2_Template, 2, 0, "div", 5)(3, TabContainerComponent_Conditional_3_Template, 2, 0, "div", 6);
|
|
2666
2862
|
i0.ɵɵelementEnd();
|
|
@@ -2681,17 +2877,21 @@ export class TabContainerComponent extends BaseAngularComponent {
|
|
|
2681
2877
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TabContainerComponent, [{
|
|
2682
2878
|
type: Component,
|
|
2683
2879
|
args: [{ standalone: false, selector: 'mj-tab-container', encapsulation: ViewEncapsulation.None, template: "<div class=\"tab-container\">\n\n <!-- Main region: nav pages (single-resource or main Golden Layout).\n Hidden (not destroyed) while the RECORDS region is showing, so nav\n content keeps its state and reappears instantly. -->\n <div class=\"main-region\" [class.region-hidden]=\"ShowRecordsRegion\">\n <!-- Single-Resource Mode: Direct component rendering without Golden Layout -->\n <!-- This avoids the 20px height issue when GL header is hidden -->\n @if (useSingleResourceMode) {\n <div #directContentContainer class=\"direct-content-container\"></div>\n } @else {\n <!-- Multi-Tab Mode: Golden Layout Container -->\n <div #glContainer class=\"gl-container\"></div>\n }\n </div>\n\n <!-- RECORDS region: a SEPARATE Golden Layout hosting only record tabs\n (records-style record opens). Always in the DOM once created so the\n layout survives visibility flips; shown only while the active tab is\n a record. Native GL tab bar = record tabs, drag-to-split included. -->\n @if (RecordsStyleActive) {\n <!-- Origin crumbs are PANE-LEVEL now (first element inside each record\n pane \u2014 see RecordOriginCrumbComponent); the region needs no bar. -->\n <div class=\"records-region\" [class.region-hidden]=\"!ShowRecordsRegion\">\n <!-- MOBILE: the GL tab strip is unusable at phone widths (one tab\n fits, no overflow UI) \u2014 the record bar replaces it and opens the\n record switcher sheet. The GL itself runs headerless (HideHeaders). -->\n @if (IsMobileRecords) {\n <mj-record-bar\n [Title]=\"RecordBarTitle\"\n [Icon]=\"RecordBarIcon\"\n [Color]=\"RecordBarColor\"\n [Count]=\"OpenRecordCount\"\n (SwitcherRequested)=\"OpenRecordSwitcher()\">\n </mj-record-bar>\n }\n <div #recordsGlContainer class=\"records-gl-container\"></div>\n </div>\n\n <!-- MOBILE record switcher: bottom sheet listing ALL open records\n (region + docked). Fixed-position \u2014 DOM location here is\n visual-neutral; living in tab-container keeps close routing on the\n same path as the tab context menu. -->\n <mj-record-switcher-sheet\n [Entries]=\"SwitcherEntries\"\n [Visible]=\"RecordSwitcherVisible\"\n (VisibleChange)=\"OnSwitcherVisibleChange($event)\"\n (ActivateRequested)=\"OnSwitcherActivate($event)\"\n (CloseRequested)=\"OnSwitcherClose($event)\">\n </mj-record-switcher-sheet>\n }\n\n <!-- Context Menu (only relevant in multi-tab mode). Real buttons with\n menu semantics: arrow keys rove, Escape closes with focus return to\n the invoking control (see onMenuKeydown / hideContextMenu). -->\n @if (contextMenuVisible) {\n <div\n class=\"context-menu\"\n role=\"menu\"\n aria-label=\"Tab actions\"\n (keydown)=\"onMenuKeydown($event)\"\n [style.left.px]=\"contextMenuX\"\n [style.top.px]=\"contextMenuY\">\n <button type=\"button\" role=\"menuitem\" class=\"context-menu-item\" (click)=\"onContextPin()\">\n <i class=\"fa-solid fa-thumbtack\" aria-hidden=\"true\"></i>\n <span>{{ isContextTabPinned ? 'Unpin Tab' : 'Pin Tab' }}</span>\n </button>\n <div class=\"context-menu-divider\"></div>\n <button type=\"button\" role=\"menuitem\" class=\"context-menu-item\" [class.new-item]=\"!isContextTabPinnedToHome\" [class.disabled]=\"isContextTabPinnedToHome\" [disabled]=\"isContextTabPinnedToHome\" (click)=\"onContextPinToHome()\">\n <i class=\"fa-solid fa-house-chimney\" aria-hidden=\"true\"></i>\n @if (isContextTabPinnedToHome) {\n <span>Pinned to Home</span>\n <span class=\"check\"><i class=\"fa-solid fa-check\" aria-hidden=\"true\"></i></span>\n } @else {\n <span>Pin to Home</span>\n }\n </button>\n @if (canContextMoveToWorkspace || canContextMoveToRecords) {\n <div class=\"context-menu-divider\"></div>\n @if (canContextMoveToWorkspace) {\n <button type=\"button\" role=\"menuitem\" class=\"context-menu-item\" (click)=\"onContextMoveToWorkspace()\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\" aria-hidden=\"true\"></i>\n <span>Move to Workspace</span>\n </button>\n }\n @if (canContextMoveToRecords) {\n <button type=\"button\" role=\"menuitem\" class=\"context-menu-item\" (click)=\"onContextMoveToRecords()\">\n <i class=\"fa-solid fa-file-lines\" aria-hidden=\"true\"></i>\n <span>Move to Records</span>\n </button>\n }\n }\n <div class=\"context-menu-divider\"></div>\n <button type=\"button\" role=\"menuitem\" class=\"context-menu-item\" (click)=\"onContextClose()\">\n <i class=\"fa-solid fa-xmark\" aria-hidden=\"true\"></i>\n <span>Close Tab</span>\n </button>\n <button type=\"button\" role=\"menuitem\" class=\"context-menu-item\" (click)=\"onContextCloseOthers()\">\n <i class=\"fa-solid fa-layer-group\" aria-hidden=\"true\"></i>\n <span>Close Others</span>\n </button>\n <button type=\"button\" role=\"menuitem\" class=\"context-menu-item\" (click)=\"onContextCloseToRight()\">\n <i class=\"fa-solid fa-angles-right\" aria-hidden=\"true\"></i>\n <span>Close to Right</span>\n </button>\n </div>\n }\n</div>\n", styles: [":host {\n display: flex;\n flex: 1;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n.tab-container {\n display: flex;\n flex-direction: column;\n flex: 1;\n width: 100%;\n overflow: hidden;\n}\n\n.gl-container {\n flex: 1;\n width: 100%;\n height: 100%;\n position: relative;\n background: var(--mj-bg-page);\n}\n\n/* Main region (nav pages) and the separate RECORDS region \u2014 exactly one is\n visible at a time. CRITICAL: the hidden region keeps its FULL LAYOUT BOX\n (visibility, not display:none). Golden Layout instances live in both;\n display:none would feed GL 0-size resizes and let it initialize/restore\n against a zero baseline \u2014 the root cause of clipped tab headers, stale\n strips, and the collapsed-sliver layout. */\n.tab-container {\n position: relative;\n}\n\n.main-region,\n.records-region {\n position: absolute;\n inset: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-page);\n}\n\n/* The records GL host fills the region below the origin bar. Must keep a\n real layout box at all times (see the region comment above) \u2014 it's a flex\n child of an always-sized absolute region, so it does. */\n.records-gl-container {\n flex: 1;\n min-height: 0;\n position: relative;\n background: var(--mj-bg-page);\n}\n\n/* Pane layout with an origin crumb as the FIRST element: the crumb keeps\n its fixed 32px (component host); the content sibling flex-fills. The\n height override neutralizes inline height:100% that cached wrapper\n elements carry from earlier renders (CSS !important beats inline). */\nmj-tab-container .lm_items > div > mj-record-origin-crumb,\n.direct-content-container > mj-record-origin-crumb {\n flex-shrink: 0;\n}\n\nmj-tab-container .lm_items > div > *:not(mj-record-origin-crumb),\n.direct-content-container > *:not(mj-record-origin-crumb) {\n flex: 1 1 auto;\n min-height: 0;\n height: auto !important;\n}\n\n/* Defense against visibility punch-through: `visibility: visible` on a\n DESCENDANT defeats an ancestor's visibility:hidden (unlike display:none).\n Real case: explorer-app's global `.visible { visibility: visible\n !important }` utility collides with components whose show-state class is\n named `visible` (several bespoke detail panels did this), leaving their\n overlays painted on top of the records region. The two-class specificity\n here outranks the single-class utility even with both !important. */\n.region-hidden,\n.region-hidden * {\n visibility: hidden !important;\n pointer-events: none !important;\n /* Region swaps must be INSTANT: `transition: all` rules on GL internals\n (e.g. .lm_stack) would otherwise transition `visibility` \u2014 which\n interpolates discretely, keeping the outgoing region painted on top for\n the full transition duration (a ~200ms flash of the record form over\n the destination page). */\n transition: none !important;\n}\n\n/* Direct content container for single-resource mode */\n/* Renders components directly without Golden Layout overhead */\n.direct-content-container {\n flex: 1;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-page);\n overflow: hidden;\n}\n\n.tab-content-container {\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n padding: 20px;\n}\n\n/* Context Menu */\n.context-menu {\n position: fixed;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n min-width: 150px;\n z-index: 10001;\n overflow: hidden;\n}\n\n.context-menu .context-menu-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n cursor: pointer;\n font-size: 13px;\n color: var(--mj-text-primary);\n transition: background 0.15s;\n /* Real <button role=\"menuitem\"> now \u2014 neutralize UA chrome */\n width: 100%;\n text-align: left;\n background: transparent;\n border: none;\n font-family: inherit;\n}\n\n/* Keyboard roving highlights like hover; ring omitted on purpose \u2014 the\n moving highlight IS the focus indicator inside a menu. */\n.context-menu .context-menu-item:focus-visible {\n outline: none;\n background: var(--mj-bg-surface-hover);\n}\n\n.context-menu .context-menu-item i {\n width: 16px;\n text-align: center;\n color: var(--mj-text-secondary);\n}\n\n.context-menu .context-menu-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.context-menu .context-menu-divider {\n height: 1px;\n background: var(--mj-border-default);\n margin: 4px 0;\n}\n\n/* Context menu item variants */\n.context-menu-item.new-item i { color: var(--mj-brand-primary); }\n.context-menu-item.new-item { font-weight: 500; }\n.context-menu-item.disabled { color: var(--mj-text-disabled); cursor: default; }\n.context-menu-item.disabled:hover { background: transparent; }\n.context-menu-item.disabled i { color: var(--mj-text-disabled); }\n.context-menu-item .check { margin-left: auto; color: var(--mj-status-success); font-size: 12px; }\n\n/* Override Golden Layout styles */\n/* Global overrides */\n\n/* Ensure GL root container fills available space */\nmj-tab-container .lm_goldenlayout {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure the root layout item fills space */\nmj-tab-container .lm_root {\n width: 100% !important;\n height: 100% !important;\n}\n\n/* Ensure proper box-sizing for all GL layout elements */\nmj-tab-container .lm_item,\nmj-tab-container .lm_content,\nmj-tab-container .lm_stack,\nmj-tab-container .lm_row,\nmj-tab-container .lm_column {\n box-sizing: border-box !important;\n}\n\n/* Ensure layout items don't overflow */\nmj-tab-container .lm_item {\n overflow: hidden !important;\n}\n\n/* SPLIT panes get a subtle frame so side-by-side content doesn't bleed\n together (single-pane layouts stay frameless). \"Adjacent to a splitter\"\n is exactly and only the split case \u2014 any orientation, any nesting. */\nmj-tab-container .lm_stack:has(+ .lm_splitter),\nmj-tab-container .lm_splitter + .lm_stack {\n border: 1px solid var(--mj-border-default) !important;\n}\n\n/* Fix for .lm_items - the content container inside stacks */\n/* This is separate from .lm_item - it holds the actual tab content */\nmj-tab-container .lm_items {\n width: 100% !important;\n height: calc(100% - 38px) !important; /* Account for header height (38px) */\n box-sizing: border-box !important;\n position: relative !important;\n}\n\n/* When tabs are maximized, no header visible */\nmj-tab-container .lm_stack.lm_maximised > .lm_items {\n height: 100% !important;\n}\n\n/* Target the anonymous ComponentItem div inside lm_items (has no class) */\n/* Created in golden-layout/src/ts/items/component-item.ts:51 without a class */\n/* NOTE: Do NOT set display here - GL uses display:none to hide inactive tabs */\nmj-tab-container .lm_items > div {\n width: 100% !important;\n height: 100% !important;\n box-sizing: border-box !important;\n flex-direction: column !important;\n}\n\n/* Only apply flex display to the active/visible tab content div */\nmj-tab-container .lm_items > div:not([style*=\"display: none\"]) {\n display: flex !important;\n}\n\n/* Clearfix for float-based row layout - GL uses float:left for horizontal panes */\nmj-tab-container .lm_row::after {\n content: \"\" !important;\n display: table !important;\n clear: both !important;\n}\n\n/* Force content children to respect parent bounds (GL sets pixel widths inline) */\nmj-tab-container .lm_content > * {\n max-width: 100% !important;\n width: 100% !important;\n}\n\nmj-tab-container .lm_content {\n background: var(--mj-bg-page) !important;\n display: flex !important;\n flex-direction: column !important;\n height: 100% !important;\n width: 100% !important;\n}\n\nmj-tab-container .lm_item_container {\n background: var(--mj-bg-page) !important;\n}\n\n/* Tab content wrapper - allow scrolling */\n.tab-content-wrapper {\n overflow: auto !important;\n}\n\n/* Make tabs larger and easier to click */\nmj-tab-container .lm_header {\n height: 38px !important;\n padding-top: 2px !important;\n padding-left: 4px !important;\n background: var(--mj-bg-surface-sunken) !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n overflow: visible !important;\n box-sizing: border-box !important;\n}\n\n/* SCROLLING TAB STRIP (browser-tab pattern, Matt's call over GL's overflow\n dropdown): tabs keep natural width and the strip scrolls horizontally.\n Works with settingsConfig()'s effectively-infinite tabOverlapAllowance \u2014\n GL then never re-homes tabs to its dropdown, only writes inline zIndex +\n negative marginLeft, both neutralized here. Scrollbar hidden per the\n browser-tab convention; wheel input is translated to horizontal scroll by\n GoldenLayoutManager.onStripWheel, and activation scrolls the tab into view. */\nmj-tab-container .lm_tabs {\n height: 36px !important;\n left: 0;\n right: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n}\n\nmj-tab-container .lm_tabs::-webkit-scrollbar {\n display: none;\n}\n\n/* Strip nudge arrows \u2014 the VISIBLE overflow affordance (created by\n GoldenLayoutManager.updateStripNudges, one pair per header, [hidden]\n unless that direction has more tabs). The gradient doubles as the\n \"content continues\" edge fade. */\nmj-tab-container .mj-strip-nudge {\n position: absolute;\n top: 0;\n height: 36px;\n width: 28px;\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n padding: 0;\n margin: 0;\n z-index: 3; /* above tabs (z 1/2) within the header context */\n font-size: 11px;\n color: var(--mj-text-secondary);\n cursor: pointer;\n}\n\nmj-tab-container .mj-strip-nudge[hidden] {\n display: none;\n}\n\nmj-tab-container .mj-strip-nudge--left {\n left: 0;\n background: linear-gradient(to right, var(--mj-bg-surface-sunken) 55%, transparent);\n justify-content: flex-start;\n padding-left: 6px;\n}\n\nmj-tab-container .mj-strip-nudge--right {\n right: 0;\n background: linear-gradient(to left, var(--mj-bg-surface-sunken) 55%, transparent);\n justify-content: flex-end;\n padding-right: 6px;\n}\n\nmj-tab-container .mj-strip-nudge:hover {\n color: var(--mj-text-primary);\n}\n\nmj-tab-container .mj-strip-nudge:focus-visible {\n outline: 2px solid var(--mj-border-focus);\n outline-offset: -2px;\n}\n\n/* Hide Golden Layout WINDOW controls (popout/maximise/stack-close). The\n scrolling strip replaces GL's lm_tabdropdown overflow menu entirely (it\n never activates with the infinite overlap allowance). */\nmj-tab-container .lm_controls .lm_popout,\nmj-tab-container .lm_controls .lm_maximise,\nmj-tab-container .lm_controls .lm_close {\n display: none !important;\n}\n\nmj-tab-container .lm_header .lm_tab {\n /* Flex centering: the type-icon slot (and any future adornment) must sit\n on the tab's vertical center \u2014 inline baseline alignment inside the\n 35px line-height text line pushed it ~15px low. */\n /* FULL FLEX FLOW (Matt's refactor): [type icon] [title] [pin] [close] are\n ordinary flex siblings \u2014 no absolute anchoring, no padding reservations,\n no vertical transforms. gap owns horizontal rhythm; align-items owns\n vertical centering for every child. */\n display: flex !important;\n align-items: center !important;\n gap: 5px !important;\n padding: 0 9px !important;\n font-size: 13px !important;\n height: 35px !important;\n /* Scrolling strip: tabs are flex items of .lm_tabs \u2014 never let them\n shrink to \"fit\" (that's what the strip's scroll is for), and zero out\n the negative overlap margins GL writes inline when tabs overflow. */\n flex: 0 0 auto !important;\n margin-left: 0 !important;\n line-height: 35px !important;\n box-sizing: border-box !important;\n cursor: pointer !important;\n user-select: none !important;\n background: transparent !important;\n border: none !important;\n border-bottom: 1px solid var(--mj-border-default) !important;\n transition: all 0.15s ease !important;\n position: relative !important;\n z-index: 1 !important;\n margin-right: 1px !important;\n}\n\n/* Pipe separators between INACTIVE tabs (browser-tab pattern): a short\n centered divider on each tab's right edge establishes separation without\n boxing every tab. Suppressed around the ACTIVE tab (its raised card has\n real edges), around the hovered tab, and after the last tab. */\nmj-tab-container .lm_header .lm_tab::after {\n content: '' !important;\n position: absolute !important;\n right: -1px !important;\n top: 50% !important;\n transform: translateY(-50%) !important;\n width: 1px !important;\n height: 16px !important;\n background: var(--mj-border-strong) !important;\n}\n\nmj-tab-container .lm_header .lm_tab.lm_active::after,\nmj-tab-container .lm_header .lm_tab:has(+ .lm_tab.lm_active)::after,\nmj-tab-container .lm_header .lm_tab:hover::after,\nmj-tab-container .lm_header .lm_tab:has(+ .lm_tab:hover)::after,\nmj-tab-container .lm_header .lm_tab:last-child::after {\n content: none !important;\n}\n\n/* Type-icon slot (Matt's tab design, 2026-07-29): every tab leads with its\n TYPE icon tinted in the app color \u2014 entity icon for records, nav-item/app\n icon for pages. The old 3px app-color left-edge bar is GONE; the icon\n tint carries app identity now. Hovering the TAB swaps the icon to an\n ellipsis: the slot is the visible \"this tab has actions\" affordance \u2014\n clicking it opens the tab-actions menu (same menu as right-click). */\nmj-tab-container .lm_header .lm_tab .mj-tab-type-slot {\n display: inline-flex !important;\n align-items: center !important;\n justify-content: center !important;\n /* 24px = WCAG 2.2 AA minimum pointer target (SC 2.5.8); glyph stays 12px */\n width: 24px !important;\n height: 24px !important;\n border-radius: 5px !important;\n flex-shrink: 0 !important;\n cursor: pointer !important;\n /* The slot is a real <button> now \u2014 neutralize UA button chrome */\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n font: inherit !important;\n color: inherit !important;\n}\n\n/* Keyboard parity with hover: focused slot shows the dots + house focus\n ring (outline idiom \u2014 GL headers clip box-shadows). */\nmj-tab-container .lm_header .lm_tab .mj-tab-type-slot:focus-visible {\n outline: 2px solid var(--mj-border-focus) !important;\n outline-offset: -2px !important;\n}\nmj-tab-container .lm_header .lm_tab .mj-tab-type-slot:focus-visible .mj-tab-type-ico {\n display: none !important;\n}\nmj-tab-container .lm_header .lm_tab .mj-tab-type-slot:focus-visible .mj-tab-dots {\n display: inline-block !important;\n}\n/* GL's base stylesheet styles EVERY `i` inside a tab as its legacy 2x19px\n absolutely-positioned corner decoration (.lm_header .lm_tab i) \u2014 which\n turns our icon elements into slivers the glyph overflows. Restore normal\n flow for the slot's icons. */\nmj-tab-container .lm_header .lm_tab .mj-tab-type-slot i {\n position: static !important;\n width: auto !important;\n height: auto !important;\n}\n\nmj-tab-container .lm_header .lm_tab .mj-tab-type-ico {\n color: var(--app-color, var(--mj-text-muted)) !important;\n font-size: 12px !important;\n line-height: 1 !important;\n}\nmj-tab-container .lm_header .lm_tab .mj-tab-dots {\n display: none !important;\n color: var(--mj-text-secondary) !important;\n font-size: 12px !important;\n line-height: 1 !important;\n}\nmj-tab-container .lm_header .lm_tab:hover .mj-tab-type-ico {\n display: none !important;\n}\nmj-tab-container .lm_header .lm_tab:hover .mj-tab-dots {\n display: inline-block !important;\n}\nmj-tab-container .lm_header .lm_tab .mj-tab-type-slot:hover {\n background: var(--mj-bg-surface-hover) !important;\n}\nmj-tab-container .lm_header .lm_tab .mj-tab-type-slot:hover .mj-tab-dots {\n color: var(--mj-text-primary) !important;\n}\n\nmj-tab-container .lm_header .lm_tab:hover {\n background: var(--mj-bg-surface-hover) !important;\n}\n\n\nmj-tab-container .lm_header .lm_tab.lm_active {\n background: var(--mj-bg-surface) !important;\n height: 36px !important;\n margin-bottom: -1px !important;\n margin-right: 0 !important;\n border: 1px solid var(--mj-border-default) !important;\n border-bottom-color: var(--mj-bg-surface) !important;\n border-radius: 4px 4px 0 0 !important;\n z-index: 2 !important;\n}\n\n\nmj-tab-container .lm_title {\n cursor: pointer !important;\n user-select: none !important;\n /* In-flow flex child: normalize the inherited 35px line-height so the\n text box is glyph-height and centers identically to its siblings;\n truncate instead of colliding when GL constrains tab width. */\n line-height: normal !important;\n flex: 0 1 auto !important;\n min-width: 0 !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n white-space: nowrap !important;\n /* Glyph-overhang room: italics (unpinned tabs) paint past the last\n glyph's advance width, and overflow:hidden clips at the padding edge \u2014\n without this the final letter loses its slant. */\n padding-right: 3px !important;\n}\n\nmj-tab-container .lm_close_tab {\n position: static !important;\n order: 10 !important;\n transform: none !important;\n margin: 0 !important;\n /* 24px WCAG target; glyph stays 10px */\n width: 24px !important;\n height: 24px !important;\n border-radius: 5px !important;\n cursor: pointer !important;\n /* ALWAYS visible (Matt's call): quiet at rest, full on its own hover/focus.\n Discoverability shouldn't depend on hovering. */\n opacity: 0.55 !important;\n transition: opacity 0.15s ease !important;\n flex-shrink: 0 !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n font-size: 10px !important;\n color: var(--mj-text-secondary) !important;\n}\n\nmj-tab-container .lm_close_tab:focus-visible {\n outline: 2px solid var(--mj-border-focus) !important;\n outline-offset: -2px !important;\n opacity: 1 !important;\n}\n\nmj-tab-container .lm_close_tab:hover {\n opacity: 1 !important;\n color: var(--mj-status-error) !important;\n /* background-COLOR, never the shorthand: GL's stock close was a\n background-image PNG and the shorthand silently wiped it (now it's an\n FA ::before glyph, but the discipline stands). */\n background-color: var(--mj-bg-surface-hover) !important;\n}\n\n/* Pinned tabs never show close button (the pin control replaces it) */\nmj-tab-container .lm_header .lm_tab.pinned .lm_close_tab {\n display: none !important;\n}\n\n\n"] }]
|
|
2684
|
-
}], () => [{ type: i1.GoldenLayoutManager }, { type: i1.WorkspaceStateManager }, { type: i1.ApplicationManager }, { type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }, { type: i0.ChangeDetectorRef }], {
|
|
2880
|
+
}], () => [{ type: i1.GoldenLayoutManager }, { type: i1.WorkspaceStateManager }, { type: i1.ApplicationManager }, { type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }, { type: i0.ChangeDetectorRef }], { GlContainer: [{
|
|
2685
2881
|
type: ViewChild,
|
|
2686
2882
|
args: ['glContainer', { static: false }]
|
|
2687
|
-
}],
|
|
2883
|
+
}], DirectContentContainer: [{
|
|
2688
2884
|
type: ViewChild,
|
|
2689
2885
|
args: ['directContentContainer', { static: false }]
|
|
2690
|
-
}],
|
|
2886
|
+
}], RecordsGlContainer: [{
|
|
2691
2887
|
type: ViewChild,
|
|
2692
2888
|
args: ['recordsGlContainer', { static: false }]
|
|
2889
|
+
}], FirstResourceLoadComplete: [{
|
|
2890
|
+
type: Output
|
|
2693
2891
|
}], firstResourceLoadComplete: [{
|
|
2694
2892
|
type: Output
|
|
2893
|
+
}], LayoutInitError: [{
|
|
2894
|
+
type: Output
|
|
2695
2895
|
}], layoutInitError: [{
|
|
2696
2896
|
type: Output
|
|
2697
2897
|
}], onWindowResize: [{
|