-
Notifications
You must be signed in to change notification settings - Fork 261
(feat) O3-4869 (un-revert) Workspace v2 #1459
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
a5c907f
(feat) O3-4869 (un-revert) Workspace v2
chibongho 64f554b
Merge branch 'main' into workspace2
denniskigen 9001f3c
Merge remote-tracking branch 'origin/main' into workspace2
chibongho 8923454
add @experimental annotations
chibongho b924cd5
address PR comments
chibongho 8c56da9
Merge remote-tracking branch 'origin/main' into workspace2
chibongho File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import { | ||
type WorkspaceDefinition2, | ||
type WorkspaceGroupDefinition2, | ||
type WorkspaceWindowDefinition2, | ||
} from '@openmrs/esm-globals'; | ||
import { createGlobalStore } from '@openmrs/esm-state'; | ||
|
||
export interface OpenedWorkspace { | ||
workspaceName: string; | ||
props: Record<string, any> | null; | ||
hasUnsavedChanges: boolean; | ||
/** Unique identifier for the workspace instance, used to track unique instances of the same workspace */ | ||
uuid: string; | ||
} | ||
export interface OpenedWindow { | ||
windowName: string; | ||
/** Root workspace at index 0, child workspaces follow */ | ||
openedWorkspaces: Array<OpenedWorkspace>; | ||
props: Record<string, any> | null; | ||
maximized: boolean; | ||
hidden: boolean; | ||
} | ||
export interface WorkspaceStoreState2 { | ||
registeredGroupsByName: Record<string, WorkspaceGroupDefinition2>; | ||
registeredWindowsByName: Record<string, WorkspaceWindowDefinition2 & { moduleName: string }>; | ||
registeredWorkspacesByName: Record<string, WorkspaceDefinition2 & { moduleName: string }>; | ||
openedGroup: { | ||
groupName: string; | ||
props: Record<string, any> | null; | ||
} | null; | ||
/** Most recently opened window at the end of array. Each element has a unique windowName */ | ||
openedWindows: Array<OpenedWindow>; | ||
|
||
workspaceTitleByWorkspaceName: Record<string, string>; | ||
} | ||
|
||
const initialState: WorkspaceStoreState2 = { | ||
registeredGroupsByName: {}, | ||
registeredWindowsByName: {}, | ||
registeredWorkspacesByName: {}, | ||
openedGroup: null, | ||
openedWindows: [], | ||
workspaceTitleByWorkspaceName: {}, | ||
}; | ||
|
||
export const workspace2Store = createGlobalStore<WorkspaceStoreState2>('workspace2', initialState); | ||
|
||
/** | ||
* Given a workspace name, return the window that the workspace belongs to | ||
* @param workspaceName | ||
* @returns | ||
*/ | ||
export function getWindowByWorkspaceName(workspaceName: string) { | ||
const { registeredWorkspacesByName, registeredWindowsByName } = workspace2Store.getState(); | ||
const workspace = registeredWorkspacesByName[workspaceName]; | ||
if (!workspace) { | ||
throw new Error(`No workspace found with name: ${workspaceName}`); | ||
} else { | ||
const workspaceWindow = registeredWindowsByName[workspace.window]; | ||
if (!workspaceWindow) { | ||
throw new Error(`No workspace window found with name: ${workspace.window} for workspace: ${workspaceName}`); | ||
} else { | ||
return workspaceWindow; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Given a window name, return the group that the window belongs to | ||
* @param windowName | ||
* @returns | ||
*/ | ||
export function getGroupByWindowName(windowName: string) { | ||
const { registeredGroupsByName, registeredWindowsByName } = workspace2Store.getState(); | ||
const workspaceWindow = registeredWindowsByName[windowName]; | ||
if (!workspaceWindow) { | ||
throw new Error(`No workspace window found with name: ${windowName}`); | ||
} else { | ||
const group = registeredGroupsByName[workspaceWindow.group]; | ||
if (!group) { | ||
throw new Error(`No workspace group found with name: ${workspaceWindow.group} for window: ${windowName}`); | ||
} else { | ||
return group; | ||
} | ||
} | ||
} | ||
|
||
export function getOpenedWindowIndexByWorkspace(workspaceName: string) { | ||
const { openedWindows } = workspace2Store.getState(); | ||
return openedWindows.findIndex((a) => | ||
a.openedWorkspaces.find((openedWorkspace) => openedWorkspace.workspaceName === workspaceName), | ||
); | ||
} | ||
|
||
export function registerWorkspaceGroups2(workspaceGroupDefs: Array<WorkspaceGroupDefinition2>) { | ||
if (workspaceGroupDefs.length == 0) { | ||
return; | ||
} | ||
const { registeredGroupsByName } = workspace2Store.getState(); | ||
const newRegisteredGroupsByName = { ...registeredGroupsByName }; | ||
for (const workspaceGroupDef of workspaceGroupDefs) { | ||
if (newRegisteredGroupsByName[workspaceGroupDef.name]) { | ||
throw new Error(`Cannot register workspace group ${workspaceGroupDef.name} more than once`); | ||
} | ||
newRegisteredGroupsByName[workspaceGroupDef.name] = workspaceGroupDef; | ||
} | ||
|
||
workspace2Store.setState({ | ||
registeredGroupsByName: newRegisteredGroupsByName, | ||
}); | ||
} | ||
|
||
export function registerWorkspaceWindows2(appName: string, workspaceWindowDefs: Array<WorkspaceWindowDefinition2>) { | ||
if (workspaceWindowDefs.length == 0) { | ||
return; | ||
} | ||
const { registeredWindowsByName } = workspace2Store.getState(); | ||
const newRegisteredWindowsByName = { ...registeredWindowsByName }; | ||
for (const windowDef of workspaceWindowDefs) { | ||
if (newRegisteredWindowsByName[windowDef.name]) { | ||
throw new Error(`Cannot register workspace window ${windowDef.name} more than once`); | ||
} | ||
const registeredWindowDef = { ...windowDef, moduleName: appName }; | ||
newRegisteredWindowsByName[windowDef.name] = registeredWindowDef; | ||
} | ||
|
||
workspace2Store.setState({ | ||
registeredWindowsByName: newRegisteredWindowsByName, | ||
}); | ||
} | ||
|
||
export function registerWorkspaces2(moduleName: string, workspaceDefs: Array<WorkspaceDefinition2>) { | ||
if (workspaceDefs.length == 0) { | ||
return; | ||
} | ||
const { registeredWorkspacesByName } = workspace2Store.getState(); | ||
const newRegisteredWorkspacesByName = { ...registeredWorkspacesByName }; | ||
for (const workspaceDef of workspaceDefs) { | ||
if (newRegisteredWorkspacesByName[workspaceDef.name]) { | ||
throw new Error(`Cannot register workspace ${workspaceDef.name} more than once`); | ||
} | ||
const workspaceDefWithLoader = { ...workspaceDef, moduleName }; | ||
newRegisteredWorkspacesByName[workspaceDef.name] = workspaceDefWithLoader; | ||
} | ||
|
||
workspace2Store.setState({ | ||
registeredWorkspacesByName: newRegisteredWorkspacesByName, | ||
}); | ||
} |
19 changes: 19 additions & 0 deletions
19
packages/framework/esm-framework/docs/functions/closeWorkspaceGroup2.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[O3 Framework](../API.md) / closeWorkspaceGroup2 | ||
|
||
# Function: closeWorkspaceGroup2() | ||
|
||
> **closeWorkspaceGroup2**(): `Promise`\<`boolean`\> | ||
|
||
Defined in: [packages/framework/esm-styleguide/src/workspaces2/workspace2.ts:69](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces2/workspace2.ts#L69) | ||
|
||
**`Experimental`** | ||
|
||
Closes the workspace group that is currently opened. Note that only one workspace group | ||
may be opened at any given time | ||
|
||
## Returns | ||
|
||
`Promise`\<`boolean`\> | ||
|
||
a Promise that resolves to true if there is no opened group to begin with or we successfully closed | ||
the opened group; false otherwise. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
packages/framework/esm-framework/docs/functions/launchWorkspace2.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
[O3 Framework](../API.md) / launchWorkspace2 | ||
|
||
# Function: launchWorkspace2() | ||
|
||
> **launchWorkspace2**\<`WorkspaceProps`, `WindowProps`, `GroupProp`\>(`workspaceName`, `workspaceProps`, `windowProps`, `groupProps`): `Promise`\<`boolean`\> | ||
|
||
Defined in: [packages/framework/esm-styleguide/src/workspaces2/workspace2.ts:127](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces2/workspace2.ts#L127) | ||
|
||
**`Experimental`** | ||
|
||
Attempts to launch the specified workspace with the given workspace props. This also implicitly opens | ||
the workspace window to which the workspace belongs (if it's not opened already), | ||
and the workspace group to which the window belongs (if it's not opened already). | ||
|
||
When calling `launchWorkspace2`, we need to also pass in the workspace props. While not required, | ||
we can also pass in the window props (shared by other workspaces in the window) and the group props | ||
(shared by all windows and their workspaces). Omitting the window props or the group props[^1] means the caller | ||
explicitly does not care what the current window props and group props are, and that they may be set | ||
by other actions (like calling `launchWorkspace2` on a different workspace with those props passed in) | ||
at a later time. | ||
|
||
If there is already an opened workspace group, and it's not the group the workspace belongs to | ||
or has incompatible[^2] group props, then we prompt the user to close the group (and its windows and their workspaces). | ||
On user confirm, the existing opened group is closed and the new workspace, along with its window and its group, | ||
is opened. | ||
|
||
If the window is already opened, but with incompatible window props, we prompt the user to close | ||
the window (and all its opened workspaces), and reopen the window with (only) the newly requested workspace. | ||
|
||
If the workspace is already opened, but with incompatible workspace props, we also prompt the user to close | ||
the **window** (and all its opened workspaces), and reopen the window with (only) the newly requested workspace. | ||
This is true regardless of whether the already opened workspace has any child workspaces. | ||
|
||
Note that calling this function *never* results in creating a child workspace in the affected window. | ||
To do so, we need to call `launchChildWorkspace` instead. | ||
|
||
[^1] Omitting window or group props is useful for workspaces that don't have ties to the window or group "context" (props). | ||
For example, in the patient chart, the visit notes / clinical forms / order basket action menu button all share | ||
a "group context" of the current visit. However, the "patient list" action menu button does not need to share that group | ||
context, so opening that workspace should not need to cause other workspaces / windows / groups to potentially close. | ||
The "patient search" workspace in the queues and ward apps is another example. | ||
|
||
[^2] 2 sets of props are compatible if either one is nullish, or if they are shallow equal. | ||
|
||
## Type Parameters | ||
|
||
### WorkspaceProps | ||
|
||
`WorkspaceProps` *extends* `object` | ||
|
||
### WindowProps | ||
|
||
`WindowProps` *extends* `object` | ||
|
||
### GroupProp | ||
|
||
`GroupProp` *extends* `object` | ||
|
||
## Parameters | ||
|
||
### workspaceName | ||
|
||
`string` | ||
|
||
### workspaceProps | ||
|
||
`null` | `WorkspaceProps` | ||
|
||
### windowProps | ||
|
||
`null` | `WindowProps` | ||
|
||
### groupProps | ||
|
||
`null` | `GroupProp` | ||
|
||
## Returns | ||
|
||
`Promise`\<`boolean`\> |
40 changes: 40 additions & 0 deletions
40
packages/framework/esm-framework/docs/functions/launchWorkspaceGroup2.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
[O3 Framework](../API.md) / launchWorkspaceGroup2 | ||
|
||
# Function: launchWorkspaceGroup2() | ||
|
||
> **launchWorkspaceGroup2**\<`GroupProps`\>(`groupName`, `groupProps`): `Promise`\<`boolean`\> | ||
|
||
Defined in: [packages/framework/esm-styleguide/src/workspaces2/workspace2.ts:29](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-styleguide/src/workspaces2/workspace2.ts#L29) | ||
|
||
**`Experimental`** | ||
|
||
Attempts to launch the specified workspace group with the given group props. Note that only one workspace group | ||
may be opened at any given time. If a workspace group is already opened, calling `launchWorkspaceGroup2` with | ||
either a different group name, or same group name but different incompatible props**, will result in prompting to | ||
confirm closing workspaces. If the user confirms, the opened group, along with its windows (and their workspaces), is closed, and | ||
the requested group is immediately opened. | ||
|
||
** 2 sets of props are compatible if either one is nullish, or if they are shallow equal. | ||
|
||
## Type Parameters | ||
|
||
### GroupProps | ||
|
||
`GroupProps` *extends* `object` | ||
|
||
## Parameters | ||
|
||
### groupName | ||
|
||
`string` | ||
|
||
### groupProps | ||
|
||
`null` | `GroupProps` | ||
|
||
## Returns | ||
|
||
`Promise`\<`boolean`\> | ||
|
||
a Promise that resolves to true if the specified workspace group with the specified group props | ||
is successfully opened, or that it already is opened. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually, we should add TSDoc comments to anything in the public API, which I assume covers all of this.