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 <cthao@redhat.com>
This commit is contained in:
parent
273cdc92d2
commit
c81f412fd5
|
@ -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<HTMLSpanElement>;
|
||||
onCloseClick: () => void;
|
||||
onExpand: () => void;
|
||||
}
|
||||
|
||||
export const WorkspaceCreationDrawer: React.FC<WorkspaceCreationDrawerProps> = ({
|
||||
children,
|
||||
isExpanded,
|
||||
drawerRef,
|
||||
title,
|
||||
info,
|
||||
onCloseClick,
|
||||
onExpand,
|
||||
}) => {
|
||||
const panelContent = (
|
||||
<DrawerPanelContent>
|
||||
<DrawerHead>
|
||||
<span role="button" tabIndex={isExpanded ? 0 : -1} ref={drawerRef as Ref<HTMLSpanElement>}>
|
||||
<Title headingLevel="h6">{title}</Title>
|
||||
</span>
|
||||
<DrawerActions>
|
||||
<DrawerCloseButton onClick={onCloseClick} />
|
||||
</DrawerActions>
|
||||
</DrawerHead>
|
||||
{info}
|
||||
</DrawerPanelContent>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer isExpanded={isExpanded} isInline onExpand={onExpand}>
|
||||
<DrawerContent panelContent={panelContent}>
|
||||
<DrawerContentBody>{children}</DrawerContentBody>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -9,12 +9,9 @@ type WorkspaceCreationImageDetailsProps = {
|
|||
export const WorkspaceCreationImageDetails: React.FunctionComponent<
|
||||
WorkspaceCreationImageDetailsProps
|
||||
> = ({ workspaceImage }) => (
|
||||
<>
|
||||
{!workspaceImage && <p>Select an image to view its details here.</p>}
|
||||
|
||||
<div style={{ marginLeft: 'var(--pf-t--global--spacer--md)' }}>
|
||||
{workspaceImage && (
|
||||
<>
|
||||
<Title headingLevel="h6">Image</Title>
|
||||
<Title headingLevel="h3">{workspaceImage.displayName}</Title>
|
||||
<br />
|
||||
<List isPlain>
|
||||
|
@ -26,5 +23,5 @@ export const WorkspaceCreationImageDetails: React.FunctionComponent<
|
|||
</List>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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<Map<string, Set<string>>>(new Map());
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const drawerRef = React.useRef<HTMLSpanElement>(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<
|
|||
<Content style={{ height: '100%' }}>
|
||||
<p>Select a workspace image and image version to use for the workspace.</p>
|
||||
<Divider />
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{imageFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceCreationImageList
|
||||
images={images}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedImage={selectedImage}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</SplitItem>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{imageDetailsContent}</SplitItem>
|
||||
</Split>
|
||||
<WorkspaceCreationDrawer
|
||||
title="Image"
|
||||
info={imageDetailsContent}
|
||||
isExpanded={isExpanded}
|
||||
onCloseClick={onCloseClick}
|
||||
onExpand={onExpand}
|
||||
>
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{imageFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceCreationImageList
|
||||
images={images}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedImage={selectedImage}
|
||||
onSelect={onClick}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</WorkspaceCreationDrawer>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,15 +9,12 @@ type WorkspaceCreationKindDetailsProps = {
|
|||
export const WorkspaceCreationKindDetails: React.FunctionComponent<
|
||||
WorkspaceCreationKindDetailsProps
|
||||
> = ({ workspaceKind }) => (
|
||||
<>
|
||||
{!workspaceKind && <p>Select a workspace kind to view its details here.</p>}
|
||||
|
||||
<div style={{ marginLeft: 'var(--pf-t--global--spacer--md)' }}>
|
||||
{workspaceKind && (
|
||||
<>
|
||||
<Title headingLevel="h6">Workspace kind</Title>
|
||||
<Title headingLevel="h3">{workspaceKind.name}</Title>
|
||||
<p>{workspaceKind.description}</p>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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<HTMLSpanElement>(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(
|
||||
() => <WorkspaceCreationKindDetails workspaceKind={selectedKind} />,
|
||||
|
@ -31,18 +51,21 @@ const WorkspaceCreationKindSelection: React.FunctionComponent<
|
|||
|
||||
return (
|
||||
<Content style={{ height: '100%' }}>
|
||||
<p>Select a workspace kind to use for the workspace.</p>
|
||||
<Divider />
|
||||
<Split hasGutter>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceCreationKindList
|
||||
allWorkspaceKinds={workspaceKinds}
|
||||
selectedKind={selectedKind}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</SplitItem>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{kindDetailsContent}</SplitItem>
|
||||
</Split>
|
||||
<WorkspaceCreationDrawer
|
||||
title="Workspace kind"
|
||||
info={kindDetailsContent}
|
||||
isExpanded={isExpanded}
|
||||
onCloseClick={onCloseClick}
|
||||
onExpand={onExpand}
|
||||
>
|
||||
<p>Select a workspace kind to use for the workspace.</p>
|
||||
<Divider />
|
||||
<WorkspaceCreationKindList
|
||||
allWorkspaceKinds={workspaceKinds}
|
||||
selectedKind={selectedKind}
|
||||
onSelect={onClick}
|
||||
/>
|
||||
</WorkspaceCreationDrawer>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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 && <p>Select a pod config to view its details here.</p>}
|
||||
|
||||
{workspacePodConfig && (
|
||||
<>
|
||||
<Title headingLevel="h6">Pod config</Title>
|
||||
<Title headingLevel="h3">{workspacePodConfig.displayName}</Title>
|
||||
<div style={{ marginLeft: 'var(--pf-t--global--spacer--md)' }}>
|
||||
<p>{workspacePodConfig.description}</p>
|
||||
<List isPlain>
|
||||
{workspacePodConfig.labels.map((label) => (
|
||||
|
@ -24,7 +20,7 @@ export const WorkspaceCreationPodConfigDetails: React.FunctionComponent<
|
|||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -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<Map<string, Set<string>>>(new Map());
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const drawerRef = React.useRef<HTMLSpanElement>(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<
|
|||
<Content style={{ height: '100%' }}>
|
||||
<p>Select a pod config to use for the workspace.</p>
|
||||
<Divider />
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{podConfigFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceCreationPodConfigList
|
||||
podConfigs={podConfigs}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedPodConfig={selectedPodConfig}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</SplitItem>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{podConfigDetailsContent}</SplitItem>
|
||||
</Split>
|
||||
|
||||
<WorkspaceCreationDrawer
|
||||
title="Pod config"
|
||||
info={podConfigDetailsContent}
|
||||
isExpanded={isExpanded}
|
||||
onCloseClick={onCloseClick}
|
||||
onExpand={onExpand}
|
||||
>
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{podConfigFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceCreationPodConfigList
|
||||
podConfigs={podConfigs}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedPodConfig={selectedPodConfig}
|
||||
onSelect={onClick}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</WorkspaceCreationDrawer>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue