Skip to content
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

(feat) O3-1422 / O3-2724: Move workspace system into the framework #979

Merged
merged 19 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,18 @@ import { ExtensionSlot, useLayoutType, useWorkspaces } from '@openmrs/esm-framew
import styles from './action-menu.module.scss';
import { ComponentContext } from '@openmrs/esm-react-utils';

interface ActionMenuInterface {}

export const ActionMenu: React.FC<ActionMenuInterface> = () => {
/**
* This renders the [Siderail and Bottom Nav](https://zeroheight.com/23a080e38/p/948cf1-siderail-and-bottom-nav/b/86907e),
* collectively known as the Action Menu. The Siderail is rendered on the right side of the screen
* on desktop, and the Bottom Nav is rendered at the bottom of the screen on tablet or mobile.
*
* The action menu provides an extension slot, to which buttons are attached as extensions. The slot
* derives its name from the `featureName` of the top-level component in which this `ActionMenu`
* appears (feature names are generally provided in the lifecycle functions in an app's `index.ts` file).
* The slot is named `action-menu-${featureName}-items-slot`. For the patient chart, this is
* `action-menu-patient-chart-items-slot`.
*/
denniskigen marked this conversation as resolved.
Show resolved Hide resolved
export function ActionMenu() {
const { active, workspaceWindowState } = useWorkspaces();
const [keyboardVisible, setKeyboardVisible] = useState(false);
const initialHeight = useRef(window.innerHeight);
Expand Down Expand Up @@ -42,6 +51,6 @@ export const ActionMenu: React.FC<ActionMenuInterface> = () => {
</div>
</aside>
);
};
}

export default ActionMenu;
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
import { Button, ComposedModal, ModalBody, ModalFooter, ModalHeader } from '@carbon/react';
import { useTranslation } from 'react-i18next';
import styles from './workspace-notification.module.scss';
import { navigate } from '@openmrs/esm-framework';
import { navigate, reportError } from '@openmrs/esm-framework';

export interface WorkspaceNotificationProps {
contextKey: string;
Expand All @@ -21,6 +21,18 @@ export function WorkspaceNotification({ contextKey }: WorkspaceNotificationProps
const { t } = useTranslation();
const { prompt } = useWorkspaces();

useEffect(() => {
// When the component initially mounts, check that it has been provided a valid context key.
// I can't think of a reason the component would mount with a valid context key but not matching the URL.
const regex = new RegExp(`\/${contextKey}(\/|$)`);
const isValidContextKey = regex.test(window.location.href);
if (!isValidContextKey) {
reportError(
`WorkspaceOverlay or WorkspaceWindow has provided an invalid context key: "${contextKey}". The context key must be part of the URL path, with no initial or trailing slash.`,
);
}
}, []);

useEffect(() => {
changeWorkspaceContext(contextKey);
return () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,32 @@ export interface WorkspaceOverlayProps {
contextKey: string;
}

/**
* Use this component to render the workspace window as an overlay in an app. An overlay is
* a way of rendering workspaces that will cover other content on the screen, rather than
* pushing it to the left (as with [[WorkspaceWindow]]). As described in the
* [ZeroHeight](https://zeroheight.com/23a080e38/p/483a22-workspace/t/34e1a1) documentation,
* this should be used on "app pages" such as the Clinic Dashboard.
*
* The context key is a string that appears in the URL, which defines the pages on which workspaces
* are valid. If the URL changes in a way such that it no longer contains the context key, then
* all workspaces will be closed. This ensures that, for example, workspaces on the home page do
* not stay open when the user transitions to the patient dashboard; and also that workspaces do
* not stay open when the user navigates to a different patient. The context key must be a valid
* sub-path of the URL, with no initial or trailing slash. So if the URL is
* `https://example.com/patient/123/foo`, then `patient` and `patient/123` and `123/foo` are valid
* context keys, but `patient/12` and `pati` are not.
*
* Workspaces may be opened with the [[launchWorkspace]] function from `@openmrs/esm-framework`
* (among other options).
*
* This component also provides everything needed for workspace notifications to be rendered.
*
* This component does not include the action menu (the right siderail). The [[ActionMenu]] component
* is provided separately.
*
* @param props.contextKey The context key (explained above)
*/
export function WorkspaceOverlay({ contextKey }: WorkspaceOverlayProps) {
const { workspaces } = useWorkspaces();
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,35 @@ export interface WorkspaceWindowProps {
additionalWorkspaceProps?: object;
}

/**
* Use this component to render the [workspace window](https://zeroheight.com/23a080e38/p/483a22-workspace)
* in an app such as the patient chart.
* When a workspace is opened, the other content on the screen will be pushed to the left.
*
* The context key is a string that appears in the URL, which defines the pages on which workspaces
* are valid. If the URL changes in a way such that it no longer contains the context key, then
* all workspaces will be closed. This ensures that, for example, workspaces on the home page do
* not stay open when the user transitions to the patient dashboard; and also that workspaces do
* not stay open when the user navigates to a different patient. The context key must be a valid
* sub-path of the URL, with no initial or trailing slash. So if the URL is
* `https://example.com/patient/123/foo`, then `patient` and `patient/123` and `123/foo` are valid
* context keys, but `patient/12` and `pati` are not.
*
* Workspaces may be opened with the [[launchWorkspace]] function from `@openmrs/esm-framework`
* (among other options).
*
* This component also provides everything needed for workspace notifications to be rendered.
*
* This component does not include the action menu (the right siderail). The [[ActionMenu]] component
* is provided separately.
*
* An extension slot is provided in the workspace header. Its name is derived from the `featureName` of
* the top-level component in which it is defined (feature names are generally provided in the lifecycle
* functions in an app's `index.ts` file). The slot is named `workspace-header-${featureName}-slot`.
* For the patient chart, this is `workspace-header-patient-chart-slot`.
*
* @param props.contextKey The context key (explained above)
*/
export function WorkspaceWindow({ contextKey, additionalWorkspaceProps }: WorkspaceWindowProps) {
const { active, workspaces, workspaceWindowState } = useWorkspaces();
const hidden = workspaceWindowState === 'hidden';
Expand Down