From c81f412fd52a463d6286dc0410b8ccdbc41b63f7 Mon Sep 17 00:00:00 2001 From: Charles Thao Date: Thu, 15 May 2025 10:50:23 -0400 Subject: [PATCH] feat(ws): Introduce drawer to workspace creation wizard (#310) fix(ws): Change label titles in Workspace Creation Add custom rules for drawer body to have full length Signed-off-by: Charles Thao --- .../Creation/WorkspaceCreationDrawer.tsx | 55 ++++++++++++++++++ .../image/WorkspaceCreationImageDetails.tsx | 7 +-- .../image/WorkspaceCreationImageSelection.tsx | 55 +++++++++++++----- .../kind/WorkspaceCreationKindDetails.tsx | 7 +-- .../kind/WorkspaceCreationKindSelection.tsx | 55 +++++++++++++----- .../WorkspaceCreationPodConfigDetails.tsx | 10 +--- .../WorkspaceCreationPodConfigSelection.tsx | 58 ++++++++++++++----- .../frontend/src/shared/style/MUI-theme.scss | 5 ++ 8 files changed, 190 insertions(+), 62 deletions(-) create mode 100644 workspaces/frontend/src/app/pages/Workspaces/Creation/WorkspaceCreationDrawer.tsx diff --git a/workspaces/frontend/src/app/pages/Workspaces/Creation/WorkspaceCreationDrawer.tsx b/workspaces/frontend/src/app/pages/Workspaces/Creation/WorkspaceCreationDrawer.tsx new file mode 100644 index 0000000..e9be4c4 --- /dev/null +++ b/workspaces/frontend/src/app/pages/Workspaces/Creation/WorkspaceCreationDrawer.tsx @@ -0,0 +1,55 @@ +import React, { Ref } from 'react'; +import { + Drawer, + DrawerPanelContent, + DrawerContent, + DrawerContentBody, + DrawerHead, + DrawerActions, + DrawerCloseButton, + Title, +} from '@patternfly/react-core'; + +interface WorkspaceCreationDrawerProps { + children: React.ReactNode; + title: string; + info: React.ReactNode; + isExpanded: boolean; + drawerRef?: Ref; + onCloseClick: () => void; + onExpand: () => void; +} + +export const WorkspaceCreationDrawer: React.FC = ({ + children, + isExpanded, + drawerRef, + title, + info, + onCloseClick, + onExpand, +}) => { + const panelContent = ( + + + }> + {title} + + + + + + {info} + + ); + + return ( + <> + + + {children} + + + + ); +}; diff --git a/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageDetails.tsx b/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageDetails.tsx index a1607c7..a909171 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageDetails.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageDetails.tsx @@ -9,12 +9,9 @@ type WorkspaceCreationImageDetailsProps = { export const WorkspaceCreationImageDetails: React.FunctionComponent< WorkspaceCreationImageDetailsProps > = ({ workspaceImage }) => ( - <> - {!workspaceImage &&

Select an image to view its details here.

} - +
{workspaceImage && ( <> - Image {workspaceImage.displayName}
@@ -26,5 +23,5 @@ export const WorkspaceCreationImageDetails: React.FunctionComponent< )} - +
); diff --git a/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageSelection.tsx b/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageSelection.tsx index e51580f..798e36f 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageSelection.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Creation/image/WorkspaceCreationImageSelection.tsx @@ -1,10 +1,10 @@ -import * as React from 'react'; +import React, { useMemo, useState, useCallback } from 'react'; import { Content, Divider, Split, SplitItem } from '@patternfly/react-core'; -import { useMemo, useState } from 'react'; import { WorkspaceCreationImageDetails } from '~/app/pages/Workspaces/Creation/image/WorkspaceCreationImageDetails'; import { WorkspaceCreationImageList } from '~/app/pages/Workspaces/Creation/image/WorkspaceCreationImageList'; import { FilterByLabels } from '~/app/pages/Workspaces/Creation/labelFilter/FilterByLabels'; import { WorkspaceImageConfigValue } from '~/shared/api/backendApiTypes'; +import { WorkspaceCreationDrawer } from '~/app/pages/Workspaces/Creation/WorkspaceCreationDrawer'; interface WorkspaceCreationImageSelectionProps { images: WorkspaceImageConfigValue[]; @@ -16,6 +16,26 @@ const WorkspaceCreationImageSelection: React.FunctionComponent< WorkspaceCreationImageSelectionProps > = ({ images, selectedImage, onSelect }) => { const [selectedLabels, setSelectedLabels] = useState>>(new Map()); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = React.useRef(undefined); + + const onExpand = useCallback(() => { + if (drawerRef.current) { + drawerRef.current.focus(); + } + }, []); + + const onClick = useCallback( + (image?: WorkspaceImageConfigValue) => { + setIsExpanded(true); + onSelect(image); + }, + [onSelect], + ); + + const onCloseClick = useCallback(() => { + setIsExpanded(false); + }, []); const imageFilterContent = useMemo( () => ( @@ -37,18 +57,25 @@ const WorkspaceCreationImageSelection: React.FunctionComponent<

Select a workspace image and image version to use for the workspace.

- - {imageFilterContent} - - - - {imageDetailsContent} - + + + {imageFilterContent} + + + + +
); }; diff --git a/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindDetails.tsx b/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindDetails.tsx index 09897d0..5330864 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindDetails.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindDetails.tsx @@ -9,15 +9,12 @@ type WorkspaceCreationKindDetailsProps = { export const WorkspaceCreationKindDetails: React.FunctionComponent< WorkspaceCreationKindDetailsProps > = ({ workspaceKind }) => ( - <> - {!workspaceKind &&

Select a workspace kind to view its details here.

} - +
{workspaceKind && ( <> - Workspace kind {workspaceKind.name}

{workspaceKind.description}

)} - +
); diff --git a/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindSelection.tsx b/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindSelection.tsx index 24a567d..d7d0b4c 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindSelection.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindSelection.tsx @@ -1,10 +1,10 @@ -import * as React from 'react'; -import { Content, Divider, Split, SplitItem } from '@patternfly/react-core'; -import { useMemo } from 'react'; +import React, { useState, useRef, useMemo, useCallback } from 'react'; +import { Content, Divider } from '@patternfly/react-core'; import { WorkspaceKind } from '~/shared/api/backendApiTypes'; +import useWorkspaceKinds from '~/app/hooks/useWorkspaceKinds'; import { WorkspaceCreationKindDetails } from '~/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindDetails'; import { WorkspaceCreationKindList } from '~/app/pages/Workspaces/Creation/kind/WorkspaceCreationKindList'; -import useWorkspaceKinds from '~/app/hooks/useWorkspaceKinds'; +import { WorkspaceCreationDrawer } from '~/app/pages/Workspaces/Creation/WorkspaceCreationDrawer'; interface WorkspaceCreationKindSelectionProps { selectedKind: WorkspaceKind | undefined; @@ -15,6 +15,26 @@ const WorkspaceCreationKindSelection: React.FunctionComponent< WorkspaceCreationKindSelectionProps > = ({ selectedKind, onSelect }) => { const [workspaceKinds, loaded, error] = useWorkspaceKinds(); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = useRef(undefined); + + const onExpand = useCallback(() => { + if (drawerRef.current) { + drawerRef.current.focus(); + } + }, []); + + const onClick = useCallback( + (kind?: WorkspaceKind) => { + setIsExpanded(true); + onSelect(kind); + }, + [onSelect], + ); + + const onCloseClick = useCallback(() => { + setIsExpanded(false); + }, []); const kindDetailsContent = useMemo( () => , @@ -31,18 +51,21 @@ const WorkspaceCreationKindSelection: React.FunctionComponent< return ( -

Select a workspace kind to use for the workspace.

- - - - - - {kindDetailsContent} - + +

Select a workspace kind to use for the workspace.

+ + +
); }; diff --git a/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigDetails.tsx b/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigDetails.tsx index 86413d2..87bb4d9 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigDetails.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigDetails.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { List, ListItem, Title } from '@patternfly/react-core'; +import { List, ListItem } from '@patternfly/react-core'; import { WorkspacePodConfigValue } from '~/shared/api/backendApiTypes'; type WorkspaceCreationPodConfigDetailsProps = { @@ -10,12 +10,8 @@ export const WorkspaceCreationPodConfigDetails: React.FunctionComponent< WorkspaceCreationPodConfigDetailsProps > = ({ workspacePodConfig }) => ( <> - {!workspacePodConfig &&

Select a pod config to view its details here.

} - {workspacePodConfig && ( - <> - Pod config - {workspacePodConfig.displayName} +

{workspacePodConfig.description}

{workspacePodConfig.labels.map((label) => ( @@ -24,7 +20,7 @@ export const WorkspaceCreationPodConfigDetails: React.FunctionComponent< ))} - +
)} ); diff --git a/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigSelection.tsx b/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigSelection.tsx index 63317cd..0de865f 100644 --- a/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigSelection.tsx +++ b/workspaces/frontend/src/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigSelection.tsx @@ -1,10 +1,10 @@ -import * as React from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { Content, Divider, Split, SplitItem } from '@patternfly/react-core'; -import { useMemo, useState } from 'react'; -import { WorkspacePodConfigValue } from '~/shared/api/backendApiTypes'; import { WorkspaceCreationPodConfigDetails } from '~/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigDetails'; import { WorkspaceCreationPodConfigList } from '~/app/pages/Workspaces/Creation/podConfig/WorkspaceCreationPodConfigList'; import { FilterByLabels } from '~/app/pages/Workspaces/Creation/labelFilter/FilterByLabels'; +import { WorkspaceCreationDrawer } from '~/app/pages/Workspaces/Creation/WorkspaceCreationDrawer'; +import { WorkspacePodConfigValue } from '~/shared/api/backendApiTypes'; interface WorkspaceCreationPodConfigSelectionProps { podConfigs: WorkspacePodConfigValue[]; @@ -16,6 +16,26 @@ const WorkspaceCreationPodConfigSelection: React.FunctionComponent< WorkspaceCreationPodConfigSelectionProps > = ({ podConfigs, selectedPodConfig, onSelect }) => { const [selectedLabels, setSelectedLabels] = useState>>(new Map()); + const [isExpanded, setIsExpanded] = useState(false); + const drawerRef = React.useRef(undefined); + + const onExpand = useCallback(() => { + if (drawerRef.current) { + drawerRef.current.focus(); + } + }, []); + + const onClick = useCallback( + (podConfig?: WorkspacePodConfigValue) => { + setIsExpanded(true); + onSelect(podConfig); + }, + [onSelect], + ); + + const onCloseClick = useCallback(() => { + setIsExpanded(false); + }, []); const podConfigFilterContent = useMemo( () => ( @@ -37,18 +57,26 @@ const WorkspaceCreationPodConfigSelection: React.FunctionComponent<

Select a pod config to use for the workspace.

- - {podConfigFilterContent} - - - - {podConfigDetailsContent} - + + + + {podConfigFilterContent} + + + + +
); }; diff --git a/workspaces/frontend/src/shared/style/MUI-theme.scss b/workspaces/frontend/src/shared/style/MUI-theme.scss index d16fb64..b973d5b 100644 --- a/workspaces/frontend/src/shared/style/MUI-theme.scss +++ b/workspaces/frontend/src/shared/style/MUI-theme.scss @@ -769,6 +769,11 @@ flex-grow: 0; } +// TODO: Remove when https://github.com/patternfly/patternfly-react/issues/11826 is resolved. +.pf-v6-c-page__main-section .pf-v6-c-page__main-body { + height: 100%; +} + .mui-theme .pf-v6-c-pagination { --pf-v6-c-pagination__total-items--Display: block; }