@openmrs/esm-styleguide 5.7.2-pre.2101 → 5.7.2
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/.turbo/turbo-build.log +8 -8
- package/dist/openmrs-esm-styleguide.js +1 -1
- package/dist/openmrs-esm-styleguide.js.map +1 -1
- package/package.json +8 -9
- package/src/icons/svgs/sticky-note-add.svg +2 -2
- package/src/modals/index.tsx +2 -1
- package/src/modals/registry.ts +48 -0
- package/src/workspaces/action-menu-button/action-menu-button.component.tsx +1 -1
- package/src/workspaces/container/workspace-container.component.tsx +1 -1
- package/src/workspaces/container/workspace-container.test.tsx +2 -3
- package/src/workspaces/container/workspace-renderer.component.tsx +1 -1
- package/src/workspaces/index.ts +1 -0
- package/src/workspaces/notification/workspace-notification.component.tsx +4 -4
- package/src/workspaces/public.ts +2 -7
- package/src/workspaces/types.ts +70 -0
- package/src/workspaces/workspaces.test.ts +9 -2
- package/src/workspaces/workspaces.ts +116 -71
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openmrs/esm-styleguide",
|
|
3
|
-
"version": "5.7.2
|
|
3
|
+
"version": "5.7.2",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "The styleguide for OpenMRS SPA",
|
|
6
6
|
"browser": "dist/openmrs-esm-styleguide.js",
|
|
@@ -64,12 +64,12 @@
|
|
|
64
64
|
"rxjs": "6.x"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@openmrs/esm-error-handling": "5.7.2
|
|
68
|
-
"@openmrs/esm-extensions": "5.7.2
|
|
69
|
-
"@openmrs/esm-navigation": "5.7.2
|
|
70
|
-
"@openmrs/esm-react-utils": "5.7.2
|
|
71
|
-
"@openmrs/esm-state": "5.7.2
|
|
72
|
-
"@openmrs/esm-translations": "5.7.2
|
|
67
|
+
"@openmrs/esm-error-handling": "5.7.2",
|
|
68
|
+
"@openmrs/esm-extensions": "5.7.2",
|
|
69
|
+
"@openmrs/esm-navigation": "5.7.2",
|
|
70
|
+
"@openmrs/esm-react-utils": "5.7.2",
|
|
71
|
+
"@openmrs/esm-state": "5.7.2",
|
|
72
|
+
"@openmrs/esm-translations": "5.7.2",
|
|
73
73
|
"@types/geopattern": "^1.2.9",
|
|
74
74
|
"autoprefixer": "^9.8.8",
|
|
75
75
|
"css-minimizer-webpack-plugin": "^1.2.0",
|
|
@@ -82,6 +82,5 @@
|
|
|
82
82
|
"rxjs": "^6.5.3",
|
|
83
83
|
"svgo-loader": "^4.0.0",
|
|
84
84
|
"webpack": "^5.88.0"
|
|
85
|
-
}
|
|
86
|
-
"stableVersion": "5.7.1"
|
|
85
|
+
}
|
|
87
86
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg">
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
<path d="M14.375 1.25h-1.25v2.5h-2.5V5h2.5v2.5h1.25V5h2.5V3.75h-2.5v-2.5z" />
|
|
3
|
+
<path d="M9.375 2.5h-5a1.254 1.254 0 0 0-1.25 1.25v12.5a1.254 1.254 0 0 0 1.25 1.25h7.5a.567.567 0 0 0 .438-.188l4.374-4.375a.566.566 0 0 0 .188-.437V8.75h-1.25v2.5h-3.75a1.254 1.254 0 0 0-1.25 1.25v3.75h-6.25V3.75h5V2.5zm6 10-3.5 3.5v-3.5h3.5z" />
|
|
4
4
|
</svg>
|
package/src/modals/index.tsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** @module @category UI */
|
|
2
2
|
import { mountRootParcel, type Parcel } from 'single-spa';
|
|
3
3
|
import { createGlobalStore } from '@openmrs/esm-state';
|
|
4
|
-
import { getModalRegistration } from '
|
|
4
|
+
import { getModalRegistration } from './registry';
|
|
5
5
|
import { reportError } from '@openmrs/esm-error-handling';
|
|
6
|
+
export * from './registry';
|
|
6
7
|
|
|
7
8
|
type ModalInstanceState = 'NEW' | 'MOUNTED' | 'TO_BE_DELETED';
|
|
8
9
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getExtensionRegistration } from '@openmrs/esm-extensions';
|
|
2
|
+
import { createGlobalStore } from '@openmrs/esm-state';
|
|
3
|
+
import type { LifeCycles } from 'single-spa';
|
|
4
|
+
|
|
5
|
+
/** @internal */
|
|
6
|
+
export interface ModalRegistration {
|
|
7
|
+
name: string;
|
|
8
|
+
load(): Promise<{ default?: LifeCycles } & LifeCycles>;
|
|
9
|
+
moduleName: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ModalRegistry {
|
|
13
|
+
/** Modals indexed by name */
|
|
14
|
+
modals: Record<string, ModalRegistration>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const modalRegistryStore = createGlobalStore<ModalRegistry>('modalRegistry', {
|
|
18
|
+
modals: {},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/** @internal */
|
|
22
|
+
export function registerModal(modalRegistration: ModalRegistration) {
|
|
23
|
+
modalRegistryStore.setState((state) => {
|
|
24
|
+
state.modals[modalRegistration.name] = modalRegistration;
|
|
25
|
+
return state;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** @internal */
|
|
30
|
+
export function getModalRegistration(modalName: string): ModalRegistration | undefined {
|
|
31
|
+
let modalRegistration = modalRegistryStore.getState().modals[modalName];
|
|
32
|
+
if (!modalRegistration) {
|
|
33
|
+
const extensionRegistration = getExtensionRegistration(modalName);
|
|
34
|
+
if (extensionRegistration) {
|
|
35
|
+
modalRegistration = {
|
|
36
|
+
name: modalName,
|
|
37
|
+
load: extensionRegistration.load,
|
|
38
|
+
moduleName: extensionRegistration.moduleName,
|
|
39
|
+
};
|
|
40
|
+
console.warn(
|
|
41
|
+
`Modal ${modalName} was registered as an extension. This is deprecated and will be removed in the future. Please register it in the "modals" section of routes.json instead of the "extensions" section.`,
|
|
42
|
+
);
|
|
43
|
+
// Register it so the warning only appears once
|
|
44
|
+
registerModal(modalRegistration);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return modalRegistration;
|
|
48
|
+
}
|
|
@@ -3,8 +3,8 @@ import React from 'react';
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { Button, IconButton } from '@carbon/react';
|
|
5
5
|
import { useLayoutType } from '@openmrs/esm-react-utils';
|
|
6
|
-
import styles from './action-menu-button.module.scss';
|
|
7
6
|
import { useWorkspaces } from '../workspaces';
|
|
7
|
+
import styles from './action-menu-button.module.scss';
|
|
8
8
|
|
|
9
9
|
interface TagsProps {
|
|
10
10
|
getIcon: (props: object) => JSX.Element;
|
|
@@ -7,8 +7,8 @@ import { getCoreTranslation, translateFrom } from '@openmrs/esm-translations';
|
|
|
7
7
|
|
|
8
8
|
import { ArrowLeftIcon, ArrowRightIcon, CloseIcon } from '../../icons';
|
|
9
9
|
import { WorkspaceNotification } from '../notification/workspace-notification.component';
|
|
10
|
-
import ActionMenu from './action-menu.component';
|
|
11
10
|
import { type OpenWorkspace, updateWorkspaceWindowState, useWorkspaces } from '../workspaces';
|
|
11
|
+
import ActionMenu from './action-menu.component';
|
|
12
12
|
import { WorkspaceRenderer } from './workspace-renderer.component';
|
|
13
13
|
import styles from './workspace.module.scss';
|
|
14
14
|
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { screen, render, within, renderHook, act } from '@testing-library/react';
|
|
4
4
|
import userEvent from '@testing-library/user-event';
|
|
5
|
-
import { registerWorkspace } from '@openmrs/esm-extensions';
|
|
6
5
|
import { ComponentContext, isDesktop, useLayoutType } from '@openmrs/esm-react-utils';
|
|
7
|
-
import { type DefaultWorkspaceProps, WorkspaceContainer, launchWorkspace, useWorkspaces } from '..';
|
|
6
|
+
import { type DefaultWorkspaceProps, WorkspaceContainer, launchWorkspace, registerWorkspace, useWorkspaces } from '..';
|
|
8
7
|
|
|
9
8
|
jest.mock('./workspace-renderer.component.tsx', () => {
|
|
10
9
|
return {
|
|
@@ -17,7 +16,7 @@ jest.mock('./workspace-renderer.component.tsx', () => {
|
|
|
17
16
|
};
|
|
18
17
|
});
|
|
19
18
|
|
|
20
|
-
const mockedIsDesktop = isDesktop as
|
|
19
|
+
const mockedIsDesktop = isDesktop as jest.Mock;
|
|
21
20
|
const mockedUseLayoutType = useLayoutType as jest.Mock;
|
|
22
21
|
|
|
23
22
|
window.history.pushState({}, 'Workspace Container', '/workspace-container');
|
|
@@ -3,8 +3,8 @@ import { mountRootParcel, type ParcelConfig } from 'single-spa';
|
|
|
3
3
|
import Parcel from 'single-spa-react/parcel';
|
|
4
4
|
import { InlineLoading } from '@carbon/react';
|
|
5
5
|
import { getCoreTranslation } from '@openmrs/esm-translations';
|
|
6
|
-
import styles from './workspace.module.scss';
|
|
7
6
|
import { type OpenWorkspace } from '../workspaces';
|
|
7
|
+
import styles from './workspace.module.scss';
|
|
8
8
|
|
|
9
9
|
interface WorkspaceRendererProps {
|
|
10
10
|
workspace: OpenWorkspace;
|
package/src/workspaces/index.ts
CHANGED
|
@@ -2,4 +2,5 @@ export * from './action-menu-button/action-menu-button.component';
|
|
|
2
2
|
export * from './container/action-menu.component';
|
|
3
3
|
export * from './container/workspace-container.component';
|
|
4
4
|
export * from './notification/workspace-notification.component';
|
|
5
|
+
export * from './types';
|
|
5
6
|
export * from './workspaces';
|
|
@@ -4,18 +4,18 @@ import { useTranslation } from 'react-i18next';
|
|
|
4
4
|
import { Button, ComposedModal, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
|
|
5
5
|
import { navigate } from '@openmrs/esm-navigation';
|
|
6
6
|
import { reportError } from '@openmrs/esm-error-handling';
|
|
7
|
-
import { escapeRegExp } from 'lodash-es';
|
|
8
|
-
import { type SingleSpaCustomEventDetail } from 'single-spa';
|
|
9
|
-
import styles from './workspace-notification.module.scss';
|
|
10
7
|
import {
|
|
11
|
-
cancelPrompt,
|
|
12
8
|
canCloseWorkspaceWithoutPrompting,
|
|
9
|
+
cancelPrompt,
|
|
13
10
|
changeWorkspaceContext,
|
|
14
11
|
closeAllWorkspaces,
|
|
15
12
|
getWorkspaceStore,
|
|
16
13
|
resetWorkspaceStore,
|
|
17
14
|
useWorkspaces,
|
|
18
15
|
} from '../workspaces';
|
|
16
|
+
import { escapeRegExp } from 'lodash-es';
|
|
17
|
+
import { type SingleSpaCustomEventDetail } from 'single-spa';
|
|
18
|
+
import styles from './workspace-notification.module.scss';
|
|
19
19
|
|
|
20
20
|
export interface WorkspaceNotificationProps {
|
|
21
21
|
contextKey: string;
|
package/src/workspaces/public.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
export * from './action-menu-button/action-menu-button.component';
|
|
2
2
|
export * from './container/workspace-container.component';
|
|
3
|
+
export { type DefaultWorkspaceProps, type CloseWorkspaceOptions } from './types';
|
|
3
4
|
export { closeWorkspace, launchWorkspace, navigateAndLaunchWorkspace, useWorkspaces } from './workspaces';
|
|
4
|
-
export {
|
|
5
|
-
type DefaultWorkspaceProps,
|
|
6
|
-
type CloseWorkspaceOptions,
|
|
7
|
-
type OpenWorkspace,
|
|
8
|
-
type WorkspacesInfo,
|
|
9
|
-
type Prompt,
|
|
10
|
-
} from './workspaces';
|
|
5
|
+
export { type OpenWorkspace, type WorkspaceRegistration, type WorkspacesInfo, type Prompt } from './workspaces';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type WorkspaceWindowState } from '@openmrs/esm-globals';
|
|
2
|
+
import { type ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
export interface CloseWorkspaceOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Whether to close the workspace ignoring all the changes present in the workspace.
|
|
7
|
+
*
|
|
8
|
+
* If ignoreChanges is true, the user will not be prompted to save changes before closing
|
|
9
|
+
* even if the `testFcn` passed to `promptBeforeClosing` returns `true`.
|
|
10
|
+
*/
|
|
11
|
+
ignoreChanges?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* If you want to take an action after the workspace is closed, you can pass your function as
|
|
14
|
+
* `onWorkspaceClose`. This function will be called only after the workspace is closed, given
|
|
15
|
+
* that the user might be shown a prompt.
|
|
16
|
+
* @returns void
|
|
17
|
+
*/
|
|
18
|
+
onWorkspaceClose?: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The default parameters received by all workspaces */
|
|
22
|
+
export interface DefaultWorkspaceProps {
|
|
23
|
+
/**
|
|
24
|
+
* Call this function to close the workspace. This function will prompt the user
|
|
25
|
+
* if there are any unsaved changes to workspace.
|
|
26
|
+
*
|
|
27
|
+
* You can pass `onWorkspaceClose` function to be called when the workspace is finally
|
|
28
|
+
* closed, given the user forcefully closes the workspace.
|
|
29
|
+
*/
|
|
30
|
+
closeWorkspace(closeWorkspaceOptions?: CloseWorkspaceOptions): void;
|
|
31
|
+
/**
|
|
32
|
+
* Call this with a no-args function that returns true if the user should be prompted before
|
|
33
|
+
* this workspace is closed; e.g. if there is unsaved data.
|
|
34
|
+
*/
|
|
35
|
+
promptBeforeClosing(testFcn: () => boolean): void;
|
|
36
|
+
/**
|
|
37
|
+
* Call this function to close the workspace after the form is saved. This function
|
|
38
|
+
* will directly close the workspace without any prompt
|
|
39
|
+
*/
|
|
40
|
+
closeWorkspaceWithSavedChanges(closeWorkspaceOptions?: CloseWorkspaceOptions): void;
|
|
41
|
+
/**
|
|
42
|
+
* Use this to set the workspace title if it needs to be set dynamically.
|
|
43
|
+
*
|
|
44
|
+
* Workspace titles generally are set in the workspace declaration in the routes.json file. They can also
|
|
45
|
+
* be set by the workspace launcher by passing `workspaceTitle` in the `additionalProps`
|
|
46
|
+
* parameter of the `launchWorkspace` function. This function is useful when the workspace
|
|
47
|
+
* title needs to be set dynamically.
|
|
48
|
+
*
|
|
49
|
+
* @param title The title to set. If using titleNode, set this to a human-readable string
|
|
50
|
+
* which will identify the workspace in notifications and other places.
|
|
51
|
+
* @param titleNode A React object to put in the workspace header in place of the title. This
|
|
52
|
+
* is useful for displaying custom elements in the header. Note that custom header
|
|
53
|
+
* elements can also be attached to the workspace header extension slots.
|
|
54
|
+
*/
|
|
55
|
+
setTitle(title: string, titleNode?: ReactNode): void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface WorkspaceWindowSize {
|
|
59
|
+
size: WorkspaceWindowState;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface WorkspaceWindowSizeProviderProps {
|
|
63
|
+
children?: React.ReactNode;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface WorkspaceWindowSizeContext {
|
|
67
|
+
windowSize: WorkspaceWindowSize;
|
|
68
|
+
updateWindowSize?(value: WorkspaceWindowState): any;
|
|
69
|
+
active: boolean;
|
|
70
|
+
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
type Prompt,
|
|
3
|
+
cancelPrompt,
|
|
4
|
+
getWorkspaceStore,
|
|
5
|
+
launchWorkspace,
|
|
6
|
+
registerWorkspace,
|
|
7
|
+
resetWorkspaceStore,
|
|
8
|
+
} from './workspaces';
|
|
9
|
+
import { registerExtension } from '@openmrs/esm-extensions';
|
|
3
10
|
import { clearMockExtensionRegistry } from '@openmrs/esm-framework/mock';
|
|
4
11
|
|
|
5
12
|
describe('workspace system', () => {
|
|
@@ -1,80 +1,14 @@
|
|
|
1
1
|
/** @module @category Workspace */
|
|
2
|
-
import {
|
|
2
|
+
import { type ReactNode, useMemo } from 'react';
|
|
3
|
+
import { type LifeCycles } from 'single-spa';
|
|
3
4
|
import _i18n from 'i18next';
|
|
4
|
-
import {
|
|
5
|
+
import { type ExtensionRegistration, getExtensionRegistration } from '@openmrs/esm-extensions';
|
|
5
6
|
import { type WorkspaceWindowState } from '@openmrs/esm-globals';
|
|
7
|
+
import { useStore } from '@openmrs/esm-react-utils';
|
|
6
8
|
import { navigate } from '@openmrs/esm-navigation';
|
|
7
9
|
import { getGlobalStore, createGlobalStore } from '@openmrs/esm-state';
|
|
8
10
|
import { getCoreTranslation, translateFrom } from '@openmrs/esm-translations';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
export interface CloseWorkspaceOptions {
|
|
12
|
-
/**
|
|
13
|
-
* Whether to close the workspace ignoring all the changes present in the workspace.
|
|
14
|
-
*
|
|
15
|
-
* If ignoreChanges is true, the user will not be prompted to save changes before closing
|
|
16
|
-
* even if the `testFcn` passed to `promptBeforeClosing` returns `true`.
|
|
17
|
-
*/
|
|
18
|
-
ignoreChanges?: boolean;
|
|
19
|
-
/**
|
|
20
|
-
* If you want to take an action after the workspace is closed, you can pass your function as
|
|
21
|
-
* `onWorkspaceClose`. This function will be called only after the workspace is closed, given
|
|
22
|
-
* that the user might be shown a prompt.
|
|
23
|
-
* @returns void
|
|
24
|
-
*/
|
|
25
|
-
onWorkspaceClose?: () => void;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** The default parameters received by all workspaces */
|
|
29
|
-
export interface DefaultWorkspaceProps {
|
|
30
|
-
/**
|
|
31
|
-
* Call this function to close the workspace. This function will prompt the user
|
|
32
|
-
* if there are any unsaved changes to workspace.
|
|
33
|
-
*
|
|
34
|
-
* You can pass `onWorkspaceClose` function to be called when the workspace is finally
|
|
35
|
-
* closed, given the user forcefully closes the workspace.
|
|
36
|
-
*/
|
|
37
|
-
closeWorkspace(closeWorkspaceOptions?: CloseWorkspaceOptions): void;
|
|
38
|
-
/**
|
|
39
|
-
* Call this with a no-args function that returns true if the user should be prompted before
|
|
40
|
-
* this workspace is closed; e.g. if there is unsaved data.
|
|
41
|
-
*/
|
|
42
|
-
promptBeforeClosing(testFcn: () => boolean): void;
|
|
43
|
-
/**
|
|
44
|
-
* Call this function to close the workspace after the form is saved. This function
|
|
45
|
-
* will directly close the workspace without any prompt
|
|
46
|
-
*/
|
|
47
|
-
closeWorkspaceWithSavedChanges(closeWorkspaceOptions?: CloseWorkspaceOptions): void;
|
|
48
|
-
/**
|
|
49
|
-
* Use this to set the workspace title if it needs to be set dynamically.
|
|
50
|
-
*
|
|
51
|
-
* Workspace titles generally are set in the workspace declaration in the routes.json file. They can also
|
|
52
|
-
* be set by the workspace launcher by passing `workspaceTitle` in the `additionalProps`
|
|
53
|
-
* parameter of the `launchWorkspace` function. This function is useful when the workspace
|
|
54
|
-
* title needs to be set dynamically.
|
|
55
|
-
*
|
|
56
|
-
* @param title The title to set. If using titleNode, set this to a human-readable string
|
|
57
|
-
* which will identify the workspace in notifications and other places.
|
|
58
|
-
* @param titleNode A React object to put in the workspace header in place of the title. This
|
|
59
|
-
* is useful for displaying custom elements in the header. Note that custom header
|
|
60
|
-
* elements can also be attached to the workspace header extension slots.
|
|
61
|
-
*/
|
|
62
|
-
setTitle(title: string, titleNode?: ReactNode): void;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface WorkspaceWindowSize {
|
|
66
|
-
size: WorkspaceWindowState;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface WorkspaceWindowSizeProviderProps {
|
|
70
|
-
children?: React.ReactNode;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface WorkspaceWindowSizeContext {
|
|
74
|
-
windowSize: WorkspaceWindowSize;
|
|
75
|
-
updateWindowSize?(value: WorkspaceWindowState): any;
|
|
76
|
-
active: boolean;
|
|
77
|
-
}
|
|
11
|
+
import { type DefaultWorkspaceProps, type CloseWorkspaceOptions } from './types';
|
|
78
12
|
|
|
79
13
|
export interface Prompt {
|
|
80
14
|
title: string;
|
|
@@ -93,10 +27,121 @@ export interface WorkspaceStoreState {
|
|
|
93
27
|
workspaceWindowState: WorkspaceWindowState;
|
|
94
28
|
}
|
|
95
29
|
|
|
30
|
+
/** See [[WorkspaceDefinition]] for more information about these properties */
|
|
31
|
+
export interface WorkspaceRegistration {
|
|
32
|
+
name: string;
|
|
33
|
+
title: string;
|
|
34
|
+
titleNode?: ReactNode;
|
|
35
|
+
type: string;
|
|
36
|
+
canHide: boolean;
|
|
37
|
+
canMaximize: boolean;
|
|
38
|
+
width: 'narrow' | 'wider' | 'extra-wide';
|
|
39
|
+
hasOwnSidebar: boolean;
|
|
40
|
+
sidebarFamily: string;
|
|
41
|
+
preferredWindowSize: WorkspaceWindowState;
|
|
42
|
+
load: () => Promise<{ default?: LifeCycles } & LifeCycles>;
|
|
43
|
+
moduleName: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
96
46
|
export interface OpenWorkspace extends WorkspaceRegistration, DefaultWorkspaceProps {
|
|
97
47
|
additionalProps: object;
|
|
98
48
|
}
|
|
99
49
|
|
|
50
|
+
interface WorkspaceRegistrationStore {
|
|
51
|
+
workspaces: Record<string, WorkspaceRegistration>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const workspaceRegistrationStore = createGlobalStore<WorkspaceRegistrationStore>('workspaceRegistrations', {
|
|
55
|
+
workspaces: {},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
/** See [[WorkspaceDefinition]] for more information about these properties */
|
|
59
|
+
export interface RegisterWorkspaceOptions {
|
|
60
|
+
name: string;
|
|
61
|
+
title: string;
|
|
62
|
+
type?: string;
|
|
63
|
+
canHide?: boolean;
|
|
64
|
+
canMaximize?: boolean;
|
|
65
|
+
width?: 'narrow' | 'wider' | 'extra-wide';
|
|
66
|
+
hasOwnSidebar?: boolean;
|
|
67
|
+
sidebarFamily?: string;
|
|
68
|
+
preferredWindowSize?: WorkspaceWindowState;
|
|
69
|
+
load: () => Promise<{ default?: LifeCycles } & LifeCycles>;
|
|
70
|
+
moduleName: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Tells the workspace system about a workspace. This is used by the app shell
|
|
75
|
+
* to register workspaces defined in the `routes.json` file.
|
|
76
|
+
* @internal
|
|
77
|
+
*/
|
|
78
|
+
export function registerWorkspace(workspace: RegisterWorkspaceOptions) {
|
|
79
|
+
workspaceRegistrationStore.setState((state) => ({
|
|
80
|
+
workspaces: {
|
|
81
|
+
...state.workspaces,
|
|
82
|
+
[workspace.name]: {
|
|
83
|
+
...workspace,
|
|
84
|
+
preferredWindowSize: workspace.preferredWindowSize ?? 'normal',
|
|
85
|
+
type: workspace.type ?? 'form',
|
|
86
|
+
canHide: workspace.canHide ?? false,
|
|
87
|
+
canMaximize: workspace.canMaximize ?? false,
|
|
88
|
+
width: workspace.width ?? 'narrow',
|
|
89
|
+
hasOwnSidebar: workspace.hasOwnSidebar ?? false,
|
|
90
|
+
sidebarFamily: workspace.sidebarFamily ?? 'default',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const workspaceExtensionWarningsIssued = new Set();
|
|
97
|
+
/**
|
|
98
|
+
* This exists for compatibility with the old way of registering
|
|
99
|
+
* workspaces (as extensions).
|
|
100
|
+
*
|
|
101
|
+
* @param name of the workspace
|
|
102
|
+
*/
|
|
103
|
+
function getWorkspaceRegistration(name: string): WorkspaceRegistration {
|
|
104
|
+
const registeredWorkspaces = workspaceRegistrationStore.getState().workspaces;
|
|
105
|
+
if (registeredWorkspaces[name]) {
|
|
106
|
+
return registeredWorkspaces[name];
|
|
107
|
+
} else {
|
|
108
|
+
const workspaceExtension = getExtensionRegistration(name);
|
|
109
|
+
if (workspaceExtension) {
|
|
110
|
+
if (!workspaceExtensionWarningsIssued.has(name)) {
|
|
111
|
+
console.warn(
|
|
112
|
+
`The workspace '${name}' is registered as an extension. This is deprecated. Please register it in the "workspaces" section of the routes.json file.`,
|
|
113
|
+
);
|
|
114
|
+
workspaceExtensionWarningsIssued.add(name);
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
name: workspaceExtension.name,
|
|
118
|
+
title: getTitleFromExtension(workspaceExtension),
|
|
119
|
+
moduleName: workspaceExtension.moduleName,
|
|
120
|
+
preferredWindowSize: workspaceExtension.meta?.screenSize ?? 'normal',
|
|
121
|
+
load: workspaceExtension.load,
|
|
122
|
+
type: workspaceExtension.meta?.type ?? 'form',
|
|
123
|
+
canHide: workspaceExtension.meta?.canHide ?? false,
|
|
124
|
+
canMaximize: workspaceExtension.meta?.canMaximize ?? false,
|
|
125
|
+
width: workspaceExtension.meta?.width ?? 'narrow',
|
|
126
|
+
sidebarFamily: 'default',
|
|
127
|
+
hasOwnSidebar: false,
|
|
128
|
+
};
|
|
129
|
+
} else {
|
|
130
|
+
throw new Error(`No workspace named '${name}' has been registered.`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getTitleFromExtension(ext: ExtensionRegistration) {
|
|
136
|
+
const title = ext?.meta?.title;
|
|
137
|
+
if (typeof title === 'string') {
|
|
138
|
+
return title;
|
|
139
|
+
} else if (title && typeof title === 'object') {
|
|
140
|
+
return translateFrom(ext.moduleName, title.key, title.default);
|
|
141
|
+
}
|
|
142
|
+
return ext.name;
|
|
143
|
+
}
|
|
144
|
+
|
|
100
145
|
/**
|
|
101
146
|
*
|
|
102
147
|
* @param name Name of the workspace
|