@scion/workbench 18.0.0-beta.1 → 18.0.0-beta.3
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/_index.scss +3 -3
- package/design/_workbench-icon-font.scss +1 -1
- package/esm2022/lib/common/objects.util.mjs +7 -1
- package/esm2022/lib/common/uid.util.mjs +22 -0
- package/esm2022/lib/content-projection/content-projection.directive.mjs +16 -17
- package/esm2022/lib/dialog//311/265workbench-dialog.mjs +3 -3
- package/esm2022/lib/filter-field/filter-field.component.mjs +5 -5
- package/esm2022/lib/layout/grid-element/grid-element.component.mjs +6 -16
- package/esm2022/lib/layout/migration/model/workbench-layout-migration-v5.model.mjs +11 -0
- package/esm2022/lib/layout/migration/workbench-layout-migration-v3.service.mjs +2 -2
- package/esm2022/lib/layout/migration/workbench-layout-migration-v5.service.mjs +67 -0
- package/esm2022/lib/layout/stringifier.mjs +70 -0
- package/esm2022/lib/layout/workbench-layout.model.mjs +1 -1
- package/esm2022/lib/layout/workench-layout-serializer.service.mjs +16 -25
- package/esm2022/lib/layout//311/265workbench-layout.mjs +14 -18
- package/esm2022/lib/microfrontend-platform/common/microfrontend.util.mjs +18 -1
- package/esm2022/lib/microfrontend-platform/initialization/microfrontend-platform-initializer.service.mjs +28 -21
- package/esm2022/lib/microfrontend-platform/initialization/workbench-host-manifest-interceptor.service.mjs +11 -1
- package/esm2022/lib/microfrontend-platform/manifest-object-cache.service.mjs +63 -0
- package/esm2022/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog-capability-validator.interceptor.mjs +5 -4
- package/esm2022/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog.component.mjs +2 -2
- package/esm2022/lib/microfrontend-platform/microfrontend-host-message-box/text-message/text-message.component.mjs +3 -3
- package/esm2022/lib/microfrontend-platform/microfrontend-host-popup/microfrontend-host-popup.component.mjs +3 -2
- package/esm2022/lib/microfrontend-platform/microfrontend-message-box/microfrontend-message-box-capability-validator.interceptor.mjs +3 -2
- package/esm2022/lib/microfrontend-platform/microfrontend-message-box/microfrontend-message-box.component.mjs +2 -2
- package/esm2022/lib/microfrontend-platform/microfrontend-perspective/microfrontend-perspective-capability-validator.interceptor.mjs +39 -0
- package/esm2022/lib/microfrontend-platform/microfrontend-perspective/microfrontend-perspective-installer.service.mjs +120 -0
- package/esm2022/lib/microfrontend-platform/microfrontend-perspective/microfrontend-perspective-intent-handler.interceptor.mjs +55 -0
- package/esm2022/lib/microfrontend-platform/microfrontend-perspective/workbench-perspective-data.mjs +19 -0
- package/esm2022/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup-capability-validator.interceptor.mjs +4 -3
- package/esm2022/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup.component.mjs +2 -13
- package/esm2022/lib/microfrontend-platform/microfrontend-view/microfrontend-view-command-handler.service.mjs +1 -16
- package/esm2022/lib/microfrontend-platform/microfrontend-view/microfrontend-view.component.mjs +42 -17
- package/esm2022/lib/microfrontend-platform/public_api.mjs +2 -1
- package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-capability-validator.interceptor.mjs +5 -4
- package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-intent-handler.interceptor.mjs +7 -4
- package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-routes.mjs +26 -4
- package/esm2022/lib/microfrontend-platform/stable-capability-id-assigner.interceptor.mjs +32 -0
- package/esm2022/lib/microfrontend-platform/workbench-microfrontend-support.mjs +23 -5
- package/esm2022/lib/page-not-found/format-url.pipe.mjs +2 -2
- package/esm2022/lib/page-not-found/page-not-found.component.mjs +3 -3
- package/esm2022/lib/part/part.component.mjs +3 -5
- package/esm2022/lib/perspective/workbench-grid-merger.service.mjs +3 -3
- package/esm2022/lib/perspective/workbench-perspective.model.mjs +1 -1
- package/esm2022/lib/perspective/workbench-perspective.service.mjs +61 -51
- package/esm2022/lib/perspective//311/265workbench-perspective.model.mjs +11 -2
- package/esm2022/lib/popup/popup.config.mjs +3 -3
- package/esm2022/lib/portal/wb-component-portal.mjs +3 -1
- package/esm2022/lib/routing/public_api.mjs +1 -2
- package/esm2022/lib/routing/routing.model.mjs +1 -1
- package/esm2022/lib/routing/workbench-auxiliary-route-installer.service.mjs +94 -0
- package/esm2022/lib/routing/workbench-layout-differ.mjs +3 -10
- package/esm2022/lib/routing/workbench-url-observer.service.mjs +31 -27
- package/esm2022/lib/routing/workbench-view-outlet-differ.mjs +58 -0
- package/esm2022/lib/routing//311/265workbench-router.service.mjs +2 -2
- package/esm2022/lib/view/view-move-handler.service.mjs +5 -5
- package/esm2022/lib/view/view.component.mjs +38 -25
- package/esm2022/lib/view/workbench-view-route-guards.mjs +2 -2
- package/esm2022/lib/view//311/265workbench-view.model.mjs +25 -19
- package/esm2022/lib/view-dnd/grid-drop-targets.util.mjs +2 -2
- package/esm2022/lib/workbench-config.mjs +1 -1
- package/esm2022/lib/workbench-id.mjs +3 -3
- package/esm2022/lib/workbench.component.mjs +2 -2
- package/esm2022/lib/workbench.constants.mjs +1 -5
- package/esm2022/lib/workbench.provider.mjs +3 -9
- package/fesm2022/scion-workbench.mjs +855 -326
- package/fesm2022/scion-workbench.mjs.map +1 -1
- package/lib/common/objects.util.d.ts +4 -0
- package/lib/common/uid.util.d.ts +9 -0
- package/lib/dialog//311/265workbench-dialog.d.ts +1 -1
- package/lib/filter-field/filter-field.component.d.ts +1 -1
- package/lib/layout/grid-element/grid-element.component.d.ts +1 -8
- package/lib/layout/migration/model/workbench-layout-migration-v5.model.d.ts +32 -0
- package/lib/layout/migration/workbench-layout-migration-v5.service.d.ts +12 -0
- package/lib/layout/stringifier.d.ts +26 -0
- package/lib/layout/workbench-layout.model.d.ts +3 -3
- package/lib/layout/workench-layout-serializer.service.d.ts +13 -15
- package/lib/layout//311/265workbench-layout.d.ts +3 -3
- package/lib/microfrontend-platform/common/microfrontend.util.d.ts +5 -1
- package/lib/microfrontend-platform/initialization/microfrontend-platform-initializer.service.d.ts +7 -3
- package/lib/microfrontend-platform/manifest-object-cache.service.d.ts +33 -0
- package/lib/microfrontend-platform/microfrontend-host-message-box/text-message/text-message.component.d.ts +1 -1
- package/lib/microfrontend-platform/microfrontend-perspective/microfrontend-perspective-capability-validator.interceptor.d.ts +10 -0
- package/lib/microfrontend-platform/microfrontend-perspective/microfrontend-perspective-installer.service.d.ts +24 -0
- package/lib/microfrontend-platform/microfrontend-perspective/microfrontend-perspective-intent-handler.interceptor.d.ts +20 -0
- package/lib/microfrontend-platform/microfrontend-perspective/workbench-perspective-data.d.ts +9 -0
- package/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup.component.d.ts +0 -4
- package/lib/microfrontend-platform/microfrontend-view/microfrontend-view-command-handler.service.d.ts +0 -4
- package/lib/microfrontend-platform/microfrontend-view/microfrontend-view.component.d.ts +7 -2
- package/lib/microfrontend-platform/public_api.d.ts +1 -0
- package/lib/microfrontend-platform/routing/microfrontend-view-capability-validator.interceptor.d.ts +1 -1
- package/lib/microfrontend-platform/routing/microfrontend-view-routes.d.ts +9 -2
- package/lib/microfrontend-platform/stable-capability-id-assigner.interceptor.d.ts +11 -0
- package/lib/perspective/workbench-perspective.model.d.ts +16 -17
- package/lib/perspective/workbench-perspective.service.d.ts +15 -7
- package/lib/perspective//311/265workbench-perspective.model.d.ts +4 -0
- package/lib/routing/public_api.d.ts +0 -1
- package/lib/routing/{workbench-auxiliary-routes-registrator.service.d.ts → workbench-auxiliary-route-installer.service.d.ts} +3 -3
- package/lib/routing/workbench-layout-differ.d.ts +1 -2
- package/lib/routing/workbench-url-observer.service.d.ts +5 -3
- package/lib/routing/workbench-view-outlet-differ.d.ts +32 -0
- package/lib/view/view.component.d.ts +8 -7
- package/lib/view//311/265workbench-view.model.d.ts +11 -7
- package/lib/workbench-config.d.ts +2 -2
- package/lib/workbench.constants.d.ts +0 -5
- package/package.json +3 -3
- package/esm2022/lib/common/uuid.util.mjs +0 -17
- package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-capability-id-assigner.interceptor.mjs +0 -41
- package/esm2022/lib/routing/workbench-auxiliary-routes-registrator.service.mjs +0 -94
- package/lib/common/uuid.util.d.ts +0 -8
- package/lib/microfrontend-platform/routing/microfrontend-view-capability-id-assigner.interceptor.d.ts +0 -10
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, Component, ChangeDetectionStrategy, Injectable, Inject, Optional, makeEnvironmentProviders, Pipe, NgZone, inject, DestroyRef, runInInjectionContext, HostBinding, Input, EventEmitter, Directive, Output, Injector, HostListener, ElementRef, isDevMode, EnvironmentInjector, ApplicationInitStatus, APP_INITIALIZER, ViewContainerRef, ViewChild, createComponent, forwardRef, ViewChildren, booleanAttribute, CUSTOM_ELEMENTS_SCHEMA, ApplicationRef, ENVIRONMENT_INITIALIZER, NgModule } from '@angular/core';
|
|
2
|
+
import { InjectionToken, Component, ChangeDetectionStrategy, Injectable, Inject, Optional, makeEnvironmentProviders, Pipe, NgZone, inject, DestroyRef, runInInjectionContext, HostBinding, Input, EventEmitter, Directive, Output, Injector, HostListener, ElementRef, isDevMode, EnvironmentInjector, ApplicationInitStatus, APP_INITIALIZER, ViewContainerRef, ViewChild, createComponent, forwardRef, ViewChildren, booleanAttribute, CUSTOM_ELEMENTS_SCHEMA, IterableDiffers, ApplicationRef, ENVIRONMENT_INITIALIZER, NgModule } from '@angular/core';
|
|
3
3
|
import { BehaviorSubject, Subject, merge, fromEvent, Observable, EMPTY, zip, of, skip, audit, concat, noop, asapScheduler, AsyncSubject, lastValueFrom, firstValueFrom, timer, combineLatest, mergeWith, identity, share, ReplaySubject, switchMap as switchMap$1, race, map as map$1, concatWith, delay, animationFrameScheduler, combineLatestWith, pairwise, withLatestFrom, interval, from, mergeMap as mergeMap$1 } from 'rxjs';
|
|
4
4
|
import { SciThrobberComponent } from '@scion/components/throbber';
|
|
5
5
|
import * as i2 from '@angular/router';
|
|
6
6
|
import { NavigationStart, Router, PRIMARY_OUTLET, RouterOutlet, NavigationEnd, UrlSegment, ChildrenOutletContexts, ActivationStart, RouterEvent, NavigationCancel, NavigationError, GuardsCheckEnd, ROUTES } from '@angular/router';
|
|
7
7
|
import { startWith, filter, map, take, mergeMap, observeOn, catchError, takeUntil, switchMap, distinctUntilChanged, first, shareReplay, expand, debounceTime } from 'rxjs/operators';
|
|
8
8
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
9
|
-
import * as
|
|
10
|
-
import { NgIf,
|
|
9
|
+
import * as i5 from '@angular/common';
|
|
10
|
+
import { NgIf, AsyncPipe, DOCUMENT, NgFor, NgClass, NgComponentOutlet, NgTemplateOutlet, KeyValuePipe, Location, LocationStrategy } from '@angular/common';
|
|
11
11
|
import { Arrays, Defined, Objects as Objects$1, Dictionaries, Observables, Maps } from '@scion/toolkit/util';
|
|
12
12
|
import * as i3 from '@angular/cdk/portal';
|
|
13
13
|
import { PortalModule, ComponentPortal, TemplatePortal, DomPortalOutlet } from '@angular/cdk/portal';
|
|
@@ -27,7 +27,7 @@ import { SciDimensionDirective, SciDimensionModule } from '@scion/components/dim
|
|
|
27
27
|
import * as i2$2 from '@angular/forms';
|
|
28
28
|
import { FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
|
|
29
29
|
import * as i2$3 from '@scion/microfrontend-platform';
|
|
30
|
-
import { MessageHeaders, MessageClient, ResponseStatusCodes, MicrofrontendPlatformConfig, APP_IDENTITY, mapToBody, HostManifestInterceptor, ObservableDecorator, IntentInterceptor, CapabilityInterceptor, MicrofrontendPlatformHost,
|
|
30
|
+
import { MessageHeaders, MessageClient, ResponseStatusCodes, MicrofrontendPlatform, PlatformState, MicrofrontendPlatformConfig, APP_IDENTITY, mapToBody, HostManifestInterceptor, ObservableDecorator, IntentInterceptor, CapabilityInterceptor, MicrofrontendPlatformHost, IntentClient, OutletRouter, ManifestService, PlatformPropertyService } from '@scion/microfrontend-platform';
|
|
31
31
|
import { Beans } from '@scion/toolkit/bean-manager';
|
|
32
32
|
import * as i1$1 from '@scion/workbench-client';
|
|
33
33
|
import { eMESSAGE_BOX_MESSAGE_PARAM, WorkbenchCapabilities, ɵMicrofrontendRouteParams as _MicrofrontendRouteParams, ɵTHEME_CONTEXT_KEY as _THEME_CONTEXT_KEY, ɵWorkbenchCommands as _WorkbenchCommands, ɵWorkbenchPopupMessageHeaders as _WorkbenchPopupMessageHeaders, ɵPOPUP_CONTEXT as _POPUP_CONTEXT, WorkbenchPopup, ɵDIALOG_CONTEXT as _DIALOG_CONTEXT, ɵWorkbenchDialogMessageHeaders as _WorkbenchDialogMessageHeaders, WorkbenchDialog as WorkbenchDialog$1, WorkbenchMessageBox, ɵMESSAGE_BOX_CONTEXT as _MESSAGE_BOX_CONTEXT, WorkbenchRouter as WorkbenchRouter$1, WorkbenchPopupService, WorkbenchMessageBoxService as WorkbenchMessageBoxService$1, ɵWorkbenchMessageBoxService as _WorkbenchMessageBoxService, WorkbenchDialogService as WorkbenchDialogService$1, ɵWorkbenchDialogService as _WorkbenchDialogService, WorkbenchNotificationService, ɵVIEW_ID_CONTEXT_KEY as _VIEW_ID_CONTEXT_KEY } from '@scion/workbench-client';
|
|
@@ -1054,10 +1054,6 @@ const MAIN_AREA_LAYOUT_QUERY_PARAM = 'main_area';
|
|
|
1054
1054
|
* DI token to inject the context in which the view tab is rendered.
|
|
1055
1055
|
*/
|
|
1056
1056
|
const VIEW_TAB_RENDERING_CONTEXT = new InjectionToken('VIEW_TAB_RENDERING_CONTEXT');
|
|
1057
|
-
/**
|
|
1058
|
-
* DI token representing the configured workbench layout.
|
|
1059
|
-
*/
|
|
1060
|
-
const WORKBENCH_LAYOUT_CONFIG = new InjectionToken('WORKBENCH_LAYOUT_CONFIG');
|
|
1061
1057
|
/**
|
|
1062
1058
|
* Prefix used to identify an anonymous perspective that the workbench creates for views moved to a new window.
|
|
1063
1059
|
*/
|
|
@@ -1468,6 +1464,12 @@ const Objects = {
|
|
|
1468
1464
|
withoutUndefinedEntries: (object) => {
|
|
1469
1465
|
return Dictionaries.withoutUndefinedEntries(object);
|
|
1470
1466
|
},
|
|
1467
|
+
/**
|
|
1468
|
+
* Stringifies given object to matrix notation: a=b;c=d;e=f
|
|
1469
|
+
*/
|
|
1470
|
+
toMatrixNotation: (object) => {
|
|
1471
|
+
return Object.entries(object ?? {}).map(([key, value]) => `${key}=${value}`).join(';');
|
|
1472
|
+
},
|
|
1471
1473
|
};
|
|
1472
1474
|
|
|
1473
1475
|
/*
|
|
@@ -1775,7 +1777,7 @@ function createNavigationFromCommands(commands, extras) {
|
|
|
1775
1777
|
* Creates navigation extras with workbench navigation instructions.
|
|
1776
1778
|
*/
|
|
1777
1779
|
function createNavigationExtras(layout, extras) {
|
|
1778
|
-
const { workbenchGrid, mainAreaGrid } = layout.serialize();
|
|
1780
|
+
const { workbenchGrid, mainAreaGrid } = layout.serialize({ excludeViewMarkedForRemoval: true });
|
|
1779
1781
|
return {
|
|
1780
1782
|
...extras,
|
|
1781
1783
|
// Instruct the Angular router to process the navigation even if the URL does not change, e.g., when changing the workbench grid which is not contained in the URL.
|
|
@@ -1849,18 +1851,11 @@ class GridElementComponent {
|
|
|
1849
1851
|
this.MTreeNode = MTreeNode;
|
|
1850
1852
|
this.MPart = MPart;
|
|
1851
1853
|
this.children = new Array();
|
|
1852
|
-
/**
|
|
1853
|
-
* Each layout change creates new model object instances since the layout is deserialized from the URL.
|
|
1854
|
-
* Therefore, the "correct" track-by function is critical to help Angular identify DOM elements for reuse, which significantly can
|
|
1855
|
-
* improve performance. Note that we use the index instead of the object identity because a different identity may be computed for
|
|
1856
|
-
* nodes when re-arranging parts. Using the index is like not using *ngFor at all.
|
|
1857
|
-
*/
|
|
1858
|
-
this.indexTrackByFn = (index) => index;
|
|
1859
1854
|
}
|
|
1860
1855
|
ngOnChanges(changes) {
|
|
1861
1856
|
this.children = this.element instanceof MTreeNode ? this.computeChildren(this.element) : [];
|
|
1862
|
-
this.parentNodeId = this.element.parent?.
|
|
1863
|
-
this.nodeId = this.element instanceof MTreeNode ? this.element.
|
|
1857
|
+
this.parentNodeId = this.element.parent?.id;
|
|
1858
|
+
this.nodeId = this.element instanceof MTreeNode ? this.element.id : undefined;
|
|
1864
1859
|
this.partId = this.element instanceof MPart ? this.element.id : undefined;
|
|
1865
1860
|
}
|
|
1866
1861
|
onSashStart() {
|
|
@@ -1869,7 +1864,7 @@ class GridElementComponent {
|
|
|
1869
1864
|
onSashEnd(treeNode, [sashSize1, sashSize2]) {
|
|
1870
1865
|
const ratio = sashSize1 / (sashSize1 + sashSize2);
|
|
1871
1866
|
this._workbenchLayoutService.notifyDragEnding();
|
|
1872
|
-
this._workbenchRouter.navigate(layout => layout.setSplitRatio(treeNode.
|
|
1867
|
+
this._workbenchRouter.navigate(layout => layout.setSplitRatio(treeNode.id, ratio)).then();
|
|
1873
1868
|
}
|
|
1874
1869
|
computeChildren(treeNode) {
|
|
1875
1870
|
const child1Visible = WorkbenchLayouts.isGridElementVisible(treeNode.child1);
|
|
@@ -1890,19 +1885,17 @@ class GridElementComponent {
|
|
|
1890
1885
|
return [];
|
|
1891
1886
|
}
|
|
1892
1887
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: GridElementComponent, deps: [{ token: ɵWorkbenchRouter }, { token: WorkbenchLayoutService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1893
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
1888
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: GridElementComponent, isStandalone: true, selector: "wb-grid-element", inputs: { element: "element" }, host: { properties: { "attr.data-parentnodeid": "this.parentNodeId", "attr.data-nodeid": "this.nodeId", "attr.data-partid": "this.partId" } }, usesOnChanges: true, ngImport: i0, template: "<!-- MPart (leaf) -->\n@if (element | wbInstanceof:MPart; as part) {\n <ng-container [cdkPortalOutlet]=\"part.id | wbPartPortal\"/>\n}\n\n<!-- MTreeNode -->\n@if (element | wbInstanceof:MTreeNode; as treeNode) {\n @if (children.length === 1) {\n <!-- Node with a single visible child. -->\n <wb-grid-element [element]=\"children[0].element\"/>\n }\n @if (children.length > 1) {\n <!-- Node with multiple visible children. -->\n <sci-sashbox [direction]=\"treeNode.direction\"\n [attr.data-nodeid]=\"treeNode.id\"\n (sashStart)=\"onSashStart()\"\n (sashEnd)=\"onSashEnd(treeNode, $event)\">\n @for (child of children; track child.element.id) {\n <ng-template sciSash [size]=\"child.size\">\n <wb-grid-element [element]=\"child.element\" [class]=\"'sash-' + ($index + 1)\"/>\n </ng-template>\n }\n </sci-sashbox>\n }\n}\n", styles: [":host{display:grid}:host>sci-sashbox{z-index:auto;--sci-sashbox-gap: 0;--sci-sashbox-splitter-background-color: var(--sci-workbench-part-divider-color);--sci-sashbox-splitter-background-color-hover: var(--sci-workbench-part-divider-color-hover);--sci-sashbox-splitter-size: var(--sci-workbench-part-divider-size);--sci-sashbox-splitter-size-hover: var(--sci-workbench-part-divider-size-hover);--sci-sashbox-splitter-touch-target-size: var(--sci-workbench-part-divider-touch-target-size);--sci-sashbox-splitter-border-radius: 0;--sci-sashbox-splitter-opacity-active: var(--sci-workbench-part-divider-opacity-active);--sci-sashbox-splitter-opacity-hover: var(--sci-workbench-part-divider-opacity-hover)}\n"], dependencies: [{ kind: "component", type: GridElementComponent, selector: "wb-grid-element", inputs: ["element"] }, { kind: "pipe", type: InstanceofPipe, name: "wbInstanceof" }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "pipe", type: PartPortalPipe, name: "wbPartPortal" }, { kind: "component", type: SciSashboxComponent, selector: "sci-sashbox", inputs: ["direction"], outputs: ["sashStart", "sashEnd"] }, { kind: "directive", type: SciSashDirective, selector: "ng-template[sciSash]", inputs: ["size", "minSize"], exportAs: ["sciSash"] }] }); }
|
|
1894
1889
|
}
|
|
1895
1890
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: GridElementComponent, decorators: [{
|
|
1896
1891
|
type: Component,
|
|
1897
1892
|
args: [{ selector: 'wb-grid-element', standalone: true, imports: [
|
|
1898
|
-
NgIf,
|
|
1899
|
-
NgFor,
|
|
1900
1893
|
InstanceofPipe,
|
|
1901
1894
|
PortalModule,
|
|
1902
1895
|
PartPortalPipe,
|
|
1903
1896
|
SciSashboxComponent,
|
|
1904
1897
|
SciSashDirective,
|
|
1905
|
-
], template: "<!-- MPart (leaf) -->\n
|
|
1898
|
+
], template: "<!-- MPart (leaf) -->\n@if (element | wbInstanceof:MPart; as part) {\n <ng-container [cdkPortalOutlet]=\"part.id | wbPartPortal\"/>\n}\n\n<!-- MTreeNode -->\n@if (element | wbInstanceof:MTreeNode; as treeNode) {\n @if (children.length === 1) {\n <!-- Node with a single visible child. -->\n <wb-grid-element [element]=\"children[0].element\"/>\n }\n @if (children.length > 1) {\n <!-- Node with multiple visible children. -->\n <sci-sashbox [direction]=\"treeNode.direction\"\n [attr.data-nodeid]=\"treeNode.id\"\n (sashStart)=\"onSashStart()\"\n (sashEnd)=\"onSashEnd(treeNode, $event)\">\n @for (child of children; track child.element.id) {\n <ng-template sciSash [size]=\"child.size\">\n <wb-grid-element [element]=\"child.element\" [class]=\"'sash-' + ($index + 1)\"/>\n </ng-template>\n }\n </sci-sashbox>\n }\n}\n", styles: [":host{display:grid}:host>sci-sashbox{z-index:auto;--sci-sashbox-gap: 0;--sci-sashbox-splitter-background-color: var(--sci-workbench-part-divider-color);--sci-sashbox-splitter-background-color-hover: var(--sci-workbench-part-divider-color-hover);--sci-sashbox-splitter-size: var(--sci-workbench-part-divider-size);--sci-sashbox-splitter-size-hover: var(--sci-workbench-part-divider-size-hover);--sci-sashbox-splitter-touch-target-size: var(--sci-workbench-part-divider-touch-target-size);--sci-sashbox-splitter-border-radius: 0;--sci-sashbox-splitter-opacity-active: var(--sci-workbench-part-divider-opacity-active);--sci-sashbox-splitter-opacity-hover: var(--sci-workbench-part-divider-opacity-hover)}\n"] }]
|
|
1906
1899
|
}], ctorParameters: () => [{ type: ɵWorkbenchRouter }, { type: WorkbenchLayoutService }], propDecorators: { parentNodeId: [{
|
|
1907
1900
|
type: HostBinding,
|
|
1908
1901
|
args: ['attr.data-parentnodeid']
|
|
@@ -2363,22 +2356,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
2363
2356
|
args: [{ name: 'wbGridElementIfVisible', standalone: true }]
|
|
2364
2357
|
}] });
|
|
2365
2358
|
|
|
2366
|
-
/*
|
|
2367
|
-
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
2368
|
-
*
|
|
2369
|
-
* This program and the accompanying materials are made
|
|
2370
|
-
* available under the terms of the Eclipse Public License 2.0
|
|
2371
|
-
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
2372
|
-
*
|
|
2373
|
-
* SPDX-License-Identifier: EPL-2.0
|
|
2374
|
-
*/
|
|
2375
|
-
/**
|
|
2376
|
-
* Generates a UUID (universally unique identifier) compliant with the RFC 4122 version 4.
|
|
2377
|
-
*/
|
|
2378
|
-
function randomUUID() {
|
|
2379
|
-
return UUID.randomUUID();
|
|
2380
|
-
}
|
|
2381
|
-
|
|
2382
2359
|
/*
|
|
2383
2360
|
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
2384
2361
|
*
|
|
@@ -2395,7 +2372,7 @@ function randomUUID() {
|
|
|
2395
2372
|
*/
|
|
2396
2373
|
const WORKBENCH_ID = new InjectionToken('WORKBENCH_ID', {
|
|
2397
2374
|
providedIn: 'root',
|
|
2398
|
-
factory: () => randomUUID(),
|
|
2375
|
+
factory: () => UUID.randomUUID(),
|
|
2399
2376
|
});
|
|
2400
2377
|
|
|
2401
2378
|
/*
|
|
@@ -2435,7 +2412,7 @@ const GridDropTargets = {
|
|
|
2435
2412
|
}
|
|
2436
2413
|
default: {
|
|
2437
2414
|
return {
|
|
2438
|
-
elementId: grid.root
|
|
2415
|
+
elementId: grid.root.id,
|
|
2439
2416
|
region: dropRegion,
|
|
2440
2417
|
workbenchId,
|
|
2441
2418
|
newPart: { ratio: .2 },
|
|
@@ -3128,7 +3105,7 @@ class WorkbenchView {
|
|
|
3128
3105
|
*/
|
|
3129
3106
|
class FormatUrlPipe {
|
|
3130
3107
|
transform(url) {
|
|
3131
|
-
return url.map(segment => segment
|
|
3108
|
+
return url.map(segment => `${segment}`).join('/');
|
|
3132
3109
|
}
|
|
3133
3110
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FormatUrlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
3134
3111
|
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.2", ngImport: i0, type: FormatUrlPipe, isStandalone: true, name: "appFormatUrl" }); }
|
|
@@ -3153,13 +3130,13 @@ class PageNotFoundComponent {
|
|
|
3153
3130
|
this.view = inject(WorkbenchView);
|
|
3154
3131
|
}
|
|
3155
3132
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: PageNotFoundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3156
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: PageNotFoundComponent, isStandalone: true, selector: "wb-page-not-found", ngImport: i0, template: "<header>Page Not Found</header>\n\n<section class=\"message\">\n The requested page <span class=\"url\">{{view.urlSegments | appFormatUrl}}</span> was not found.\n <br>\n The URL may have changed. Try to open the view again.\n</section>\n\n<button (click)=\"view.close()\">Close</button>\n\n@if (isDevMode) {\n <section class=\"developer-hint\">\n You can create a custom \"
|
|
3133
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: PageNotFoundComponent, isStandalone: true, selector: "wb-page-not-found", ngImport: i0, template: "<header>Page Not Found</header>\n\n<section class=\"message\">\n The requested page <span class=\"url\">{{view.urlSegments | appFormatUrl}}</span> was not found.\n <br>\n The URL may have changed. Try to open the view again.\n</section>\n\n<button (click)=\"view.close()\">Close</button>\n\n@if (isDevMode) {\n <section class=\"developer-hint\">\n You can create a custom \"Not Found\" page component and register it in the workbench configuration to personalize this page.\n </section>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:2em;padding:1em;align-items:center}:host>header{font-weight:700;font-size:1.3rem}:host>section.message{text-align:center;line-height:1.75}:host>section.message>span.url{font-weight:700}:host>section.developer-hint{border:1px solid var(--sci-color-accent);border-radius:var(--sci-corner);padding:1em;max-width:550px;color:var(--sci-color-accent);font-family:monospace;text-align:center}:host>button{all:unset;cursor:pointer;padding:.5em 1.5em;color:var(--sci-color-accent-inverse);background-color:var(--sci-color-accent);background-clip:padding-box;border:1px solid var(--sci-color-accent);border-radius:var(--sci-corner);text-align:center}:host>button:focus,:host>button:active{border-color:transparent;outline:1px solid var(--sci-color-accent);color:var(--sci-color-accent-inverse)}\n"], dependencies: [{ kind: "pipe", type: FormatUrlPipe, name: "appFormatUrl" }] }); }
|
|
3157
3134
|
}
|
|
3158
3135
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: PageNotFoundComponent, decorators: [{
|
|
3159
3136
|
type: Component,
|
|
3160
3137
|
args: [{ selector: 'wb-page-not-found', standalone: true, imports: [
|
|
3161
3138
|
FormatUrlPipe,
|
|
3162
|
-
], template: "<header>Page Not Found</header>\n\n<section class=\"message\">\n The requested page <span class=\"url\">{{view.urlSegments | appFormatUrl}}</span> was not found.\n <br>\n The URL may have changed. Try to open the view again.\n</section>\n\n<button (click)=\"view.close()\">Close</button>\n\n@if (isDevMode) {\n <section class=\"developer-hint\">\n You can create a custom \"
|
|
3139
|
+
], template: "<header>Page Not Found</header>\n\n<section class=\"message\">\n The requested page <span class=\"url\">{{view.urlSegments | appFormatUrl}}</span> was not found.\n <br>\n The URL may have changed. Try to open the view again.\n</section>\n\n<button (click)=\"view.close()\">Close</button>\n\n@if (isDevMode) {\n <section class=\"developer-hint\">\n You can create a custom \"Not Found\" page component and register it in the workbench configuration to personalize this page.\n </section>\n}\n", styles: [":host{display:flex;flex-direction:column;gap:2em;padding:1em;align-items:center}:host>header{font-weight:700;font-size:1.3rem}:host>section.message{text-align:center;line-height:1.75}:host>section.message>span.url{font-weight:700}:host>section.developer-hint{border:1px solid var(--sci-color-accent);border-radius:var(--sci-corner);padding:1em;max-width:550px;color:var(--sci-color-accent);font-family:monospace;text-align:center}:host>button{all:unset;cursor:pointer;padding:.5em 1.5em;color:var(--sci-color-accent-inverse);background-color:var(--sci-color-accent);background-clip:padding-box;border:1px solid var(--sci-color-accent);border-radius:var(--sci-corner);text-align:center}:host>button:focus,:host>button:active{border-color:transparent;outline:1px solid var(--sci-color-accent);color:var(--sci-color-accent-inverse)}\n"] }]
|
|
3163
3140
|
}] });
|
|
3164
3141
|
|
|
3165
3142
|
/*
|
|
@@ -3241,7 +3218,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
3241
3218
|
/**
|
|
3242
3219
|
* Facilitates the registration of auxiliary routes of top-level routes.
|
|
3243
3220
|
*/
|
|
3244
|
-
class
|
|
3221
|
+
class WorkbenchAuxiliaryRouteInstaller {
|
|
3245
3222
|
constructor(_workbenchConfig, _router) {
|
|
3246
3223
|
this._workbenchConfig = _workbenchConfig;
|
|
3247
3224
|
this._router = _router;
|
|
@@ -3265,7 +3242,7 @@ class WorkbenchAuxiliaryRoutesRegistrator {
|
|
|
3265
3242
|
...this._router.config
|
|
3266
3243
|
.filter(route => !route.outlet || route.outlet === PRIMARY_OUTLET)
|
|
3267
3244
|
.map(route => ({ ...route, data: { ...route.data, [WorkbenchRouteData.ɵoutlet]: outlet } })),
|
|
3268
|
-
// Register "
|
|
3245
|
+
// Register "Not Found" page route as the last route of the outlet.
|
|
3269
3246
|
{
|
|
3270
3247
|
path: '**',
|
|
3271
3248
|
loadComponent: () => this._workbenchConfig.pageNotFoundComponent ?? PageNotFoundComponent,
|
|
@@ -3301,10 +3278,10 @@ class WorkbenchAuxiliaryRoutesRegistrator {
|
|
|
3301
3278
|
const newRoutes = [...config];
|
|
3302
3279
|
this._router.config.splice(0, this._router.config.length, ...newRoutes);
|
|
3303
3280
|
}
|
|
3304
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type:
|
|
3305
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type:
|
|
3281
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchAuxiliaryRouteInstaller, deps: [{ token: WorkbenchConfig }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3282
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchAuxiliaryRouteInstaller, providedIn: 'root' }); }
|
|
3306
3283
|
}
|
|
3307
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type:
|
|
3284
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchAuxiliaryRouteInstaller, decorators: [{
|
|
3308
3285
|
type: Injectable,
|
|
3309
3286
|
args: [{ providedIn: 'root' }]
|
|
3310
3287
|
}], ctorParameters: () => [{ type: WorkbenchConfig }, { type: i2.Router }] });
|
|
@@ -3792,13 +3769,13 @@ class WorkbenchRouterLinkDirective {
|
|
|
3792
3769
|
ngOnDestroy() {
|
|
3793
3770
|
this._ngOnDestroy$.next();
|
|
3794
3771
|
}
|
|
3795
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchRouterLinkDirective, deps: [{ token: WorkbenchRouter }, { token: i2.Router }, { token: i2.ActivatedRoute }, { token:
|
|
3772
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchRouterLinkDirective, deps: [{ token: WorkbenchRouter }, { token: i2.Router }, { token: i2.ActivatedRoute }, { token: i5.LocationStrategy }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: WorkbenchView, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3796
3773
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.2", type: WorkbenchRouterLinkDirective, isStandalone: true, selector: "[wbRouterLink]", inputs: { wbRouterLink: "wbRouterLink", extras: ["wbRouterLinkExtras", "extras"] }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.metaKey)" }, properties: { "attr.href": "this.href" } }, usesOnChanges: true, ngImport: i0 }); }
|
|
3797
3774
|
}
|
|
3798
3775
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchRouterLinkDirective, decorators: [{
|
|
3799
3776
|
type: Directive,
|
|
3800
3777
|
args: [{ selector: '[wbRouterLink]', standalone: true }]
|
|
3801
|
-
}], ctorParameters: () => [{ type: WorkbenchRouter }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type:
|
|
3778
|
+
}], ctorParameters: () => [{ type: WorkbenchRouter }, { type: i2.Router }, { type: i2.ActivatedRoute }, { type: i5.LocationStrategy }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: WorkbenchView, decorators: [{
|
|
3802
3779
|
type: Optional
|
|
3803
3780
|
}] }], propDecorators: { href: [{
|
|
3804
3781
|
type: HostBinding,
|
|
@@ -3924,6 +3901,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
3924
3901
|
args: [{ providedIn: 'root' }]
|
|
3925
3902
|
}] });
|
|
3926
3903
|
|
|
3904
|
+
/*
|
|
3905
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
3906
|
+
*
|
|
3907
|
+
* This program and the accompanying materials are made
|
|
3908
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
3909
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
3910
|
+
*
|
|
3911
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
3912
|
+
*/
|
|
3913
|
+
/**
|
|
3914
|
+
* Generates a UID (unique identifier).
|
|
3915
|
+
*/
|
|
3916
|
+
const UID = {
|
|
3917
|
+
/**
|
|
3918
|
+
* Generates a UID (unique identifier) with length 8.
|
|
3919
|
+
*/
|
|
3920
|
+
randomUID: () => {
|
|
3921
|
+
return UUID.randomUUID().substring(0, 8);
|
|
3922
|
+
},
|
|
3923
|
+
};
|
|
3924
|
+
|
|
3927
3925
|
/*
|
|
3928
3926
|
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
3929
3927
|
*
|
|
@@ -3958,7 +3956,7 @@ class WorkbenchLayoutMigrationV3 {
|
|
|
3958
3956
|
// Consider the ids of views contained in the URL as already used.
|
|
3959
3957
|
// Otherwise, when migrating the main area and using a view id already present in the perspective,
|
|
3960
3958
|
// the view outlet would not be removed from the URL, resulting the migrated view to display
|
|
3961
|
-
// "
|
|
3959
|
+
// "Not Found" page or incorrect content.
|
|
3962
3960
|
const viewOutlets = RouterUtils.parseViewOutlets(this.getCurrentUrl());
|
|
3963
3961
|
const usedViewIds = new Set([...viewOutlets.keys(), ...collectViewIds(partGridV2.root)]);
|
|
3964
3962
|
// Migrate the grid.
|
|
@@ -4140,6 +4138,140 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
4140
4138
|
args: [{ providedIn: 'root' }]
|
|
4141
4139
|
}] });
|
|
4142
4140
|
|
|
4141
|
+
/*
|
|
4142
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
4143
|
+
*
|
|
4144
|
+
* This program and the accompanying materials are made
|
|
4145
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
4146
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
4147
|
+
*
|
|
4148
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
4149
|
+
*/
|
|
4150
|
+
/**
|
|
4151
|
+
* Migrates the workbench layout from version 4 to version 5.
|
|
4152
|
+
*
|
|
4153
|
+
* TODO [Angular 20] Remove migrator.
|
|
4154
|
+
*/
|
|
4155
|
+
class WorkbenchLayoutMigrationV5 {
|
|
4156
|
+
migrate(json) {
|
|
4157
|
+
const partGridV4 = JSON.parse(json);
|
|
4158
|
+
// Migrate the grid.
|
|
4159
|
+
const partGridV5 = {
|
|
4160
|
+
...partGridV4,
|
|
4161
|
+
root: migrateGridElement(partGridV4.root),
|
|
4162
|
+
};
|
|
4163
|
+
return JSON.stringify(partGridV5);
|
|
4164
|
+
function migrateGridElement(elementV4) {
|
|
4165
|
+
switch (elementV4.type) {
|
|
4166
|
+
case 'MTreeNode':
|
|
4167
|
+
return migrateNode(elementV4);
|
|
4168
|
+
case 'MPart':
|
|
4169
|
+
return migratePart(elementV4);
|
|
4170
|
+
default:
|
|
4171
|
+
throw Error(`[WorkbenchLayoutError] Unable to migrate to the latest version. Expected element to be of type 'MPart' or 'MTreeNode'. [version=3, element=${JSON.stringify(elementV4)}]`);
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
function migrateNode(nodeV4) {
|
|
4175
|
+
return {
|
|
4176
|
+
...nodeV4,
|
|
4177
|
+
id: UID.randomUID(),
|
|
4178
|
+
child1: migrateGridElement(nodeV4.child1),
|
|
4179
|
+
child2: migrateGridElement(nodeV4.child2),
|
|
4180
|
+
};
|
|
4181
|
+
}
|
|
4182
|
+
function migratePart(partV4) {
|
|
4183
|
+
return { ...partV4, views: partV4.views.map(migrateView) };
|
|
4184
|
+
}
|
|
4185
|
+
function migrateView(viewV4) {
|
|
4186
|
+
const viewV5 = {
|
|
4187
|
+
...viewV4,
|
|
4188
|
+
uid: UID.randomUID(),
|
|
4189
|
+
navigation: viewV4.navigation ? { ...viewV4.navigation, id: UID.randomUID() } : undefined,
|
|
4190
|
+
};
|
|
4191
|
+
if (!viewV5.navigation) {
|
|
4192
|
+
delete viewV5.navigation;
|
|
4193
|
+
}
|
|
4194
|
+
return viewV5;
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchLayoutMigrationV5, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4198
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchLayoutMigrationV5, providedIn: 'root' }); }
|
|
4199
|
+
}
|
|
4200
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchLayoutMigrationV5, decorators: [{
|
|
4201
|
+
type: Injectable,
|
|
4202
|
+
args: [{ providedIn: 'root' }]
|
|
4203
|
+
}] });
|
|
4204
|
+
|
|
4205
|
+
/*
|
|
4206
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
4207
|
+
*
|
|
4208
|
+
* This program and the accompanying materials are made
|
|
4209
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
4210
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
4211
|
+
*
|
|
4212
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
4213
|
+
*/
|
|
4214
|
+
/**
|
|
4215
|
+
* Stringifies given data, exluding specified fields from serialization.
|
|
4216
|
+
*
|
|
4217
|
+
* To exclude a field, specify the path to the field in the object tree,
|
|
4218
|
+
* using the slash as delimiter. The path supports the asterisk (`*`) to match a
|
|
4219
|
+
* single segment or the globstar (`**`) to match multiple segments.
|
|
4220
|
+
*/
|
|
4221
|
+
function stringify(data, exclusions) {
|
|
4222
|
+
if (!exclusions?.length) {
|
|
4223
|
+
return JSON.stringify(data);
|
|
4224
|
+
}
|
|
4225
|
+
const objectStack = new Array();
|
|
4226
|
+
const compiledExclusions = exclusions.map(exclusion => new CompiledExclusion(exclusion));
|
|
4227
|
+
return JSON.stringify(data, (key, value) => {
|
|
4228
|
+
if (key === '') { // root node
|
|
4229
|
+
return value;
|
|
4230
|
+
}
|
|
4231
|
+
// Remove object(s) from the stack if finished their serialization.
|
|
4232
|
+
while (objectStack.at(-1)?.fieldsToSerialize.size === 0) {
|
|
4233
|
+
objectStack.pop();
|
|
4234
|
+
}
|
|
4235
|
+
// Mark current field as serialized.
|
|
4236
|
+
objectStack.at(-1)?.fieldsToSerialize.delete(key);
|
|
4237
|
+
// Check if to exclude the current field from serialization.
|
|
4238
|
+
const exclude = compiledExclusions.some(exclusion => exclusion.matches(objectStack, key, value));
|
|
4239
|
+
// Push object to stack if type of object.
|
|
4240
|
+
if (!exclude && typeof value === 'object') {
|
|
4241
|
+
objectStack.push({ key, value, fieldsToSerialize: new Set(Object.keys(value)) });
|
|
4242
|
+
}
|
|
4243
|
+
return exclude ? undefined : value;
|
|
4244
|
+
});
|
|
4245
|
+
}
|
|
4246
|
+
/**
|
|
4247
|
+
* Represents an exclusion, with the path compiled to a regex.
|
|
4248
|
+
*/
|
|
4249
|
+
class CompiledExclusion {
|
|
4250
|
+
constructor(exclusion) {
|
|
4251
|
+
exclusion = typeof exclusion === 'string' ? ({ path: exclusion, predicate: () => true }) : exclusion;
|
|
4252
|
+
const path = exclusion.path
|
|
4253
|
+
.replaceAll('/*/', '/[^/]+/') // replace asterisk to match single segment
|
|
4254
|
+
.replaceAll('**/', '.+/') // replace globstar to match multiple root segments
|
|
4255
|
+
.replaceAll('/**/', '/.+/'); // replace globstar to match multiple segments
|
|
4256
|
+
this._regex = new RegExp(`^${path}$`);
|
|
4257
|
+
this._predicate = exclusion.predicate;
|
|
4258
|
+
}
|
|
4259
|
+
/**
|
|
4260
|
+
* Tests if given field matches this exclusion.
|
|
4261
|
+
*/
|
|
4262
|
+
matches(objectStack, key, value) {
|
|
4263
|
+
const path = objectStack.map(objectValue => objectValue.key).concat(key).join('/');
|
|
4264
|
+
if (!this._regex.test(path)) {
|
|
4265
|
+
return false;
|
|
4266
|
+
}
|
|
4267
|
+
const objectPath = objectStack.map(objectValue => objectValue.value);
|
|
4268
|
+
if (!this._predicate(objectPath, key, value)) {
|
|
4269
|
+
return false;
|
|
4270
|
+
}
|
|
4271
|
+
return true;
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
|
|
4143
4275
|
/*
|
|
4144
4276
|
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
4145
4277
|
*
|
|
@@ -4156,25 +4288,20 @@ class WorkbenchLayoutSerializer {
|
|
|
4156
4288
|
constructor() {
|
|
4157
4289
|
this._workbenchLayoutMigrator = new WorkbenchMigrator()
|
|
4158
4290
|
.registerMigration(2, inject(WorkbenchLayoutMigrationV3))
|
|
4159
|
-
.registerMigration(3, inject(WorkbenchLayoutMigrationV4))
|
|
4291
|
+
.registerMigration(3, inject(WorkbenchLayoutMigrationV4))
|
|
4292
|
+
.registerMigration(4, inject(WorkbenchLayoutMigrationV5));
|
|
4160
4293
|
}
|
|
4161
|
-
serializeGrid(grid,
|
|
4294
|
+
serializeGrid(grid, flags) {
|
|
4162
4295
|
if (grid === null || grid === undefined) {
|
|
4163
4296
|
return null;
|
|
4164
4297
|
}
|
|
4165
|
-
const
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
if (!options?.includeMarkedForRemovalFlag) {
|
|
4173
|
-
transientFields.add('markedForRemoval');
|
|
4174
|
-
}
|
|
4175
|
-
const json = JSON.stringify(grid, (key, value) => {
|
|
4176
|
-
return transientFields.has(key) ? undefined : value;
|
|
4177
|
-
});
|
|
4298
|
+
const json = stringify(grid, new Array()
|
|
4299
|
+
.concat('**/parent')
|
|
4300
|
+
.concat('migrated')
|
|
4301
|
+
.concat(flags?.excludeTreeNodeId ? ({ path: '**/id', predicate: context => context.at(-1) instanceof MTreeNode }) : [])
|
|
4302
|
+
.concat(flags?.excludeViewUid ? '**/views/*/uid' : [])
|
|
4303
|
+
.concat(flags?.excludeViewMarkedForRemoval ? '**/views/*/markedForRemoval' : [])
|
|
4304
|
+
.concat(flags?.excludeViewNavigationId ? '**/views/*/navigation/id' : []));
|
|
4178
4305
|
return window.btoa(`${json}${VERSION_SEPARATOR$1}${WORKBENCH_LAYOUT_VERSION}`);
|
|
4179
4306
|
}
|
|
4180
4307
|
/**
|
|
@@ -4187,11 +4314,10 @@ class WorkbenchLayoutSerializer {
|
|
|
4187
4314
|
// Parse the JSON.
|
|
4188
4315
|
const grid = JSON.parse(migratedJsonGrid, (key, value) => {
|
|
4189
4316
|
if (MPart.isMPart(value)) {
|
|
4190
|
-
|
|
4191
|
-
return new MPart({ ...value, views }); // create a class object from the object literal
|
|
4317
|
+
return new MPart(value); // create a class object from the object literal
|
|
4192
4318
|
}
|
|
4193
4319
|
if (MTreeNode.isMTreeNode(value)) {
|
|
4194
|
-
return new MTreeNode(
|
|
4320
|
+
return new MTreeNode(value); // create a class object from the object literal
|
|
4195
4321
|
}
|
|
4196
4322
|
return value;
|
|
4197
4323
|
});
|
|
@@ -4238,11 +4364,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
4238
4364
|
*
|
|
4239
4365
|
* @see WorkbenchMigrator
|
|
4240
4366
|
*/
|
|
4241
|
-
const WORKBENCH_LAYOUT_VERSION =
|
|
4242
|
-
/**
|
|
4243
|
-
* Fields not serialized into JSON representation.
|
|
4244
|
-
*/
|
|
4245
|
-
const TRANSIENT_FIELDS = new Set().add('parent').add('migrated');
|
|
4367
|
+
const WORKBENCH_LAYOUT_VERSION = 5;
|
|
4246
4368
|
/**
|
|
4247
4369
|
* Separates the serialized JSON model and its version in the base64-encoded string.
|
|
4248
4370
|
*
|
|
@@ -4491,10 +4613,10 @@ class ɵWorkbenchLayout {
|
|
|
4491
4613
|
addView(id, options) {
|
|
4492
4614
|
const workingCopy = this.workingCopy();
|
|
4493
4615
|
if (WorkbenchLayouts.isViewId(id)) {
|
|
4494
|
-
workingCopy.__addView({ id, uid:
|
|
4616
|
+
workingCopy.__addView({ id, uid: UID.randomUID() }, options);
|
|
4495
4617
|
}
|
|
4496
4618
|
else {
|
|
4497
|
-
workingCopy.__addView({ id: this.computeNextViewId(), alternativeId: id, uid:
|
|
4619
|
+
workingCopy.__addView({ id: this.computeNextViewId(), alternativeId: id, uid: UID.randomUID() }, options);
|
|
4498
4620
|
}
|
|
4499
4621
|
return workingCopy;
|
|
4500
4622
|
}
|
|
@@ -4587,11 +4709,11 @@ class ɵWorkbenchLayout {
|
|
|
4587
4709
|
/**
|
|
4588
4710
|
* Serializes this layout into a URL-safe base64 string.
|
|
4589
4711
|
*/
|
|
4590
|
-
serialize() {
|
|
4712
|
+
serialize(flags) {
|
|
4591
4713
|
const isMainAreaEmpty = (this.mainAreaGrid?.root instanceof MPart && this.mainAreaGrid.root.views.length === 0) ?? true;
|
|
4592
4714
|
return {
|
|
4593
|
-
workbenchGrid: this._serializer.serializeGrid(this.workbenchGrid),
|
|
4594
|
-
mainAreaGrid: isMainAreaEmpty ? null : this._serializer.serializeGrid(this._grids.mainArea),
|
|
4715
|
+
workbenchGrid: this._serializer.serializeGrid(this.workbenchGrid, flags),
|
|
4716
|
+
mainAreaGrid: isMainAreaEmpty ? null : this._serializer.serializeGrid(this._grids.mainArea, flags),
|
|
4595
4717
|
workbenchViewOutlets: this._serializer.serializeViewOutlets(this.viewOutlets({ grid: 'workbench' })),
|
|
4596
4718
|
mainAreaViewOutlets: this._serializer.serializeViewOutlets(this.viewOutlets({ grid: 'mainArea' })),
|
|
4597
4719
|
};
|
|
@@ -4616,7 +4738,7 @@ class ɵWorkbenchLayout {
|
|
|
4616
4738
|
const ratio = relativeTo.ratio ?? .5;
|
|
4617
4739
|
// Create a new tree node.
|
|
4618
4740
|
const newTreeNode = new MTreeNode({
|
|
4619
|
-
|
|
4741
|
+
id: UID.randomUID(),
|
|
4620
4742
|
child1: addBefore ? newPart : referenceElement,
|
|
4621
4743
|
child2: addBefore ? referenceElement : newPart,
|
|
4622
4744
|
direction: relativeTo.align === 'left' || relativeTo.align === 'right' ? 'row' : 'column',
|
|
@@ -4722,6 +4844,7 @@ class ɵWorkbenchLayout {
|
|
|
4722
4844
|
this._viewStates.delete(view.id);
|
|
4723
4845
|
}
|
|
4724
4846
|
view.navigation = Objects.withoutUndefinedEntries({
|
|
4847
|
+
id: UID.randomUID(),
|
|
4725
4848
|
hint: extras?.hint,
|
|
4726
4849
|
cssClass: extras?.cssClass ? Arrays.coerce(extras.cssClass) : undefined,
|
|
4727
4850
|
});
|
|
@@ -4864,12 +4987,7 @@ class ɵWorkbenchLayout {
|
|
|
4864
4987
|
return this.findTreeElements((element) => element === findBy.element, { findFirst: true, grid: gridName }).length > 0;
|
|
4865
4988
|
});
|
|
4866
4989
|
if (!gridName) {
|
|
4867
|
-
|
|
4868
|
-
throw Error(`[NullGridError] No grid found that contains the part '${findBy.element.id}'".`);
|
|
4869
|
-
}
|
|
4870
|
-
else {
|
|
4871
|
-
throw Error(`[NullGridError] No grid found that contains the node '${findBy.element.nodeId}'".`);
|
|
4872
|
-
}
|
|
4990
|
+
throw Error(`[NullGridError] No grid found that contains the ${findBy.element instanceof MPart ? 'part' : 'node'} '${findBy.element.id}'".`);
|
|
4873
4991
|
}
|
|
4874
4992
|
return this._grids[gridName];
|
|
4875
4993
|
}
|
|
@@ -4882,7 +5000,7 @@ class ɵWorkbenchLayout {
|
|
|
4882
5000
|
*/
|
|
4883
5001
|
findTreeElement(findBy) {
|
|
4884
5002
|
const element = this.findTreeElements((element) => {
|
|
4885
|
-
return element
|
|
5003
|
+
return element.id === findBy.id;
|
|
4886
5004
|
}, { findFirst: true }).at(0);
|
|
4887
5005
|
if (!element) {
|
|
4888
5006
|
throw Error(`[NullElementError] No element found with id '${findBy.id}'.`);
|
|
@@ -4932,8 +5050,8 @@ class ɵWorkbenchLayout {
|
|
|
4932
5050
|
*/
|
|
4933
5051
|
workingCopy() {
|
|
4934
5052
|
return runInInjectionContext(this._injector, () => new ɵWorkbenchLayout({
|
|
4935
|
-
workbenchGrid: this._serializer.serializeGrid(this.workbenchGrid
|
|
4936
|
-
mainAreaGrid: this._serializer.serializeGrid(this._grids.mainArea
|
|
5053
|
+
workbenchGrid: this._serializer.serializeGrid(this.workbenchGrid),
|
|
5054
|
+
mainAreaGrid: this._serializer.serializeGrid(this._grids.mainArea),
|
|
4937
5055
|
viewOutlets: Object.fromEntries(this._viewOutlets),
|
|
4938
5056
|
viewStates: Object.fromEntries(this._viewStates),
|
|
4939
5057
|
maximized: this._maximized,
|
|
@@ -5031,7 +5149,7 @@ function coercePosition(position, part) {
|
|
|
5031
5149
|
*/
|
|
5032
5150
|
const MAIN_AREA_INITIAL_PART_ID = new InjectionToken('MAIN_AREA_INITIAL_PART_ID', {
|
|
5033
5151
|
providedIn: 'root',
|
|
5034
|
-
factory: () =>
|
|
5152
|
+
factory: () => UID.randomUID(),
|
|
5035
5153
|
});
|
|
5036
5154
|
/**
|
|
5037
5155
|
* Provides the instant when a part was last activated.
|
|
@@ -5169,8 +5287,8 @@ class WorkbenchGridMerger {
|
|
|
5169
5287
|
* Performs a merge of given local and remote layouts, using the base layout as the common ancestor.
|
|
5170
5288
|
*/
|
|
5171
5289
|
merge(grids) {
|
|
5172
|
-
const serializedBaseLayout = grids.base.serialize();
|
|
5173
|
-
const serializedRemoteLayout = grids.remote.serialize();
|
|
5290
|
+
const serializedBaseLayout = grids.base.serialize({ excludeTreeNodeId: true, excludeViewUid: true, excludeViewNavigationId: true });
|
|
5291
|
+
const serializedRemoteLayout = grids.remote.serialize({ excludeTreeNodeId: true, excludeViewUid: true, excludeViewNavigationId: true });
|
|
5174
5292
|
if (serializedBaseLayout.workbenchGrid !== serializedRemoteLayout.workbenchGrid) {
|
|
5175
5293
|
return grids.remote;
|
|
5176
5294
|
}
|
|
@@ -5563,7 +5681,16 @@ class ɵWorkbenchPerspective {
|
|
|
5563
5681
|
* Creates the initial layout of this perspective as defined in the perspective definition.
|
|
5564
5682
|
*/
|
|
5565
5683
|
async createInitialPerspectiveLayout() {
|
|
5566
|
-
|
|
5684
|
+
const initialLayout = await runInInjectionContext(this._environmentInjector, () => this._initialLayoutFn(this._workbenchLayoutFactory));
|
|
5685
|
+
return this.ensureActiveView(initialLayout);
|
|
5686
|
+
}
|
|
5687
|
+
/**
|
|
5688
|
+
* Activates the first view of each part if not specified.
|
|
5689
|
+
*/
|
|
5690
|
+
ensureActiveView(layout) {
|
|
5691
|
+
return layout.parts()
|
|
5692
|
+
.filter(part => part.views?.length)
|
|
5693
|
+
.reduce((acc, part) => part.activeViewId ? acc : acc.activateView(part.views[0].id), layout);
|
|
5567
5694
|
}
|
|
5568
5695
|
/**
|
|
5569
5696
|
* Subscribes to workbench layout changes, invoking the given callback on layout change, but only if this perspective is active.
|
|
@@ -5643,32 +5770,37 @@ class ɵWorkbenchPerspective {
|
|
|
5643
5770
|
* Enables registration and activation of perspectives.
|
|
5644
5771
|
*/
|
|
5645
5772
|
class WorkbenchPerspectiveService {
|
|
5646
|
-
constructor(
|
|
5647
|
-
this.
|
|
5773
|
+
constructor(_workbenchConfig, _perspectiveRegistry, _environmentInjector, _applicationInitStatus, _workbenchPerspectiveStorageService) {
|
|
5774
|
+
this._workbenchConfig = _workbenchConfig;
|
|
5648
5775
|
this._perspectiveRegistry = _perspectiveRegistry;
|
|
5649
5776
|
this._environmentInjector = _environmentInjector;
|
|
5777
|
+
this._applicationInitStatus = _applicationInitStatus;
|
|
5650
5778
|
this._workbenchPerspectiveStorageService = _workbenchPerspectiveStorageService;
|
|
5651
|
-
workbenchStartup.whenStarted
|
|
5652
|
-
.then(() => this.activateInitialPerspective())
|
|
5653
|
-
.catch(error => logger.error(() => 'Failed to initialize perspectives', error));
|
|
5654
5779
|
}
|
|
5655
5780
|
async init() {
|
|
5656
5781
|
await this.registerPerspectivesFromConfig();
|
|
5657
5782
|
await this.registerAnonymousPerspectiveFromWindowName();
|
|
5783
|
+
await this.activateInitialPerspective();
|
|
5658
5784
|
}
|
|
5659
5785
|
/**
|
|
5660
5786
|
* Registers perspectives configured in {@link WorkbenchConfig}.
|
|
5661
5787
|
*/
|
|
5662
5788
|
async registerPerspectivesFromConfig() {
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5789
|
+
const layout = this._workbenchConfig.layout;
|
|
5790
|
+
// Create perspective from layout (if any).
|
|
5791
|
+
if (typeof layout === 'function') {
|
|
5792
|
+
await this.registerPerspective({ id: DEFAULT_WORKBENCH_PERSPECTIVE_ID, layout });
|
|
5793
|
+
}
|
|
5794
|
+
// Register configured perspectives (if any).
|
|
5795
|
+
else if (layout?.perspectives?.length) {
|
|
5796
|
+
for (const perspective of layout.perspectives) {
|
|
5669
5797
|
await this.registerPerspective(perspective);
|
|
5670
5798
|
}
|
|
5671
5799
|
}
|
|
5800
|
+
// Register default perspective if no perspective is registered.
|
|
5801
|
+
else if (!this._perspectiveRegistry.perspectives.length) {
|
|
5802
|
+
await this.registerPerspective({ id: DEFAULT_WORKBENCH_PERSPECTIVE_ID, layout: ((factory) => factory.addPart(MAIN_AREA)) });
|
|
5803
|
+
}
|
|
5672
5804
|
}
|
|
5673
5805
|
/**
|
|
5674
5806
|
* Registers an anonymous perspective if the window name indicates it.
|
|
@@ -5724,55 +5856,62 @@ class WorkbenchPerspectiveService {
|
|
|
5724
5856
|
await this.activePerspective?.reset();
|
|
5725
5857
|
}
|
|
5726
5858
|
/**
|
|
5727
|
-
* Activates the initial perspective
|
|
5859
|
+
* Activates the initial perspective.
|
|
5728
5860
|
*/
|
|
5729
5861
|
async activateInitialPerspective() {
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
return perspectiveFromStorage;
|
|
5741
|
-
}
|
|
5742
|
-
// Determine the initial perspective using information from the config.
|
|
5743
|
-
const perspectiveFromConfig = typeof this._layoutConfig === 'object' ? this._layoutConfig.initialPerspective : null;
|
|
5744
|
-
if (!perspectiveFromConfig) {
|
|
5745
|
-
return this._perspectiveRegistry.perspectives[0]?.id;
|
|
5746
|
-
}
|
|
5747
|
-
if (typeof perspectiveFromConfig === 'string') {
|
|
5748
|
-
return perspectiveFromConfig;
|
|
5749
|
-
}
|
|
5750
|
-
if (typeof perspectiveFromConfig === 'function') {
|
|
5751
|
-
return (await runInInjectionContext(this._environmentInjector, () => perspectiveFromConfig([...this._perspectiveRegistry.perspectives])))?.id;
|
|
5752
|
-
}
|
|
5753
|
-
return undefined;
|
|
5754
|
-
})();
|
|
5755
|
-
// Select initial perspective.
|
|
5756
|
-
if (initialPerspectiveId) {
|
|
5757
|
-
await this.switchPerspective(initialPerspectiveId, { storePerspectiveAsActive: false });
|
|
5862
|
+
if (!this._perspectiveRegistry.perspectives.length) {
|
|
5863
|
+
throw Error('[NullPerspectiveError] No perspective found to activate.');
|
|
5864
|
+
}
|
|
5865
|
+
const perspectiveId = await this.determineInitialPerspective() ?? this._perspectiveRegistry.perspectives[0].id;
|
|
5866
|
+
const activation = this.switchPerspective(perspectiveId, { storePerspectiveAsActive: false });
|
|
5867
|
+
// Switching perspective blocks until the initial navigation has been performed. By default, Angular performs
|
|
5868
|
+
// the initial navigation after running app initializers. Therefore, do not await perspective activation when
|
|
5869
|
+
// starting the workbench during app initialization. Otherwise, Angular would never complete app initialization.
|
|
5870
|
+
if (this._applicationInitStatus.done) {
|
|
5871
|
+
await activation;
|
|
5758
5872
|
}
|
|
5759
5873
|
}
|
|
5874
|
+
/**
|
|
5875
|
+
* Determines which perspective to activate, with the following precedence:
|
|
5876
|
+
*
|
|
5877
|
+
* 1. Perspective defined as window name.
|
|
5878
|
+
* 2. Perspective defined in storage.
|
|
5879
|
+
* 3. Perspective configured in the workbench config.
|
|
5880
|
+
*/
|
|
5881
|
+
async determineInitialPerspective() {
|
|
5882
|
+
// Find perspective in window name.
|
|
5883
|
+
const perspectiveFromWindow = parsePerspectiveIdFromWindowName();
|
|
5884
|
+
if (perspectiveFromWindow && this._perspectiveRegistry.has(perspectiveFromWindow)) {
|
|
5885
|
+
return perspectiveFromWindow;
|
|
5886
|
+
}
|
|
5887
|
+
// Find perspective in storage.
|
|
5888
|
+
const perspectiveFromStorage = await this._workbenchPerspectiveStorageService.loadActivePerspectiveId();
|
|
5889
|
+
if (perspectiveFromStorage && this._perspectiveRegistry.has(perspectiveFromStorage)) {
|
|
5890
|
+
return perspectiveFromStorage;
|
|
5891
|
+
}
|
|
5892
|
+
// Find perspective in config.
|
|
5893
|
+
const perspectiveFromConfig = typeof this._workbenchConfig.layout === 'object' && this._workbenchConfig.layout.initialPerspective;
|
|
5894
|
+
if (typeof perspectiveFromConfig === 'string') {
|
|
5895
|
+
return perspectiveFromConfig;
|
|
5896
|
+
}
|
|
5897
|
+
if (typeof perspectiveFromConfig === 'function') {
|
|
5898
|
+
return (await runInInjectionContext(this._environmentInjector, () => perspectiveFromConfig([...this._perspectiveRegistry.perspectives])));
|
|
5899
|
+
}
|
|
5900
|
+
return undefined;
|
|
5901
|
+
}
|
|
5760
5902
|
/**
|
|
5761
5903
|
* Returns the currently active perspective, or `null` if there is no current perspective.
|
|
5762
5904
|
*/
|
|
5763
5905
|
get activePerspective() {
|
|
5764
5906
|
return this._perspectiveRegistry.perspectives.find(perspective => perspective.active) ?? null;
|
|
5765
5907
|
}
|
|
5766
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchPerspectiveService, deps: [{ token:
|
|
5908
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchPerspectiveService, deps: [{ token: WorkbenchConfig }, { token: WorkbenchPerspectiveRegistry }, { token: i0.EnvironmentInjector }, { token: i0.ApplicationInitStatus }, { token: WorkbenchPerspectiveStorageService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5767
5909
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchPerspectiveService, providedIn: 'root' }); }
|
|
5768
5910
|
}
|
|
5769
5911
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchPerspectiveService, decorators: [{
|
|
5770
5912
|
type: Injectable,
|
|
5771
5913
|
args: [{ providedIn: 'root' }]
|
|
5772
|
-
}], ctorParameters: () => [{ type:
|
|
5773
|
-
type: Inject,
|
|
5774
|
-
args: [WORKBENCH_LAYOUT_CONFIG]
|
|
5775
|
-
}] }, { type: WorkbenchPerspectiveRegistry }, { type: i0.EnvironmentInjector }, { type: WorkbenchPerspectiveStorageService }, { type: WorkbenchStartup }, { type: Logger }] });
|
|
5914
|
+
}], ctorParameters: () => [{ type: WorkbenchConfig }, { type: WorkbenchPerspectiveRegistry }, { type: i0.EnvironmentInjector }, { type: i0.ApplicationInitStatus }, { type: WorkbenchPerspectiveStorageService }] });
|
|
5776
5915
|
/**
|
|
5777
5916
|
* Identifier for the "default" perspective that the workbench creates if not providing a named layout.
|
|
5778
5917
|
*/
|
|
@@ -6328,6 +6467,8 @@ class WbComponentPortal {
|
|
|
6328
6467
|
throw Error(`[PortalConstructError] Component already constructed. [component=${this._componentType}]`);
|
|
6329
6468
|
}
|
|
6330
6469
|
this._componentRef = this.createComponent(injectionContext);
|
|
6470
|
+
// Trigger change detection to complete the initialization of the component, important for components detached from the Angular component tree.
|
|
6471
|
+
this._componentRef.changeDetectorRef.detectChanges();
|
|
6331
6472
|
}
|
|
6332
6473
|
/**
|
|
6333
6474
|
* Attaches this portal to the given {@link ViewContainerRef} according to the following rules:
|
|
@@ -7367,7 +7508,7 @@ class ɵWorkbenchDialog {
|
|
|
7367
7508
|
/**
|
|
7368
7509
|
* Unique identity of this dialog.
|
|
7369
7510
|
*/
|
|
7370
|
-
this.id = randomUUID();
|
|
7511
|
+
this.id = UUID.randomUUID();
|
|
7371
7512
|
/**
|
|
7372
7513
|
* Indicates whether this dialog is blocked by other dialog(s) that overlay this dialog.
|
|
7373
7514
|
*/
|
|
@@ -8138,7 +8279,7 @@ class ɵPopup {
|
|
|
8138
8279
|
* Indicates whether this popup is blocked by dialog(s) that overlay it.
|
|
8139
8280
|
*/
|
|
8140
8281
|
this.blockedBy$ = new BehaviorSubject(null);
|
|
8141
|
-
this.id = this._config.id ?? randomUUID();
|
|
8282
|
+
this.id = this._config.id ?? UUID.randomUUID();
|
|
8142
8283
|
this.cssClasses = Arrays.coerce(this._config.cssClass);
|
|
8143
8284
|
this.blockWhenDialogOpened();
|
|
8144
8285
|
}
|
|
@@ -8767,7 +8908,6 @@ class ɵWorkbenchView {
|
|
|
8767
8908
|
this._viewDragService = inject(ViewDragService);
|
|
8768
8909
|
this._activationInstantProvider = inject(ActivationInstantProvider);
|
|
8769
8910
|
this._workbenchDialogRegistry = inject(WorkbenchDialogRegistry);
|
|
8770
|
-
this._part$ = new BehaviorSubject(undefined);
|
|
8771
8911
|
this._menuItemProviders$ = new BehaviorSubject([]);
|
|
8772
8912
|
this._scrolledIntoView$ = new BehaviorSubject(true);
|
|
8773
8913
|
this._adapters = new Map();
|
|
@@ -8780,13 +8920,17 @@ class ɵWorkbenchView {
|
|
|
8780
8920
|
this.dirty = false;
|
|
8781
8921
|
this.scrollTop = 0;
|
|
8782
8922
|
this.scrollLeft = 0;
|
|
8783
|
-
this.active$ = new BehaviorSubject(false);
|
|
8784
8923
|
this.blockedBy$ = new BehaviorSubject(null);
|
|
8785
8924
|
this.classList = new ClassList();
|
|
8786
8925
|
this.menuItems$ = combineLatest([this._menuItemProviders$, this._workbenchService.viewMenuItemProviders$])
|
|
8787
8926
|
.pipe(map(([localMenuItemProviders, globalMenuItemProviders]) => localMenuItemProviders.concat(globalMenuItemProviders)), mapArray(menuItemFactoryFn => menuItemFactoryFn(this)), filterArray((menuItem) => menuItem !== null));
|
|
8927
|
+
const mView = options.layout.view({ viewId: this.id });
|
|
8928
|
+
const mPart = options.layout.part({ viewId: this.id });
|
|
8929
|
+
this.uid = mView.uid;
|
|
8930
|
+
this.alternativeId = mView.alternativeId;
|
|
8931
|
+
this.partId$ = new BehaviorSubject(mPart.id);
|
|
8932
|
+
this.active$ = new BehaviorSubject(mPart.activeViewId === this.id);
|
|
8788
8933
|
this.portal = this.createPortal(options.component);
|
|
8789
|
-
this.trackViewActivation();
|
|
8790
8934
|
this.touchOnActivate();
|
|
8791
8935
|
this.blockWhenDialogOpened();
|
|
8792
8936
|
this.detectRouteActivation();
|
|
@@ -8826,14 +8970,28 @@ class ɵWorkbenchView {
|
|
|
8826
8970
|
onLayoutChange(layout) {
|
|
8827
8971
|
const mPart = layout.part({ viewId: this.id });
|
|
8828
8972
|
const mView = layout.view({ viewId: this.id });
|
|
8973
|
+
const prevNavigationId = this.navigationId;
|
|
8829
8974
|
this.uid = mView.uid;
|
|
8830
8975
|
this.alternativeId = mView.alternativeId;
|
|
8831
8976
|
this.urlSegments = layout.urlSegments({ viewId: this.id });
|
|
8977
|
+
this.navigationId = mView.navigation?.id;
|
|
8832
8978
|
this.navigationHint = mView.navigation?.hint;
|
|
8833
8979
|
this.state = layout.viewState({ viewId: this.id });
|
|
8834
8980
|
this.classList.set(mView.cssClass, { scope: 'layout' });
|
|
8835
8981
|
this.classList.set(mView.navigation?.cssClass, { scope: 'navigation' });
|
|
8836
|
-
|
|
8982
|
+
if (mPart.id !== this.partId$.value) {
|
|
8983
|
+
this.partId$.next(mPart.id);
|
|
8984
|
+
}
|
|
8985
|
+
const active = mPart.activeViewId === this.id;
|
|
8986
|
+
if (active !== this.active) {
|
|
8987
|
+
this.active$.next(active);
|
|
8988
|
+
}
|
|
8989
|
+
// Inactive views are not checked for changes since detached from the Angular component tree.
|
|
8990
|
+
// To complete the initialization of the routed content (to ensure that `ngOnInit` is called),
|
|
8991
|
+
// we manually trigger change detection.
|
|
8992
|
+
if (!this.active && this.portal.isConstructed && prevNavigationId !== this.navigationId) {
|
|
8993
|
+
this.portal.componentRef.changeDetectorRef.detectChanges();
|
|
8994
|
+
}
|
|
8837
8995
|
}
|
|
8838
8996
|
/**
|
|
8839
8997
|
* Returns the component of this view. Returns `null` if not navigated the view, or before it was activated for the first time.
|
|
@@ -8913,7 +9071,7 @@ class ɵWorkbenchView {
|
|
|
8913
9071
|
}
|
|
8914
9072
|
/** @inheritDoc */
|
|
8915
9073
|
get part() {
|
|
8916
|
-
return
|
|
9074
|
+
return this._partRegistry.get(this.partId$.value);
|
|
8917
9075
|
}
|
|
8918
9076
|
/** @inheritDoc */
|
|
8919
9077
|
close(target) {
|
|
@@ -8998,15 +9156,6 @@ class ɵWorkbenchView {
|
|
|
8998
9156
|
get destroyed() {
|
|
8999
9157
|
return this.portal.isDestroyed;
|
|
9000
9158
|
}
|
|
9001
|
-
/**
|
|
9002
|
-
* Monitors the associated part to check if this view is currently active, updating the active state of this view accordingly.
|
|
9003
|
-
*/
|
|
9004
|
-
trackViewActivation() {
|
|
9005
|
-
this._part$
|
|
9006
|
-
.pipe(switchMap$1(part => part?.activeViewId$ ?? EMPTY), map(activeViewId => activeViewId === this.id), bufferLatestUntilLayoutChange(), // Prevent the (de-)activation of potentially wrong views while updating the layout.
|
|
9007
|
-
distinctUntilChanged(), takeUntilDestroyed(this._destroyRef))
|
|
9008
|
-
.subscribe(this.active$);
|
|
9009
|
-
}
|
|
9010
9159
|
/**
|
|
9011
9160
|
* Updates the activation instant when this view is activated.
|
|
9012
9161
|
*/
|
|
@@ -9579,25 +9728,18 @@ class ViewComponent {
|
|
|
9579
9728
|
get viewId() {
|
|
9580
9729
|
return this._view.id;
|
|
9581
9730
|
}
|
|
9582
|
-
get cssClasses() {
|
|
9583
|
-
return this._view.classList.value.join(' ');
|
|
9584
|
-
}
|
|
9585
9731
|
get isViewDragActive() {
|
|
9586
9732
|
return this._viewDragService.viewDragData !== null;
|
|
9587
9733
|
}
|
|
9588
|
-
constructor(_view,
|
|
9734
|
+
constructor(_view, _viewDragService, _logger) {
|
|
9589
9735
|
this._view = _view;
|
|
9590
|
-
this._logger = _logger;
|
|
9591
|
-
this._host = _host;
|
|
9592
9736
|
this._viewDragService = _viewDragService;
|
|
9737
|
+
this._logger = _logger;
|
|
9593
9738
|
this._viewport$ = new AsyncSubject();
|
|
9594
9739
|
this._logger.debug(() => `Constructing ViewComponent. [viewId=${this.viewId}]`, LoggerNames.LIFECYCLE);
|
|
9595
|
-
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
combineLatest([this._view.active$, this._viewport$])
|
|
9599
|
-
.pipe(takeUntilDestroyed())
|
|
9600
|
-
.subscribe(([active, viewport]) => active ? this.onActivateView(viewport) : this.onDeactivateView(viewport));
|
|
9740
|
+
this.installMenuItemAccelerators();
|
|
9741
|
+
this.subscribeForViewActivation();
|
|
9742
|
+
this.addViewClassesToHost();
|
|
9601
9743
|
}
|
|
9602
9744
|
onActivateView(viewport) {
|
|
9603
9745
|
viewport.focus();
|
|
@@ -9608,13 +9750,33 @@ class ViewComponent {
|
|
|
9608
9750
|
this._view.scrollTop = viewport.scrollTop;
|
|
9609
9751
|
this._view.scrollLeft = viewport.scrollLeft;
|
|
9610
9752
|
}
|
|
9753
|
+
installMenuItemAccelerators() {
|
|
9754
|
+
inject(ViewMenuService).installMenuItemAccelerators$(inject((ElementRef)), this._view)
|
|
9755
|
+
.pipe(takeUntilDestroyed())
|
|
9756
|
+
.subscribe();
|
|
9757
|
+
}
|
|
9758
|
+
subscribeForViewActivation() {
|
|
9759
|
+
combineLatest([this._view.active$, this._viewport$])
|
|
9760
|
+
.pipe(takeUntilDestroyed())
|
|
9761
|
+
.subscribe(([active, viewport]) => {
|
|
9762
|
+
active ? this.onActivateView(viewport) : this.onDeactivateView(viewport);
|
|
9763
|
+
});
|
|
9764
|
+
}
|
|
9765
|
+
addViewClassesToHost() {
|
|
9766
|
+
const ngClass = inject(NgClass);
|
|
9767
|
+
this._view.classList.value$
|
|
9768
|
+
.pipe(takeUntilDestroyed())
|
|
9769
|
+
.subscribe(cssClasses => {
|
|
9770
|
+
ngClass.ngClass = cssClasses;
|
|
9771
|
+
});
|
|
9772
|
+
}
|
|
9611
9773
|
ngOnDestroy() {
|
|
9612
9774
|
this._logger.debug(() => `Destroying ViewComponent [viewId=${this.viewId}]'`, LoggerNames.LIFECYCLE);
|
|
9613
9775
|
}
|
|
9614
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ViewComponent, deps: [{ token: ɵWorkbenchView }, { token:
|
|
9615
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: ViewComponent, isStandalone: true, selector: "wb-view", host: { properties: { "attr.data-viewid": "this.viewId", "
|
|
9776
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ViewComponent, deps: [{ token: ɵWorkbenchView }, { token: ViewDragService }, { token: Logger }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9777
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: ViewComponent, isStandalone: true, selector: "wb-view", host: { properties: { "attr.data-viewid": "this.viewId", "class.view-drag": "this.isViewDragActive" } }, providers: [
|
|
9616
9778
|
configureViewGlassPane(),
|
|
9617
|
-
], viewQueries: [{ propertyName: "setViewport", first: true, predicate: SciViewportComponent, descendants: true }], hostDirectives: [{ directive: GlassPaneDirective }], ngImport: i0, template: "<sci-viewport cdkTrapFocus>\n <router-outlet [name]=\"viewId\"/>\n</sci-viewport>\n", styles: [":host{display:flex;flex-direction:column;background-color:var(--sci-workbench-view-background-color);color:var(--sci-color-text)}wb-workbench:has(wb-main-area-layout) wb-part:not(.main-area) :host{background-color:var(--sci-workbench-view-peripheral-background-color)}:host.view-drag{pointer-events:none}:host>sci-viewport{flex:1 1 0}:host>sci-viewport>router-outlet{position:absolute}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i2$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: SciViewportComponent, selector: "sci-viewport", inputs: ["scrollbarStyle"], outputs: ["scroll"] }] }); }
|
|
9779
|
+
], viewQueries: [{ propertyName: "setViewport", first: true, predicate: SciViewportComponent, descendants: true }], hostDirectives: [{ directive: GlassPaneDirective }, { directive: i5.NgClass }], ngImport: i0, template: "<sci-viewport cdkTrapFocus>\n <router-outlet [name]=\"viewId\"/>\n</sci-viewport>\n", styles: [":host{display:flex;flex-direction:column;background-color:var(--sci-workbench-view-background-color);color:var(--sci-color-text)}wb-workbench:has(wb-main-area-layout) wb-part:not(.main-area) :host{background-color:var(--sci-workbench-view-peripheral-background-color)}:host.view-drag{pointer-events:none}:host>sci-viewport{flex:1 1 0}:host>sci-viewport>router-outlet{position:absolute}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i2$1.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: SciViewportComponent, selector: "sci-viewport", inputs: ["scrollbarStyle"], outputs: ["scroll"] }] }); }
|
|
9618
9780
|
}
|
|
9619
9781
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ViewComponent, decorators: [{
|
|
9620
9782
|
type: Component,
|
|
@@ -9624,18 +9786,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
9624
9786
|
SciViewportComponent,
|
|
9625
9787
|
], hostDirectives: [
|
|
9626
9788
|
GlassPaneDirective,
|
|
9789
|
+
NgClass,
|
|
9627
9790
|
], providers: [
|
|
9628
9791
|
configureViewGlassPane(),
|
|
9629
9792
|
], template: "<sci-viewport cdkTrapFocus>\n <router-outlet [name]=\"viewId\"/>\n</sci-viewport>\n", styles: [":host{display:flex;flex-direction:column;background-color:var(--sci-workbench-view-background-color);color:var(--sci-color-text)}wb-workbench:has(wb-main-area-layout) wb-part:not(.main-area) :host{background-color:var(--sci-workbench-view-peripheral-background-color)}:host.view-drag{pointer-events:none}:host>sci-viewport{flex:1 1 0}:host>sci-viewport>router-outlet{position:absolute}\n"] }]
|
|
9630
|
-
}], ctorParameters: () => [{ type: ɵWorkbenchView }, { type:
|
|
9793
|
+
}], ctorParameters: () => [{ type: ɵWorkbenchView }, { type: ViewDragService }, { type: Logger }], propDecorators: { setViewport: [{
|
|
9631
9794
|
type: ViewChild,
|
|
9632
9795
|
args: [SciViewportComponent]
|
|
9633
9796
|
}], viewId: [{
|
|
9634
9797
|
type: HostBinding,
|
|
9635
9798
|
args: ['attr.data-viewid']
|
|
9636
|
-
}], cssClasses: [{
|
|
9637
|
-
type: HostBinding,
|
|
9638
|
-
args: ['attr.class']
|
|
9639
9799
|
}], isViewDragActive: [{
|
|
9640
9800
|
type: HostBinding,
|
|
9641
9801
|
args: ['class.view-drag']
|
|
@@ -10342,7 +10502,7 @@ class FilterFieldComponent {
|
|
|
10342
10502
|
this._cd = _cd;
|
|
10343
10503
|
this._cvaChangeFn = noop;
|
|
10344
10504
|
this._cvaTouchedFn = noop;
|
|
10345
|
-
this.id = randomUUID();
|
|
10505
|
+
this.id = UUID.randomUUID();
|
|
10346
10506
|
/**
|
|
10347
10507
|
* Emits on filter change.
|
|
10348
10508
|
*/
|
|
@@ -10406,13 +10566,13 @@ class FilterFieldComponent {
|
|
|
10406
10566
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FilterFieldComponent, deps: [{ token: i0.ElementRef }, { token: i2$1.FocusMonitor }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10407
10567
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: FilterFieldComponent, isStandalone: true, selector: "wb-filter-field", inputs: { tabindex: "tabindex", placeholder: "placeholder", disabled: "disabled" }, outputs: { filter: "filter" }, host: { listeners: { "focus": "focus()" }, properties: { "attr.tabindex": "this.componentTabindex", "class.empty": "this.empty" } }, providers: [
|
|
10408
10568
|
{ provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => FilterFieldComponent) },
|
|
10409
|
-
], viewQueries: [{ propertyName: "_inputElement", first: true, predicate: ["input"], descendants: true, static: true }], ngImport: i0, template: "<label [for]=\"id\" class=\"filter-icon scion-workbench-icons\">search</label>\n<input #input\n [attr.id]=\"id\"\n autocomplete=\"off\"\n [formControl]=\"formControl\"\n [tabindex]=\"tabindex ?? 0\"\n [placeholder]=\"placeholder ?? ''\">\n<button class=\"clear scion-workbench-icons\" tabindex=\"-1\" (click)=\"onClear()\">\n clear\n</button>\n", styles: [":host{display:inline-flex;flex-direction:row;gap:.5em;padding:.25em .5em}:host>label.filter-icon{flex:none;align-self:center;-webkit-user-select:none;user-select:none;font-size:1.5em}:host>input{all:unset;flex:auto;min-width:0}:host>button.clear{all:unset;flex:none;align-self:center;opacity:.75;cursor:pointer}:host>button.clear:hover{opacity:1}:host:not(:focus-within):not(:hover)>button.clear,:host:has(>input:disabled)>button.clear,:host.empty>button.clear{visibility:hidden}:host:has(>input:disabled)>label.filter-icon{color:var(--sci-color-text-subtlest)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10569
|
+
], viewQueries: [{ propertyName: "_inputElement", first: true, predicate: ["input"], descendants: true, static: true }], ngImport: i0, template: "<label [for]=\"id\" class=\"filter-icon scion-workbench-icons\">search</label>\n<input #input\n [attr.id]=\"id\"\n autocomplete=\"off\"\n [formControl]=\"formControl\"\n [tabindex]=\"tabindex ?? 0\"\n [placeholder]=\"placeholder ?? ''\">\n<button class=\"clear scion-workbench-icons\" tabindex=\"-1\" (click)=\"onClear()\">\n clear\n</button>\n", styles: [":host{display:inline-flex;flex-direction:row;gap:.5em;padding:.25em .5em}:host>label.filter-icon{flex:none;align-self:center;-webkit-user-select:none;user-select:none;font-size:1.5em}:host>input{all:unset;flex:auto;min-width:0}:host>input::placeholder{color:var(--sci-color-gray-400)}:host>button.clear{all:unset;flex:none;align-self:center;opacity:.75;cursor:pointer}:host>button.clear:hover{opacity:1}:host:not(:focus-within):not(:hover)>button.clear,:host:has(>input:disabled)>button.clear,:host.empty>button.clear{visibility:hidden}:host:has(>input:disabled)>label.filter-icon{color:var(--sci-color-text-subtlest)}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10410
10570
|
}
|
|
10411
10571
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FilterFieldComponent, decorators: [{
|
|
10412
10572
|
type: Component,
|
|
10413
10573
|
args: [{ selector: 'wb-filter-field', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ReactiveFormsModule], providers: [
|
|
10414
10574
|
{ provide: NG_VALUE_ACCESSOR, multi: true, useExisting: forwardRef(() => FilterFieldComponent) },
|
|
10415
|
-
], template: "<label [for]=\"id\" class=\"filter-icon scion-workbench-icons\">search</label>\n<input #input\n [attr.id]=\"id\"\n autocomplete=\"off\"\n [formControl]=\"formControl\"\n [tabindex]=\"tabindex ?? 0\"\n [placeholder]=\"placeholder ?? ''\">\n<button class=\"clear scion-workbench-icons\" tabindex=\"-1\" (click)=\"onClear()\">\n clear\n</button>\n", styles: [":host{display:inline-flex;flex-direction:row;gap:.5em;padding:.25em .5em}:host>label.filter-icon{flex:none;align-self:center;-webkit-user-select:none;user-select:none;font-size:1.5em}:host>input{all:unset;flex:auto;min-width:0}:host>button.clear{all:unset;flex:none;align-self:center;opacity:.75;cursor:pointer}:host>button.clear:hover{opacity:1}:host:not(:focus-within):not(:hover)>button.clear,:host:has(>input:disabled)>button.clear,:host.empty>button.clear{visibility:hidden}:host:has(>input:disabled)>label.filter-icon{color:var(--sci-color-text-subtlest)}\n"] }]
|
|
10575
|
+
], template: "<label [for]=\"id\" class=\"filter-icon scion-workbench-icons\">search</label>\n<input #input\n [attr.id]=\"id\"\n autocomplete=\"off\"\n [formControl]=\"formControl\"\n [tabindex]=\"tabindex ?? 0\"\n [placeholder]=\"placeholder ?? ''\">\n<button class=\"clear scion-workbench-icons\" tabindex=\"-1\" (click)=\"onClear()\">\n clear\n</button>\n", styles: [":host{display:inline-flex;flex-direction:row;gap:.5em;padding:.25em .5em}:host>label.filter-icon{flex:none;align-self:center;-webkit-user-select:none;user-select:none;font-size:1.5em}:host>input{all:unset;flex:auto;min-width:0}:host>input::placeholder{color:var(--sci-color-gray-400)}:host>button.clear{all:unset;flex:none;align-self:center;opacity:.75;cursor:pointer}:host>button.clear:hover{opacity:1}:host:not(:focus-within):not(:hover)>button.clear,:host:has(>input:disabled)>button.clear,:host.empty>button.clear{visibility:hidden}:host:has(>input:disabled)>label.filter-icon{color:var(--sci-color-text-subtlest)}\n"] }]
|
|
10416
10576
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i2$1.FocusMonitor }, { type: i0.ChangeDetectorRef }], propDecorators: { tabindex: [{
|
|
10417
10577
|
type: Input
|
|
10418
10578
|
}], placeholder: [{
|
|
@@ -11329,8 +11489,6 @@ class PartComponent {
|
|
|
11329
11489
|
.pipe(mapArray(viewId => this._viewRegistry.get(viewId)), filterArray(view => !view.active && !view.portal.isConstructed), mergeMap$1(views => from(views)))
|
|
11330
11490
|
.subscribe(inactiveView => {
|
|
11331
11491
|
inactiveView.portal.createComponentFromInjectionContext(this._injector);
|
|
11332
|
-
// Trigger manual change detection cycle because the view is not yet added to the Angular component tree. Otherwise, routed content would not be attached.
|
|
11333
|
-
inactiveView.portal.componentRef.changeDetectorRef.detectChanges();
|
|
11334
11492
|
});
|
|
11335
11493
|
}
|
|
11336
11494
|
/**
|
|
@@ -11353,7 +11511,7 @@ class PartComponent {
|
|
|
11353
11511
|
this._logger.debug(() => `Destroying PartComponent [partId=${this.partId}]'`, LoggerNames.LIFECYCLE);
|
|
11354
11512
|
}
|
|
11355
11513
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: PartComponent, deps: [{ token: WORKBENCH_ID }, { token: WorkbenchViewRegistry }, { token: ViewDragService }, { token: i0.Injector }, { token: Logger }, { token: i0.ChangeDetectorRef }, { token: ɵWorkbenchPart }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11356
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: PartComponent, isStandalone: true, selector: "wb-part", host: { properties: { "attr.tabindex": "this.tabIndex", "attr.data-partid": "this.partId", "class.e2e-main-area": "this.isInMainArea", "class.main-area": "this.isMainArea", "class.active": "this.isActive" } }, ngImport: i0, template: "<wb-part-bar
|
|
11514
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: PartComponent, isStandalone: true, selector: "wb-part", host: { properties: { "attr.tabindex": "this.tabIndex", "attr.data-partid": "this.partId", "class.e2e-main-area": "this.isInMainArea", "class.main-area": "this.isMainArea", "class.active": "this.isActive" } }, ngImport: i0, template: "<wb-part-bar/>\n\n<div wbViewDropZone\n [wbViewDropZoneSize]=\".3\"\n [wbViewDropZonePlaceholderSize]=\".5\"\n [wbViewDropZoneCssClass]=\"'e2e-part'\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"active-view e2e-active-view\">\n <ng-container *wbPortalOutlet=\"part.activeViewId$ | async | wbViewPortal\"/>\n</div>\n", styles: [":host{display:flex;flex-direction:column;outline:none}:host>wb-part-bar{flex:none}:host>div.active-view{flex:auto;display:grid;position:relative}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: PartBarComponent, selector: "wb-part-bar" }, { kind: "directive", type: ViewDropZoneDirective, selector: "[wbViewDropZone]", inputs: ["wbViewDropZoneRegions", "wbViewDropZoneCssClass", "wbViewDropZoneSize", "wbViewDropZonePlaceholderSize"], outputs: ["wbViewDropZoneDrop"] }, { kind: "directive", type: WorkbenchPortalOutletDirective, selector: "ng-template[wbPortalOutlet]", inputs: ["wbPortalOutlet"] }, { kind: "pipe", type: ViewPortalPipe, name: "wbViewPortal" }] }); }
|
|
11357
11515
|
}
|
|
11358
11516
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: PartComponent, decorators: [{
|
|
11359
11517
|
type: Component,
|
|
@@ -11364,7 +11522,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
11364
11522
|
ViewDropZoneDirective,
|
|
11365
11523
|
WorkbenchPortalOutletDirective,
|
|
11366
11524
|
ViewPortalPipe,
|
|
11367
|
-
], template: "<wb-part-bar
|
|
11525
|
+
], template: "<wb-part-bar/>\n\n<div wbViewDropZone\n [wbViewDropZoneSize]=\".3\"\n [wbViewDropZonePlaceholderSize]=\".5\"\n [wbViewDropZoneCssClass]=\"'e2e-part'\"\n (wbViewDropZoneDrop)=\"onViewDrop($event)\"\n class=\"active-view e2e-active-view\">\n <ng-container *wbPortalOutlet=\"part.activeViewId$ | async | wbViewPortal\"/>\n</div>\n", styles: [":host{display:flex;flex-direction:column;outline:none}:host>wb-part-bar{flex:none}:host>div.active-view{flex:auto;display:grid;position:relative}\n"] }]
|
|
11368
11526
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
11369
11527
|
type: Inject,
|
|
11370
11528
|
args: [WORKBENCH_ID]
|
|
@@ -11448,15 +11606,9 @@ class WorkbenchLayoutDiffer {
|
|
|
11448
11606
|
/**
|
|
11449
11607
|
* Computes differences in the layout since last time {@link WorkbenchLayoutDiffer#diff} was invoked.
|
|
11450
11608
|
*/
|
|
11451
|
-
diff(workbenchLayout
|
|
11609
|
+
diff(workbenchLayout) {
|
|
11452
11610
|
const parts = workbenchLayout?.parts().map(part => part.id);
|
|
11453
|
-
|
|
11454
|
-
// Otherwise, the initial navigation for a URL with outlets of views contained in the workbench grid would fail as their view routes would be
|
|
11455
|
-
// registered too late.
|
|
11456
|
-
const views = new Set([
|
|
11457
|
-
...RouterUtils.parseViewOutlets(urlTree).keys(),
|
|
11458
|
-
...(workbenchLayout?.views().map(view => view.id) ?? []),
|
|
11459
|
-
]);
|
|
11611
|
+
const views = workbenchLayout?.views().map(view => view.id);
|
|
11460
11612
|
return new WorkbenchLayoutDiff({
|
|
11461
11613
|
parts: this._partsDiffer.diff(parts),
|
|
11462
11614
|
views: this._viewsDiffer.diff(views),
|
|
@@ -11493,6 +11645,61 @@ class WorkbenchLayoutDiff {
|
|
|
11493
11645
|
}
|
|
11494
11646
|
}
|
|
11495
11647
|
|
|
11648
|
+
/*
|
|
11649
|
+
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11650
|
+
*
|
|
11651
|
+
* This program and the accompanying materials are made
|
|
11652
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
11653
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
11654
|
+
*
|
|
11655
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
11656
|
+
*/
|
|
11657
|
+
/**
|
|
11658
|
+
* Stateful differ to compute view outlets.
|
|
11659
|
+
*
|
|
11660
|
+
* Use this differ to register/unregister view auxiliary routes.
|
|
11661
|
+
*
|
|
11662
|
+
* Because the layout is not available during initial navigation and empty-path views do not have
|
|
11663
|
+
* an outlet in the URL, this differ uses both, outlets in the URL and views in the layout.
|
|
11664
|
+
*/
|
|
11665
|
+
class WorkbenchViewOutletDiffer {
|
|
11666
|
+
constructor(differs) {
|
|
11667
|
+
this._differ = differs.find([]).create();
|
|
11668
|
+
}
|
|
11669
|
+
/**
|
|
11670
|
+
* Computes differences since last time {@link WorkbenchViewOutletDiffer#diff} was invoked.
|
|
11671
|
+
*/
|
|
11672
|
+
diff(workbenchLayout, urlTree) {
|
|
11673
|
+
const views = workbenchLayout?.views().map(view => view.id) ?? [];
|
|
11674
|
+
const viewOutlets = RouterUtils.parseViewOutlets(urlTree).keys();
|
|
11675
|
+
const changes = this._differ.diff(new Set([...viewOutlets, ...views]));
|
|
11676
|
+
return new WorkbenchViewOutletDiff(changes);
|
|
11677
|
+
}
|
|
11678
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchViewOutletDiffer, deps: [{ token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
11679
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchViewOutletDiffer, providedIn: 'root' }); }
|
|
11680
|
+
}
|
|
11681
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchViewOutletDiffer, decorators: [{
|
|
11682
|
+
type: Injectable,
|
|
11683
|
+
args: [{ providedIn: 'root' }]
|
|
11684
|
+
}], ctorParameters: () => [{ type: i0.IterableDiffers }] });
|
|
11685
|
+
/**
|
|
11686
|
+
* Lists the view outlets added/removed in the current navigation.
|
|
11687
|
+
*/
|
|
11688
|
+
class WorkbenchViewOutletDiff {
|
|
11689
|
+
constructor(changes) {
|
|
11690
|
+
this.addedViewOutlets = new Array();
|
|
11691
|
+
this.removedViewOutlets = new Array();
|
|
11692
|
+
changes?.forEachAddedItem(({ item }) => this.addedViewOutlets.push(item));
|
|
11693
|
+
changes?.forEachRemovedItem(({ item }) => this.removedViewOutlets.push(item));
|
|
11694
|
+
}
|
|
11695
|
+
toString() {
|
|
11696
|
+
return `${new Array()
|
|
11697
|
+
.concat(this.addedViewOutlets.length ? `addedViewOutlets=[${this.addedViewOutlets}]` : [])
|
|
11698
|
+
.concat(this.removedViewOutlets.length ? `removedViewOutlets=[${this.removedViewOutlets}]` : [])
|
|
11699
|
+
.join(', ')}`;
|
|
11700
|
+
}
|
|
11701
|
+
}
|
|
11702
|
+
|
|
11496
11703
|
/*
|
|
11497
11704
|
* Copyright (c) 2018-2023 Swiss Federal Railways
|
|
11498
11705
|
*
|
|
@@ -11656,9 +11863,9 @@ class WorkbenchMessageBoxDiff {
|
|
|
11656
11863
|
* - Parses the serialized layout and injects it into {@link WorkbenchLayoutService}.
|
|
11657
11864
|
*/
|
|
11658
11865
|
class WorkbenchUrlObserver {
|
|
11659
|
-
constructor(_router,
|
|
11866
|
+
constructor(_router, _auxiliaryRouteInstaller, _viewRegistry, _partRegistry, _workbenchLayoutService, _environmentInjector, _workbenchRouter, _workbenchLayoutFactory, _workbenchLayoutDiffer, _workbenchViewOutletDiffer, _workbenchPopupDiffer, _workbenchDialogDiffer, _workbenchMessageBoxDiffer, _logger) {
|
|
11660
11867
|
this._router = _router;
|
|
11661
|
-
this.
|
|
11868
|
+
this._auxiliaryRouteInstaller = _auxiliaryRouteInstaller;
|
|
11662
11869
|
this._viewRegistry = _viewRegistry;
|
|
11663
11870
|
this._partRegistry = _partRegistry;
|
|
11664
11871
|
this._workbenchLayoutService = _workbenchLayoutService;
|
|
@@ -11666,6 +11873,7 @@ class WorkbenchUrlObserver {
|
|
|
11666
11873
|
this._workbenchRouter = _workbenchRouter;
|
|
11667
11874
|
this._workbenchLayoutFactory = _workbenchLayoutFactory;
|
|
11668
11875
|
this._workbenchLayoutDiffer = _workbenchLayoutDiffer;
|
|
11876
|
+
this._workbenchViewOutletDiffer = _workbenchViewOutletDiffer;
|
|
11669
11877
|
this._workbenchPopupDiffer = _workbenchPopupDiffer;
|
|
11670
11878
|
this._workbenchDialogDiffer = _workbenchDialogDiffer;
|
|
11671
11879
|
this._workbenchMessageBoxDiffer = _workbenchMessageBoxDiffer;
|
|
@@ -11739,7 +11947,8 @@ class WorkbenchUrlObserver {
|
|
|
11739
11947
|
});
|
|
11740
11948
|
return {
|
|
11741
11949
|
layout,
|
|
11742
|
-
layoutDiff: this._workbenchLayoutDiffer.diff(layout
|
|
11950
|
+
layoutDiff: this._workbenchLayoutDiffer.diff(layout),
|
|
11951
|
+
viewOutletDiff: this._workbenchViewOutletDiffer.diff(layout, urlTree),
|
|
11743
11952
|
popupDiff: this._workbenchPopupDiffer.diff(urlTree),
|
|
11744
11953
|
dialogDiff: this._workbenchDialogDiffer.diff(urlTree),
|
|
11745
11954
|
messageBoxDiff: this._workbenchMessageBoxDiffer.diff(urlTree),
|
|
@@ -11751,27 +11960,27 @@ class WorkbenchUrlObserver {
|
|
|
11751
11960
|
registerAddedOutletAuxiliaryRoutes() {
|
|
11752
11961
|
const navigationContext = this._workbenchRouter.getCurrentNavigationContext();
|
|
11753
11962
|
// Register view auxiliary routes.
|
|
11754
|
-
const
|
|
11755
|
-
if (
|
|
11756
|
-
const auxiliaryRoutes = this.
|
|
11757
|
-
this._logger.debug(() => `Registered auxiliary routes for views: ${
|
|
11963
|
+
const addedViewOutlets = navigationContext.viewOutletDiff.addedViewOutlets;
|
|
11964
|
+
if (addedViewOutlets.length) {
|
|
11965
|
+
const auxiliaryRoutes = this._auxiliaryRouteInstaller.registerAuxiliaryRoutes(addedViewOutlets, { canMatchNotFoundPage: [canMatchNotFoundPage] });
|
|
11966
|
+
this._logger.debug(() => `Registered auxiliary routes for views: ${addedViewOutlets}`, LoggerNames.ROUTING, auxiliaryRoutes);
|
|
11758
11967
|
}
|
|
11759
11968
|
// Register popup auxiliary routes.
|
|
11760
11969
|
const addedPopupOutlets = navigationContext.popupDiff.addedPopupOutlets;
|
|
11761
11970
|
if (addedPopupOutlets.length) {
|
|
11762
|
-
const auxiliaryRoutes = this.
|
|
11971
|
+
const auxiliaryRoutes = this._auxiliaryRouteInstaller.registerAuxiliaryRoutes(addedPopupOutlets);
|
|
11763
11972
|
this._logger.debug(() => `Registered auxiliary routes for popups: ${addedPopupOutlets}`, LoggerNames.ROUTING, auxiliaryRoutes);
|
|
11764
11973
|
}
|
|
11765
11974
|
// Register dialog auxiliary routes.
|
|
11766
11975
|
const addedDialogOutlets = navigationContext.dialogDiff.addedDialogOutlets;
|
|
11767
11976
|
if (addedDialogOutlets.length) {
|
|
11768
|
-
const auxiliaryRoutes = this.
|
|
11977
|
+
const auxiliaryRoutes = this._auxiliaryRouteInstaller.registerAuxiliaryRoutes(addedDialogOutlets);
|
|
11769
11978
|
this._logger.debug(() => `Registered auxiliary routes for dialogs: ${addedDialogOutlets}`, LoggerNames.ROUTING, auxiliaryRoutes);
|
|
11770
11979
|
}
|
|
11771
11980
|
// Register message box auxiliary routes.
|
|
11772
11981
|
const addedMessageBoxOutlets = navigationContext.messageBoxDiff.addedMessageBoxOutlets;
|
|
11773
11982
|
if (addedMessageBoxOutlets.length) {
|
|
11774
|
-
const auxiliaryRoutes = this.
|
|
11983
|
+
const auxiliaryRoutes = this._auxiliaryRouteInstaller.registerAuxiliaryRoutes(addedMessageBoxOutlets);
|
|
11775
11984
|
this._logger.debug(() => `Registered auxiliary routes for message boxes: ${addedMessageBoxOutlets}`, LoggerNames.ROUTING, auxiliaryRoutes);
|
|
11776
11985
|
}
|
|
11777
11986
|
}
|
|
@@ -11783,7 +11992,8 @@ class WorkbenchUrlObserver {
|
|
|
11783
11992
|
undoWorkbenchDiffers() {
|
|
11784
11993
|
const prevNavigateLayout = this._workbenchLayoutService.layout; // Layout in `WorkbenchLayoutService` is only updated after successful navigation
|
|
11785
11994
|
const prevNavigateUrl = this._router.parseUrl(this._router.url); // Browser URL is only updated after successful navigation
|
|
11786
|
-
this._workbenchLayoutDiffer.diff(prevNavigateLayout
|
|
11995
|
+
this._workbenchLayoutDiffer.diff(prevNavigateLayout);
|
|
11996
|
+
this._workbenchViewOutletDiffer.diff(prevNavigateLayout, prevNavigateUrl);
|
|
11787
11997
|
this._workbenchPopupDiffer.diff(prevNavigateUrl);
|
|
11788
11998
|
this._workbenchDialogDiffer.diff(prevNavigateUrl);
|
|
11789
11999
|
this._workbenchMessageBoxDiffer.diff(prevNavigateUrl);
|
|
@@ -11796,13 +12006,13 @@ class WorkbenchUrlObserver {
|
|
|
11796
12006
|
undoAuxiliaryRoutesRegistration() {
|
|
11797
12007
|
const navigationContext = this._workbenchRouter.getCurrentNavigationContext();
|
|
11798
12008
|
const addedOutlets = [
|
|
11799
|
-
...navigationContext.
|
|
12009
|
+
...navigationContext.viewOutletDiff.addedViewOutlets,
|
|
11800
12010
|
...navigationContext.popupDiff.addedPopupOutlets,
|
|
11801
12011
|
...navigationContext.dialogDiff.addedDialogOutlets,
|
|
11802
12012
|
...navigationContext.messageBoxDiff.addedMessageBoxOutlets,
|
|
11803
12013
|
];
|
|
11804
12014
|
if (addedOutlets.length) {
|
|
11805
|
-
this.
|
|
12015
|
+
this._auxiliaryRouteInstaller.unregisterAuxiliaryRoutes(addedOutlets);
|
|
11806
12016
|
this._logger.debug(() => `Undo auxiliary routes registration for outlet(s): ${addedOutlets}`, LoggerNames.ROUTING);
|
|
11807
12017
|
}
|
|
11808
12018
|
}
|
|
@@ -11845,14 +12055,14 @@ class WorkbenchUrlObserver {
|
|
|
11845
12055
|
unregisterRemovedOutletAuxiliaryRoutes() {
|
|
11846
12056
|
const navigationContext = this._workbenchRouter.getCurrentNavigationContext();
|
|
11847
12057
|
const removedOutlets = [
|
|
11848
|
-
...navigationContext.
|
|
12058
|
+
...navigationContext.viewOutletDiff.removedViewOutlets,
|
|
11849
12059
|
...navigationContext.popupDiff.removedPopupOutlets,
|
|
11850
12060
|
...navigationContext.dialogDiff.removedDialogOutlets,
|
|
11851
12061
|
...navigationContext.messageBoxDiff.removedMessageBoxOutlets,
|
|
11852
12062
|
];
|
|
11853
12063
|
if (removedOutlets.length) {
|
|
11854
12064
|
this._logger.debug(() => 'Unregistering outlet auxiliary routes: ', LoggerNames.ROUTING, removedOutlets);
|
|
11855
|
-
this.
|
|
12065
|
+
this._auxiliaryRouteInstaller.unregisterAuxiliaryRoutes(removedOutlets);
|
|
11856
12066
|
}
|
|
11857
12067
|
}
|
|
11858
12068
|
/**
|
|
@@ -11860,10 +12070,10 @@ class WorkbenchUrlObserver {
|
|
|
11860
12070
|
* - For each removed view, destroys the {@link WorkbenchView} and unregisters it in {@link WorkbenchViewRegistry}
|
|
11861
12071
|
*/
|
|
11862
12072
|
updateViewRegistry() {
|
|
11863
|
-
const { layoutDiff } = this._workbenchRouter.getCurrentNavigationContext();
|
|
12073
|
+
const { layoutDiff, layout } = this._workbenchRouter.getCurrentNavigationContext();
|
|
11864
12074
|
layoutDiff.addedViews.forEach(viewId => {
|
|
11865
12075
|
this._logger.debug(() => `Constructing ɵWorkbenchView [viewId=${viewId}]`, LoggerNames.LIFECYCLE);
|
|
11866
|
-
this._viewRegistry.register(this.createWorkbenchView(viewId));
|
|
12076
|
+
this._viewRegistry.register(this.createWorkbenchView(viewId, layout));
|
|
11867
12077
|
});
|
|
11868
12078
|
layoutDiff.removedViews.forEach(viewId => {
|
|
11869
12079
|
this._logger.debug(() => `Destroying ɵWorkbenchView [viewId=${viewId}]`, LoggerNames.LIFECYCLE);
|
|
@@ -11890,8 +12100,8 @@ class WorkbenchUrlObserver {
|
|
|
11890
12100
|
component: partId === MAIN_AREA ? MainAreaLayoutComponent : PartComponent,
|
|
11891
12101
|
}));
|
|
11892
12102
|
}
|
|
11893
|
-
createWorkbenchView(viewId) {
|
|
11894
|
-
return runInInjectionContext(this._environmentInjector, () => new ɵWorkbenchView(viewId, { component: ViewComponent }));
|
|
12103
|
+
createWorkbenchView(viewId, layout) {
|
|
12104
|
+
return runInInjectionContext(this._environmentInjector, () => new ɵWorkbenchView(viewId, { component: ViewComponent, layout }));
|
|
11895
12105
|
}
|
|
11896
12106
|
installRouterEventListeners() {
|
|
11897
12107
|
this._router.events
|
|
@@ -11914,13 +12124,13 @@ class WorkbenchUrlObserver {
|
|
|
11914
12124
|
}
|
|
11915
12125
|
});
|
|
11916
12126
|
}
|
|
11917
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchUrlObserver, deps: [{ token: i2.Router }, { token:
|
|
12127
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchUrlObserver, deps: [{ token: i2.Router }, { token: WorkbenchAuxiliaryRouteInstaller }, { token: WorkbenchViewRegistry }, { token: WorkbenchPartRegistry }, { token: WorkbenchLayoutService }, { token: i0.EnvironmentInjector }, { token: ɵWorkbenchRouter }, { token: ɵWorkbenchLayoutFactory }, { token: WorkbenchLayoutDiffer }, { token: WorkbenchViewOutletDiffer }, { token: WorkbenchPopupDiffer }, { token: WorkbenchDialogDiffer }, { token: WorkbenchMessageBoxDiffer }, { token: Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
11918
12128
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchUrlObserver, providedIn: 'root' }); }
|
|
11919
12129
|
}
|
|
11920
12130
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchUrlObserver, decorators: [{
|
|
11921
12131
|
type: Injectable,
|
|
11922
12132
|
args: [{ providedIn: 'root' }]
|
|
11923
|
-
}], ctorParameters: () => [{ type: i2.Router }, { type:
|
|
12133
|
+
}], ctorParameters: () => [{ type: i2.Router }, { type: WorkbenchAuxiliaryRouteInstaller }, { type: WorkbenchViewRegistry }, { type: WorkbenchPartRegistry }, { type: WorkbenchLayoutService }, { type: i0.EnvironmentInjector }, { type: ɵWorkbenchRouter }, { type: ɵWorkbenchLayoutFactory }, { type: WorkbenchLayoutDiffer }, { type: WorkbenchViewOutletDiffer }, { type: WorkbenchPopupDiffer }, { type: WorkbenchDialogDiffer }, { type: WorkbenchMessageBoxDiffer }, { type: Logger }] });
|
|
11924
12134
|
|
|
11925
12135
|
/**
|
|
11926
12136
|
* Updates the workbench layout when the user moves a view.
|
|
@@ -11971,7 +12181,7 @@ class ViewMoveHandler {
|
|
|
11971
12181
|
await this._workbenchRouter.navigate(layout => {
|
|
11972
12182
|
const newViewId = event.source.alternativeViewId ?? layout.computeNextViewId();
|
|
11973
12183
|
if (addToNewPart) {
|
|
11974
|
-
const newPartId = event.target.newPart?.id ??
|
|
12184
|
+
const newPartId = event.target.newPart?.id ?? UID.randomUID();
|
|
11975
12185
|
return layout
|
|
11976
12186
|
.addPart(newPartId, { relativeTo: event.target.elementId, align: coerceAlignProperty(region), ratio: event.target.newPart?.ratio }, { structural: false })
|
|
11977
12187
|
.addView(newViewId, { partId: newPartId, activateView: true, activatePart: true, cssClass: event.source.classList?.get('layout') })
|
|
@@ -12004,7 +12214,7 @@ class ViewMoveHandler {
|
|
|
12004
12214
|
})
|
|
12005
12215
|
.navigateView(newViewId, commands, { hint: event.source.navigationHint, cssClass: event.source.classList?.get('navigation') });
|
|
12006
12216
|
});
|
|
12007
|
-
const target = generatePerspectiveWindowName(`${ANONYMOUS_PERSPECTIVE_ID_PREFIX}${
|
|
12217
|
+
const target = generatePerspectiveWindowName(`${ANONYMOUS_PERSPECTIVE_ID_PREFIX}${UID.randomUID()}`);
|
|
12008
12218
|
if (window.open(this._locationStrategy.prepareExternalUrl(this._router.serializeUrl(urlTree)), target)) {
|
|
12009
12219
|
await this.removeView(event);
|
|
12010
12220
|
}
|
|
@@ -12015,7 +12225,7 @@ class ViewMoveHandler {
|
|
|
12015
12225
|
async moveView(event) {
|
|
12016
12226
|
const addToNewPart = !!event.target.region;
|
|
12017
12227
|
if (addToNewPart) {
|
|
12018
|
-
const newPartId = event.target.newPart?.id ??
|
|
12228
|
+
const newPartId = event.target.newPart?.id ?? UID.randomUID();
|
|
12019
12229
|
await this._workbenchRouter.navigate(layout => layout
|
|
12020
12230
|
.addPart(newPartId, { relativeTo: event.target.elementId, align: coerceAlignProperty(event.target.region), ratio: event.target.newPart?.ratio }, { structural: false })
|
|
12021
12231
|
.moveView(event.source.viewId, newPartId, { activatePart: true, activateView: true }));
|
|
@@ -12029,7 +12239,7 @@ class ViewMoveHandler {
|
|
|
12029
12239
|
}));
|
|
12030
12240
|
}
|
|
12031
12241
|
}
|
|
12032
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ViewMoveHandler, deps: [{ token: WORKBENCH_ID }, { token: ɵWorkbenchRouter }, { token: ɵWorkbenchLayoutFactory }, { token: ViewDragService }, { token: i2.Router }, { token:
|
|
12242
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ViewMoveHandler, deps: [{ token: WORKBENCH_ID }, { token: ɵWorkbenchRouter }, { token: ɵWorkbenchLayoutFactory }, { token: ViewDragService }, { token: i2.Router }, { token: i5.LocationStrategy }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
12033
12243
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ViewMoveHandler }); }
|
|
12034
12244
|
}
|
|
12035
12245
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ViewMoveHandler, decorators: [{
|
|
@@ -12037,7 +12247,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
12037
12247
|
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
12038
12248
|
type: Inject,
|
|
12039
12249
|
args: [WORKBENCH_ID]
|
|
12040
|
-
}] }, { type: ɵWorkbenchRouter }, { type: ɵWorkbenchLayoutFactory }, { type: ViewDragService }, { type: i2.Router }, { type:
|
|
12250
|
+
}] }, { type: ɵWorkbenchRouter }, { type: ɵWorkbenchLayoutFactory }, { type: ViewDragService }, { type: i2.Router }, { type: i5.LocationStrategy }] });
|
|
12041
12251
|
function coerceAlignProperty(region) {
|
|
12042
12252
|
switch (region) {
|
|
12043
12253
|
case 'west':
|
|
@@ -12110,7 +12320,7 @@ const TEXT_MESSAGE_BOX_CAPABILITY_IDENTITY_PROPERTY = 'ɵidentity';
|
|
|
12110
12320
|
/**
|
|
12111
12321
|
* Value to identify the built-in text message box capability.
|
|
12112
12322
|
*/
|
|
12113
|
-
const TEXT_MESSAGE_BOX_CAPABILITY_IDENTITY = randomUUID();
|
|
12323
|
+
const TEXT_MESSAGE_BOX_CAPABILITY_IDENTITY = UUID.randomUUID();
|
|
12114
12324
|
|
|
12115
12325
|
var textMessage_component = /*#__PURE__*/Object.freeze({
|
|
12116
12326
|
__proto__: null,
|
|
@@ -12129,6 +12339,7 @@ class WorkbenchHostManifestInterceptor {
|
|
|
12129
12339
|
intercept(hostManifest) {
|
|
12130
12340
|
hostManifest.intentions = [
|
|
12131
12341
|
...hostManifest.intentions || [],
|
|
12342
|
+
providePerspectiveIntention(),
|
|
12132
12343
|
provideViewIntention(),
|
|
12133
12344
|
];
|
|
12134
12345
|
hostManifest.capabilities = [
|
|
@@ -12143,6 +12354,15 @@ class WorkbenchHostManifestInterceptor {
|
|
|
12143
12354
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: WorkbenchHostManifestInterceptor, decorators: [{
|
|
12144
12355
|
type: Injectable
|
|
12145
12356
|
}] });
|
|
12357
|
+
/**
|
|
12358
|
+
* Provides a wildcard perspective intention for the workbench to register perspective capabilities as workbench perspectives.
|
|
12359
|
+
*/
|
|
12360
|
+
function providePerspectiveIntention() {
|
|
12361
|
+
return {
|
|
12362
|
+
type: WorkbenchCapabilities.Perspective,
|
|
12363
|
+
qualifier: { '*': '*' },
|
|
12364
|
+
};
|
|
12365
|
+
}
|
|
12146
12366
|
/**
|
|
12147
12367
|
* Provides a wildcard view intention for the workbench to read view capabilities during microfrontend view routing.
|
|
12148
12368
|
*/
|
|
@@ -12222,6 +12442,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
12222
12442
|
type: Injectable
|
|
12223
12443
|
}], ctorParameters: () => [{ type: i0.NgZone }] });
|
|
12224
12444
|
|
|
12445
|
+
/*
|
|
12446
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
12447
|
+
*
|
|
12448
|
+
* This program and the accompanying materials are made
|
|
12449
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
12450
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
12451
|
+
*
|
|
12452
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
12453
|
+
*/
|
|
12454
|
+
/**
|
|
12455
|
+
* Handles perspective intents, instructing the workbench to switch perspective.
|
|
12456
|
+
*/
|
|
12457
|
+
class MicrofrontendPerspectiveIntentHandler {
|
|
12458
|
+
constructor(_workbenchService, _logger) {
|
|
12459
|
+
this._workbenchService = _workbenchService;
|
|
12460
|
+
this._logger = _logger;
|
|
12461
|
+
}
|
|
12462
|
+
/**
|
|
12463
|
+
* Perspective intents are handled in this interceptor and then swallowed.
|
|
12464
|
+
*/
|
|
12465
|
+
intercept(intentMessage, next) {
|
|
12466
|
+
if (intentMessage.intent.type === WorkbenchCapabilities.Perspective) {
|
|
12467
|
+
return this.consumePerspectiveIntent(intentMessage);
|
|
12468
|
+
}
|
|
12469
|
+
else {
|
|
12470
|
+
return next.handle(intentMessage);
|
|
12471
|
+
}
|
|
12472
|
+
}
|
|
12473
|
+
async consumePerspectiveIntent(message) {
|
|
12474
|
+
const replyTo = message.headers.get(MessageHeaders.ReplyTo);
|
|
12475
|
+
const success = await this.switchPerspective(message);
|
|
12476
|
+
if (replyTo) {
|
|
12477
|
+
await Beans.get(MessageClient).publish(replyTo, success, { headers: new Map().set(MessageHeaders.Status, ResponseStatusCodes.TERMINAL) });
|
|
12478
|
+
}
|
|
12479
|
+
}
|
|
12480
|
+
switchPerspective(message) {
|
|
12481
|
+
const perspectiveId = message.capability.metadata.id;
|
|
12482
|
+
this._logger.debug(() => `Switching to perspective ${perspectiveId}.`, LoggerNames.MICROFRONTEND);
|
|
12483
|
+
return this._workbenchService.switchPerspective(perspectiveId);
|
|
12484
|
+
}
|
|
12485
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveIntentHandler, deps: [{ token: WorkbenchService }, { token: Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
12486
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveIntentHandler }); }
|
|
12487
|
+
}
|
|
12488
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveIntentHandler, decorators: [{
|
|
12489
|
+
type: Injectable
|
|
12490
|
+
}], ctorParameters: () => [{ type: WorkbenchService }, { type: Logger }] });
|
|
12491
|
+
|
|
12492
|
+
/*
|
|
12493
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
12494
|
+
*
|
|
12495
|
+
* This program and the accompanying materials are made
|
|
12496
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
12497
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
12498
|
+
*
|
|
12499
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
12500
|
+
*/
|
|
12501
|
+
/**
|
|
12502
|
+
* Provides cached access to manifest objects.
|
|
12503
|
+
*/
|
|
12504
|
+
class ManifestObjectCache {
|
|
12505
|
+
constructor(_manifestService) {
|
|
12506
|
+
this._manifestService = _manifestService;
|
|
12507
|
+
this._capabilities$ = new BehaviorSubject(new Map());
|
|
12508
|
+
this.installCapabilityLookup();
|
|
12509
|
+
}
|
|
12510
|
+
async init() {
|
|
12511
|
+
await firstValueFrom(this._capabilities$);
|
|
12512
|
+
}
|
|
12513
|
+
/**
|
|
12514
|
+
* Tests if given capability exists.
|
|
12515
|
+
*/
|
|
12516
|
+
hasCapability(capabilityId) {
|
|
12517
|
+
return this._capabilities$.value.has(capabilityId);
|
|
12518
|
+
}
|
|
12519
|
+
getCapability(capabilityId, options) {
|
|
12520
|
+
const capability = this._capabilities$.value.get(capabilityId);
|
|
12521
|
+
if (!capability && !options) {
|
|
12522
|
+
throw Error(`[NullCapabilityError] No capability found with id '${capabilityId}'.`);
|
|
12523
|
+
}
|
|
12524
|
+
return capability ?? null;
|
|
12525
|
+
}
|
|
12526
|
+
/**
|
|
12527
|
+
* Looks up specified capability.
|
|
12528
|
+
*
|
|
12529
|
+
* Upon subscription, emits the requested capability, and then emits continuously when it changes. It never completes.
|
|
12530
|
+
*/
|
|
12531
|
+
observeCapability$(capabilityId) {
|
|
12532
|
+
return this._capabilities$
|
|
12533
|
+
.pipe(startWith(undefined), map(() => this.getCapability(capabilityId, { orElse: null })), distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)));
|
|
12534
|
+
}
|
|
12535
|
+
installCapabilityLookup() {
|
|
12536
|
+
this._manifestService.lookupCapabilities$()
|
|
12537
|
+
.pipe(takeUntilDestroyed())
|
|
12538
|
+
.subscribe(capabilities => {
|
|
12539
|
+
this._capabilities$.next(capabilities.reduce((acc, capability) => acc.set(capability.metadata.id, capability), new Map()));
|
|
12540
|
+
});
|
|
12541
|
+
}
|
|
12542
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ManifestObjectCache, deps: [{ token: i2$3.ManifestService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
12543
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ManifestObjectCache }); }
|
|
12544
|
+
}
|
|
12545
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ManifestObjectCache, decorators: [{
|
|
12546
|
+
type: Injectable
|
|
12547
|
+
}], ctorParameters: () => [{ type: i2$3.ManifestService }] });
|
|
12548
|
+
|
|
12225
12549
|
/*
|
|
12226
12550
|
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
12227
12551
|
*
|
|
@@ -12260,7 +12584,8 @@ const MicrofrontendViewRoutes = {
|
|
|
12260
12584
|
const injector = inject(Injector);
|
|
12261
12585
|
return (segments, group, route) => {
|
|
12262
12586
|
// Test if the path matches.
|
|
12263
|
-
|
|
12587
|
+
const microfrontendRoute = MicrofrontendViewRoutes.parseMicrofrontendRoute(segments);
|
|
12588
|
+
if (!microfrontendRoute) {
|
|
12264
12589
|
return null;
|
|
12265
12590
|
}
|
|
12266
12591
|
// Test if navigating a view.
|
|
@@ -12299,8 +12624,14 @@ const MicrofrontendViewRoutes = {
|
|
|
12299
12624
|
/**
|
|
12300
12625
|
* Tests given URL to be a microfrontend route.
|
|
12301
12626
|
*/
|
|
12302
|
-
|
|
12303
|
-
|
|
12627
|
+
parseMicrofrontendRoute: (segments) => {
|
|
12628
|
+
if (segments.length === 2 && segments[0].path === MicrofrontendViewRoutes.ROUTE_PREFIX) {
|
|
12629
|
+
return {
|
|
12630
|
+
capabilityId: segments[1].path,
|
|
12631
|
+
params: segments[1].parameters,
|
|
12632
|
+
};
|
|
12633
|
+
}
|
|
12634
|
+
return null;
|
|
12304
12635
|
},
|
|
12305
12636
|
/**
|
|
12306
12637
|
* Splits given params into URL and transient params.
|
|
@@ -12317,6 +12648,19 @@ const MicrofrontendViewRoutes = {
|
|
|
12317
12648
|
return groups;
|
|
12318
12649
|
}, { urlParams: {}, transientParams: {} });
|
|
12319
12650
|
},
|
|
12651
|
+
/**
|
|
12652
|
+
* Matches the route if target of a view capability (microfrontend) and the capability exists.
|
|
12653
|
+
*/
|
|
12654
|
+
canMatchViewCapability: ((_route, segments) => {
|
|
12655
|
+
const microfrontendRoute = MicrofrontendViewRoutes.parseMicrofrontendRoute(segments);
|
|
12656
|
+
if (!microfrontendRoute) {
|
|
12657
|
+
return false;
|
|
12658
|
+
}
|
|
12659
|
+
if (MicrofrontendPlatform.state !== PlatformState.Started) {
|
|
12660
|
+
return true; // match until started the microfrontend platform to avoid flickering.
|
|
12661
|
+
}
|
|
12662
|
+
return inject(ManifestObjectCache).hasCapability(microfrontendRoute.capabilityId);
|
|
12663
|
+
}),
|
|
12320
12664
|
};
|
|
12321
12665
|
|
|
12322
12666
|
/*
|
|
@@ -12388,10 +12732,12 @@ class MicrofrontendViewIntentHandler {
|
|
|
12388
12732
|
const { urlParams, transientParams } = MicrofrontendViewRoutes.splitParams(intentParams, viewCapability);
|
|
12389
12733
|
const targets = this.resolveTargets(message, extras);
|
|
12390
12734
|
const commands = extras.close ? [] : MicrofrontendViewRoutes.createMicrofrontendNavigateCommands(viewCapability.metadata.id, urlParams);
|
|
12735
|
+
const partId = extras.close ? undefined : extras.partId;
|
|
12391
12736
|
this._logger.debug(() => `Navigating to: ${viewCapability.properties.path}`, LoggerNames.MICROFRONTEND_ROUTING, commands, viewCapability, transientParams);
|
|
12392
12737
|
const navigations = await Promise.all(Arrays.coerce(targets).map(target => {
|
|
12393
12738
|
return this._workbenchRouter.navigate(commands, {
|
|
12394
12739
|
target,
|
|
12740
|
+
partId,
|
|
12395
12741
|
activate: extras.activate,
|
|
12396
12742
|
close: extras.close,
|
|
12397
12743
|
position: extras.position ?? extras.blankInsertionIndex,
|
|
@@ -12412,10 +12758,10 @@ class MicrofrontendViewIntentHandler {
|
|
|
12412
12758
|
throw Error(`[NavigateError] The target must be empty if closing a view [target=${(extras.target)}]`);
|
|
12413
12759
|
}
|
|
12414
12760
|
if (extras.close) {
|
|
12415
|
-
return this.resolvePresentViewIds(intentMessage, { matchWildcardParams: true }) ?? [];
|
|
12761
|
+
return this.resolvePresentViewIds(intentMessage, extras, { matchWildcardParams: true }) ?? [];
|
|
12416
12762
|
}
|
|
12417
12763
|
if (!extras.target || extras.target === 'auto') {
|
|
12418
|
-
return this.resolvePresentViewIds(intentMessage) ?? 'blank';
|
|
12764
|
+
return this.resolvePresentViewIds(intentMessage, extras) ?? 'blank';
|
|
12419
12765
|
}
|
|
12420
12766
|
return extras.target;
|
|
12421
12767
|
}
|
|
@@ -12425,10 +12771,11 @@ class MicrofrontendViewIntentHandler {
|
|
|
12425
12771
|
*
|
|
12426
12772
|
* Allows matching wildcard parameters by setting the option `matchWildcardParameters` to `true`.
|
|
12427
12773
|
*/
|
|
12428
|
-
resolvePresentViewIds(intentMessage, options) {
|
|
12774
|
+
resolvePresentViewIds(intentMessage, extras, options) {
|
|
12429
12775
|
const requiredParams = intentMessage.capability.params?.filter(param => param.required).map(param => param.name) ?? [];
|
|
12430
12776
|
const matchWildcardParams = options?.matchWildcardParams ?? false;
|
|
12431
12777
|
const viewIds = this._viewRegistry.views
|
|
12778
|
+
.filter(view => !extras.partId || extras.partId === view.part.id)
|
|
12432
12779
|
.filter(view => {
|
|
12433
12780
|
const microfrontendWorkbenchView = view.adapt(MicrofrontendWorkbenchView);
|
|
12434
12781
|
if (!microfrontendWorkbenchView) {
|
|
@@ -12505,6 +12852,22 @@ const Microfrontends = {
|
|
|
12505
12852
|
}
|
|
12506
12853
|
});
|
|
12507
12854
|
},
|
|
12855
|
+
/**
|
|
12856
|
+
* Creates a stable identifier for given capability.
|
|
12857
|
+
*/
|
|
12858
|
+
createStableIdentifier: async (capability) => {
|
|
12859
|
+
const qualifier = capability.qualifier;
|
|
12860
|
+
const application = capability.metadata.appSymbolicName;
|
|
12861
|
+
// Create identifier consisting of vendor and sorted qualifier entries.
|
|
12862
|
+
const identifier = Object.entries(qualifier)
|
|
12863
|
+
.sort(([key1], [key2]) => key1.localeCompare(key2))
|
|
12864
|
+
.reduce((acc, [key, value]) => acc.concat(key).concat(`${value}`), [application])
|
|
12865
|
+
.join(';');
|
|
12866
|
+
// Hash the identifier.
|
|
12867
|
+
const identifierHash = await Crypto.digest(identifier);
|
|
12868
|
+
// Use the first 7 digits of the hash.
|
|
12869
|
+
return identifierHash.substring(0, 7);
|
|
12870
|
+
},
|
|
12508
12871
|
/**
|
|
12509
12872
|
* Replaces named parameters in the given value with values contained in the given {@link Map}.
|
|
12510
12873
|
* Named parameters begin with a colon (`:`).
|
|
@@ -12559,12 +12922,6 @@ class MicrofrontendPopupComponent {
|
|
|
12559
12922
|
this.splash = inject(MicrofrontendPlatformConfig).splash ?? MicrofrontendSplashComponent;
|
|
12560
12923
|
}
|
|
12561
12924
|
ngOnInit() {
|
|
12562
|
-
// Obtain the capability provider.
|
|
12563
|
-
const application = this.lookupApplication(this.popupCapability.metadata.appSymbolicName);
|
|
12564
|
-
if (!application) {
|
|
12565
|
-
this.popup.closeWithError(`[NullApplicationError] Unexpected. Cannot resolve application '${this.popupCapability.metadata.appSymbolicName}'.`);
|
|
12566
|
-
return;
|
|
12567
|
-
}
|
|
12568
12925
|
// Listen to popup close requests.
|
|
12569
12926
|
this._messageClient.observe$(_WorkbenchCommands.popupCloseTopic(this.popup.id))
|
|
12570
12927
|
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
@@ -12581,6 +12938,7 @@ class MicrofrontendPopupComponent {
|
|
|
12581
12938
|
// Propagate workbench and color theme to the microfrontend.
|
|
12582
12939
|
this.propagateWorkbenchTheme();
|
|
12583
12940
|
// Navigate to the microfrontend.
|
|
12941
|
+
const application = this._manifestService.getApplication(this.popupCapability.metadata.appSymbolicName);
|
|
12584
12942
|
this._logger.debug(() => `Loading microfrontend into workbench popup [app=${this.popupCapability.metadata.appSymbolicName}, baseUrl=${application.baseUrl}, path=${(this.popupCapability.properties.path)}].`, LoggerNames.MICROFRONTEND, this._popupContext.params, this.popupCapability);
|
|
12585
12943
|
this._outletRouter.navigate(this.popupCapability.properties.path, {
|
|
12586
12944
|
outlet: this.popup.id,
|
|
@@ -12600,12 +12958,6 @@ class MicrofrontendPopupComponent {
|
|
|
12600
12958
|
this._host.nativeElement.dispatchEvent(new CustomEvent('sci-microfrontend-focusin', { bubbles: true }));
|
|
12601
12959
|
}
|
|
12602
12960
|
}
|
|
12603
|
-
/**
|
|
12604
|
-
* Looks up the application registered under the given symbolic name. Returns `undefined` if not found.
|
|
12605
|
-
*/
|
|
12606
|
-
lookupApplication(symbolicName) {
|
|
12607
|
-
return this._manifestService.applications.find(app => app.symbolicName === symbolicName);
|
|
12608
|
-
}
|
|
12609
12961
|
/**
|
|
12610
12962
|
* Sets the {@link isWorkbenchDrag} property when a workbench drag operation is detected,
|
|
12611
12963
|
* such as when dragging a view or moving a sash.
|
|
@@ -12678,7 +13030,7 @@ class MicrofrontendHostPopupComponent {
|
|
|
12678
13030
|
this._singleNavigationExecutor = inject(SINGLE_NAVIGATION_EXECUTOR);
|
|
12679
13031
|
const popupContext = popup.input;
|
|
12680
13032
|
const capability = popupContext.capability;
|
|
12681
|
-
const path = Defined.orElseThrow(capability.properties.path, () => Error(`[PopupProviderError] Missing required path for popup capability
|
|
13033
|
+
const path = Defined.orElseThrow(capability.properties.path, () => Error(`[PopupProviderError] Missing required path for popup capability [application="${capability.metadata.appSymbolicName}", capability=${Objects.toMatrixNotation(capability.qualifier)}]`));
|
|
12682
13034
|
const params = popupContext.params;
|
|
12683
13035
|
this.outletName = POPUP_ID_PREFIX.concat(popup.id);
|
|
12684
13036
|
this.outletInjector = Injector.create({
|
|
@@ -12901,7 +13253,7 @@ class MicrofrontendDialogComponent {
|
|
|
12901
13253
|
this.navigate();
|
|
12902
13254
|
}
|
|
12903
13255
|
navigate() {
|
|
12904
|
-
const application = this._manifestService.
|
|
13256
|
+
const application = this._manifestService.getApplication(this.capability.metadata.appSymbolicName);
|
|
12905
13257
|
this._logger.debug(() => `Loading microfrontend into workbench dialog [app=${this.capability.metadata.appSymbolicName}, baseUrl=${application.baseUrl}, path=${this.capability.properties.path}].`, LoggerNames.MICROFRONTEND, this.params, this.capability);
|
|
12906
13258
|
this._outletRouter.navigate(this.capability.properties.path, {
|
|
12907
13259
|
outlet: this.dialog.id,
|
|
@@ -13307,7 +13659,7 @@ class MicrofrontendMessageBoxComponent {
|
|
|
13307
13659
|
this.navigate();
|
|
13308
13660
|
}
|
|
13309
13661
|
navigate() {
|
|
13310
|
-
const application = this._manifestService.
|
|
13662
|
+
const application = this._manifestService.getApplication(this.capability.metadata.appSymbolicName);
|
|
13311
13663
|
this._logger.debug(() => `Loading microfrontend into workbench message box [app=${this.capability.metadata.appSymbolicName}, baseUrl=${application.baseUrl}, path=${this.capability.properties.path}].`, LoggerNames.MICROFRONTEND, this.params, this.capability);
|
|
13312
13664
|
this._outletRouter.navigate(this.capability.properties.path, {
|
|
13313
13665
|
outlet: this.outletName,
|
|
@@ -13483,7 +13835,7 @@ function hasLegacyContent(intentMessage) {
|
|
|
13483
13835
|
}
|
|
13484
13836
|
|
|
13485
13837
|
/**
|
|
13486
|
-
* Asserts view capabilities to have required properties
|
|
13838
|
+
* Asserts view capabilities to have required properties.
|
|
13487
13839
|
*/
|
|
13488
13840
|
class MicrofrontendViewCapabilityValidator {
|
|
13489
13841
|
async intercept(capability) {
|
|
@@ -13492,13 +13844,13 @@ class MicrofrontendViewCapabilityValidator {
|
|
|
13492
13844
|
}
|
|
13493
13845
|
const viewCapability = capability;
|
|
13494
13846
|
// Assert the view capability to have a qualifier set.
|
|
13495
|
-
if (!
|
|
13847
|
+
if (!Object.keys(viewCapability.qualifier ?? {}).length) {
|
|
13496
13848
|
throw Error(`[NullQualifierError] View capability requires a qualifier [capability=${JSON.stringify(viewCapability)}]`);
|
|
13497
13849
|
}
|
|
13498
13850
|
// Assert the view capability to have a path set.
|
|
13499
13851
|
const path = viewCapability.properties?.path;
|
|
13500
13852
|
if (path === undefined || path === null) {
|
|
13501
|
-
throw Error(`[NullPathError] View capability requires a path to the microfrontend in its properties [capability
|
|
13853
|
+
throw Error(`[NullPathError] View capability requires a path to the microfrontend in its properties [application="${viewCapability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(viewCapability.qualifier)}"]`);
|
|
13502
13854
|
}
|
|
13503
13855
|
return capability;
|
|
13504
13856
|
}
|
|
@@ -13510,41 +13862,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
13510
13862
|
}] });
|
|
13511
13863
|
|
|
13512
13864
|
/**
|
|
13513
|
-
*
|
|
13865
|
+
* Asserts perspective capabilities to have required properties.
|
|
13514
13866
|
*/
|
|
13515
|
-
class
|
|
13867
|
+
class MicrofrontendPerspectiveCapabilityValidator {
|
|
13516
13868
|
async intercept(capability) {
|
|
13517
|
-
if (capability.type !== WorkbenchCapabilities.
|
|
13869
|
+
if (capability.type !== WorkbenchCapabilities.Perspective) {
|
|
13518
13870
|
return capability;
|
|
13519
13871
|
}
|
|
13520
|
-
const
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
}
|
|
13872
|
+
const perspectiveCapability = capability;
|
|
13873
|
+
// Assert the perspective capability to have a qualifier set.
|
|
13874
|
+
if (!Object.keys(perspectiveCapability.qualifier ?? {}).length) {
|
|
13875
|
+
throw Error(`[NullQualifierError] Perspective capability requires a qualifier [capability=${JSON.stringify(perspectiveCapability)}]`);
|
|
13876
|
+
}
|
|
13877
|
+
// Assert the perspective capability to have a layout set.
|
|
13878
|
+
if (!perspectiveCapability.properties?.layout) {
|
|
13879
|
+
throw Error(`[NullLayoutError] Perspective capability requires a layout [application="${perspectiveCapability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(perspectiveCapability.qualifier)}"]`);
|
|
13880
|
+
}
|
|
13881
|
+
// Assert the perspective capability to define parts.
|
|
13882
|
+
if (!perspectiveCapability.properties.layout.length) {
|
|
13883
|
+
throw Error(`[NullLayoutError] Perspective capability requires parts [application="${perspectiveCapability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(perspectiveCapability.qualifier)}"]`);
|
|
13884
|
+
}
|
|
13885
|
+
// Assert no views to be added to the main area.
|
|
13886
|
+
if (perspectiveCapability.properties.layout.find(part => part.id === MAIN_AREA)?.views?.length) {
|
|
13887
|
+
throw Error(`[PerspectiveLayoutError] Perspective capability cannot add views to the main area [application="${perspectiveCapability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(perspectiveCapability.qualifier)}"]`);
|
|
13888
|
+
}
|
|
13889
|
+
return capability;
|
|
13525
13890
|
}
|
|
13526
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type:
|
|
13527
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type:
|
|
13891
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveCapabilityValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
13892
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveCapabilityValidator }); }
|
|
13528
13893
|
}
|
|
13529
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type:
|
|
13894
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveCapabilityValidator, decorators: [{
|
|
13530
13895
|
type: Injectable
|
|
13531
13896
|
}] });
|
|
13532
|
-
/**
|
|
13533
|
-
* Creates a stable identifier for given view capability.
|
|
13534
|
-
*/
|
|
13535
|
-
async function createStableViewIdentifier(capability) {
|
|
13536
|
-
const qualifier = capability.qualifier;
|
|
13537
|
-
const vendor = capability.metadata.appSymbolicName;
|
|
13538
|
-
// Create identifier consisting of vendor and sorted qualifier entries.
|
|
13539
|
-
const identifier = Object.keys(qualifier)
|
|
13540
|
-
.sort()
|
|
13541
|
-
.reduce((acc, qualifierKey) => acc.concat(qualifierKey).concat(`${qualifier[qualifierKey]}`), [vendor])
|
|
13542
|
-
.join(';');
|
|
13543
|
-
// Hash the identifier.
|
|
13544
|
-
const identifierHash = await Crypto.digest(identifier);
|
|
13545
|
-
// Use the first 7 digits of the hash.
|
|
13546
|
-
return identifierHash.substring(0, 7);
|
|
13547
|
-
}
|
|
13548
13897
|
|
|
13549
13898
|
/**
|
|
13550
13899
|
* Asserts popup capabilities to have required properties.
|
|
@@ -13556,13 +13905,13 @@ class MicrofrontendPopupCapabilityValidator {
|
|
|
13556
13905
|
}
|
|
13557
13906
|
const popupCapability = capability;
|
|
13558
13907
|
// Assert the popup capability to have a qualifier set.
|
|
13559
|
-
if (!
|
|
13908
|
+
if (!Object.keys(popupCapability.qualifier ?? {}).length) {
|
|
13560
13909
|
throw Error(`[NullQualifierError] Popup capability requires a qualifier [capability=${JSON.stringify(popupCapability)}]`);
|
|
13561
13910
|
}
|
|
13562
13911
|
// Assert the popup capability to have a path set.
|
|
13563
13912
|
const path = popupCapability.properties?.path;
|
|
13564
13913
|
if (path === undefined || path === null) {
|
|
13565
|
-
throw Error(`[NullPathError] Popup capability requires a path to the microfrontend in its properties [capability
|
|
13914
|
+
throw Error(`[NullPathError] Popup capability requires a path to the microfrontend in its properties [application="${popupCapability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(popupCapability.qualifier)}"]`);
|
|
13566
13915
|
}
|
|
13567
13916
|
return popupCapability;
|
|
13568
13917
|
}
|
|
@@ -13592,13 +13941,13 @@ class MicrofrontendDialogCapabilityValidator {
|
|
|
13592
13941
|
}
|
|
13593
13942
|
const dialogCapability = capability;
|
|
13594
13943
|
// Assert the dialog capability to have a qualifier.
|
|
13595
|
-
if (!
|
|
13944
|
+
if (!Object.keys(dialogCapability.qualifier ?? {}).length) {
|
|
13596
13945
|
throw Error(`[NullQualifierError] Dialog capability requires a qualifier [capability=${JSON.stringify(dialogCapability)}]`);
|
|
13597
13946
|
}
|
|
13598
13947
|
// Assert the dialog capability to have a path.
|
|
13599
13948
|
const path = dialogCapability.properties?.path;
|
|
13600
13949
|
if (path === undefined || path === null) {
|
|
13601
|
-
throw Error(`[NullPathError] Dialog capability requires a path to the microfrontend in its properties [capability
|
|
13950
|
+
throw Error(`[NullPathError] Dialog capability requires a path to the microfrontend in its properties [application="${dialogCapability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(dialogCapability.qualifier)}"]`);
|
|
13602
13951
|
}
|
|
13603
13952
|
// Assert the dialog capability to have a height and width, unless provided by the host application.
|
|
13604
13953
|
this.assertSize(dialogCapability);
|
|
@@ -13611,7 +13960,7 @@ class MicrofrontendDialogCapabilityValidator {
|
|
|
13611
13960
|
}
|
|
13612
13961
|
const size = capability.properties?.size;
|
|
13613
13962
|
if (!size?.width || !size?.height) {
|
|
13614
|
-
throw Error(`[NullSizeError] Dialog capability requires width and height in its size properties [capability
|
|
13963
|
+
throw Error(`[NullSizeError] Dialog capability requires width and height in its size properties [application="${capability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(capability.qualifier)}"]`);
|
|
13615
13964
|
}
|
|
13616
13965
|
}
|
|
13617
13966
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendDialogCapabilityValidator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -13633,7 +13982,7 @@ class MicrofrontendMessageBoxCapabilityValidator {
|
|
|
13633
13982
|
// Assert capability to have a path.
|
|
13634
13983
|
const path = messageBoxCapability.properties?.path;
|
|
13635
13984
|
if (path === undefined || path === null) {
|
|
13636
|
-
throw Error(`[NullPathError] MessageBox capability requires a path to the microfrontend in its properties [capability
|
|
13985
|
+
throw Error(`[NullPathError] MessageBox capability requires a path to the microfrontend in its properties [application="${messageBoxCapability.metadata.appSymbolicName}", capability="${Objects.toMatrixNotation(messageBoxCapability.qualifier)}"]`);
|
|
13637
13986
|
}
|
|
13638
13987
|
// Assert capability other than the built-in text messsage box capability to have a qualifier.
|
|
13639
13988
|
if (!isBuiltInTextMessageBoxCapability(messageBoxCapability) && !Object.keys(messageBoxCapability.qualifier ?? {}).length) {
|
|
@@ -13651,6 +14000,34 @@ function isBuiltInTextMessageBoxCapability(capability) {
|
|
|
13651
14000
|
return capability.properties[TEXT_MESSAGE_BOX_CAPABILITY_IDENTITY_PROPERTY] === TEXT_MESSAGE_BOX_CAPABILITY_IDENTITY;
|
|
13652
14001
|
}
|
|
13653
14002
|
|
|
14003
|
+
/**
|
|
14004
|
+
* Assigns perspective and view capabilities a stable identifer based on the qualifier and application.
|
|
14005
|
+
*/
|
|
14006
|
+
class StableCapabilityIdAssigner {
|
|
14007
|
+
constructor() {
|
|
14008
|
+
this._types = new Set()
|
|
14009
|
+
.add(WorkbenchCapabilities.Perspective)
|
|
14010
|
+
.add(WorkbenchCapabilities.View);
|
|
14011
|
+
}
|
|
14012
|
+
async intercept(capability) {
|
|
14013
|
+
if (!this._types.has(capability.type)) {
|
|
14014
|
+
return capability;
|
|
14015
|
+
}
|
|
14016
|
+
return {
|
|
14017
|
+
...capability,
|
|
14018
|
+
metadata: {
|
|
14019
|
+
...capability.metadata,
|
|
14020
|
+
id: await Microfrontends.createStableIdentifier(capability),
|
|
14021
|
+
},
|
|
14022
|
+
};
|
|
14023
|
+
}
|
|
14024
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: StableCapabilityIdAssigner, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
14025
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: StableCapabilityIdAssigner }); }
|
|
14026
|
+
}
|
|
14027
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: StableCapabilityIdAssigner, decorators: [{
|
|
14028
|
+
type: Injectable
|
|
14029
|
+
}] });
|
|
14030
|
+
|
|
13654
14031
|
/*
|
|
13655
14032
|
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
13656
14033
|
*
|
|
@@ -13664,20 +14041,22 @@ function isBuiltInTextMessageBoxCapability(capability) {
|
|
|
13664
14041
|
* Initializes and starts the SCION Microfrontend Platform in host mode.
|
|
13665
14042
|
*/
|
|
13666
14043
|
class MicrofrontendPlatformInitializer {
|
|
13667
|
-
constructor(_microfrontendPlatformConfigLoader, _hostManifestInterceptor, _ngZoneObservableDecorator, _viewIntentHandler, _popupIntentHandler, _dialogIntentHandler, _messageBoxIntentHandler, _messageBoxLegacyIntentTranslator, _viewCapabilityValidator,
|
|
14044
|
+
constructor(_microfrontendPlatformConfigLoader, _hostManifestInterceptor, _ngZoneObservableDecorator, _perspectiveIntentHandler, _viewIntentHandler, _popupIntentHandler, _dialogIntentHandler, _messageBoxIntentHandler, _messageBoxLegacyIntentTranslator, _viewCapabilityValidator, _perspectiveCapabilityValidator, _popupCapabilityValidator, _dialogCapabilityValidator, _messageBoxCapabilityValidator, _stableCapabilityIdAssigner, _injector, _zone, _logger) {
|
|
13668
14045
|
this._microfrontendPlatformConfigLoader = _microfrontendPlatformConfigLoader;
|
|
13669
14046
|
this._hostManifestInterceptor = _hostManifestInterceptor;
|
|
13670
14047
|
this._ngZoneObservableDecorator = _ngZoneObservableDecorator;
|
|
14048
|
+
this._perspectiveIntentHandler = _perspectiveIntentHandler;
|
|
13671
14049
|
this._viewIntentHandler = _viewIntentHandler;
|
|
13672
14050
|
this._popupIntentHandler = _popupIntentHandler;
|
|
13673
14051
|
this._dialogIntentHandler = _dialogIntentHandler;
|
|
13674
14052
|
this._messageBoxIntentHandler = _messageBoxIntentHandler;
|
|
13675
14053
|
this._messageBoxLegacyIntentTranslator = _messageBoxLegacyIntentTranslator;
|
|
13676
14054
|
this._viewCapabilityValidator = _viewCapabilityValidator;
|
|
13677
|
-
this.
|
|
14055
|
+
this._perspectiveCapabilityValidator = _perspectiveCapabilityValidator;
|
|
13678
14056
|
this._popupCapabilityValidator = _popupCapabilityValidator;
|
|
13679
14057
|
this._dialogCapabilityValidator = _dialogCapabilityValidator;
|
|
13680
14058
|
this._messageBoxCapabilityValidator = _messageBoxCapabilityValidator;
|
|
14059
|
+
this._stableCapabilityIdAssigner = _stableCapabilityIdAssigner;
|
|
13681
14060
|
this._injector = _injector;
|
|
13682
14061
|
this._zone = _zone;
|
|
13683
14062
|
this._logger = _logger;
|
|
@@ -13706,6 +14085,8 @@ class MicrofrontendPlatformInitializer {
|
|
|
13706
14085
|
Beans.register(HostManifestInterceptor, { useValue: this._hostManifestInterceptor, multi: true });
|
|
13707
14086
|
// Synchronize emissions of Observables exposed by the SCION Microfrontend Platform with the Angular zone.
|
|
13708
14087
|
Beans.register(ObservableDecorator, { useValue: this._ngZoneObservableDecorator });
|
|
14088
|
+
// Register perspective interceptor to switch perspective.
|
|
14089
|
+
Beans.register(IntentInterceptor, { useValue: this._perspectiveIntentHandler, multi: true });
|
|
13709
14090
|
// Register view intent interceptor to open the corresponding view.
|
|
13710
14091
|
Beans.register(IntentInterceptor, { useValue: this._viewIntentHandler, multi: true });
|
|
13711
14092
|
// Register popup intent interceptor to open the corresponding popup.
|
|
@@ -13716,16 +14097,18 @@ class MicrofrontendPlatformInitializer {
|
|
|
13716
14097
|
Beans.register(IntentInterceptor, { useValue: this._messageBoxLegacyIntentTranslator, multi: true });
|
|
13717
14098
|
// Register message box intent interceptor to open the corresponding message box.
|
|
13718
14099
|
Beans.register(IntentInterceptor, { useValue: this._messageBoxIntentHandler, multi: true });
|
|
14100
|
+
// Register perspective capability interceptor to assert required perspective capability properties.
|
|
14101
|
+
Beans.register(CapabilityInterceptor, { useValue: this._perspectiveCapabilityValidator, multi: true });
|
|
13719
14102
|
// Register view capability interceptor to assert required view capability properties.
|
|
13720
14103
|
Beans.register(CapabilityInterceptor, { useValue: this._viewCapabilityValidator, multi: true });
|
|
13721
|
-
// Register view capability interceptor to assign view capabilities a stable identifier required for persistent navigation.
|
|
13722
|
-
Beans.register(CapabilityInterceptor, { useValue: this._viewCapabilityIdAssigner, multi: true });
|
|
13723
14104
|
// Register popup capability interceptor to assert required popup capability properties.
|
|
13724
14105
|
Beans.register(CapabilityInterceptor, { useValue: this._popupCapabilityValidator, multi: true });
|
|
13725
14106
|
// Register dialog capability interceptor to assert required dialog capability properties.
|
|
13726
14107
|
Beans.register(CapabilityInterceptor, { useValue: this._dialogCapabilityValidator, multi: true });
|
|
13727
14108
|
// Register message box capability interceptor to assert required capability properties.
|
|
13728
14109
|
Beans.register(CapabilityInterceptor, { useValue: this._messageBoxCapabilityValidator, multi: true });
|
|
14110
|
+
// Register capability interceptor to assign perspective and view capabilities a stable identifier.
|
|
14111
|
+
Beans.register(CapabilityInterceptor, { useValue: this._stableCapabilityIdAssigner, multi: true });
|
|
13729
14112
|
// Inject services registered under {MICROFRONTEND_PLATFORM_POST_STARTUP} DI token;
|
|
13730
14113
|
// must be done in runlevel 2, i.e., before activator microfrontends are installed.
|
|
13731
14114
|
Beans.registerInitializer({
|
|
@@ -13741,13 +14124,12 @@ class MicrofrontendPlatformInitializer {
|
|
|
13741
14124
|
ngOnDestroy() {
|
|
13742
14125
|
MicrofrontendPlatform.destroy().then();
|
|
13743
14126
|
}
|
|
13744
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPlatformInitializer, deps: [{ token: MicrofrontendPlatformConfigLoader }, { token: WorkbenchHostManifestInterceptor }, { token: NgZoneObservableDecorator }, { token: MicrofrontendViewIntentHandler }, { token: MicrofrontendPopupIntentHandler }, { token: MicrofrontendDialogIntentHandler }, { token: MicrofrontendMessageBoxIntentHandler }, { token: MicrofrontendMessageBoxLegacyIntentTranslator }, { token: MicrofrontendViewCapabilityValidator }, { token:
|
|
13745
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPlatformInitializer
|
|
14127
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPlatformInitializer, deps: [{ token: MicrofrontendPlatformConfigLoader }, { token: WorkbenchHostManifestInterceptor }, { token: NgZoneObservableDecorator }, { token: MicrofrontendPerspectiveIntentHandler }, { token: MicrofrontendViewIntentHandler }, { token: MicrofrontendPopupIntentHandler }, { token: MicrofrontendDialogIntentHandler }, { token: MicrofrontendMessageBoxIntentHandler }, { token: MicrofrontendMessageBoxLegacyIntentTranslator }, { token: MicrofrontendViewCapabilityValidator }, { token: MicrofrontendPerspectiveCapabilityValidator }, { token: MicrofrontendPopupCapabilityValidator }, { token: MicrofrontendDialogCapabilityValidator }, { token: MicrofrontendMessageBoxCapabilityValidator }, { token: StableCapabilityIdAssigner }, { token: i0.Injector }, { token: i0.NgZone }, { token: Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
14128
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPlatformInitializer }); }
|
|
13746
14129
|
}
|
|
13747
14130
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPlatformInitializer, decorators: [{
|
|
13748
|
-
type: Injectable
|
|
13749
|
-
|
|
13750
|
-
}], ctorParameters: () => [{ type: MicrofrontendPlatformConfigLoader }, { type: WorkbenchHostManifestInterceptor }, { type: NgZoneObservableDecorator }, { type: MicrofrontendViewIntentHandler }, { type: MicrofrontendPopupIntentHandler }, { type: MicrofrontendDialogIntentHandler }, { type: MicrofrontendMessageBoxIntentHandler }, { type: MicrofrontendMessageBoxLegacyIntentTranslator }, { type: MicrofrontendViewCapabilityValidator }, { type: MicrofrontendViewCapabilityIdAssigner }, { type: MicrofrontendPopupCapabilityValidator }, { type: MicrofrontendDialogCapabilityValidator }, { type: MicrofrontendMessageBoxCapabilityValidator }, { type: i0.Injector }, { type: i0.NgZone }, { type: Logger }] });
|
|
14131
|
+
type: Injectable
|
|
14132
|
+
}], ctorParameters: () => [{ type: MicrofrontendPlatformConfigLoader }, { type: WorkbenchHostManifestInterceptor }, { type: NgZoneObservableDecorator }, { type: MicrofrontendPerspectiveIntentHandler }, { type: MicrofrontendViewIntentHandler }, { type: MicrofrontendPopupIntentHandler }, { type: MicrofrontendDialogIntentHandler }, { type: MicrofrontendMessageBoxIntentHandler }, { type: MicrofrontendMessageBoxLegacyIntentTranslator }, { type: MicrofrontendViewCapabilityValidator }, { type: MicrofrontendPerspectiveCapabilityValidator }, { type: MicrofrontendPopupCapabilityValidator }, { type: MicrofrontendDialogCapabilityValidator }, { type: MicrofrontendMessageBoxCapabilityValidator }, { type: StableCapabilityIdAssigner }, { type: i0.Injector }, { type: i0.NgZone }, { type: Logger }] });
|
|
13751
14133
|
|
|
13752
14134
|
/*
|
|
13753
14135
|
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
@@ -13769,24 +14151,12 @@ class MicrofrontendViewCommandHandler {
|
|
|
13769
14151
|
this._viewRegistry = _viewRegistry;
|
|
13770
14152
|
this._logger = _logger;
|
|
13771
14153
|
this._subscriptions = new Set();
|
|
13772
|
-
this.installViewActiveStatePublisher();
|
|
13773
14154
|
this._subscriptions.add(this.installViewTitleCommandHandler());
|
|
13774
14155
|
this._subscriptions.add(this.installViewHeadingCommandHandler());
|
|
13775
14156
|
this._subscriptions.add(this.installViewDirtyCommandHandler());
|
|
13776
14157
|
this._subscriptions.add(this.installViewClosableCommandHandler());
|
|
13777
14158
|
this._subscriptions.add(this.installViewCloseCommandHandler());
|
|
13778
14159
|
}
|
|
13779
|
-
/**
|
|
13780
|
-
* Notifies microfrontends about the active state of the embedding view.
|
|
13781
|
-
*/
|
|
13782
|
-
installViewActiveStatePublisher() {
|
|
13783
|
-
this._viewRegistry.views$
|
|
13784
|
-
.pipe(switchMap(views => merge(...views.map(view => view.active$.pipe(map(() => view))))), takeUntilDestroyed())
|
|
13785
|
-
.subscribe((view) => {
|
|
13786
|
-
const commandTopic = _WorkbenchCommands.viewActiveTopic(view.id);
|
|
13787
|
-
this._messageClient.publish(commandTopic, view.active, { retain: true }).then();
|
|
13788
|
-
});
|
|
13789
|
-
}
|
|
13790
14160
|
/**
|
|
13791
14161
|
* Handles commands to update the title of a view.
|
|
13792
14162
|
*/
|
|
@@ -13934,17 +14304,12 @@ class ContentProjectionDirective {
|
|
|
13934
14304
|
this._contentViewRef.onDestroy(() => dispose$.next());
|
|
13935
14305
|
// Position projected content out of the document flow relative to the page viewport.
|
|
13936
14306
|
this.styleContent({ position: 'fixed' });
|
|
13937
|
-
// Align content each time the
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
.
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
// We ignore this event to preserve the dimension of projected content, crucial, for example, if projected
|
|
13944
|
-
// content implements virtual scrolling. Otherwise, its content would reload when adding the host to the DOM again.
|
|
13945
|
-
// For example, inactive views are removed from the DOM.
|
|
13946
|
-
return;
|
|
13947
|
-
}
|
|
14307
|
+
// Align content each time the size of the host element changes, or when the content is attached to the DOM.
|
|
14308
|
+
// For example, moving a view to another part of the same size will not trigger a dimension change event.
|
|
14309
|
+
merge(fromDimension$(this._host.nativeElement), this._view?.portal.attached$.pipe(filter(Boolean)) ?? EMPTY)
|
|
14310
|
+
.pipe(observeOn(animationFrameScheduler), // Align to host boundaries right before the next repaint.
|
|
14311
|
+
takeUntil(dispose$))
|
|
14312
|
+
.subscribe(() => {
|
|
13948
14313
|
this.alignContentToHostBoundaries();
|
|
13949
14314
|
});
|
|
13950
14315
|
// Hide content when contextual view is detached, e.g., if not active, or located in the peripheral area and the main area is maximized.
|
|
@@ -13959,6 +14324,13 @@ class ContentProjectionDirective {
|
|
|
13959
14324
|
*/
|
|
13960
14325
|
alignContentToHostBoundaries() {
|
|
13961
14326
|
const hostPosition = this._host.nativeElement.getBoundingClientRect();
|
|
14327
|
+
if (!hostPosition.width && !hostPosition.height) {
|
|
14328
|
+
// When removing the bounding box element (this directive's host) from the DOM, its dimension drops to 0.
|
|
14329
|
+
// We ignore this event to preserve the dimension of projected content, crucial, for example, if projected
|
|
14330
|
+
// content implements virtual scrolling. Otherwise, its content would reload when adding the host to the DOM again.
|
|
14331
|
+
// For example, inactive views are removed from the DOM.
|
|
14332
|
+
return;
|
|
14333
|
+
}
|
|
13962
14334
|
this.styleContent({
|
|
13963
14335
|
top: `${hostPosition.top}px`,
|
|
13964
14336
|
left: `${hostPosition.left}px`,
|
|
@@ -13994,9 +14366,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
13994
14366
|
type: Input,
|
|
13995
14367
|
args: [{ alias: 'wbContentProjectionContent', required: true }]
|
|
13996
14368
|
}] } });
|
|
13997
|
-
function isNullDimension(dimension) {
|
|
13998
|
-
return dimension.offsetWidth === 0 && dimension.offsetHeight === 0;
|
|
13999
|
-
}
|
|
14000
14369
|
|
|
14001
14370
|
/*
|
|
14002
14371
|
* Copyright (c) 2018-2022 Swiss Federal Railways
|
|
@@ -14065,11 +14434,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
14065
14434
|
* Embeds the microfrontend of a view capability.
|
|
14066
14435
|
*/
|
|
14067
14436
|
class MicrofrontendViewComponent {
|
|
14068
|
-
constructor(_host, _route, _outletRouter, _manifestService, _messageClient, _destroyRef, _logger, _viewContextMenuService, _workbenchLayoutService, _workbenchRouter, _injector, _cd, view, iframeHostRef) {
|
|
14437
|
+
constructor(_host, _route, _outletRouter, _manifestService, _manifestObjectCache, _messageClient, _destroyRef, _logger, _viewContextMenuService, _workbenchLayoutService, _workbenchRouter, _injector, _cd, view, iframeHostRef) {
|
|
14069
14438
|
this._host = _host;
|
|
14070
14439
|
this._route = _route;
|
|
14071
14440
|
this._outletRouter = _outletRouter;
|
|
14072
14441
|
this._manifestService = _manifestService;
|
|
14442
|
+
this._manifestObjectCache = _manifestObjectCache;
|
|
14073
14443
|
this._messageClient = _messageClient;
|
|
14074
14444
|
this._destroyRef = _destroyRef;
|
|
14075
14445
|
this._logger = _logger;
|
|
@@ -14084,6 +14454,7 @@ class MicrofrontendViewComponent {
|
|
|
14084
14454
|
this._universalKeystrokes = [
|
|
14085
14455
|
'keydown.escape', // allows closing notifications
|
|
14086
14456
|
];
|
|
14457
|
+
this.capability = null;
|
|
14087
14458
|
/**
|
|
14088
14459
|
* Indicates whether a workbench drag operation is in progress, such as when dragging a view or moving a sash.
|
|
14089
14460
|
*/
|
|
@@ -14092,6 +14463,8 @@ class MicrofrontendViewComponent {
|
|
|
14092
14463
|
this.keystrokesToBubble$ = combineLatest([this.viewContextMenuKeystrokes$(), of(this._universalKeystrokes)])
|
|
14093
14464
|
.pipe(map(keystrokes => new Array().concat(...keystrokes)));
|
|
14094
14465
|
this.installWorkbenchDragDetector();
|
|
14466
|
+
this.installViewActivePublisher();
|
|
14467
|
+
this.installPartIdPublisher();
|
|
14095
14468
|
this.splash = inject(MicrofrontendPlatformConfig).splash ?? MicrofrontendSplashComponent;
|
|
14096
14469
|
}
|
|
14097
14470
|
ngOnInit() {
|
|
@@ -14108,7 +14481,7 @@ class MicrofrontendViewComponent {
|
|
|
14108
14481
|
async onNavigate(prevCapability, capability, params) {
|
|
14109
14482
|
if (!capability) {
|
|
14110
14483
|
this._logger.warn(() => `[NullCapabilityError] No application found to provide a view capability of id '${params[_MicrofrontendRouteParams.ɵVIEW_CAPABILITY_ID]}'. Maybe, the requested view is not public API or the providing application not available.`, LoggerNames.MICROFRONTEND_ROUTING);
|
|
14111
|
-
|
|
14484
|
+
this.unload();
|
|
14112
14485
|
return;
|
|
14113
14486
|
}
|
|
14114
14487
|
this.capability = capability;
|
|
@@ -14132,7 +14505,7 @@ class MicrofrontendViewComponent {
|
|
|
14132
14505
|
await this.waitForCapabilityParam(capability.metadata.id);
|
|
14133
14506
|
}
|
|
14134
14507
|
// Navigate to the microfrontend.
|
|
14135
|
-
const application = this._manifestService.
|
|
14508
|
+
const application = this._manifestService.getApplication(capability.metadata.appSymbolicName);
|
|
14136
14509
|
this._logger.debug(() => `Loading microfrontend into workbench view [viewId=${this.view.id}, app=${capability.metadata.appSymbolicName}, baseUrl=${application.baseUrl}, path=${(capability.properties.path)}].`, LoggerNames.MICROFRONTEND_ROUTING, params, capability);
|
|
14137
14510
|
await this._outletRouter.navigate(capability.properties.path, {
|
|
14138
14511
|
outlet: this.view.id,
|
|
@@ -14142,14 +14515,14 @@ class MicrofrontendViewComponent {
|
|
|
14142
14515
|
showSplash: capability.properties.showSplash,
|
|
14143
14516
|
ɵcapabilityId: capability.metadata.id,
|
|
14144
14517
|
});
|
|
14145
|
-
// Inactive views are detached from the Angular
|
|
14146
|
-
//
|
|
14518
|
+
// Inactive views are not checked for changes since detached from the Angular component tree.
|
|
14519
|
+
// So, we manually trigger change detection to update attributes on the `sci-router-outlet`.
|
|
14147
14520
|
if (!this.view.active) {
|
|
14148
14521
|
this._cd.detectChanges();
|
|
14149
14522
|
}
|
|
14150
14523
|
}
|
|
14151
14524
|
fetchCapability$(capabilityId) {
|
|
14152
|
-
return this.
|
|
14525
|
+
return this._manifestObjectCache.observeCapability$(capabilityId);
|
|
14153
14526
|
}
|
|
14154
14527
|
installMenuItemAccelerators$() {
|
|
14155
14528
|
// Since the iframe is added at a top-level location in the DOM, that is, not as a child element of this component,
|
|
@@ -14204,6 +14577,22 @@ class MicrofrontendViewComponent {
|
|
|
14204
14577
|
this.view.closable = viewCapability.properties.closable ?? true;
|
|
14205
14578
|
this.view.dirty = false;
|
|
14206
14579
|
}
|
|
14580
|
+
installViewActivePublisher() {
|
|
14581
|
+
this.view.active$
|
|
14582
|
+
.pipe(takeUntilDestroyed())
|
|
14583
|
+
.subscribe(active => {
|
|
14584
|
+
const commandTopic = _WorkbenchCommands.viewActiveTopic(this.view.id);
|
|
14585
|
+
this._messageClient.publish(commandTopic, active, { retain: true }).then();
|
|
14586
|
+
});
|
|
14587
|
+
}
|
|
14588
|
+
installPartIdPublisher() {
|
|
14589
|
+
this.view.partId$
|
|
14590
|
+
.pipe(takeUntilDestroyed())
|
|
14591
|
+
.subscribe(partId => {
|
|
14592
|
+
const commandTopic = _WorkbenchCommands.viewPartIdTopic(this.view.id);
|
|
14593
|
+
this._messageClient.publish(commandTopic, partId, { retain: true }).then();
|
|
14594
|
+
});
|
|
14595
|
+
}
|
|
14207
14596
|
/**
|
|
14208
14597
|
* Promise that resolves once params contain the given capability id.
|
|
14209
14598
|
*/
|
|
@@ -14264,14 +14653,18 @@ class MicrofrontendViewComponent {
|
|
|
14264
14653
|
propagateWorkbenchTheme() {
|
|
14265
14654
|
runInInjectionContext(this._injector, () => Microfrontends.propagateTheme(this.routerOutletElement.nativeElement));
|
|
14266
14655
|
}
|
|
14267
|
-
|
|
14268
|
-
//
|
|
14656
|
+
unload() {
|
|
14657
|
+
// Delete retained messages to free resources.
|
|
14269
14658
|
this._messageClient.publish(_WorkbenchCommands.viewActiveTopic(this.view.id), undefined, { retain: true }).then();
|
|
14270
14659
|
this._messageClient.publish(_WorkbenchCommands.viewParamsTopic(this.view.id), undefined, { retain: true }).then();
|
|
14660
|
+
this._messageClient.publish(_WorkbenchCommands.viewPartIdTopic(this.view.id), undefined, { retain: true }).then();
|
|
14271
14661
|
this._outletRouter.navigate(null, { outlet: this.view.id }).then();
|
|
14272
14662
|
this.view.unregisterAdapter(MicrofrontendWorkbenchView);
|
|
14273
14663
|
}
|
|
14274
|
-
|
|
14664
|
+
ngOnDestroy() {
|
|
14665
|
+
this.unload();
|
|
14666
|
+
}
|
|
14667
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendViewComponent, deps: [{ token: i0.ElementRef }, { token: i2.ActivatedRoute }, { token: i2$3.OutletRouter }, { token: i2$3.ManifestService }, { token: ManifestObjectCache }, { token: i2$3.MessageClient }, { token: i0.DestroyRef }, { token: Logger }, { token: ViewMenuService }, { token: WorkbenchLayoutService }, { token: WorkbenchRouter }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: ɵWorkbenchView }, { token: IFRAME_HOST }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14275
14668
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: MicrofrontendViewComponent, isStandalone: true, selector: "wb-microfrontend-view", viewQueries: [{ propertyName: "routerOutletElement", first: true, predicate: ["router_outlet"], descendants: true, static: true }], ngImport: i0, template: "<wb-content-as-overlay [overlayHost]=\"iframeHostRef.ref$ | async\">\n <div class=\"microfrontend-view\"\n [class.workbench-drag]=\"isWorkbenchDrag\"\n [attr.data-viewid]=\"view.id\"\n wbGlassPane>\n <sci-router-outlet #router_outlet\n [name]=\"view.id\"\n [attr.data-capabilityid]=\"capability?.metadata!.id\"\n [attr.data-app]=\"capability?.metadata!.appSymbolicName\"\n [ngClass]=\"view.classList.value\"\n (focuswithin)=\"onFocusWithin($event)\"\n [keystrokes]=\"keystrokesToBubble$ | async\">\n <ng-container *ngComponentOutlet=\"splash\"></ng-container>\n </sci-router-outlet>\n </div>\n</wb-content-as-overlay>\n", styles: [":host{display:grid}div.microfrontend-view{display:grid}div.microfrontend-view.workbench-drag{pointer-events:none}div.microfrontend-view>sci-router-outlet::part(splash){display:grid}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "component", type: ContentAsOverlayComponent, selector: "wb-content-as-overlay", inputs: ["overlayHost"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: GlassPaneDirective, selector: "[wbGlassPane]" }], viewProviders: [
|
|
14276
14669
|
configureMicrofrontendGlassPane(),
|
|
14277
14670
|
] }); }
|
|
@@ -14287,7 +14680,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
14287
14680
|
], viewProviders: [
|
|
14288
14681
|
configureMicrofrontendGlassPane(),
|
|
14289
14682
|
], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: "<wb-content-as-overlay [overlayHost]=\"iframeHostRef.ref$ | async\">\n <div class=\"microfrontend-view\"\n [class.workbench-drag]=\"isWorkbenchDrag\"\n [attr.data-viewid]=\"view.id\"\n wbGlassPane>\n <sci-router-outlet #router_outlet\n [name]=\"view.id\"\n [attr.data-capabilityid]=\"capability?.metadata!.id\"\n [attr.data-app]=\"capability?.metadata!.appSymbolicName\"\n [ngClass]=\"view.classList.value\"\n (focuswithin)=\"onFocusWithin($event)\"\n [keystrokes]=\"keystrokesToBubble$ | async\">\n <ng-container *ngComponentOutlet=\"splash\"></ng-container>\n </sci-router-outlet>\n </div>\n</wb-content-as-overlay>\n", styles: [":host{display:grid}div.microfrontend-view{display:grid}div.microfrontend-view.workbench-drag{pointer-events:none}div.microfrontend-view>sci-router-outlet::part(splash){display:grid}\n"] }]
|
|
14290
|
-
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i2.ActivatedRoute }, { type: i2$3.OutletRouter }, { type: i2$3.ManifestService }, { type: i2$3.MessageClient }, { type: i0.DestroyRef }, { type: Logger }, { type: ViewMenuService }, { type: WorkbenchLayoutService }, { type: WorkbenchRouter }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: ɵWorkbenchView }, { type: ViewContainerReference, decorators: [{
|
|
14683
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i2.ActivatedRoute }, { type: i2$3.OutletRouter }, { type: i2$3.ManifestService }, { type: ManifestObjectCache }, { type: i2$3.MessageClient }, { type: i0.DestroyRef }, { type: Logger }, { type: ViewMenuService }, { type: WorkbenchLayoutService }, { type: WorkbenchRouter }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: ɵWorkbenchView }, { type: ViewContainerReference, decorators: [{
|
|
14291
14684
|
type: Inject,
|
|
14292
14685
|
args: [IFRAME_HOST]
|
|
14293
14686
|
}] }], propDecorators: { routerOutletElement: [{
|
|
@@ -14310,6 +14703,132 @@ function configureMicrofrontendGlassPane() {
|
|
|
14310
14703
|
];
|
|
14311
14704
|
}
|
|
14312
14705
|
|
|
14706
|
+
/*
|
|
14707
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
14708
|
+
*
|
|
14709
|
+
* This program and the accompanying materials are made
|
|
14710
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
14711
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
14712
|
+
*
|
|
14713
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
14714
|
+
*/
|
|
14715
|
+
/**
|
|
14716
|
+
* Keys for associating workbench-specific data with a perspective.
|
|
14717
|
+
*/
|
|
14718
|
+
const WorkbenchPerspectiveData = {
|
|
14719
|
+
/**
|
|
14720
|
+
* Property to get the capability providing the perspective.
|
|
14721
|
+
*/
|
|
14722
|
+
capability: 'ɵcapability',
|
|
14723
|
+
};
|
|
14724
|
+
|
|
14725
|
+
/*
|
|
14726
|
+
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
14727
|
+
*
|
|
14728
|
+
* This program and the accompanying materials are made
|
|
14729
|
+
* available under the terms of the Eclipse Public License 2.0
|
|
14730
|
+
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
14731
|
+
*
|
|
14732
|
+
* SPDX-License-Identifier: EPL-2.0
|
|
14733
|
+
*/
|
|
14734
|
+
/**
|
|
14735
|
+
* Registers perspectives for workbench perspective capabilities.
|
|
14736
|
+
*/
|
|
14737
|
+
class MicrofrontendPerspectiveInstaller {
|
|
14738
|
+
constructor(_manifestService, _workbenchService, _logger) {
|
|
14739
|
+
this._manifestService = _manifestService;
|
|
14740
|
+
this._workbenchService = _workbenchService;
|
|
14741
|
+
this._logger = _logger;
|
|
14742
|
+
this.installPerspectiveCapabilityListener();
|
|
14743
|
+
}
|
|
14744
|
+
installPerspectiveCapabilityListener() {
|
|
14745
|
+
const differ = inject(IterableDiffers).find([]).create((_index, perspectiveCapability) => perspectiveCapability.metadata.id);
|
|
14746
|
+
this._manifestService.lookupCapabilities$({ type: WorkbenchCapabilities.Perspective })
|
|
14747
|
+
.pipe(takeUntilDestroyed())
|
|
14748
|
+
.subscribe(perspectiveCapabilities => {
|
|
14749
|
+
const changes = differ.diff(perspectiveCapabilities);
|
|
14750
|
+
changes?.forEachAddedItem(({ item: perspectiveCapability }) => this.registerPerspective(perspectiveCapability));
|
|
14751
|
+
});
|
|
14752
|
+
}
|
|
14753
|
+
async registerPerspective(perspectiveCapability) {
|
|
14754
|
+
return this._workbenchService.registerPerspective({
|
|
14755
|
+
id: perspectiveCapability.metadata.id,
|
|
14756
|
+
layout: this.createLayout(perspectiveCapability),
|
|
14757
|
+
data: {
|
|
14758
|
+
...perspectiveCapability.properties?.data,
|
|
14759
|
+
[WorkbenchPerspectiveData.capability]: perspectiveCapability,
|
|
14760
|
+
},
|
|
14761
|
+
});
|
|
14762
|
+
}
|
|
14763
|
+
createLayout(perspectiveCapability) {
|
|
14764
|
+
return async (factory) => {
|
|
14765
|
+
const [initialPart, ...parts] = perspectiveCapability.properties.layout;
|
|
14766
|
+
// Add parts to the layout.
|
|
14767
|
+
let layout = factory.addPart(initialPart.id);
|
|
14768
|
+
for (const part of parts) {
|
|
14769
|
+
layout = layout.addPart(part.id, {
|
|
14770
|
+
relativeTo: part.relativeTo,
|
|
14771
|
+
align: part.align,
|
|
14772
|
+
ratio: part.ratio,
|
|
14773
|
+
});
|
|
14774
|
+
}
|
|
14775
|
+
// Add views to the layout.
|
|
14776
|
+
for (const part of [initialPart, ...parts]) {
|
|
14777
|
+
if (!part.views?.length) {
|
|
14778
|
+
continue;
|
|
14779
|
+
}
|
|
14780
|
+
for (const [viewIndex, view] of part.views.entries()) {
|
|
14781
|
+
const viewCapabilities = await this.lookupViewCapabilities(view.qualifier, {
|
|
14782
|
+
perspectiveProvider: perspectiveCapability.metadata.appSymbolicName,
|
|
14783
|
+
perspectiveQualifier: perspectiveCapability.qualifier,
|
|
14784
|
+
});
|
|
14785
|
+
viewCapabilities
|
|
14786
|
+
.map(viewCapability => viewCapability.metadata.id)
|
|
14787
|
+
.sort() // Ensure stable view order in case multiple capabilities match the qualifier.
|
|
14788
|
+
.forEach(viewCapabilityId => {
|
|
14789
|
+
const commands = MicrofrontendViewRoutes.createMicrofrontendNavigateCommands(viewCapabilityId, view.params ?? {});
|
|
14790
|
+
const alternativeViewId = `${part.id}-${viewCapabilityId}-${viewIndex}`;
|
|
14791
|
+
layout = layout
|
|
14792
|
+
.addView(alternativeViewId, { partId: part.id, activateView: view.active })
|
|
14793
|
+
.navigateView(alternativeViewId, commands, { cssClass: view.cssClass });
|
|
14794
|
+
});
|
|
14795
|
+
// Navigate to the "~" route if not finding a view capability, e.g., because the perspective provider references a private view capability
|
|
14796
|
+
// or has not declared an intention. Since there is no route registered under /~ the "Not Found" page will be displayed.
|
|
14797
|
+
if (!viewCapabilities.length) {
|
|
14798
|
+
this._logger.warn(() => `[NullCapabilityError] The perspective '${Objects.toMatrixNotation(perspectiveCapability.qualifier)}' cannot find the view '${Objects.toMatrixNotation(view.qualifier)}'. Verify the application is available and the view exists.`, LoggerNames.MICROFRONTEND);
|
|
14799
|
+
const alternativeViewId = `${part.id}-${viewIndex}`;
|
|
14800
|
+
layout = layout
|
|
14801
|
+
.addView(alternativeViewId, { partId: part.id, activateView: view.active })
|
|
14802
|
+
.navigateView(alternativeViewId, ['~', view.qualifier], { cssClass: view.cssClass });
|
|
14803
|
+
}
|
|
14804
|
+
}
|
|
14805
|
+
}
|
|
14806
|
+
return layout;
|
|
14807
|
+
};
|
|
14808
|
+
}
|
|
14809
|
+
/**
|
|
14810
|
+
* Searches for views that match the specified qualifier and are accessible to the perspective provider,
|
|
14811
|
+
* i.e., its own view capabilities or public view capabilities of other applications the perspective provider
|
|
14812
|
+
* has an intention for.
|
|
14813
|
+
*/
|
|
14814
|
+
async lookupViewCapabilities(qualifier, perspective) {
|
|
14815
|
+
const viewCapabilities$ = this._manifestService.lookupCapabilities$({ type: WorkbenchCapabilities.View, qualifier })
|
|
14816
|
+
.pipe(filterArray(async (viewCapability) => {
|
|
14817
|
+
const allowed = await firstValueFrom(this._manifestService.isApplicationQualified$(perspective.perspectiveProvider, { capabilityId: viewCapability.metadata.id }));
|
|
14818
|
+
if (!allowed) {
|
|
14819
|
+
this._logger.warn(`[NotQualifiedError] Application '${(perspective.perspectiveProvider)}' is not allowed to reference the view '${Objects.toMatrixNotation(viewCapability.qualifier)}' in the perspective '${Objects.toMatrixNotation(perspective.perspectiveQualifier)}'. Ensure you have specified an intention and that the view is public.`, LoggerNames.MICROFRONTEND);
|
|
14820
|
+
}
|
|
14821
|
+
return allowed;
|
|
14822
|
+
}));
|
|
14823
|
+
return firstValueFrom(viewCapabilities$);
|
|
14824
|
+
}
|
|
14825
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveInstaller, deps: [{ token: i2$3.ManifestService }, { token: WorkbenchService }, { token: Logger }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
14826
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveInstaller }); }
|
|
14827
|
+
}
|
|
14828
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: MicrofrontendPerspectiveInstaller, decorators: [{
|
|
14829
|
+
type: Injectable
|
|
14830
|
+
}], ctorParameters: () => [{ type: i2$3.ManifestService }, { type: WorkbenchService }, { type: Logger }] });
|
|
14831
|
+
|
|
14313
14832
|
/*
|
|
14314
14833
|
* Copyright (c) 2018-2024 Swiss Federal Railways
|
|
14315
14834
|
*
|
|
@@ -14346,20 +14865,34 @@ function provideWorkbenchMicrofrontendSupport(workbenchConfig) {
|
|
|
14346
14865
|
useClass: MicrofrontendNotificationIntentHandler,
|
|
14347
14866
|
multi: true,
|
|
14348
14867
|
},
|
|
14868
|
+
{
|
|
14869
|
+
provide: MICROFRONTEND_PLATFORM_POST_STARTUP,
|
|
14870
|
+
useClass: MicrofrontendPerspectiveInstaller,
|
|
14871
|
+
multi: true,
|
|
14872
|
+
},
|
|
14873
|
+
{
|
|
14874
|
+
provide: MICROFRONTEND_PLATFORM_POST_STARTUP,
|
|
14875
|
+
useExisting: ManifestObjectCache,
|
|
14876
|
+
multi: true,
|
|
14877
|
+
},
|
|
14349
14878
|
{
|
|
14350
14879
|
provide: MicrofrontendPlatformConfig,
|
|
14351
14880
|
useFactory: () => Defined.orElseThrow(inject(MicrofrontendPlatformInitializer).config, () => Error('[MicrofrontendPlatformError] Illegal state: Microfrontend platform configuration not loaded.')),
|
|
14352
14881
|
},
|
|
14882
|
+
MicrofrontendPlatformInitializer,
|
|
14883
|
+
MicrofrontendPerspectiveIntentHandler,
|
|
14353
14884
|
MicrofrontendViewIntentHandler,
|
|
14354
14885
|
MicrofrontendPopupIntentHandler,
|
|
14355
14886
|
MicrofrontendDialogIntentHandler,
|
|
14356
14887
|
MicrofrontendMessageBoxLegacyIntentTranslator,
|
|
14357
14888
|
MicrofrontendMessageBoxIntentHandler,
|
|
14889
|
+
MicrofrontendPerspectiveCapabilityValidator,
|
|
14358
14890
|
MicrofrontendViewCapabilityValidator,
|
|
14359
|
-
MicrofrontendViewCapabilityIdAssigner,
|
|
14360
14891
|
MicrofrontendPopupCapabilityValidator,
|
|
14361
14892
|
MicrofrontendDialogCapabilityValidator,
|
|
14362
14893
|
MicrofrontendMessageBoxCapabilityValidator,
|
|
14894
|
+
StableCapabilityIdAssigner,
|
|
14895
|
+
ManifestObjectCache,
|
|
14363
14896
|
NgZoneObservableDecorator,
|
|
14364
14897
|
WorkbenchHostManifestInterceptor,
|
|
14365
14898
|
provideBuiltInTextMessageBoxCapabilityRoute(),
|
|
@@ -14420,7 +14953,7 @@ function provideMicrofrontendViewRoute() {
|
|
|
14420
14953
|
useFactory: () => ({
|
|
14421
14954
|
matcher: MicrofrontendViewRoutes.provideMicrofrontendRouteMatcher(),
|
|
14422
14955
|
component: MicrofrontendViewComponent,
|
|
14423
|
-
canMatch: [canMatchWorkbenchView(true)],
|
|
14956
|
+
canMatch: [canMatchWorkbenchView(true), MicrofrontendViewRoutes.canMatchViewCapability],
|
|
14424
14957
|
}),
|
|
14425
14958
|
},
|
|
14426
14959
|
]);
|
|
@@ -14571,17 +15104,13 @@ function provideWorkbench(config) {
|
|
|
14571
15104
|
provide: WorkbenchStorage,
|
|
14572
15105
|
useClass: config.storage ?? DefaultWorkbenchStorage,
|
|
14573
15106
|
},
|
|
14574
|
-
{
|
|
14575
|
-
provide: WORKBENCH_LAYOUT_CONFIG,
|
|
14576
|
-
useFactory: () => config.layout ?? ((factory) => factory.addPart(MAIN_AREA)),
|
|
14577
|
-
},
|
|
14578
15107
|
{
|
|
14579
15108
|
provide: WORKBENCH_PRE_STARTUP,
|
|
14580
15109
|
useExisting: WorkbenchThemeSwitcher,
|
|
14581
15110
|
multi: true,
|
|
14582
15111
|
},
|
|
14583
15112
|
{
|
|
14584
|
-
provide:
|
|
15113
|
+
provide: WORKBENCH_POST_STARTUP,
|
|
14585
15114
|
multi: true,
|
|
14586
15115
|
useExisting: WorkbenchPerspectiveService,
|
|
14587
15116
|
},
|
|
@@ -15054,5 +15583,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
|
|
|
15054
15583
|
* Generated bundle index. Do not edit.
|
|
15055
15584
|
*/
|
|
15056
15585
|
|
|
15057
|
-
export { LogAppender, LogLevel, Logger, LoggerName, MAIN_AREA, MICROFRONTEND_PLATFORM_POST_STARTUP, MICROFRONTEND_PLATFORM_PRE_STARTUP, MicrofrontendPlatformConfigLoader, Notification, NotificationService, Popup, PopupConfig, PopupService, VIEW_TAB_RENDERING_CONTEXT, WORKBENCH_ID, WORKBENCH_POST_STARTUP, WORKBENCH_PRE_STARTUP, WORKBENCH_STARTUP,
|
|
15586
|
+
export { LogAppender, LogLevel, Logger, LoggerName, MAIN_AREA, MICROFRONTEND_PLATFORM_POST_STARTUP, MICROFRONTEND_PLATFORM_PRE_STARTUP, MicrofrontendPlatformConfigLoader, Notification, NotificationService, Popup, PopupConfig, PopupService, VIEW_TAB_RENDERING_CONTEXT, WORKBENCH_ID, WORKBENCH_POST_STARTUP, WORKBENCH_PRE_STARTUP, WORKBENCH_STARTUP, WorkbenchComponent, WorkbenchConfig, WorkbenchDialog, WorkbenchDialogActionDirective, WorkbenchDialogFooterDirective, WorkbenchDialogHeaderDirective, WorkbenchDialogService, WorkbenchLauncher, WorkbenchLayoutFactory, WorkbenchMessageBoxService, WorkbenchModule, WorkbenchPart, WorkbenchPartActionDirective, WorkbenchPerspectiveData, WorkbenchRouteData, WorkbenchRouter, WorkbenchRouterLinkDirective, WorkbenchService, WorkbenchStartup, WorkbenchStorage, WorkbenchTestingModule, WorkbenchView, WorkbenchViewMenuItemDirective, canMatchWorkbenchView, provideWorkbench, provideWorkbenchForTest };
|
|
15058
15587
|
//# sourceMappingURL=scion-workbench.mjs.map
|