fix(ws): Implement dual scrolling for workspace kind wizard (#484)
Signed-off-by: Jenny <32821331+jenny-s51@users.noreply.github.com> fix(ws): remove extra DrawerPanelBody remove unused file Signed-off-by: Jenny <32821331+jenny-s51@users.noreply.github.com> fix(ws): remove comment and hide drawer on previousStep callback Signed-off-by: Jenny <32821331+jenny-s51@users.noreply.github.com> fix(ws): when navigating between wizard steps, show drawer for steps that have drawer content
This commit is contained in:
parent
e05d4ad298
commit
3542f848de
|
@ -2,14 +2,21 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||
import {
|
||||
Button,
|
||||
Content,
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerContentBody,
|
||||
DrawerPanelContent,
|
||||
DrawerHead,
|
||||
DrawerActions,
|
||||
DrawerCloseButton,
|
||||
DrawerPanelBody,
|
||||
Flex,
|
||||
FlexItem,
|
||||
PageGroup,
|
||||
PageSection,
|
||||
ProgressStep,
|
||||
ProgressStepper,
|
||||
Stack,
|
||||
StackItem,
|
||||
Title,
|
||||
} from '@patternfly/react-core';
|
||||
import useGenericObjectState from '~/app/hooks/useGenericObjectState';
|
||||
import { useNotebookAPI } from '~/app/hooks/useNotebookAPI';
|
||||
|
@ -18,10 +25,18 @@ import { WorkspaceFormKindSelection } from '~/app/pages/Workspaces/Form/kind/Wor
|
|||
import { WorkspaceFormPodConfigSelection } from '~/app/pages/Workspaces/Form/podConfig/WorkspaceFormPodConfigSelection';
|
||||
import { WorkspaceFormPropertiesSelection } from '~/app/pages/Workspaces/Form/properties/WorkspaceFormPropertiesSelection';
|
||||
import { WorkspaceFormData } from '~/app/types';
|
||||
import { WorkspaceCreate } from '~/shared/api/backendApiTypes';
|
||||
import {
|
||||
WorkspaceCreate,
|
||||
WorkspaceKind,
|
||||
WorkspaceImageConfigValue,
|
||||
WorkspacePodConfigValue,
|
||||
} from '~/shared/api/backendApiTypes';
|
||||
import useWorkspaceFormData from '~/app/hooks/useWorkspaceFormData';
|
||||
import { useTypedNavigate } from '~/app/routerHelper';
|
||||
import { useWorkspaceFormLocationData } from '~/app/hooks/useWorkspaceFormLocationData';
|
||||
import { WorkspaceFormKindDetails } from '~/app/pages/Workspaces/Form/kind/WorkspaceFormKindDetails';
|
||||
import { WorkspaceFormImageDetails } from '~/app/pages/Workspaces/Form/image/WorkspaceFormImageDetails';
|
||||
import { WorkspaceFormPodConfigDetails } from '~/app/pages/Workspaces/Form/podConfig/WorkspaceFormPodConfigDetails';
|
||||
|
||||
enum WorkspaceFormSteps {
|
||||
KindSelection,
|
||||
|
@ -52,6 +67,7 @@ const WorkspaceForm: React.FC = () => {
|
|||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(WorkspaceFormSteps.KindSelection);
|
||||
const [drawerExpanded, setDrawerExpanded] = useState(false);
|
||||
|
||||
const [data, setData, resetData, replaceData] =
|
||||
useGenericObjectState<WorkspaceFormData>(initialFormData);
|
||||
|
@ -76,30 +92,46 @@ const WorkspaceForm: React.FC = () => {
|
|||
[currentStep],
|
||||
);
|
||||
|
||||
const isStepValid = useCallback(
|
||||
(step: WorkspaceFormSteps) => {
|
||||
switch (step) {
|
||||
case WorkspaceFormSteps.KindSelection:
|
||||
return !!data.kind;
|
||||
case WorkspaceFormSteps.ImageSelection:
|
||||
return !!data.image;
|
||||
case WorkspaceFormSteps.PodConfigSelection:
|
||||
return !!data.podConfig;
|
||||
case WorkspaceFormSteps.Properties:
|
||||
return !!data.properties.workspaceName.trim();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[data.kind, data.image, data.podConfig, data.properties.workspaceName],
|
||||
);
|
||||
|
||||
const showDrawer = useCallback(
|
||||
(step: WorkspaceFormSteps) =>
|
||||
// Only show drawer for steps that have drawer content
|
||||
step !== WorkspaceFormSteps.Properties && isStepValid(step),
|
||||
[isStepValid],
|
||||
);
|
||||
|
||||
const previousStep = useCallback(() => {
|
||||
setCurrentStep(currentStep - 1);
|
||||
}, [currentStep]);
|
||||
const newStep = currentStep - 1;
|
||||
setCurrentStep(newStep);
|
||||
setDrawerExpanded(showDrawer(newStep));
|
||||
}, [currentStep, showDrawer]);
|
||||
|
||||
const nextStep = useCallback(() => {
|
||||
setCurrentStep(currentStep + 1);
|
||||
}, [currentStep]);
|
||||
const newStep = currentStep + 1;
|
||||
setCurrentStep(newStep);
|
||||
setDrawerExpanded(showDrawer(newStep));
|
||||
}, [currentStep, showDrawer]);
|
||||
|
||||
const canGoToPreviousStep = useMemo(() => currentStep > 0, [currentStep]);
|
||||
|
||||
const isCurrentStepValid = useMemo(() => {
|
||||
switch (currentStep) {
|
||||
case WorkspaceFormSteps.KindSelection:
|
||||
return !!data.kind;
|
||||
case WorkspaceFormSteps.ImageSelection:
|
||||
return !!data.image;
|
||||
case WorkspaceFormSteps.PodConfigSelection:
|
||||
return !!data.podConfig;
|
||||
case WorkspaceFormSteps.Properties:
|
||||
return !!data.properties.workspaceName.trim();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}, [currentStep, data]);
|
||||
const isCurrentStepValid = useMemo(() => isStepValid(currentStep), [isStepValid, currentStep]);
|
||||
|
||||
const canGoToNextStep = useMemo(
|
||||
() => currentStep < Object.keys(WorkspaceFormSteps).length / 2 - 1,
|
||||
|
@ -168,6 +200,63 @@ const WorkspaceForm: React.FC = () => {
|
|||
navigate('workspaces');
|
||||
}, [navigate]);
|
||||
|
||||
const handleKindSelect = useCallback(
|
||||
(kind: WorkspaceKind | undefined) => {
|
||||
if (kind) {
|
||||
resetData();
|
||||
setData('kind', kind);
|
||||
setDrawerExpanded(true);
|
||||
}
|
||||
},
|
||||
[resetData, setData],
|
||||
);
|
||||
|
||||
const handleImageSelect = useCallback(
|
||||
(image: WorkspaceImageConfigValue | undefined) => {
|
||||
if (image) {
|
||||
setData('image', image);
|
||||
setDrawerExpanded(true);
|
||||
}
|
||||
},
|
||||
[setData],
|
||||
);
|
||||
|
||||
const handlePodConfigSelect = useCallback(
|
||||
(podConfig: WorkspacePodConfigValue | undefined) => {
|
||||
if (podConfig) {
|
||||
setData('podConfig', podConfig);
|
||||
setDrawerExpanded(true);
|
||||
}
|
||||
},
|
||||
[setData],
|
||||
);
|
||||
|
||||
const getDrawerContent = () => {
|
||||
switch (currentStep) {
|
||||
case WorkspaceFormSteps.KindSelection:
|
||||
return <WorkspaceFormKindDetails workspaceKind={data.kind} />;
|
||||
case WorkspaceFormSteps.ImageSelection:
|
||||
return <WorkspaceFormImageDetails workspaceImage={data.image} />;
|
||||
case WorkspaceFormSteps.PodConfigSelection:
|
||||
return <WorkspaceFormPodConfigDetails workspacePodConfig={data.podConfig} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const getDrawerTitle = () => {
|
||||
switch (currentStep) {
|
||||
case WorkspaceFormSteps.KindSelection:
|
||||
return 'Workspace Kind';
|
||||
case WorkspaceFormSteps.ImageSelection:
|
||||
return 'Image';
|
||||
case WorkspaceFormSteps.PodConfigSelection:
|
||||
return 'Pod Config';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
if (initialFormDataError) {
|
||||
return <p>Error loading workspace data: {initialFormDataError.message}</p>; // TODO: UX for error state
|
||||
}
|
||||
|
@ -176,137 +265,160 @@ const WorkspaceForm: React.FC = () => {
|
|||
return <p>Loading...</p>; // TODO: UX for loading state
|
||||
}
|
||||
|
||||
const panelContent = (
|
||||
<DrawerPanelContent>
|
||||
<DrawerHead>
|
||||
<Title headingLevel="h1">{getDrawerTitle()}</Title>
|
||||
<DrawerActions>
|
||||
<DrawerCloseButton onClick={() => setDrawerExpanded(false)} />
|
||||
</DrawerActions>
|
||||
</DrawerHead>
|
||||
<DrawerPanelBody className="workspace-form__drawer-panel-body">
|
||||
{getDrawerContent()}
|
||||
</DrawerPanelBody>
|
||||
</DrawerPanelContent>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageGroup isFilled={false} stickyOnBreakpoint={{ default: 'top' }}>
|
||||
<PageSection>
|
||||
<Stack hasGutter>
|
||||
<Flex direction={{ default: 'column' }} rowGap={{ default: 'rowGapXl' }}>
|
||||
<FlexItem>
|
||||
<Content>
|
||||
<h1>{`${mode === 'create' ? 'Create' : 'Edit'} workspace`}</h1>
|
||||
</Content>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<ProgressStepper aria-label="Workspace form stepper">
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.KindSelection)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.KindSelection}
|
||||
id="kind-selection-step"
|
||||
titleId="kind-selection-step-title"
|
||||
aria-label="Kind selection step"
|
||||
>
|
||||
Workspace Kind
|
||||
</ProgressStep>
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.ImageSelection)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.ImageSelection}
|
||||
id="image-selection-step"
|
||||
titleId="image-selection-step-title"
|
||||
aria-label="Image selection step"
|
||||
>
|
||||
Image
|
||||
</ProgressStep>
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.PodConfigSelection)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.PodConfigSelection}
|
||||
id="pod-config-selection-step"
|
||||
titleId="pod-config-selection-step-title"
|
||||
aria-label="Pod config selection step"
|
||||
>
|
||||
Pod Config
|
||||
</ProgressStep>
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.Properties)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.Properties}
|
||||
id="properties-step"
|
||||
titleId="properties-step-title"
|
||||
aria-label="Properties step"
|
||||
>
|
||||
Properties
|
||||
</ProgressStep>
|
||||
</ProgressStepper>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
<StackItem>
|
||||
<p>{stepDescriptions[currentStep]}</p>
|
||||
</StackItem>
|
||||
</Stack>
|
||||
</PageSection>
|
||||
</PageGroup>
|
||||
<PageSection isFilled>
|
||||
{currentStep === WorkspaceFormSteps.KindSelection && (
|
||||
<WorkspaceFormKindSelection
|
||||
selectedKind={data.kind}
|
||||
onSelect={(kind) => {
|
||||
resetData();
|
||||
setData('kind', kind);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{currentStep === WorkspaceFormSteps.ImageSelection && (
|
||||
<WorkspaceFormImageSelection
|
||||
selectedImage={data.image}
|
||||
onSelect={(image) => setData('image', image)}
|
||||
images={data.kind?.podTemplate.options.imageConfig.values ?? []}
|
||||
/>
|
||||
)}
|
||||
{currentStep === WorkspaceFormSteps.PodConfigSelection && (
|
||||
<WorkspaceFormPodConfigSelection
|
||||
selectedPodConfig={data.podConfig}
|
||||
onSelect={(podConfig) => setData('podConfig', podConfig)}
|
||||
podConfigs={data.kind?.podTemplate.options.podConfig.values ?? []}
|
||||
/>
|
||||
)}
|
||||
{currentStep === WorkspaceFormSteps.Properties && (
|
||||
<WorkspaceFormPropertiesSelection
|
||||
selectedProperties={data.properties}
|
||||
onSelect={(properties) => setData('properties', properties)}
|
||||
selectedImage={data.image}
|
||||
/>
|
||||
)}
|
||||
</PageSection>
|
||||
<PageSection isFilled={false} stickyOnBreakpoint={{ default: 'bottom' }}>
|
||||
<Flex>
|
||||
<FlexItem>
|
||||
<Button
|
||||
variant="secondary"
|
||||
ouiaId="Secondary"
|
||||
onClick={previousStep}
|
||||
isDisabled={!canGoToPreviousStep}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
{canGoToNextStep ? (
|
||||
<Button
|
||||
variant="primary"
|
||||
ouiaId="Primary"
|
||||
onClick={nextStep}
|
||||
isDisabled={!isCurrentStepValid}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="primary"
|
||||
ouiaId="Primary"
|
||||
onClick={handleSubmit}
|
||||
isDisabled={!canSubmit}
|
||||
>
|
||||
{mode === 'create' ? 'Create' : 'Save'}
|
||||
</Button>
|
||||
)}
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<Button variant="link" isInline onClick={cancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
</PageSection>
|
||||
</>
|
||||
<Drawer isInline isExpanded={drawerExpanded}>
|
||||
<DrawerContent panelContent={panelContent}>
|
||||
<DrawerContentBody>
|
||||
<Flex
|
||||
direction={{ default: 'column' }}
|
||||
flexWrap={{ default: 'nowrap' }}
|
||||
style={{ height: '100%' }}
|
||||
>
|
||||
<FlexItem>
|
||||
<PageSection>
|
||||
<Stack hasGutter>
|
||||
<Flex direction={{ default: 'column' }} rowGap={{ default: 'rowGapXl' }}>
|
||||
<FlexItem>
|
||||
<Content>
|
||||
<h1>{`${mode === 'create' ? 'Create' : 'Edit'} workspace`}</h1>
|
||||
<p>{stepDescriptions[currentStep]}</p>
|
||||
</Content>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<ProgressStepper aria-label="Workspace form stepper">
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.KindSelection)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.KindSelection}
|
||||
id="kind-selection-step"
|
||||
titleId="kind-selection-step-title"
|
||||
aria-label="Kind selection step"
|
||||
>
|
||||
Workspace Kind
|
||||
</ProgressStep>
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.ImageSelection)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.ImageSelection}
|
||||
id="image-selection-step"
|
||||
titleId="image-selection-step-title"
|
||||
aria-label="Image selection step"
|
||||
>
|
||||
Image
|
||||
</ProgressStep>
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.PodConfigSelection)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.PodConfigSelection}
|
||||
id="pod-config-selection-step"
|
||||
titleId="pod-config-selection-step-title"
|
||||
aria-label="Pod config selection step"
|
||||
>
|
||||
Pod Config
|
||||
</ProgressStep>
|
||||
<ProgressStep
|
||||
variant={getStepVariant(WorkspaceFormSteps.Properties)}
|
||||
isCurrent={currentStep === WorkspaceFormSteps.Properties}
|
||||
id="properties-step"
|
||||
titleId="properties-step-title"
|
||||
aria-label="Properties step"
|
||||
>
|
||||
Properties
|
||||
</ProgressStep>
|
||||
</ProgressStepper>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
</Stack>
|
||||
</PageSection>
|
||||
</FlexItem>
|
||||
<FlexItem flex={{ default: 'flex_1' }}>
|
||||
<PageSection isFilled>
|
||||
{currentStep === WorkspaceFormSteps.KindSelection && (
|
||||
<WorkspaceFormKindSelection
|
||||
selectedKind={data.kind}
|
||||
onSelect={handleKindSelect}
|
||||
/>
|
||||
)}
|
||||
{currentStep === WorkspaceFormSteps.ImageSelection && (
|
||||
<WorkspaceFormImageSelection
|
||||
selectedImage={data.image}
|
||||
onSelect={handleImageSelect}
|
||||
images={data.kind?.podTemplate.options.imageConfig.values ?? []}
|
||||
/>
|
||||
)}
|
||||
{currentStep === WorkspaceFormSteps.PodConfigSelection && (
|
||||
<WorkspaceFormPodConfigSelection
|
||||
selectedPodConfig={data.podConfig}
|
||||
onSelect={handlePodConfigSelect}
|
||||
podConfigs={data.kind?.podTemplate.options.podConfig.values ?? []}
|
||||
/>
|
||||
)}
|
||||
{currentStep === WorkspaceFormSteps.Properties && (
|
||||
<WorkspaceFormPropertiesSelection
|
||||
selectedProperties={data.properties}
|
||||
onSelect={(properties) => setData('properties', properties)}
|
||||
selectedImage={data.image}
|
||||
/>
|
||||
)}
|
||||
</PageSection>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<PageSection>
|
||||
<Flex>
|
||||
<FlexItem>
|
||||
<Button
|
||||
variant="secondary"
|
||||
ouiaId="Secondary"
|
||||
onClick={previousStep}
|
||||
isDisabled={!canGoToPreviousStep}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
{canGoToNextStep ? (
|
||||
<Button
|
||||
variant="primary"
|
||||
ouiaId="Primary"
|
||||
onClick={nextStep}
|
||||
isDisabled={!isCurrentStepValid}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="primary"
|
||||
ouiaId="Primary"
|
||||
onClick={handleSubmit}
|
||||
isDisabled={!canSubmit}
|
||||
>
|
||||
{mode === 'create' ? 'Create' : 'Save'}
|
||||
</Button>
|
||||
)}
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<Button variant="link" isInline onClick={cancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
</PageSection>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
</DrawerContentBody>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ type WorkspaceFormImageDetailsProps = {
|
|||
export const WorkspaceFormImageDetails: React.FunctionComponent<WorkspaceFormImageDetailsProps> = ({
|
||||
workspaceImage,
|
||||
}) => (
|
||||
<div style={{ marginLeft: 'var(--pf-t--global--spacer--md)' }}>
|
||||
<>
|
||||
{workspaceImage && (
|
||||
<>
|
||||
<Title headingLevel="h3">{workspaceImage.displayName}</Title>
|
||||
|
@ -38,5 +38,5 @@ export const WorkspaceFormImageDetails: React.FunctionComponent<WorkspaceFormIma
|
|||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Content, Split, SplitItem } from '@patternfly/react-core';
|
||||
import { WorkspaceFormImageDetails } from '~/app/pages/Workspaces/Form/image/WorkspaceFormImageDetails';
|
||||
import { WorkspaceFormImageList } from '~/app/pages/Workspaces/Form/image/WorkspaceFormImageList';
|
||||
import { FilterByLabels } from '~/app/pages/Workspaces/Form/labelFilter/FilterByLabels';
|
||||
import { WorkspaceImageConfigValue } from '~/shared/api/backendApiTypes';
|
||||
import { WorkspaceFormDrawer } from '~/app/pages/Workspaces/Form/WorkspaceFormDrawer';
|
||||
|
||||
interface WorkspaceFormImageSelectionProps {
|
||||
images: WorkspaceImageConfigValue[];
|
||||
|
@ -18,26 +16,6 @@ const WorkspaceFormImageSelection: React.FunctionComponent<WorkspaceFormImageSel
|
|||
onSelect,
|
||||
}) => {
|
||||
const [selectedLabels, setSelectedLabels] = useState<Map<string, Set<string>>>(new Map());
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const drawerRef = 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(
|
||||
() => (
|
||||
|
@ -50,32 +28,19 @@ const WorkspaceFormImageSelection: React.FunctionComponent<WorkspaceFormImageSel
|
|||
[images, selectedLabels, setSelectedLabels],
|
||||
);
|
||||
|
||||
const imageDetailsContent = useMemo(
|
||||
() => <WorkspaceFormImageDetails workspaceImage={selectedImage} />,
|
||||
[selectedImage],
|
||||
);
|
||||
|
||||
return (
|
||||
<Content style={{ height: '100%' }}>
|
||||
<WorkspaceFormDrawer
|
||||
title="Image"
|
||||
info={imageDetailsContent}
|
||||
isExpanded={isExpanded}
|
||||
onCloseClick={onCloseClick}
|
||||
onExpand={onExpand}
|
||||
>
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{imageFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceFormImageList
|
||||
images={images}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedImage={selectedImage}
|
||||
onSelect={onClick}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</WorkspaceFormDrawer>
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{imageFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceFormImageList
|
||||
images={images}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedImage={selectedImage}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -9,12 +9,12 @@ type WorkspaceFormKindDetailsProps = {
|
|||
export const WorkspaceFormKindDetails: React.FunctionComponent<WorkspaceFormKindDetailsProps> = ({
|
||||
workspaceKind,
|
||||
}) => (
|
||||
<div style={{ marginLeft: 'var(--pf-t--global--spacer--md)' }}>
|
||||
<>
|
||||
{workspaceKind && (
|
||||
<>
|
||||
<Title headingLevel="h3">{workspaceKind.displayName}</Title>
|
||||
<p>{workspaceKind.description}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import React from 'react';
|
||||
import { Content } from '@patternfly/react-core';
|
||||
import { WorkspaceKind } from '~/shared/api/backendApiTypes';
|
||||
import useWorkspaceKinds from '~/app/hooks/useWorkspaceKinds';
|
||||
import { WorkspaceFormKindDetails } from '~/app/pages/Workspaces/Form/kind/WorkspaceFormKindDetails';
|
||||
import { WorkspaceFormKindList } from '~/app/pages/Workspaces/Form/kind/WorkspaceFormKindList';
|
||||
import { WorkspaceFormDrawer } from '~/app/pages/Workspaces/Form/WorkspaceFormDrawer';
|
||||
|
||||
interface WorkspaceFormKindSelectionProps {
|
||||
selectedKind: WorkspaceKind | undefined;
|
||||
|
@ -16,31 +14,6 @@ const WorkspaceFormKindSelection: React.FunctionComponent<WorkspaceFormKindSelec
|
|||
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(
|
||||
() => <WorkspaceFormKindDetails workspaceKind={selectedKind} />,
|
||||
[selectedKind],
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return <p>Error loading workspace kinds: {error.message}</p>; // TODO: UX for error state
|
||||
|
@ -52,19 +25,11 @@ const WorkspaceFormKindSelection: React.FunctionComponent<WorkspaceFormKindSelec
|
|||
|
||||
return (
|
||||
<Content style={{ height: '100%' }}>
|
||||
<WorkspaceFormDrawer
|
||||
title="Workspace kind"
|
||||
info={kindDetailsContent}
|
||||
isExpanded={isExpanded}
|
||||
onCloseClick={onCloseClick}
|
||||
onExpand={onExpand}
|
||||
>
|
||||
<WorkspaceFormKindList
|
||||
allWorkspaceKinds={workspaceKinds}
|
||||
selectedKind={selectedKind}
|
||||
onSelect={onClick}
|
||||
/>
|
||||
</WorkspaceFormDrawer>
|
||||
<WorkspaceFormKindList
|
||||
allWorkspaceKinds={workspaceKinds}
|
||||
selectedKind={selectedKind}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -19,10 +19,12 @@ export const WorkspaceFormPodConfigDetails: React.FunctionComponent<
|
|||
> = ({ workspacePodConfig }) => (
|
||||
<>
|
||||
{workspacePodConfig && (
|
||||
<div style={{ marginLeft: 'var(--pf-t--global--spacer--md)' }}>
|
||||
<>
|
||||
<Title headingLevel="h3">{workspacePodConfig.displayName}</Title>{' '}
|
||||
<p>{workspacePodConfig.description}</p>
|
||||
<br />
|
||||
<Divider />
|
||||
<br />
|
||||
{workspacePodConfig.labels.map((label) => (
|
||||
<DescriptionList
|
||||
key={label.key}
|
||||
|
@ -37,7 +39,7 @@ export const WorkspaceFormPodConfigDetails: React.FunctionComponent<
|
|||
</DescriptionListGroup>
|
||||
</DescriptionList>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { Content, Split, SplitItem } from '@patternfly/react-core';
|
||||
import { WorkspaceFormPodConfigDetails } from '~/app/pages/Workspaces/Form/podConfig/WorkspaceFormPodConfigDetails';
|
||||
import { WorkspaceFormPodConfigList } from '~/app/pages/Workspaces/Form/podConfig/WorkspaceFormPodConfigList';
|
||||
import { FilterByLabels } from '~/app/pages/Workspaces/Form/labelFilter/FilterByLabels';
|
||||
import { WorkspaceFormDrawer } from '~/app/pages/Workspaces/Form/WorkspaceFormDrawer';
|
||||
import { WorkspacePodConfigValue } from '~/shared/api/backendApiTypes';
|
||||
|
||||
interface WorkspaceFormPodConfigSelectionProps {
|
||||
|
@ -16,26 +14,6 @@ const WorkspaceFormPodConfigSelection: React.FunctionComponent<
|
|||
WorkspaceFormPodConfigSelectionProps
|
||||
> = ({ podConfigs, selectedPodConfig, onSelect }) => {
|
||||
const [selectedLabels, setSelectedLabels] = useState<Map<string, Set<string>>>(new Map());
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const drawerRef = 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(
|
||||
() => (
|
||||
|
@ -48,32 +26,19 @@ const WorkspaceFormPodConfigSelection: React.FunctionComponent<
|
|||
[podConfigs, selectedLabels, setSelectedLabels],
|
||||
);
|
||||
|
||||
const podConfigDetailsContent = useMemo(
|
||||
() => <WorkspaceFormPodConfigDetails workspacePodConfig={selectedPodConfig} />,
|
||||
[selectedPodConfig],
|
||||
);
|
||||
|
||||
return (
|
||||
<Content style={{ height: '100%' }}>
|
||||
<WorkspaceFormDrawer
|
||||
title="Pod config"
|
||||
info={podConfigDetailsContent}
|
||||
isExpanded={isExpanded}
|
||||
onCloseClick={onCloseClick}
|
||||
onExpand={onExpand}
|
||||
>
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{podConfigFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceFormPodConfigList
|
||||
podConfigs={podConfigs}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedPodConfig={selectedPodConfig}
|
||||
onSelect={onClick}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</WorkspaceFormDrawer>
|
||||
<Split hasGutter>
|
||||
<SplitItem style={{ minWidth: '200px' }}>{podConfigFilterContent}</SplitItem>
|
||||
<SplitItem isFilled>
|
||||
<WorkspaceFormPodConfigList
|
||||
podConfigs={podConfigs}
|
||||
selectedLabels={selectedLabels}
|
||||
selectedPodConfig={selectedPodConfig}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
</SplitItem>
|
||||
</Split>
|
||||
</Content>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue