-
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
Conversation
This reverts commit fca7d4a.
Size Change: -1.48 MB (-18.88%) 👏 Total Size: 6.34 MB
ℹ️ View Unchanged
|
} | ||
} | ||
|
||
export function getOpenedWindowIndexByWorkspace(workspaceName: string) { |
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.
export function renderWorkspaceWindowsAndMenu(target: HTMLElement | null) { | ||
if (target) { | ||
const root = createRoot(target); | ||
root.render(<WorkspaceWindowsAndMenu />); | ||
} | ||
} |
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.
I'd also probably prefer if this were done as part of the primary navigation app and not the app shell (since we have some things like the login page which shouldn't need this.
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.
I wanted to follow the pattern with modals, toasts and notifications to have their root as part of the app shell. Workspace v1 was the odd one out in that we needed to have <WorkspaceContainer>
defined in each app.
* [¹] 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 sets of props are compatible if either one is nullish, or if they are shallow equal. |
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.
It would probably be better to format these as actual Markdown foot notes, i.e., [^1]
then [^1]: Blah blah blah
. We at least have a chance in correctly creating links for those.
It would be good (eventually) to include one or two @example
uses here too.
* @experimental | ||
*/ | ||
export async function launchWorkspace2< | ||
WorkspaceProps extends Record<string, any>, |
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.
I tend to prefer:
WorkspaceProps extends Record<string, any>, | |
WorkspaceProps extends Record<string, unknown>, |
Unless we really can't...
if (a == null || b == null) { | ||
return true; | ||
} |
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.
if (a == null || b == null) { | |
return true; | |
} | |
if (a === null || b === null) { | |
return true; | |
} |
// check that every prop in a is also in b, and they are equal | ||
for (let key in a) { | ||
if (!(key in b) || a[key] !== b[key]) { | ||
return false; | ||
} | ||
} | ||
|
||
// check that every prop in b is also in a, and they are equal | ||
for (let key in b) { | ||
if (!(key in a) || a[key] !== b[key]) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} |
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.
We actually have a shallowEqual()
function which should be slightly more efficient.
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.
Left a few suggestions. Feel free to ignore the updated comment suggestions if they don't resonate.
<div class="omrs-snackbars-container"></div> | ||
<div class="omrs-modals-container"></div> | ||
<div id="omrs-left-nav-container"></div> | ||
<div id="omrs-workspace-container"></div> |
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.
<div id="omrs-workspace-container"></div> | |
<div id="omrs-workspaces-container"></div> |
To accurately reflect that it renders multiple workspaces instead of a single one.
grid-area: leftNav; | ||
} | ||
|
||
#omrs-workspace-container { |
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.
#omrs-workspace-container { | |
#omrs-workspaces-container { |
} | ||
|
||
function showWorkspacesAndActionMenu() { | ||
renderWorkspaceWindowsAndMenu(document.querySelector('#omrs-workspace-container')); |
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.
renderWorkspaceWindowsAndMenu(document.querySelector('#omrs-workspace-container')); | |
renderWorkspaceWindowsAndMenu(document.querySelector('#omrs-workspaces-container')); |
tagContent?: React.ReactNode; | ||
} | ||
|
||
function Tags({ getIcon, isWindowHidden: isWindowHidden, tagContent }: TagsProps) { |
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.
function Tags({ getIcon, isWindowHidden: isWindowHidden, tagContent }: TagsProps) { | |
function Tags({ getIcon, isWindowHidden, tagContent }: TagsProps) { |
This destructuring alias shouldn't be necessary as it's using the same name as the original.
const isFocused = isCurrentWindowFocused(openedWindows, window); | ||
|
||
const onClick = async () => { | ||
if (isWindowOpened) { | ||
if (!isFocused) { | ||
restoreWindow(window.windowName); | ||
} | ||
} else { | ||
const shouldLaunch = await (onBeforeWorkspaceLaunch?.() ?? true); | ||
if (shouldLaunch) { | ||
const { workspaceName, workspaceProps, windowProps } = workspaceToLaunch; | ||
launchWorkspace2(workspaceName, workspaceProps, windowProps); | ||
} | ||
} | ||
}; |
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.
const isFocused = isCurrentWindowFocused(openedWindows, window); | |
const onClick = async () => { | |
if (isWindowOpened) { | |
if (!isFocused) { | |
restoreWindow(window.windowName); | |
} | |
} else { | |
const shouldLaunch = await (onBeforeWorkspaceLaunch?.() ?? true); | |
if (shouldLaunch) { | |
const { workspaceName, workspaceProps, windowProps } = workspaceToLaunch; | |
launchWorkspace2(workspaceName, workspaceProps, windowProps); | |
} | |
} | |
}; | |
const isFocused = useMemo(() => isCurrentWindowFocused(openedWindows, window), [openedWindows, window]); | |
const onClick = async () => { | |
try { | |
if (isWindowOpened) { | |
if (!isFocused) { | |
restoreWindow(window.windowName); | |
} | |
return; | |
} | |
const shouldLaunch = await (onBeforeWorkspaceLaunch?.() ?? true); | |
if (shouldLaunch) { | |
const { workspaceName, workspaceProps, windowProps } = workspaceToLaunch; | |
launchWorkspace2(workspaceName, workspaceProps, windowProps); | |
} | |
} catch (error) { | |
console.error('Failed to handle workspace action:', error); | |
} | |
}; |
Could potentially be refactored to this to simplify the complex conditional logic and optimize the computation (less important here).
// most recently opened action appended to the end | ||
{ | ||
windowName: windowName, | ||
openedWorkspaces: [newOpenedWorkspace(workspaceName, workspaceProps)], // root workspace at index 0 |
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.
openedWorkspaces: [newOpenedWorkspace(workspaceName, workspaceProps)], // root workspace at index 0 | |
openedWorkspaces: [newOpenedWorkspace(workspaceName, workspaceProps)], // single workspace in new array |
return true; | ||
} | ||
|
||
// check that every prop in a is also in b, and they are equal |
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.
// check that every prop in a is also in b, and they are equal | |
// check that every prop in a is also in b, and they are equal (bidirectional check) |
const openedWindowIndex = getOpenedWindowIndexByWorkspace(workspaceName); | ||
const isWindowAlreadyOpened = openedWindowIndex >= 0; | ||
|
||
// if current opened group is not the same as the requested group, or if the group props are different, then prompt for unsaved changes |
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.
// if current opened group is not the same as the requested group, or if the group props are different, then prompt for unsaved changes | |
// Check if we need to prompt for group change due to incompatible props | |
// if current opened group is not the same as the requested group, or if the group props are different, then prompt for unsaved changes |
} else { | ||
return false; | ||
} | ||
} else if (isWindowAlreadyOpened) { |
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.
} else if (isWindowAlreadyOpened) { | |
// Handle case where window is already opened | |
} else if (isWindowAlreadyOpened) { |
return false; | ||
} | ||
} | ||
} else { |
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.
} else { | |
// Create new window when none exists | |
} else { |
This reverts commit fca7d4a.
Requirements
feat
,fix
, orchore
, among others). See existing PR titles for inspiration.If applicable
Summary
This PR un-reverts the initial workspace v2 check-in (#1424), which was reverted in fca7d4a for the 3.5 release.
This should not affect how the current workspace system works.
Screenshots
Related Issue
Other