/** @module @category Workspace */ import React, { useContext } from 'react'; import classNames from 'classnames'; import { Button, IconButton } from '@carbon/react'; import { SingleSpaContext } from 'single-spa-react'; import { ComponentContext, useLayoutType } from '@openmrs/esm-react-utils'; import { type OpenedWindow } from '@openmrs/esm-extensions'; import { launchWorkspace2, useWorkspace2Store } from '../workspace2'; import styles from './action-menu-button2.module.scss'; interface TagsProps { getIcon: (props: object) => JSX.Element; hasUnsavedChanges: boolean; tagContent?: React.ReactNode; } function Tags({ getIcon, hasUnsavedChanges, tagContent }: TagsProps) { return ( <> {getIcon({ size: 16 })} {hasUnsavedChanges ? ( ! ) : ( {tagContent} )} ); } export interface ActionMenuButtonProps2 { icon: (props: object) => JSX.Element; label: string; tagContent?: string | React.ReactNode; workspaceToLaunch: { workspaceName: string; workspaceProps?: Record; windowProps?: Record; }; /** * An optional callback function to run before launching the workspace. * If provided, the workspace will only be launched if this function returns true. * This can be used to perform checks or prompt the user before launching the workspace. * Note that this function does not run if the action button's window is already opened; * it will just restore (unhide) the window. * */ onBeforeWorkspaceLaunch?: () => Promise; } /** * The ActionMenuButton2 component is used to render a button in the action menu of a workspace group. * The button is associated with a specific workspace window, defined in routes.json of the app with the button. * When one or more workspaces within the window are opened, the button will be highlighted: * bold blue when the window is focused (un-minimized and in front), green when unfocused. * If any workspace in the window has unsaved changes, an exclamation mark will be displayed * on top of the icon. * * On clicked, The button either: * 1. hides the workspace window if it is opened and focused; or * 2. restores the workspace window if it is opened and unfocused; or * 3. launches a workspace from within that window, if the window is not opened. * * @experimental */ export const ActionMenuButton2: React.FC = ({ icon: getIcon, label, tagContent, workspaceToLaunch, onBeforeWorkspaceLaunch, }) => { const layout = useLayoutType(); const { openedWindows, restoreWindow, hideWindow, isMostRecentlyOpenedWindowHidden } = useWorkspace2Store(); const { extension } = useContext(ComponentContext); const openedWindowIndex = openedWindows.findIndex((w) => w.windowName === extension?.extensionId); // can be undefined if the window is not opened const window: OpenedWindow | undefined = openedWindows[openedWindowIndex]; const isWindowOpened = window != null; const isWindowHidden = isWindowOpened && (openedWindowIndex < openedWindows.length - 1 || isMostRecentlyOpenedWindowHidden); const isWindowFocused = isWindowOpened && !isWindowHidden; const hasUnsavedChanges = window?.openedWorkspaces.some((w) => w.hasUnsavedChanges) ?? false; const onClick = async () => { if (isWindowOpened) { if (isWindowHidden) { restoreWindow(window.windowName); } else { hideWindow(); } } else { const shouldLaunch = await (onBeforeWorkspaceLaunch?.() ?? true); if (shouldLaunch) { const { workspaceName, workspaceProps, windowProps } = workspaceToLaunch; launchWorkspace2(workspaceName, workspaceProps, windowProps); } } }; if (layout === 'tablet' || layout === 'phone') { return ( ); } return (
); };