UNPKG

@scion/workbench

Version:

SCION Workbench enables the creation of Angular web applications that require a flexible layout to display content side-by-side or stacked, all personalizable by the user via drag & drop. This type of layout is ideal for applications with non-linear workf

1,258 lines (1,246 loc) 227 kB
import * as _angular_cdk_portal from '@angular/cdk/portal'; import { ComponentType, ComponentPortal } from '@angular/cdk/portal'; import * as i0 from '@angular/core'; import { InjectionToken, Signal, TemplateRef, Injector, Type, EnvironmentProviders, WritableSignal, Provider, ViewContainerRef, ComponentRef, AbstractType, ElementRef, StaticProvider, PipeTransform } from '@angular/core'; import { MicrofrontendPlatformConfig } from '@scion/microfrontend-platform'; import * as _angular_router from '@angular/router'; import { UrlSegment, NavigationExtras, ActivatedRoute, CanMatchFn } from '@angular/router'; import { Observable, BehaviorSubject } from 'rxjs'; import * as _scion_workbench from '@scion/workbench'; /** * Set of log levels to control logging output. */ declare enum LogLevel { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3 } /** * Provides information about a message to be logged. */ interface LogEvent { /** * Severity of the message. */ level: LogLevel; /** * Name of the logger used to log the message. */ logger: string; /** * Supplies the message. */ messageSupplier: () => string; /** * Arguments as passed to the logger. */ args: any[]; } /** * Delivers log events to a destination, e.g., writing logs to the console. */ declare abstract class LogAppender { /** * Each message to be logged is passed to this method in the form of a {@link LogEvent} object. */ abstract onLogMessage(event: LogEvent): void; static ɵfac: i0.ɵɵFactoryDeclaration<LogAppender, never>; static ɵprov: i0.ɵɵInjectableDeclaration<LogAppender>; } /** * Logger name to be used to log a message. * * Pass an instance of this class as the first argument to the logger when logging a message. */ declare class LoggerName { private readonly _value; constructor(_value: string); toString(): string; } /** * Logger used by the workbench to log messages. * * Log messages are passed to registered log appenders in the form of log events for delivery to a destination. * * When configuring the workbench, you can register one or more log appenders and specify the minimum severity * level a message must have in order to be logged. At runtime, you can change the minimum required log level * by setting the `loglevel` query parameter. For example, to log messages with debug severity or higher, set * the query parameters as follows: `loglevel=debug`. * * By default, if not registering a log appender, the workbench registers a console log appender. The default * minimal required log level is set to {@link LogLevel#INFO}. * * @see {@link LogAppender} */ declare abstract class Logger { /** * Log level of the workbench logger. */ abstract readonly logLevel: LogLevel; /** * Logs a message with debug severity. * * For messages that are expensive to compose, you can provide a message supplier function. * The logger will call this function only if at least `DEBUG` log level is enabled. * * Optionally, you can pass the logger name as the first argument in the `args` list. The log message * will then be prefixed with that logger name. Logger names must be instances of {@link LoggerName}. */ abstract debug(message: string | (() => string), ...args: any[]): void; abstract debug(message: string | (() => string), loggerName: LoggerName, ...args: any[]): void; /** * Logs a message with info severity. * * For messages that are expensive to compose, you can provide a message supplier function. * The logger will call this function only if at least `INFO` log level is enabled. * * Optionally, you can pass the logger name as the first argument in the `args` list. The log message * will then be prefixed with that logger name. Logger names must be instances of {@link LoggerName}. */ abstract info(message: string | (() => string), ...args: any[]): void; abstract info(message: string | (() => string), loggerName: LoggerName, ...args: any[]): void; /** * Logs a message with warn severity. * * For messages that are expensive to compose, you can provide a message supplier function. * The logger will call this function only if at least `WARN` log level is enabled. * * Optionally, you can pass the logger name as the first argument in the `args` list. The log message * will then be prefixed with that logger name. Logger names must be instances of {@link LoggerName}. */ abstract warn(message: string | (() => string), ...args: any[]): void; abstract warn(message: string | (() => string), loggerName: LoggerName, ...args: any[]): void; /** * Logs a message with error severity. * * For messages that are expensive to compose, you can provide a message supplier function. * The logger will call this function only if at least `ERROR` log level is enabled. * * Optionally, you can pass the logger name as the first argument in the `args` list. The log message * will then be prefixed with that logger name. Logger names must be instances of {@link LoggerName}. */ abstract error(message: string | (() => string), ...args: any[]): void; abstract error(message: string | (() => string), loggerName: LoggerName, ...args: any[]): void; static ɵfac: i0.ɵɵFactoryDeclaration<Logger, never>; static ɵprov: i0.ɵɵInjectableDeclaration<Logger>; } /** * Allows loading the configuration for the SCION Microfrontend Platform asynchronously, e.g., over the network or from a JSON file. */ declare abstract class MicrofrontendPlatformConfigLoader { /** * Loads the platform configuration asynchronously. */ abstract load(): Promise<MicrofrontendPlatformConfig>; static ɵfac: i0.ɵɵFactoryDeclaration<MicrofrontendPlatformConfigLoader, never>; static ɵprov: i0.ɵɵInjectableDeclaration<MicrofrontendPlatformConfigLoader>; } /** * Represents the id prefix of parts. * * @see PartId */ declare const PART_ID_PREFIX = "part."; /** * Represents the id prefix of views. * * @see ViewId */ declare const VIEW_ID_PREFIX = "view."; /** * Represents the id prefix of activities. */ declare const ACTIVITY_ID_PREFIX = "activity."; /** * Represents the id prefix of popups. */ declare const POPUP_ID_PREFIX = "popup."; /** * Represents the id prefix of dialogs. */ declare const DIALOG_ID_PREFIX = "dialog."; /** * Represents the id prefix of message boxes. */ declare const MESSAGE_BOX_ID_PREFIX = "messagebox."; /** * Format of a part outlet name. */ type PartOutlet = `${typeof PART_ID_PREFIX}${string}`; /** * Format of a view outlet name. */ type ViewOutlet = `${typeof VIEW_ID_PREFIX}${number}`; /** * Format of a popup outlet name. */ type PopupOutlet = `${typeof POPUP_ID_PREFIX}${string}`; /** * Format of a dialog outlet name. */ type DialogOutlet = `${typeof DIALOG_ID_PREFIX}${string}`; /** * Format of a messagebox outlet name. */ type MessageBoxOutlet = `${typeof MESSAGE_BOX_ID_PREFIX}${string}`; /** * Union of workbench outlets. */ type WorkbenchOutlet = PartOutlet | ViewOutlet | PopupOutlet | DialogOutlet | MessageBoxOutlet; /** * Defines the context in which a viewtab is rendered. * * - `tab`: if rendered as view tab in the tabbar * - `list-item`: if rendered as list item in the view list menu * - `drag-image`: if rendered as drag image while dragging a view tab */ type ViewTabRenderingContext = 'tab' | 'list-item' | 'drag-image'; /** * DI token to inject the context in which the view tab is rendered. */ declare const VIEW_TAB_RENDERING_CONTEXT: InjectionToken<ViewTabRenderingContext>; /** * A part is a visual workbench element to create the workbench layout. Parts can be docked to the side or * positioned relative to each other. A part can be a stack of views or display content. * * The part component can inject this handle to interact with the part. * * @see WorkbenchView */ declare abstract class WorkbenchPart { /** * Unique identity of this part. */ abstract readonly id: PartId; /** * Alternative identity of this part. * * A part can have an alternative id, a meaningful but not necessarily unique name. A part can * be identified either by its unique or alternative id. * * @see id */ abstract readonly alternativeId: string | undefined; /** * Title displayed in the part bar. * * Note that the title of the top-leftmost part of a docked part cannot be changed. */ abstract get title(): Signal<string | undefined>; abstract set title(title: string | undefined); /** * Indicates whether this part is located in the workbench main area. */ abstract readonly isInMainArea: boolean; /** * Indicates whether this part is located in the workbench peripheral area. */ abstract readonly peripheral: Signal<boolean>; /** * Indicates whether this part is the top-leftmost part. */ abstract readonly topLeft: Signal<boolean>; /** * Indicates whether this part is the top-rightmost part. */ abstract readonly topRight: Signal<boolean>; /** * Indicates whether this part is active or inactive. */ abstract readonly active: Signal<boolean>; /** * Identifies the active view, or `null` if none. */ abstract readonly activeViewId: Signal<ViewId | null>; /** * Identifies views opened in this part. */ abstract readonly viewIds: Signal<ViewId[]>; /** * Actions associated with this part. */ abstract readonly actions: Signal<WorkbenchPartAction[]>; /** * Specifies CSS class(es) to add to the part, e.g., to locate the part in tests. */ abstract get cssClass(): Signal<string[]>; abstract set cssClass(cssClass: string | string[]); /** * Provides navigation details of this part. * * A part can be navigated to display content when its view stack is empty. * A navigated part can still have views but won't display navigated content unless its view stack is empty. * * A part can be navigated using {@link WorkbenchLayout#navigatePart}. */ abstract readonly navigation: Signal<WorkbenchPartNavigation | undefined>; } /** * Format of a part identifier. * * Each part is assigned a unique identifier (e.g., `part.9fdf7ab4`, `part.c6485225`, etc.). * A part can also have an alternative id, a meaningful but not necessarily unique name. A part can * be identified either by its unique or alternative id. */ type PartId = PartOutlet; /** * Provides navigation details of a workbench part. */ interface WorkbenchPartNavigation { /** * Path of this part. */ path: UrlSegment[]; /** * Hint passed to the navigation. */ hint?: string; /** * Data passed to the navigation. */ data?: NavigationData; /** * State passed to the navigation. */ state?: NavigationState; } /** * The signature of a function to confirm closing a view., e.g., if dirty. * * The function can call `inject` to get dependencies. */ type CanCloseFn = () => Observable<boolean> | Promise<boolean> | boolean; /** * Reference to a `CanClose` guard registered on a view. */ interface CanCloseRef { /** * Removes the `CanClose` guard from the view. * * Has no effect if another guard was registered in the meantime. */ dispose(): void; } /** * Represents an action of a {@link WorkbenchPart}. * * Part actions are displayed in the part bar, enabling interaction with the part and its content. Actions can be aligned to the left or right. */ interface WorkbenchPartAction { /** * Specifies the content of the action. * * Use a {@link ComponentType} to render a component, or a {@link TemplateRef} to render a template. * * The component and template can inject the {@link WorkbenchPart}, either through dependency injection or default template-local variable (`let-part`). */ content: ComponentType<unknown> | TemplateRef<unknown>; /** * Optional data to pass to the component or template. * * If using a component, inputs are available as input properties. * * ```ts * @Component({...}) * class ActionComponent { * someInput = input.required<string>(); * } * ``` * * If using a template, inputs are available for binding via local template let declarations. * * ```html * <ng-template let-input="someInput"> * ... * </ng-template> * ``` */ inputs?: { [name: string]: unknown; }; /** * Sets the injector for the instantiation of the component or template, giving control over the objects available for injection. * * ```ts * Injector.create({ * parent: ..., * providers: [ * {provide: <TOKEN>, useValue: <VALUE>} * ], * }) * ``` */ injector?: Injector; /** * Controls where to place this action in the part bar. Defaults to `end`. */ align?: 'start' | 'end'; /** * Specifies CSS class(es) to add to the action, e.g., to locate the action in tests. */ cssClass?: string | string[]; } /** * Represents a menu item contained in the context menu of a {@link WorkbenchView}. * * Right-clicking on a view tab opens a context menu to interact with the view and its content. */ interface WorkbenchMenuItem { /** * Specifies the content of the menu item. * * Use a {@link ComponentType} to render a component, or a {@link TemplateRef} to render a template. * * The component and template can inject the {@link WorkbenchView}, either through dependency injection or default template-local variable (`let-view`). */ content: ComponentType<unknown> | TemplateRef<unknown>; /** * Optional data to pass to the component or template. * * If using a component, inputs are available as input properties. * * ```ts * @Component({...}) * class MenuItemComponent { * someInput = input.required<string>(); * } * ``` * * If using a template, inputs are available for binding via local template let declarations. * * ```html * <ng-template let-input="someInput"> * ... * </ng-template> * ``` */ inputs?: { [name: string]: unknown; }; /** * Sets the injector for the instantiation of the component or template, giving control over the objects available for injection. * * ```ts * Injector.create({ * parent: ..., * providers: [ * {provide: <TOKEN>, useValue: <VALUE>} * ], * }) * ``` */ injector?: Injector; /** * Function invoked when the menu item is clicked. * * The function can call `inject` to get any required dependencies. */ onAction: () => void; /** * Binds keyboard accelerator(s) to the menu item, e.g., ['ctrl', 'alt', 1]. * * Supported modifiers are 'ctrl', 'shift', 'alt' and 'meta'. */ accelerator?: string[]; /** * Enables grouping of menu items. */ group?: string; /** * Controls if the menu item is disabled. Defaults to `false`. */ disabled?: boolean; /** * Specifies CSS class(es) to add to the menu item, e.g., to locate the menu item in tests. */ cssClass?: string | string[]; } /** * Signature of a function to contribute an action to a {@link WorkbenchPart}. * * The function: * - Can return a component or template, or an object literal for more control. * - Is called per part. Returning the action adds it to the part, returning `null` skips it. * - Can call `inject` to get any required dependencies. * - Runs in a reactive context and is called again when tracked signals change. * Use Angular's `untracked` function to execute code outside this reactive context. */ type WorkbenchPartActionFn = (part: WorkbenchPart) => WorkbenchPartAction | ComponentType<unknown> | TemplateRef<unknown> | null; /** * Signature of a function to contribute a menu item to the context menu of a {@link WorkbenchView}. * * The function: * - Is called per view. Returning the menu item adds it to the context menu of the view, returning `null` skips it. * - Can call `inject` to get any required dependencies. * - Runs in a reactive context and is called again when tracked signals change. * Use Angular's `untracked` function to execute code outside this reactive context. */ type WorkbenchViewMenuItemFn = (view: WorkbenchView) => WorkbenchMenuItem | null; /** * Information about a workbench theme. * * @deprecated since version 19.0.0-beta.3. Read the theme from `WorkbenchService.settings.theme` signal, and the color scheme from 'getComputedStyle(inject(DOCUMENT).documentElement).colorScheme'. API will be removed in version 21. */ interface WorkbenchTheme { /** * The name of the theme. */ name: string; /** * The color scheme of the theme. */ colorScheme: 'light' | 'dark'; } /** * Signature of a function to provide texts to the SCION Workbench. * * Texts starting with the percent symbol (`%`) are passed to the text provider for translation, with the percent symbol omitted. * Otherwise, the text is returned as is. * * A text provider can be registered via configuration passed to the {@link provideWorkbench} function. * * The function: * - Can call `inject` to get any required dependencies. * - Can call `toSignal` to convert an Observable to a Signal. * * @param key - Key for which to provide the text. * @param params - Parameters associated with the translation key. * @return The text associated with the provided key, or `undefined` if not found. */ type WorkbenchTextProviderFn = (key: string, params: { [name: string]: string; }) => Signal<string> | string | undefined; /** * Represents either a text or a key for translation. * * A translation key starts with the percent symbol (`%`) and can include parameters in matrix notation. * Key and parameters are passed to {@link WorkbenchConfig.textProvider} for translation. * * Examples: * - `text`: no translatable text * - `%key`: translation key * - `%key;param=value`: translation key with a single param * - `%key;param1=value1;param2=value2`: translation key with multiple parameters */ type Translatable = string | `%${string}`; /** * A view is a visual workbench element for displaying content stacked or side-by-side in the workbench layout. * * Users can drag views from one part to another, even across windows, or place them side-by-side, horizontally and vertically. * * The view component can inject this handle to interact with the view. * * @see WorkbenchRouter */ declare abstract class WorkbenchView { /** * Unique identity of this view. * * @see alternativeId */ abstract readonly id: ViewId; /** * Alternative identity of this view. * * A view can have an alternative id, a meaningful but not necessarily unique name. A view can * be identified either by its unique or alternative id. * * @see id */ abstract readonly alternativeId: string | undefined; /** * Provides navigation details of this view. * * A view can be navigated using {@link WorkbenchRouter#navigate} or {@link WorkbenchLayout#navigateView}. */ abstract readonly navigation: Signal<WorkbenchViewNavigation | undefined>; /** * Hint passed to the navigation. * * @deprecated since version 19.0.0-beta.2. Use {@link navigation.hint} instead. API will be removed in version 21. */ abstract readonly navigationHint: Signal<string | undefined>; /** * Data passed to the navigation. * * @deprecated since version 19.0.0-beta.2. Use {@link navigation.data} instead. API will be removed in version 21. */ abstract readonly navigationData: Signal<NavigationData>; /** * State passed to the navigation. * * @deprecated since version 19.0.0-beta.2. Use {@link navigation.state} instead. API will be removed in version 21. */ abstract readonly navigationState: Signal<NavigationState>; /** * Part which contains this view. * * Note: the part of a view can change, e.g., when the view is moved to another part. */ abstract readonly part: Signal<WorkbenchPart>; /** * Title displayed in the view tab. */ abstract get title(): Signal<Translatable | null>; abstract set title(title: Translatable | null); /** * Subtitle displayed in the view tab. */ abstract get heading(): Signal<Translatable | null>; abstract set heading(heading: Translatable | null); /** * Specifies CSS class(es) to add to the view, e.g., to locate the view in tests. */ abstract get cssClass(): Signal<string[]>; abstract set cssClass(cssClass: string | string[]); /** * Indicates whether the view has unsaved changes. * If marked as dirty, a visual indicator is displayed in the view tab. */ abstract get dirty(): Signal<boolean>; abstract set dirty(dirty: boolean); /** * Controls whether the view can be closed. Defaults to `true`. */ abstract get closable(): Signal<boolean>; abstract set closable(closable: boolean); /** * Indicates whether this view is active or inactive. */ abstract readonly active: Signal<boolean>; /** * The position of this view in the tabbar. */ abstract readonly position: Signal<number>; /** * `True` when this view is the first view in the tabbar. */ abstract readonly first: Signal<boolean>; /** * `True` when this view is the last view in the tabbar. */ abstract readonly last: Signal<boolean>; /** * Indicates whether the tab of this view is scrolled into the tabbar. */ abstract readonly scrolledIntoView: Signal<boolean>; /** * Menu items associated with this view. */ abstract readonly menuItems: Signal<WorkbenchMenuItem[]>; /** * Indicates whether this view is destroyed. */ abstract readonly destroyed: boolean; /** * URL associated with this view. * * @deprecated since version 19.0.0-beta.2. Use {@link navigation.path} instead. API will be removed in version 21. */ abstract readonly urlSegments: Signal<UrlSegment[]>; /** * Activates this view. * * Note: This instruction runs asynchronously via URL routing. */ abstract activate(): Promise<boolean>; /** * Destroys this view (or sibling views) and the associated routed component. * * Note: This instruction runs asynchronously via URL routing. * * @param target * Allows to control which view(s) to close: * * - self: closes this view * - all-views: closes all views of this part * - other-views: closes the other views of this part * - views-to-the-right: closes the views to the right of this view * - views-to-the-left: closes the views to the left of this view * */ abstract close(target?: 'self' | 'all-views' | 'other-views' | 'views-to-the-right' | 'views-to-the-left'): Promise<boolean>; /** * Moves this view to a new browser window. */ abstract move(target: 'new-window'): void; /** * Moves this view to a different or new part in the specified region. * * Specifying a target workbench identifier allows the view to be moved to a workbench in a different browser window. * The target workbench ID is available via {@link WORKBENCH_ID} DI token in the target application. */ abstract move(partId: string, options?: { region?: 'north' | 'south' | 'west' | 'east'; workbenchId?: string; }): void; /** * Registers a guard to confirm closing the view, replacing any previous guard. * * The callback can call `inject` to get dependencies. * * Example: * ```ts * import {inject} from '@angular/core'; * import {WorkbenchMessageBoxService, WorkbenchView} from '@scion/workbench'; * * inject(WorkbenchView).canClose(async () => { * if (!inject(WorkbenchView).dirty()) { * return true; * } * const action = await inject(WorkbenchMessageBoxService).open('Do you want to save changes?', { * actions: { * yes: 'Yes', * no: 'No', * cancel: 'Cancel' * } * }); * * switch (action) { * case 'yes': * // Store changes ... * return true; * case 'no': * return true; * default: * return false; * } * }); * ``` * * @param canClose - Callback to confirm closing the view. * @returns Reference to the `CanClose` guard, which can be used to unregister the guard. */ abstract canClose(canClose: CanCloseFn): CanCloseRef; } /** * Format of a view identifier. * * Each view is assigned a unique identifier (e.g., `view.1`, `view.2`, etc.). * A view can also have an alternative id, a meaningful but not necessarily unique name. A view can * be identified either by its unique or alternative id. */ type ViewId = ViewOutlet; /** * Provides navigation details of a workbench view. */ interface WorkbenchViewNavigation { /** * Path of this view. */ path: UrlSegment[]; /** * Hint passed to the navigation. */ hint?: string; /** * Data passed to the navigation. */ data?: NavigationData; /** * State passed to the navigation. */ state?: NavigationState; } /** * Options to control the navigation. */ interface WorkbenchNavigationExtras extends NavigationExtras { /** * Controls where to open the view. Defaults to `auto`. * * One of: * - 'auto': Navigates existing views that match the path, or opens a new view otherwise. Matrix params do not affect view resolution. * - 'blank': Opens a new view and navigates it. * - <viewId>: Navigates the specified view. If already opened, replaces it, or opens a new view otherwise. */ target?: ViewId | string | 'blank' | 'auto'; /** * Controls in which part to navigate views. * * If {@link target} is `blank`, opens the view in the specified part. * If {@link target} is `auto`, navigates matching views in the specified part, or opens a new view in that part otherwise. * * If the specified part is not in the layout, opens the view in the active part, with the active part of the main area, if any, taking precedence. */ partId?: PartId | string; /** * Allows differentiation between routes with identical paths. * * Multiple views can navigate to the same path but still resolve to different routes, e.g., the empty-path route to maintain a clean URL. * Like the path, a hint affects view resolution. If set, the router will only navigate views with an equivalent hint, or if not set, views without a hint. * * Example route config matching routes based on the hint passed to the navigation: * ```ts * import {canMatchWorkbenchView} from '@scion/workbench'; * * const routes = [ * { * path: '', * component: View1Component, * canMatch: [canMatchWorkbenchView('hint-1')], // matches navigations with hint 'hint-1' * }, * { * path: '', * component: View2Component, * canMatch: [canMatchWorkbenchView('hint-2')], // matches navigations with hint 'hint-2' * }, * ]; * ``` * @see canMatchWorkbenchView */ hint?: string; /** * Instructs the router to activate the view. Defaults to `true`. */ activate?: boolean; /** * Specifies where to insert the view into the tab bar. Has no effect if navigating an existing view. Defaults to after the active view. */ position?: number | 'start' | 'end' | 'before-active-view' | 'after-active-view'; /** * Associates data with the navigation. * * Unlike matrix parameters, navigation data is stored in the layout and not added to the URL, allowing data to be passed to an empty-path navigation. * * Data must be JSON serializable. Data can be read from {@link WorkbenchView.navigation.data}. */ data?: NavigationData; /** * Passes state to the navigation. * * State is not persistent, unlike {@link data}; however, state is added to the browser's session history to support back/forward browser navigation. * State can be read from {@link WorkbenchView.navigation.state} or from the browser's session history via `history.state`. */ state?: NavigationState; /** * Closes views that match the specified path and navigation hint. Matrix parameters do not affect view resolution. * The path supports the asterisk wildcard segment (`*`) to match views with any value in a segment. * To close a specific view, set a view target instead of a path. */ close?: boolean; /** * Specifies CSS class(es) to add to the view, e.g., to locate the view in tests. */ cssClass?: string | string[]; } /** * Represents an ordered list of path segments instructing the router which route to navigate to. * * A command can be a string or an object literal. A string represents a path segment, an object literal associates matrix parameters with the preceding segment. * Multiple segments can be combined into a single command, separated by a forward slash. * * The first path segment supports the usage of navigational symbols such as `/`, `./`, or `../`. * * Examples: * - Navigates to the path 'path/to/view', passing two parameters: * ['path', 'to', 'view', {param1: 'value1', param2: 'value2'}] * - Alternative syntax using a combined segment: * ['path/to/view', {param1: 'value1', param2: 'value2'}] */ type Commands = readonly unknown[]; /** * URL segments of workbench elements contained in the workbench layout. */ interface Outlets { [outlet: WorkbenchOutlet]: UrlSegment[]; } /** * State associated with a navigation. */ interface NavigationStates { [outlet: WorkbenchOutlet]: NavigationState; } /** * State passed to a navigation. * * State is not persistent, unlike {@link data}; however, state is added to the browser's session history to support back/forward browser navigation. */ interface NavigationState { [key: string]: unknown; } /** * Data associated with a navigation. Data must be JSON serializable. */ interface NavigationData { [key: string]: unknown; } /** * Signature of a function to modify the workbench layout. * * The router will invoke this function with the current workbench layout. The layout has methods for modifying it. * The layout is immutable; each modification creates a new instance. * * The function can call `inject` to get any required dependencies. * * ## Workbench Layout * The workbench layout is an arrangement of parts and views. Parts can be docked to the side or positioned relative to each other. * Views are stacked in parts and can be dragged to other parts. Content can be displayed in both parts and views. * * ## Example * The following example adds a part to the left of the main area, inserts a view and navigates it. * * ```ts * inject(WorkbenchRouter).navigate(layout => layout * .addPart('left', {relativeTo: MAIN_AREA, align: 'left'}) * .addView('navigator', {partId: 'left'}) * .navigateView('navigator', ['path/to/view']) * .activateView('navigator') * ); * ``` * * @param layout - Reference to the current workbench layout for modification. * @return Modified layout, or `null` to cancel the navigation. */ type NavigateFn = (layout: WorkbenchLayout) => Promise<WorkbenchLayout | null> | WorkbenchLayout | null; /** * Format of an activity identifier. * * Each activity is assigned a unique identifier (e.g., `activity.9fdf7ab4`, `activity.c6485225`, etc.). * * @docs-private Not public API, intended for internal use only. */ type ActivityId = `${typeof ACTIVITY_ID_PREFIX}${string}`; /** * Defines the arrangement of docked parts (also referred to as activities) in the workbench. * * Docked parts can be minimized to create more space for the main content. * * A part can be docked to the left, right, or bottom side of the workbench. * Each side has two docking areas: `left-top` and `left-bottom`, `right-top` and `right-bottom`, and `bottom-left` and `bottom-right`. * Parts added to the same area are stacked, with only one part active per stack. If there is an active part in both stacks of a side, * the two parts are split vertically or horizontally, depending on the side. * * A docked part may be navigated to display content, have views, or define a layout with multiple parts aligned relative to each other. * * The M-prefix indicates this object is a model object that is serialized and stored, requiring migration on breaking change. */ interface MActivityLayout { toolbars: { leftTop: MActivityStack; leftBottom: MActivityStack; rightTop: MActivityStack; rightBottom: MActivityStack; bottomLeft: MActivityStack; bottomRight: MActivityStack; }; panels: { left: { width: number; ratio: number; }; right: { width: number; ratio: number; }; bottom: { height: number; ratio: number; }; }; } /** * Stack of activities in a docking area. * * The M-prefix indicates this object is a model object that is serialized and stored, requiring migration on breaking change. */ interface MActivityStack { /** * List of activities in the stack. */ activities: MActivity[]; /** * Reference to the currently active activity in the stack. */ activeActivityId?: ActivityId; /** * Reference to the activity that was active prior to minimization, used to restore the active activity when exiting minimization mode. */ minimizedActivityId?: ActivityId; } /** * Represents an activity docked to a side of the workbench. * * The M-prefix indicates this object is a model object that is serialized and stored, requiring migration on breaking change. */ interface MActivity { /** @see DockedPartExtras#ɵactivityId */ id: ActivityId; /** * Refers to the docked part specified when creating the activity. * * Characteristics of the reference part: * - Structural part, remaining even if its last view is removed. * - Provides the title of the activity, independent of visibility and position in the layout. * - Explicitly removing this part removes the activity. */ referencePartId: PartId; /** @see DockedPartExtras#icon */ icon: string; /** @see DockedPartExtras#label */ label: Translatable; /** @see DockedPartExtras#tooltip */ tooltip?: Translatable; /** @see DockedPartExtras#cssClass */ cssClass?: string | string[]; } /** * Factory for creating a {@link WorkbenchLayout}. */ declare abstract class WorkbenchLayoutFactory { /** * Creates a layout with given part. * * @param id - The id of the part. Use {@link MAIN_AREA} to add the main area. * @param extras - Controls how to add the part to the layout. * @param extras.activate - Controls whether to activate the part. If not set, defaults to `false`. * @return layout with the part added. */ abstract addPart(id: string | MAIN_AREA, extras?: PartExtras): WorkbenchLayout; static ɵfac: i0.ɵɵFactoryDeclaration<WorkbenchLayoutFactory, never>; static ɵprov: i0.ɵɵInjectableDeclaration<WorkbenchLayoutFactory>; } /** * The workbench layout is an arrangement of parts and views. Parts can be docked to the side or positioned relative to each other. * Views are stacked in parts and can be dragged to other parts. Content can be displayed in both parts and views. * * A typical workbench application has a main area part and other parts docked to the side, providing navigation and context-sensitive assistance to * support the user's workflow. * * Multiple layouts, called perspectives, can be created. Users can switch between perspectives. Perspectives share the same main area, if any. * * The layout has methods for modifying it. The layout is immutable; each modification creates a new instance. */ interface WorkbenchLayout { /** * Adds a part with the given id to this layout. Position and size are expressed relative to a reference part. * * A part can also be aligned relative to a docked part, enabling inline layouts within docked parts, such as splitting the docked parts into multiple sections. * * @param id - The id of the part to add. Use {@link MAIN_AREA} to add the main area. * @param relativeTo - Specifies the reference part to lay out the part. * @param extras - Controls how to add the part to the layout. * @return a copy of this layout with the part added. */ addPart(id: string | MAIN_AREA, relativeTo: ReferencePart, extras?: PartExtras): WorkbenchLayout; /** * Adds a part with the given id to this layout, docking it to the specified docking area. * * Docked parts can be minimized to create more space for the main content. Users cannot drag views into or out of docked parts. * * A part can be docked to the left, right, or bottom side of the workbench. * Each side has two docking areas: `left-top` and `left-bottom`, `right-top` and `right-bottom`, and `bottom-left` and `bottom-right`. * Parts added to the same area are stacked, with only one part active per stack. If there is an active part in both stacks of a side, * the two parts are split vertically or horizontally, depending on the side. * * A docked part may be navigated to display content, have views, or define a layout with multiple parts aligned relative to each other. * * @param id - The id of the part to add. * @param dockTo - Controls to which area to dock the part. * @param extras - Controls how to add the part to the layout. * @return a copy of this layout with the part added. */ addPart(id: string, dockTo: DockingArea, extras: DockedPartExtras): WorkbenchLayout; /** * Navigates the specified part based on the provided array of commands and extras. * * Navigating a part displays content when its view stack is empty. A navigated part can still have views but won't display * navigated content unless its view stack is empty. Views cannot be dragged into parts displaying navigated content, except * for the main area part. * * A command can be a string or an object literal. A string represents a path segment, an object literal associates matrix parameters with the preceding segment. * Multiple segments can be combined into a single command, separated by a forward slash. * * By default, navigation is absolute. Set `relativeTo` in extras for relative navigation. * * Usage: * ``` * layout.navigatePart(partId, ['path', 'to', 'part', {param 'value'}]); * layout.navigatePart(partId, ['path/to/part', {param: 'value'}]); * ``` * * @param id - Identifies the part for navigation. * @param commands - Instructs the router which route to navigate to. * @param extras - Controls navigation: * @param extras.hint - Allows differentiation between routes with identical paths. * Multiple parts can navigate to the same path but still resolve to different routes, e.g., the empty-path route to maintain a clean URL. * * Example: * ```ts * import {canMatchWorkbenchPart} from '@scion/workbench'; * * const routes = [ * { * path: '', * component: Part1Component, * canMatch: [canMatchWorkbenchPart('hint-1')], // matches navigations with hint 'hint-1' * }, * { * path: '', * component: Part2Component, * canMatch: [canMatchWorkbenchPart('hint-2')], // matches navigations with hint 'hint-1' * }, * ]; * ``` * @param extras.relativeTo - Specifies the route for relative navigation, supporting navigational symbols such as '/', './', or '../' in the commands. * @param extras.data - Associates data with the navigation. * Unlike matrix parameters, navigation data is stored in the layout and not added to the URL, allowing data to be passed to an empty-path navigation. * Data must be JSON serializable. Data can be read from {@link WorkbenchPart.navigation.data}. * @param extras.state - Passes state to the navigation. * State is not persistent, unlike {@link data}; however, state is added to the browser's session history to support back/forward browser navigation. * State can be read from {@link WorkbenchPart.navigation.state} or from the browser's session history via `history.state`. * @param extras.cssClass - Specifies CSS class(es) to add to the part, e.g., to locate the part in tests. * @return a copy of this layout with the part navigated. */ navigatePart(id: string, commands: Commands, extras?: { hint?: string; relativeTo?: ActivatedRoute; data?: NavigationData; state?: NavigationState; cssClass?: string | string[]; }): WorkbenchLayout; /** * Adds a view to the specified part. * * @param id - The id of the view to add. * @param extras - Controls how to add the view to the layout. * @param extras.partId - References the part to which to add the view. * @param extras.position - Specifies the position where to insert the view. The position is zero-based. Defaults to `end`. * @param extras.activateView - Controls whether to activate the view. Defaults to `false`. * @param extras.activatePart - Controls whether to activate the part that contains the view. Defaults to `false`. * @param extras.cssClass - Specifies CSS class(es) to add to the view, e.g., to locate the view in tests. * @return a copy of this layout with the view added. */ addView(id: string, extras: { partId: string; position?: number | 'start' | 'end' | 'before-active-view' | 'after-active-view'; activateView?: boolean; activatePart?: boolean; cssClass?: string | string[]; }): WorkbenchLayout; /** * Navigates the specified view based on the provided array of commands and extras. * * A command can be a string or an object literal. A string represents a path segment, an object literal associates matrix parameters with the preceding segment. * Multiple segments can be combined into a single command, separated by a forward slash. * * By default, navigation is absolute. Set `relativeTo` in extras for relative navigation. * * Usage: * ``` * layout.navigateView(viewId, ['path', 'to', 'view', {param 'value'}]); * layout.navigateView(viewId, ['path/to/view', {param: 'value'}]); * ``` * * @param id - Identifies the view for navigation. * @param commands - Instructs the router which route to navigate to. * @param extras - Controls navigation: * @param extras.hint - Allows differentiation between routes with identical paths. * Multiple views can navigate to the same path but still resolve to different routes, e.g., the empty-path route to maintain a clean URL. * Like the path, a hint affects view resolution. If set, the router will only navigate views with an equivalent hint, or if not set, views without a hint. * * Example route config matching routes based on the hint passed to the navigation: * ```ts * import {canMatchWorkbenchView} from '@scion/workbench'; * * const routes = [ * { * path: '', * component: View1Component, * canMatch: [canMatchWorkbenchView('hint-1')], // matches navigations with hint 'hint-1' * }, * { * path: '', * component: View2Component, * canMatch: [canMatchWorkbenchView('hint-2')], // matches navigations with hint 'hint-2' * }, * ]; * ``` * @param extras.relativeTo - Specifies the route for relative navigation, supporting navigational symbols such as '/', './', or '../' in the commands. * @param extras.data - Associates data with the navigation. * Unlike matrix parameters, navigation data is stored in the layout and not added to the URL, allowing data to be passed to an empty-path navigation. * Data must be JSON serializable. Data can be read from {@link WorkbenchView.navigation.data}. * @param extras.state - Passes state to the navigation. * State is not persistent, unlike {@link data}; however, state is added to the browser's session history to support back/forward browser navigation. * State can be read from {@link WorkbenchView.navigation.state} or from the browser's session history via `history.state`. * @param extras.cssClass - Specifies CSS class(es) to add to the view, e.g., to locate the view in tests. * @return a copy of this layout with the view navigated. */ navigateView(id: string, commands: Commands, extras?: { hint?: string; relativeTo?: ActivatedRoute; data?: NavigationData; state?: NavigationState; cssClass?: string | string[]; }): WorkbenchLayout; /** * Removes given view from the layout. * * - If the view is active, the last used view is activated. * - If the view is the last view in the part, the part is removed unless it is the last part in its grid or a structural part. * * @param id - Specifies the id of the view to remove. * @return a copy of this layout with the view removed. */ removeView(id: string): WorkbenchLayout; /** * Removes given part from the layout. * * If the part is active, the last used part is activated. * * @param id - The id of the part to remove. * @return a copy of this layout with the part removed. */ removePart(id: string): WorkbenchLayout; /** * Moves a view to a different part or moves it within a part. * * @param id - The id of the view to be moved. * @param targetPartId - The id of the part to which to move the view. * @param options - Controls moving of the view. * @param options.position - Specifies the position where to move the view in the target part. The position is zero-based. Defaults to `end` when moving the view to a different part. * @param options.activateView - Controls if to activate the view. Defaults to `false`. * @param options.activatePart - Controls if to activate the target part. Defaults to `false`. * @return a copy of this layout with the view moved. */ moveView(id: string, targetPartId: string, options?: { position?: number | 'start' | 'end' | 'before-active-view' | 'after-active-view'; activateView?: boolean; activatePart?: boolean; }): WorkbenchLayout; /** * Activates the given view. * * @param id - The id of the view which to activate. * @param options - Controls view activation. * @param options.activatePart - Controls whether to activate the part that contains the view. Defaults to `false`. * @return a copy of this layout with the view activated. */ activateView(id: string, options?: { activatePart?: boolean; }): WorkbenchLayout; /** * Activates the given part. * * @param id - The id of the part which to activate. * @return a copy of this layout with the part activated. */ activatePart(id: string): WorkbenchLayout; /** * Applies a modification function to this layout, enabling conditional changes while maintaining method chaining. * * @param modifyFn - A function that takes the current layout and returns a modified layout. * @return The modified layout returned by the modify function. */ modify(modifyFn: (layout: WorkbenchLayout) => WorkbenchLayout): WorkbenchLayout; } /** * Describes how to lay out a part relative to another part. */ interface ReferencePart { /** * Specifies the part which to use as the reference part to lay out the part. * If not set, the part will be aligned relative to the root of the workbench layout. */ relativeT