@scion/workbench 17.0.0-beta.6 → 17.0.0-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/esm2022/lib/common/class-list.mjs +61 -0
  2. package/esm2022/lib/dialog/workbench-dialog.mjs +1 -1
  3. package/esm2022/lib/dialog/workbench-dialog.options.mjs +1 -1
  4. package/esm2022/lib/dialog//311/265workbench-dialog.mjs +2 -20
  5. package/esm2022/lib/layout/main-area-layout/main-area-layout.component.mjs +2 -1
  6. package/esm2022/lib/layout/workbench-layout.component.mjs +2 -1
  7. package/esm2022/lib/layout/workbench-layouts.util.mjs +17 -16
  8. package/esm2022/lib/logging/logger-names.mjs +8 -9
  9. package/esm2022/lib/microfrontend-platform/common/microfrontend.util.mjs +55 -0
  10. package/esm2022/lib/microfrontend-platform/initialization/microfrontend-platform-initializer.service.mjs +32 -20
  11. package/esm2022/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog-capability-validator.interceptor.mjs +53 -0
  12. package/esm2022/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog-intent-handler.interceptor.mjs +85 -0
  13. package/esm2022/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog.component.mjs +140 -0
  14. package/esm2022/lib/microfrontend-platform/microfrontend-host-dialog/microfrontend-host-dialog.component.mjs +122 -0
  15. package/esm2022/lib/microfrontend-platform/microfrontend-host-popup/microfrontend-host-popup.component.mjs +3 -3
  16. package/esm2022/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup-capability-validator.interceptor.mjs +30 -0
  17. package/esm2022/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup-intent-handler.interceptor.mjs +130 -0
  18. package/esm2022/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup.component.mjs +16 -28
  19. package/esm2022/lib/microfrontend-platform/microfrontend-view/microfrontend-view-command-handler.service.mjs +7 -29
  20. package/esm2022/lib/microfrontend-platform/microfrontend-view/microfrontend-view.component.mjs +70 -124
  21. package/esm2022/lib/microfrontend-platform/microfrontend-view/microfrontend-workbench-view.model.mjs +23 -0
  22. package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-capability-id-assigner.interceptor.mjs +41 -0
  23. package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-capability-validator.interceptor.mjs +30 -0
  24. package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-intent-handler.interceptor.mjs +123 -0
  25. package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-routes.mjs +98 -0
  26. package/esm2022/lib/microfrontend-platform/workbench-microfrontend-support.mjs +31 -35
  27. package/esm2022/lib/part/part-bar/part-bar.component.mjs +2 -1
  28. package/esm2022/lib/part/part.component.mjs +2 -1
  29. package/esm2022/lib/part/view-context-menu/view-menu.service.mjs +2 -2
  30. package/esm2022/lib/part/view-tab/view-tab.component.mjs +4 -3
  31. package/esm2022/lib/perspective/workbench-perspective-storage.service.mjs +1 -1
  32. package/esm2022/lib/perspective/workbench-perspective-view-conflict-resolver.service.mjs +1 -1
  33. package/esm2022/lib/perspective//311/265workbench-perspective.model.mjs +1 -1
  34. package/esm2022/lib/routing/public_api.mjs +1 -1
  35. package/esm2022/lib/routing/router.util.mjs +20 -43
  36. package/esm2022/lib/routing/routing.model.mjs +11 -0
  37. package/esm2022/lib/routing/workbench-auxiliary-routes-registrator.service.mjs +1 -2
  38. package/esm2022/lib/routing/workbench-dialog-differ.mjs +51 -0
  39. package/esm2022/lib/routing/workbench-navigational-states.mjs +28 -18
  40. package/esm2022/lib/routing/workbench-route-data.mjs +6 -15
  41. package/esm2022/lib/routing/workbench-router-link.directive.mjs +2 -3
  42. package/esm2022/lib/routing/workbench-router.service.mjs +5 -5
  43. package/esm2022/lib/routing/workbench-url-observer.service.mjs +37 -12
  44. package/esm2022/lib/view/view.component.mjs +6 -9
  45. package/esm2022/lib/view/workbench-view.model.mjs +1 -1
  46. package/esm2022/lib/view//311/265workbench-view.model.mjs +34 -6
  47. package/esm2022/lib/view-dnd/grid-drop-targets.util.mjs +33 -32
  48. package/esm2022/lib/view-dnd/view-drag.service.mjs +1 -1
  49. package/esm2022/lib/view-dnd/view-tab-drag-image-renderer.service.mjs +6 -6
  50. package/esm2022/lib/workbench.constants.mjs +6 -2
  51. package/fesm2022/scion-workbench.mjs +978 -541
  52. package/fesm2022/scion-workbench.mjs.map +1 -1
  53. package/lib/common/class-list.d.ts +51 -0
  54. package/lib/dialog/workbench-dialog.d.ts +2 -6
  55. package/lib/dialog/workbench-dialog.options.d.ts +1 -1
  56. package/lib/dialog//311/265workbench-dialog.d.ts +2 -4
  57. package/lib/layout/workbench-layouts.util.d.ts +4 -6
  58. package/lib/logging/logger-names.d.ts +7 -7
  59. package/lib/microfrontend-platform/common/microfrontend.util.d.ts +22 -0
  60. package/lib/microfrontend-platform/initialization/microfrontend-platform-initializer.service.d.ts +15 -9
  61. package/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog-capability-validator.interceptor.d.ts +11 -0
  62. package/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog-intent-handler.interceptor.d.ts +28 -0
  63. package/lib/microfrontend-platform/microfrontend-dialog/microfrontend-dialog.component.d.ts +52 -0
  64. package/lib/microfrontend-platform/microfrontend-host-dialog/microfrontend-host-dialog.component.d.ts +37 -0
  65. package/lib/microfrontend-platform/microfrontend-popup/{microfrontend-popup-capability-interceptor.service.d.ts → microfrontend-popup-capability-validator.interceptor.d.ts} +3 -3
  66. package/lib/microfrontend-platform/microfrontend-popup/{microfrontend-popup-intent-interceptor.service.d.ts → microfrontend-popup-intent-handler.interceptor.d.ts} +9 -6
  67. package/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup.component.d.ts +7 -10
  68. package/lib/microfrontend-platform/microfrontend-view/microfrontend-view-command-handler.service.d.ts +2 -9
  69. package/lib/microfrontend-platform/microfrontend-view/microfrontend-view.component.d.ts +8 -14
  70. package/lib/microfrontend-platform/microfrontend-view/microfrontend-workbench-view.model.d.ts +14 -0
  71. package/lib/microfrontend-platform/routing/microfrontend-view-capability-id-assigner.interceptor.d.ts +10 -0
  72. package/lib/microfrontend-platform/routing/{microfrontend-view-capability-interceptor.service.d.ts → microfrontend-view-capability-validator.interceptor.d.ts} +3 -3
  73. package/lib/microfrontend-platform/routing/{microfrontend-view-intent-interceptor.service.d.ts → microfrontend-view-intent-handler.interceptor.d.ts} +6 -5
  74. package/lib/microfrontend-platform/routing/microfrontend-view-routes.d.ts +49 -0
  75. package/lib/microfrontend-platform/workbench-microfrontend-support.d.ts +1 -0
  76. package/lib/perspective/workbench-perspective-storage.service.d.ts +1 -1
  77. package/lib/perspective/workbench-perspective-view-conflict-resolver.service.d.ts +1 -1
  78. package/lib/routing/public_api.d.ts +2 -1
  79. package/lib/routing/router.util.d.ts +12 -20
  80. package/lib/routing/routing.model.d.ts +30 -0
  81. package/lib/routing/workbench-auxiliary-routes-registrator.service.d.ts +2 -3
  82. package/lib/routing/workbench-dialog-differ.d.ts +25 -0
  83. package/lib/routing/workbench-navigational-states.d.ts +16 -13
  84. package/lib/routing/workbench-route-data.d.ts +5 -13
  85. package/lib/routing/workbench-router.service.d.ts +7 -22
  86. package/lib/routing/workbench-url-observer.service.d.ts +13 -1
  87. package/lib/view/workbench-view.model.d.ts +9 -8
  88. package/lib/view//311/265workbench-view.model.d.ts +21 -2
  89. package/lib/view-dnd/grid-drop-targets.util.d.ts +15 -17
  90. package/lib/view-dnd/view-drag.service.d.ts +3 -0
  91. package/lib/workbench.constants.d.ts +4 -0
  92. package/package.json +2 -2
  93. package/esm2022/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup-capability-interceptor.service.mjs +0 -30
  94. package/esm2022/lib/microfrontend-platform/microfrontend-popup/microfrontend-popup-intent-interceptor.service.mjs +0 -130
  95. package/esm2022/lib/microfrontend-platform/routing/microfrontend-navigational-states.mjs +0 -22
  96. package/esm2022/lib/microfrontend-platform/routing/microfrontend-routes.mjs +0 -71
  97. package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-capability-interceptor.service.mjs +0 -54
  98. package/esm2022/lib/microfrontend-platform/routing/microfrontend-view-intent-interceptor.service.mjs +0 -123
  99. package/esm2022/lib/routing/navigation-state.resolver.mjs +0 -54
  100. package/lib/microfrontend-platform/routing/microfrontend-navigational-states.d.ts +0 -11
  101. package/lib/microfrontend-platform/routing/microfrontend-routes.d.ts +0 -38
  102. package/lib/routing/navigation-state.resolver.d.ts +0 -12
@@ -0,0 +1,49 @@
1
+ import { Params, UrlMatcher, UrlSegment } from '@angular/router';
2
+ import { WorkbenchViewCapability } from '@scion/workbench-client';
3
+ import { Commands } from '../../routing/routing.model';
4
+ /**
5
+ * Provides functions and constants specific to microfrontend routes.
6
+ */
7
+ export declare const MicrofrontendViewRoutes: {
8
+ /**
9
+ * Prefix to identify a microfrontend route.
10
+ */
11
+ readonly ROUTE_PREFIX: "~";
12
+ /**
13
+ * Key for associating transient parameters with a navigation.
14
+ */
15
+ readonly STATE_TRANSIENT_PARAMS: "transientParams";
16
+ /**
17
+ * Custom URL matcher for microfrontend URLs, enabling transient parameters to be provided as regular route parameters.
18
+ *
19
+ * A microfrontend route consists of two segments:
20
+ * 1. An identifier segment (`~`) to identify a microfrontend route.
21
+ * 2. Capability segment to identify the microfrontend capability.
22
+ *
23
+ * Parameters are included in the second segment as matrix parameters.
24
+ *
25
+ * Example URL: `~/a538d2a;param1=value1;param2=value
26
+ *
27
+ * @see MicrofrontendViewRoutes.createMicrofrontendNavigateCommands
28
+ */
29
+ readonly provideMicrofrontendRouteMatcher: () => UrlMatcher;
30
+ /**
31
+ * Creates routing commands to navigate a microfrontend.
32
+ *
33
+ * Format: ['~', '<capabilityId>, {params}]
34
+ *
35
+ * @see MicrofrontendViewRoutes.provideMicrofrontendRouteMatcher
36
+ */
37
+ readonly createMicrofrontendNavigateCommands: (viewCapabilityId: string, params: Params) => Commands;
38
+ /**
39
+ * Tests given URL to be a microfrontend route.
40
+ */
41
+ readonly isMicrofrontendRoute: (segments: UrlSegment[]) => boolean;
42
+ /**
43
+ * Splits given params into URL and transient params.
44
+ */
45
+ readonly splitParams: (params: Params, capability: WorkbenchViewCapability) => {
46
+ urlParams: Params;
47
+ transientParams: Params;
48
+ };
49
+ };
@@ -1,5 +1,6 @@
1
1
  import { EnvironmentProviders } from '@angular/core';
2
2
  import { WorkbenchModuleConfig } from '../workbench-module-config';
3
+ import './microfrontend-platform.config';
3
4
  /**
4
5
  * Provides a set of DI providers to set up microfrontend support in the workbench.
5
6
  */
@@ -1,5 +1,5 @@
1
1
  import { WorkbenchStorage } from '../storage/workbench-storage';
2
- import { Commands } from '../routing/workbench-router.service';
2
+ import { Commands } from '../routing/routing.model';
3
3
  import * as i0 from "@angular/core";
4
4
  /**
5
5
  * Provides API to read/write perspective data from/to {@link WorkbenchStorage}.
@@ -1,6 +1,6 @@
1
1
  import { MPartGrid } from '../layout/workbench-layout.model';
2
2
  import { ɵWorkbenchLayoutFactory } from '../layout/ɵworkbench-layout.factory';
3
- import { Commands } from '../routing/workbench-router.service';
3
+ import { Commands } from '../routing/routing.model';
4
4
  import * as i0 from "@angular/core";
5
5
  /**
6
6
  * Detects and resolves name conflicts of view names, that may occur when switching between perspectives.
@@ -1,4 +1,5 @@
1
- export { WorkbenchRouter, WorkbenchNavigationExtras, Commands } from './workbench-router.service';
1
+ export { WorkbenchRouter, WorkbenchNavigationExtras } from './workbench-router.service';
2
2
  export { WorkbenchRouterLinkDirective } from './workbench-router-link.directive';
3
3
  export { WorkbenchAuxiliaryRoutesRegistrator } from './workbench-auxiliary-routes-registrator.service';
4
4
  export { WorkbenchRouteData } from './workbench-route-data';
5
+ export { Commands, ViewState } from './routing.model';
@@ -1,31 +1,23 @@
1
1
  import { ActivatedRouteSnapshot, Router, UrlSegment } from '@angular/router';
2
- import { Commands } from './workbench-router.service';
3
- export declare namespace RouterUtils {
4
- /**
5
- * Replaces named parameters in the given path with values contained in the given {@link Map}.
6
- * Named parameters begin with a colon (`:`) and are allowed in path segments, query parameters, matrix parameters
7
- * and the fragment part.
8
- *
9
- * Some examples about the usage of named parameters:
10
- * /segment/:param1/segment/:param2 // path params
11
- * /segment/segment;matrixParam1=:param1;matrixParam2=:param2 // matrix params
12
- * /segment/segment?queryParam1=:param1&queryParam2=:param2 // query params
13
- */
14
- function substituteNamedParameters(path: string | null, params?: Map<string, any>): string | null;
2
+ import { Commands } from './routing.model';
3
+ /**
4
+ * Provides utility functions for router operations.
5
+ */
6
+ export declare const RouterUtils: {
15
7
  /**
16
8
  * Converts URL segments into an array of routable commands to be passed to the Angular router for navigation.
17
9
  */
18
- function segmentsToCommands(segments: UrlSegment[]): Commands[];
10
+ readonly segmentsToCommands: (segments: UrlSegment[]) => Commands[];
19
11
  /**
20
12
  * Reads specified outlets from the current URL, optionally applying a `replacer` function to replace the commands of an outlet.
21
13
  */
22
- function outletsFromCurrentUrl(router: Router, outletNames: string[], replacer?: (outlet: string, commands: Commands) => Commands | null): {
14
+ readonly outletsFromCurrentUrl: (router: Router, outletNames: string[], replacer?: ((outlet: string, commands: Commands) => Commands | null) | undefined) => {
23
15
  [viewId: string]: Commands;
24
16
  };
25
17
  /**
26
18
  * Parses the given path including any matrix parameters into URL segments.
27
19
  */
28
- function parsePath(router: Router, path: string): UrlSegment[];
20
+ readonly parsePath: (router: Router, path: string) => UrlSegment[];
29
21
  /**
30
22
  * Resolves to the actual {@link ActivatedRouteSnapshot} loaded into a router outlet.
31
23
  *
@@ -33,14 +25,14 @@ export declare namespace RouterUtils {
33
25
  * or resolver, is not always the route that is actually loaded into the outlet, for example, if the route
34
26
  * is a child of a component-less route.
35
27
  */
36
- function resolveActualRouteSnapshot(route: ActivatedRouteSnapshot): ActivatedRouteSnapshot;
28
+ readonly resolveActualRouteSnapshot: (route: ActivatedRouteSnapshot) => ActivatedRouteSnapshot;
37
29
  /**
38
30
  * Looks for requested data on given route, or its parent route(s) if not declared.
39
31
  */
40
- function lookupRouteData<T>(activatedRoute: ActivatedRouteSnapshot, dataKey: string): T | undefined;
32
+ readonly lookupRouteData: <T>(activatedRoute: ActivatedRouteSnapshot, dataKey: string) => T | undefined;
41
33
  /**
42
34
  * Tests if the given view can be the target of a primary route.
43
35
  * Such views have an id that begins with the view prefix.
44
36
  */
45
- function isPrimaryRouteTarget(viewId: string): boolean;
46
- }
37
+ readonly isPrimaryRouteTarget: (viewId: string) => boolean;
38
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Represents an ordered list of path segments instructing the router which route to navigate to.
3
+ *
4
+ * A command can be either a `string` or an object literal. String literals represent path segments, while object literals associate data
5
+ * with the preceding path segment. Multiple path segments can be combined into a single command, separated by a forward slash. The first
6
+ * path segment supports the usage of navigational symbols such as `/`, `./`, or `../`.
7
+ *
8
+ * Example:
9
+ * - Navigate to the path 'path/to/view', passing two parameters:
10
+ * ['path', 'to', 'view', {param1: 'value1', param2: 'value2'}]
11
+ * - Alternative syntax using a combined segment:
12
+ * ['path/to/view', {param1: 'value1', param2: 'value2'}]
13
+ */
14
+ export type Commands = any[];
15
+ /**
16
+ * Navigational view states associated with a workbench navigation.
17
+ */
18
+ export type ViewStates = {
19
+ [viewId: string]: ViewState;
20
+ };
21
+ /**
22
+ * State associated with a view navigation.
23
+ *
24
+ * State is written to the browser session history, not to the URL, so will be lost on page reload.
25
+ *
26
+ * State can be read from {@link WorkbenchView.state}, or the browser's session history via `history.state`.
27
+ */
28
+ export type ViewState = {
29
+ [key: string]: unknown;
30
+ };
@@ -1,4 +1,4 @@
1
- import { CanActivateFn, CanDeactivateFn, Data, ResolveData, Router, Routes } from '@angular/router';
1
+ import { CanActivateFn, CanDeactivateFn, Data, Router, Routes } from '@angular/router';
2
2
  import * as i0 from "@angular/core";
3
3
  /**
4
4
  * Registers auxiliary routes for views.
@@ -29,8 +29,7 @@ export declare class WorkbenchAuxiliaryRoutesRegistrator {
29
29
  * Controls the creation of auxiliary routes for a named router outlet.
30
30
  */
31
31
  export interface OutletAuxiliaryRouteConfig {
32
- canDeactivate?: CanDeactivateFn<any>[];
33
32
  canActivate?: CanActivateFn[];
33
+ canDeactivate?: CanDeactivateFn<any>[];
34
34
  data?: Data;
35
- resolve?: ResolveData;
36
35
  }
@@ -0,0 +1,25 @@
1
+ import { IterableChanges, IterableDiffers } from '@angular/core';
2
+ import { UrlTree } from '@angular/router';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Stateful differ for finding added/removed dialogs.
6
+ */
7
+ export declare class WorkbenchDialogDiffer {
8
+ private _dialogDiffer;
9
+ constructor(differs: IterableDiffers);
10
+ /**
11
+ * Computes differences in the URL since last time {@link WorkbenchDialogDiffer#diff} was invoked.
12
+ */
13
+ diff(urlTree: UrlTree): WorkbenchDialogDiff;
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<WorkbenchDialogDiffer, never>;
15
+ static ɵprov: i0.ɵɵInjectableDeclaration<WorkbenchDialogDiffer>;
16
+ }
17
+ /**
18
+ * Lists the dialogs added/removed in the current navigation.
19
+ */
20
+ export declare class WorkbenchDialogDiff {
21
+ readonly addedDialogOutlets: string[];
22
+ readonly removedDialogOutlets: string[];
23
+ constructor(changes: IterableChanges<string> | null);
24
+ toString(): string;
25
+ }
@@ -1,18 +1,24 @@
1
- import { Dictionary } from '@scion/toolkit/util';
2
1
  import { Navigation, NavigationExtras } from '@angular/router';
2
+ import { ViewState, ViewStates } from './routing.model';
3
3
  /**
4
4
  * Provides methods to associate {@link WorkbenchNavigationalState} with a navigation.
5
5
  */
6
- export declare namespace WorkbenchNavigationalStates {
6
+ export declare const WorkbenchNavigationalStates: {
7
7
  /**
8
8
  * Returns workbench-specific state associated with given navigation, or `null` if not a workbench navigation.
9
9
  */
10
- function fromNavigation(navigation: Navigation): WorkbenchNavigationalState | null;
10
+ readonly fromNavigation: (navigation: Navigation) => WorkbenchNavigationalState | null;
11
+ /**
12
+ * Resolves navigational state associated with a view.
13
+ *
14
+ * TODO [WB-LAYOUT] Remove when migrated to the new Router API as state is retained in layout.
15
+ */
16
+ readonly resolveViewState: (viewId: string) => ViewState | undefined;
11
17
  /**
12
18
  * Associates workbench-specific state with given navigation extras.
13
19
  */
14
- function addToNavigationExtras(extras: NavigationExtras, state: WorkbenchNavigationalState): void;
15
- }
20
+ readonly addToNavigationExtras: (extras: NavigationExtras, state: WorkbenchNavigationalState) => void;
21
+ };
16
22
  /**
17
23
  * Represents workbench-specific state associated with a navigation.
18
24
  */
@@ -28,19 +34,16 @@ export interface WorkbenchNavigationalState {
28
34
  */
29
35
  maximized: boolean;
30
36
  /**
31
- * View state to be associated with the navigation.
32
- * View state can be read from {@link ActivatedRoute.data} using the key {@link WorkbenchRouteData.state}.
37
+ * View states to be associated with the navigation.
33
38
  */
34
- viewStates: {
35
- [viewId: string]: Dictionary;
36
- };
39
+ viewStates: ViewStates;
37
40
  }
38
41
  /**
39
42
  * Keys for associating state with a view navigation.
40
43
  */
41
- export declare namespace WorkbenchNavigationalViewStates {
44
+ export declare const WorkbenchNavigationalViewStates: {
42
45
  /**
43
46
  * Key for associating CSS class(es) with a view state.
44
47
  */
45
- const cssClass = "\u0275cssClass";
46
- }
48
+ readonly cssClass: "ɵcssClass";
49
+ };
@@ -3,25 +3,17 @@
3
3
  *
4
4
  * @see Route.data
5
5
  */
6
- export declare namespace WorkbenchRouteData {
6
+ export declare const WorkbenchRouteData: {
7
7
  /**
8
8
  * Key to define the title of a view in {@link Route.data}.
9
9
  */
10
- const title = "\u0275workbenchViewTitle";
10
+ readonly title: "ɵworkbenchViewTitle";
11
11
  /**
12
12
  * Key to define the heading of a view in {@link Route.data}.
13
13
  */
14
- const heading = "\u0275workbenchViewHeading";
14
+ readonly heading: "ɵworkbenchViewHeading";
15
15
  /**
16
16
  * Key to associate CSS class(es) with a view in {@link Route.data}, useful in end-to-end tests for locating views and view tabs.
17
17
  */
18
- const cssClass = "\u0275workbenchViewCssClass";
19
- /**
20
- * Key for reading view-specific navigational state from {@link ActivatedRoute.data}.
21
- *
22
- * The state object contains user-defined state passed to navigation extras.
23
- *
24
- * @see WorkbenchNavigationalState
25
- */
26
- const state = "\u0275workbenchViewState";
27
- }
18
+ readonly cssClass: "ɵworkbenchViewCssClass";
19
+ };
@@ -1,9 +1,9 @@
1
1
  import { NavigationExtras, Router } from '@angular/router';
2
- import { Dictionary } from '@scion/toolkit/util';
3
2
  import { NgZone, OnDestroy } from '@angular/core';
4
3
  import { WorkbenchLayoutService } from '../layout/workbench-layout.service';
5
4
  import { WorkbenchViewRegistry } from '../view/workbench-view.registry';
6
5
  import { ɵWorkbenchLayout } from '../layout/ɵworkbench-layout';
6
+ import { Commands, ViewState, ViewStates } from './routing.model';
7
7
  import * as i0 from "@angular/core";
8
8
  /**
9
9
  * Provides workbench view navigation capabilities based on Angular Router.
@@ -129,32 +129,19 @@ export interface WorkbenchNavigationExtras extends NavigationExtras {
129
129
  */
130
130
  blankInsertionIndex?: number | 'start' | 'end';
131
131
  /**
132
- * State that will be passed to the navigation.
132
+ * Associates state with a view navigation.
133
133
  *
134
- * See {@link NavigationExtras#state} for detailed instructions on how to access passed state during and after the navigation.
134
+ * State is written to the browser session history, not to the URL, so will be lost on page reload.
135
135
  *
136
- * In addition, the workbench router makes state available to the routed component as resolved data under the key {@link WorkbenchRouteData.state}.
136
+ * State can be read from {@link WorkbenchView.state}, or the browser's session history via `history.state`.
137
137
  */
138
- state?: Dictionary;
138
+ state?: ViewState;
139
139
  /**
140
140
  * Specifies CSS class(es) to be added to the view, useful in end-to-end tests for locating view and view tab.
141
141
  * CSS class(es) will not be added to the browser URL, consequently will not survive a page reload.
142
142
  */
143
143
  cssClass?: string | string[];
144
144
  }
145
- /**
146
- * An array of URL fragments with which to construct a view's URL.
147
- *
148
- * If the path is static, can be the literal URL string. For a dynamic path, pass an array of path segments,
149
- * followed by the parameters for each segment.
150
- *
151
- * The last segment allows adding matrix parameters in the form of a dictionary to provide additional data along
152
- * with the URL. Matrix parameters do not affect route resolution. In the routed component, matrix parameters are
153
- * available in {@link ActivatedRoute#params}.
154
- *
155
- * Example command array with 'details' as matrix parameter: `['user', userName, {details: true}]`,
156
- */
157
- export type Commands = any[];
158
145
  /**
159
146
  * Information about a workbench navigation operation.
160
147
  */
@@ -172,9 +159,7 @@ export interface WorkbenchNavigation {
172
159
  [outlet: string]: Commands | null;
173
160
  };
174
161
  /**
175
- * State to be passed to the routed component as resolved data under the key {@link WorkbenchRouteData.state}.
162
+ * View states to be associated with the navigation.
176
163
  */
177
- viewStates?: {
178
- [outlet: string]: Dictionary;
179
- };
164
+ viewStates?: ViewStates;
180
165
  }
@@ -9,6 +9,7 @@ import { WorkbenchLayoutDiffer } from './workbench-layout-differ';
9
9
  import { WorkbenchPopupDiffer } from './workbench-popup-differ';
10
10
  import { Logger } from '../logging';
11
11
  import { ɵWorkbenchLayoutFactory } from '../layout/ɵworkbench-layout.factory';
12
+ import { WorkbenchDialogDiffer } from './workbench-dialog-differ';
12
13
  import * as i0 from "@angular/core";
13
14
  /**
14
15
  * Tracks the browser URL for workbench layout changes.
@@ -30,8 +31,9 @@ export declare class WorkbenchUrlObserver {
30
31
  private _workbenchLayoutFactory;
31
32
  private _workbenchLayoutDiffer;
32
33
  private _workbenchPopupDiffer;
34
+ private _workbenchDialogDiffer;
33
35
  private _logger;
34
- constructor(_router: Router, _auxRoutesRegistrator: WorkbenchAuxiliaryRoutesRegistrator, _viewRegistry: WorkbenchViewRegistry, _partRegistry: WorkbenchPartRegistry, _workbenchLayoutService: WorkbenchLayoutService, _environmentInjector: EnvironmentInjector, _workbenchRouter: WorkbenchRouter, _workbenchLayoutFactory: ɵWorkbenchLayoutFactory, _workbenchLayoutDiffer: WorkbenchLayoutDiffer, _workbenchPopupDiffer: WorkbenchPopupDiffer, _logger: Logger);
36
+ constructor(_router: Router, _auxRoutesRegistrator: WorkbenchAuxiliaryRoutesRegistrator, _viewRegistry: WorkbenchViewRegistry, _partRegistry: WorkbenchPartRegistry, _workbenchLayoutService: WorkbenchLayoutService, _environmentInjector: EnvironmentInjector, _workbenchRouter: WorkbenchRouter, _workbenchLayoutFactory: ɵWorkbenchLayoutFactory, _workbenchLayoutDiffer: WorkbenchLayoutDiffer, _workbenchPopupDiffer: WorkbenchPopupDiffer, _workbenchDialogDiffer: WorkbenchDialogDiffer, _logger: Logger);
35
37
  /** Invoked at the beginning of each navigation */
36
38
  private onNavigationStart;
37
39
  /** Invoked upon successful navigation */
@@ -54,6 +56,10 @@ export declare class WorkbenchUrlObserver {
54
56
  * For each added popup, registers auxiliary routes of all primary routes.
55
57
  */
56
58
  registerAddedPopupAuxiliaryRoutes(): void;
59
+ /**
60
+ * For each added dialog, registers auxiliary routes of all primary routes.
61
+ */
62
+ registerAddedDialogAuxiliaryRoutes(): void;
57
63
  /**
58
64
  * Reverts the workbench layout differ to the state before the navigation.
59
65
  *
@@ -66,6 +72,12 @@ export declare class WorkbenchUrlObserver {
66
72
  * Invoke this method after navigation failure or cancellation. The navigation is cancelled when guards perform a redirect or reject navigation.
67
73
  */
68
74
  private undoWorkbenchPopupDiffer;
75
+ /**
76
+ * Reverts the dialog outlet differ to the state before the navigation.
77
+ *
78
+ * Invoke this method after navigation failure or cancellation. The navigation is cancelled when guards perform a redirect or reject navigation.
79
+ */
80
+ private undoWorkbenchDialogDiffer;
69
81
  /**
70
82
  * Undoes the registration of auxiliary routes.
71
83
  *
@@ -3,6 +3,7 @@ import { UrlSegment } from '@angular/router';
3
3
  import { Disposable } from '../common/disposable';
4
4
  import { WorkbenchMenuItem } from '../workbench.model';
5
5
  import { WorkbenchPart } from '../part/workbench-part.model';
6
+ import { ViewState } from '../routing/routing.model';
6
7
  /**
7
8
  * A view is a visual workbench component for displaying content stacked or side-by-side.
8
9
  *
@@ -32,11 +33,7 @@ export declare abstract class WorkbenchView {
32
33
  /**
33
34
  * Specifies CSS class(es) to be added to the view, useful in end-to-end tests for locating view and view tab.
34
35
  */
35
- abstract set cssClass(cssClass: string | string[]);
36
- /**
37
- * CSS classes associated with the view.
38
- */
39
- abstract readonly cssClasses: string[];
36
+ abstract cssClass: string | string[];
40
37
  /**
41
38
  * Specifies if the content of the current view is dirty.
42
39
  * If dirty, a dirty marker is displayed in the view tab.
@@ -77,11 +74,15 @@ export declare abstract class WorkbenchView {
77
74
  */
78
75
  abstract readonly destroyed: boolean;
79
76
  /**
80
- * Returns the URL segments of this view.
81
- *
82
- * A {@link UrlSegment} is a part of a URL between the two slashes. It contains a path and the matrix parameters associated with the segment.
77
+ * URL associated with this view.
83
78
  */
84
79
  abstract readonly urlSegments: UrlSegment[];
80
+ /**
81
+ * State associated with this view.
82
+ *
83
+ * Note that state is volatile, meaning it is not encoded in the URL but read from the browser session history; thus, it will be lost when the page is reloaded.
84
+ */
85
+ abstract readonly state: ViewState;
85
86
  /**
86
87
  * Activates this view.
87
88
  *
@@ -6,9 +6,12 @@ import { WorkbenchView } from './workbench-view.model';
6
6
  import { WorkbenchPart } from '../part/workbench-part.model';
7
7
  import { ComponentType } from '@angular/cdk/portal';
8
8
  import { WbComponentPortal } from '../portal/wb-component-portal';
9
+ import { AbstractType, Type } from '@angular/core';
9
10
  import { ɵWorkbenchLayout } from '../layout/ɵworkbench-layout';
10
11
  import { ɵWorkbenchDialog } from '../dialog/ɵworkbench-dialog';
11
12
  import { Blockable } from '../glass-pane/blockable';
13
+ import { ViewState } from '../routing/routing.model';
14
+ import { ClassList } from '../common/class-list';
12
15
  export declare class ɵWorkbenchView implements WorkbenchView, Blockable {
13
16
  readonly id: string;
14
17
  private readonly _workbenchId;
@@ -23,6 +26,7 @@ export declare class ɵWorkbenchView implements WorkbenchView, Blockable {
23
26
  private readonly _part$;
24
27
  private readonly _menuItemProviders$;
25
28
  private readonly _scrolledIntoView$;
29
+ private readonly _adapters;
26
30
  private readonly _destroyRef;
27
31
  private _activationInstant;
28
32
  private _closable;
@@ -31,11 +35,12 @@ export declare class ɵWorkbenchView implements WorkbenchView, Blockable {
31
35
  dirty: boolean;
32
36
  scrollTop: number;
33
37
  scrollLeft: number;
38
+ state: ViewState;
34
39
  readonly active$: BehaviorSubject<boolean>;
35
- readonly cssClasses$: BehaviorSubject<string[]>;
36
40
  readonly menuItems$: Observable<WorkbenchMenuItem[]>;
37
41
  readonly blockedBy$: BehaviorSubject<ɵWorkbenchDialog<unknown> | null>;
38
42
  readonly portal: WbComponentPortal;
43
+ readonly classList: ClassList;
39
44
  constructor(id: string, options: {
40
45
  component: ComponentType<ViewComponent>;
41
46
  });
@@ -48,7 +53,7 @@ export declare class ɵWorkbenchView implements WorkbenchView, Blockable {
48
53
  get last(): boolean;
49
54
  get position(): number;
50
55
  set cssClass(cssClass: string | string[]);
51
- get cssClasses(): string[];
56
+ get cssClass(): string[];
52
57
  get active(): boolean;
53
58
  set closable(closable: boolean);
54
59
  get closable(): boolean;
@@ -78,6 +83,20 @@ export declare class ɵWorkbenchView implements WorkbenchView, Blockable {
78
83
  }): void;
79
84
  get urlSegments(): UrlSegment[];
80
85
  registerMenuItem(menuItem: WorkbenchMenuItem): Disposable;
86
+ /**
87
+ * Registers an adapter for this view, replacing any previously registered adapter of the same type.
88
+ *
89
+ * Adapters enable loosely coupled extension of an object, allowing one object to be adapted to another.
90
+ */
91
+ registerAdapter<T>(adapterType: AbstractType<T> | Type<T>, object: T): void;
92
+ /**
93
+ * Unregisters the given adapter. Has no effect if not registered.
94
+ */
95
+ unregisterAdapter(adapterType: AbstractType<unknown> | Type<unknown>): void;
96
+ /**
97
+ * Adapts this object to the specified type. Returns `null` if no such object can be found.
98
+ */
99
+ adapt<T>(adapterType: AbstractType<T> | Type<T>): T | null;
81
100
  get destroyed(): boolean;
82
101
  /**
83
102
  * Monitors the associated part to check if this view is currently active, updating the active state of this view accordingly.
@@ -1,24 +1,22 @@
1
1
  import { ViewMoveEventTarget } from './view-drag.service';
2
2
  import { MPartGrid } from '../layout/workbench-layout.model';
3
- /**
4
- * Resolves the drop target for moving a view to the root part (or node) of a grid.
5
- *
6
- * Examples:
7
- * - Droping a view at the grid's boundaries (north, south, east, west).
8
- * - Dropping a view on the grid's start page (center).
9
- *
10
- * When dropping a view on the grid's start page, the root of the grid can be a part or a node,
11
- * depending on whether the grid contains structural parts.
12
- */
13
- declare function resolve(target: {
14
- grid: MPartGrid;
15
- dropRegion: 'west' | 'east' | 'north' | 'south' | 'center';
16
- workbenchId: string;
17
- }): ViewMoveEventTarget;
18
3
  /**
19
4
  * Provides helper functions for dragging a view to a grid.
20
5
  */
21
6
  export declare const GridDropTargets: {
22
- readonly resolve: typeof resolve;
7
+ /**
8
+ * Resolves the drop target for moving a view to the root part (or node) of a grid.
9
+ *
10
+ * Examples:
11
+ * - Droping a view at the grid's boundaries (north, south, east, west).
12
+ * - Dropping a view on the grid's start page (center).
13
+ *
14
+ * When dropping a view on the grid's start page, the root of the grid can be a part or a node,
15
+ * depending on whether the grid contains structural parts.
16
+ */
17
+ readonly resolve: (target: {
18
+ grid: MPartGrid;
19
+ dropRegion: 'west' | 'east' | 'north' | 'south' | 'center';
20
+ workbenchId: string;
21
+ }) => ViewMoveEventTarget;
23
22
  };
24
- export {};
@@ -1,6 +1,7 @@
1
1
  import { NgZone, OnDestroy } from '@angular/core';
2
2
  import { Observable } from 'rxjs';
3
3
  import { UrlSegment } from '@angular/router';
4
+ import { ClassListMap } from '../common/class-list';
4
5
  import * as i0 from "@angular/core";
5
6
  /**
6
7
  * Events fired during view drag and drop operation.
@@ -130,6 +131,7 @@ export interface ViewDragData {
130
131
  viewTabWidth: number;
131
132
  viewTabHeight: number;
132
133
  workbenchId: string;
134
+ classList?: ClassListMap;
133
135
  }
134
136
  /**
135
137
  * Event emitted when moving a view.
@@ -146,6 +148,7 @@ export interface ViewMoveEventSource {
146
148
  partId: string;
147
149
  viewUrlSegments: UrlSegment[];
148
150
  workbenchId: string;
151
+ classList?: ClassListMap;
149
152
  }
150
153
  /**
151
154
  * Describes the target location for moving a view.
@@ -16,6 +16,10 @@ export declare const VIEW_ID_PREFIX = "view.";
16
16
  * Represents the id prefix of popups.
17
17
  */
18
18
  export declare const POPUP_ID_PREFIX = "popup.";
19
+ /**
20
+ * Represents the id prefix of dialogs.
21
+ */
22
+ export declare const DIALOG_ID_PREFIX = "dialog.";
19
23
  /**
20
24
  * Name of the query parameter that contains the layout of the main area.
21
25
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scion/workbench",
3
- "version": "17.0.0-beta.6",
3
+ "version": "17.0.0-beta.7",
4
4
  "description": "SCION Workbench enables the creation of Angular web applications that require a flexible layout to arrange content side-by-side or stacked, all personalizable by the user via drag & drop.",
5
5
  "license": "EPL-2.0",
6
6
  "private": false,
@@ -39,7 +39,7 @@
39
39
  "@scion/components": "^17.0.0",
40
40
  "@scion/toolkit": "^1.4.0",
41
41
  "@scion/microfrontend-platform": "^1.2.1",
42
- "@scion/workbench-client": "^1.0.0-beta.20",
42
+ "@scion/workbench-client": "^1.0.0-beta.21",
43
43
  "rxjs": "^7.8.0"
44
44
  },
45
45
  "peerDependenciesMeta": {
@@ -1,30 +0,0 @@
1
- import { Injectable } from '@angular/core';
2
- import { WorkbenchCapabilities } from '@scion/workbench-client';
3
- import * as i0 from "@angular/core";
4
- /**
5
- * Asserts popup capabilities to have required properties.
6
- */
7
- export class MicrofrontendPopupCapabilityInterceptor {
8
- async intercept(capability) {
9
- if (capability.type !== WorkbenchCapabilities.Popup) {
10
- return capability;
11
- }
12
- const popupCapability = capability;
13
- // Assert the popup capability to have a qualifier set.
14
- if (!popupCapability.qualifier || !Object.keys(popupCapability.qualifier).length) {
15
- throw Error(`[NullQualifierError] Popup capability requires a qualifier [capability=${JSON.stringify(popupCapability)}]`);
16
- }
17
- // Assert the popup capability to have a path set.
18
- const path = popupCapability.properties?.path;
19
- if (path === undefined || path === null) {
20
- throw Error(`[NullPathError] Popup capability requires a path to the microfrontend in its properties [capability=${JSON.stringify(popupCapability)}]`);
21
- }
22
- return popupCapability;
23
- }
24
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.3", ngImport: i0, type: MicrofrontendPopupCapabilityInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
25
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.3", ngImport: i0, type: MicrofrontendPopupCapabilityInterceptor }); }
26
- }
27
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.3", ngImport: i0, type: MicrofrontendPopupCapabilityInterceptor, decorators: [{
28
- type: Injectable
29
- }] });
30
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWljcm9mcm9udGVuZC1wb3B1cC1jYXBhYmlsaXR5LWludGVyY2VwdG9yLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9zY2lvbi93b3JrYmVuY2gvc3JjL2xpYi9taWNyb2Zyb250ZW5kLXBsYXRmb3JtL21pY3JvZnJvbnRlbmQtcG9wdXAvbWljcm9mcm9udGVuZC1wb3B1cC1jYXBhYmlsaXR5LWludGVyY2VwdG9yLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBV0EsT0FBTyxFQUFDLFVBQVUsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUMscUJBQXFCLEVBQTJCLE1BQU0seUJBQXlCLENBQUM7O0FBRXhGOztHQUVHO0FBRUgsTUFBTSxPQUFPLHVDQUF1QztJQUUzQyxLQUFLLENBQUMsU0FBUyxDQUFDLFVBQXNCO1FBQzNDLElBQUksVUFBVSxDQUFDLElBQUksS0FBSyxxQkFBcUIsQ0FBQyxLQUFLLEVBQUU7WUFDbkQsT0FBTyxVQUFVLENBQUM7U0FDbkI7UUFFRCxNQUFNLGVBQWUsR0FBRyxVQUFzQyxDQUFDO1FBQy9ELHVEQUF1RDtRQUN2RCxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sRUFBRTtZQUNoRixNQUFNLEtBQUssQ0FBQywwRUFBMEUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLENBQUM7U0FDM0g7UUFFRCxrREFBa0Q7UUFDbEQsTUFBTSxJQUFJLEdBQUcsZUFBZSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUM7UUFDOUMsSUFBSSxJQUFJLEtBQUssU0FBUyxJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7WUFDdkMsTUFBTSxLQUFLLENBQUMsdUdBQXVHLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3hKO1FBRUQsT0FBTyxlQUFlLENBQUM7SUFDekIsQ0FBQzs4R0FwQlUsdUNBQXVDO2tIQUF2Qyx1Q0FBdUM7OzJGQUF2Qyx1Q0FBdUM7a0JBRG5ELFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IChjKSAyMDE4LTIwMjIgU3dpc3MgRmVkZXJhbCBSYWlsd2F5c1xuICpcbiAqIFRoaXMgcHJvZ3JhbSBhbmQgdGhlIGFjY29tcGFueWluZyBtYXRlcmlhbHMgYXJlIG1hZGVcbiAqIGF2YWlsYWJsZSB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEVjbGlwc2UgUHVibGljIExpY2Vuc2UgMi4wXG4gKiB3aGljaCBpcyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cuZWNsaXBzZS5vcmcvbGVnYWwvZXBsLTIuMC9cbiAqXG4gKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogRVBMLTIuMFxuICovXG5cbmltcG9ydCB7Q2FwYWJpbGl0eSwgQ2FwYWJpbGl0eUludGVyY2VwdG9yfSBmcm9tICdAc2Npb24vbWljcm9mcm9udGVuZC1wbGF0Zm9ybSc7XG5pbXBvcnQge0luamVjdGFibGV9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtXb3JrYmVuY2hDYXBhYmlsaXRpZXMsIFdvcmtiZW5jaFBvcHVwQ2FwYWJpbGl0eX0gZnJvbSAnQHNjaW9uL3dvcmtiZW5jaC1jbGllbnQnO1xuXG4vKipcbiAqIEFzc2VydHMgcG9wdXAgY2FwYWJpbGl0aWVzIHRvIGhhdmUgcmVxdWlyZWQgcHJvcGVydGllcy5cbiAqL1xuQEluamVjdGFibGUoLyogRE8gTk9UIFBST1ZJREUgdmlhICdwcm92aWRlZEluJyBtZXRhZGF0YSBhcyBvbmx5IHJlZ2lzdGVyZWQgaWYgbWljcm9mcm9udGVuZCBzdXBwb3J0IGlzIGVuYWJsZWQuICovKVxuZXhwb3J0IGNsYXNzIE1pY3JvZnJvbnRlbmRQb3B1cENhcGFiaWxpdHlJbnRlcmNlcHRvciBpbXBsZW1lbnRzIENhcGFiaWxpdHlJbnRlcmNlcHRvciB7XG5cbiAgcHVibGljIGFzeW5jIGludGVyY2VwdChjYXBhYmlsaXR5OiBDYXBhYmlsaXR5KTogUHJvbWlzZTxDYXBhYmlsaXR5PiB7XG4gICAgaWYgKGNhcGFiaWxpdHkudHlwZSAhPT0gV29ya2JlbmNoQ2FwYWJpbGl0aWVzLlBvcHVwKSB7XG4gICAgICByZXR1cm4gY2FwYWJpbGl0eTtcbiAgICB9XG5cbiAgICBjb25zdCBwb3B1cENhcGFiaWxpdHkgPSBjYXBhYmlsaXR5IGFzIFdvcmtiZW5jaFBvcHVwQ2FwYWJpbGl0eTtcbiAgICAvLyBBc3NlcnQgdGhlIHBvcHVwIGNhcGFiaWxpdHkgdG8gaGF2ZSBhIHF1YWxpZmllciBzZXQuXG4gICAgaWYgKCFwb3B1cENhcGFiaWxpdHkucXVhbGlmaWVyIHx8ICFPYmplY3Qua2V5cyhwb3B1cENhcGFiaWxpdHkucXVhbGlmaWVyKS5sZW5ndGgpIHtcbiAgICAgIHRocm93IEVycm9yKGBbTnVsbFF1YWxpZmllckVycm9yXSBQb3B1cCBjYXBhYmlsaXR5IHJlcXVpcmVzIGEgcXVhbGlmaWVyIFtjYXBhYmlsaXR5PSR7SlNPTi5zdHJpbmdpZnkocG9wdXBDYXBhYmlsaXR5KX1dYCk7XG4gICAgfVxuXG4gICAgLy8gQXNzZXJ0IHRoZSBwb3B1cCBjYXBhYmlsaXR5IHRvIGhhdmUgYSBwYXRoIHNldC5cbiAgICBjb25zdCBwYXRoID0gcG9wdXBDYXBhYmlsaXR5LnByb3BlcnRpZXM/LnBhdGg7XG4gICAgaWYgKHBhdGggPT09IHVuZGVmaW5lZCB8fCBwYXRoID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBFcnJvcihgW051bGxQYXRoRXJyb3JdIFBvcHVwIGNhcGFiaWxpdHkgcmVxdWlyZXMgYSBwYXRoIHRvIHRoZSBtaWNyb2Zyb250ZW5kIGluIGl0cyBwcm9wZXJ0aWVzIFtjYXBhYmlsaXR5PSR7SlNPTi5zdHJpbmdpZnkocG9wdXBDYXBhYmlsaXR5KX1dYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBvcHVwQ2FwYWJpbGl0eTtcbiAgfVxufVxuIl19