WizardV2: Validate steps through redux state

Store validation status in redux state.
This is bit complex on the redux side, but pretty simple on the components.
It allows for reuse of the validation state instead of revalidating wherever needed.
This commit is contained in:
Ondrej Ezr 2024-04-16 18:43:11 +02:00 committed by Klara Simickova
parent be5311e66a
commit 709ae39d23
8 changed files with 204 additions and 19 deletions

View file

@ -17,7 +17,7 @@ import {
selectBlueprintDescription,
selectBlueprintName,
} from '../../../../store/wizardSlice';
import { ValidatedTextInput } from '../../ValidatedTextInput';
import { StateValidatedInput } from '../../ValidatedTextInput';
import {
isBlueprintDescriptionValid,
isBlueprintNameValid,
@ -52,9 +52,11 @@ const DetailsStep = () => {
blueprint.
</Text>
<FormGroup isRequired label="Blueprint name" fieldId="blueprint-name">
<ValidatedTextInput
<StateValidatedInput
ariaLabel="blueprint name"
dataTestId="blueprint"
stepId="details"
inputId="blueprint-name"
value={blueprintName}
validator={isBlueprintNameValid}
onChange={handleNameChange}
@ -74,9 +76,11 @@ const DetailsStep = () => {
label="Blueprint description"
fieldId="blueprint-description-name"
>
<ValidatedTextInput
<StateValidatedInput
ariaLabel="blueprint description"
dataTestId="blueprint description"
stepId="details"
inputId="blueprint-description"
value={blueprintDescription || ''}
validator={isBlueprintDescriptionValid}
onChange={handleDescriptionChange}

View file

@ -18,11 +18,13 @@ import {
type CreateDropdownProps = {
getBlueprintPayload: () => Promise<'' | CreateBlueprintRequest | undefined>;
setIsOpen: (isOpen: boolean) => void;
isDisabled?: boolean;
};
export const CreateSaveAndBuildBtn = ({
getBlueprintPayload,
setIsOpen,
isDisabled,
}: CreateDropdownProps) => {
const [buildBlueprint] = useComposeBlueprintMutation();
const [createBlueprint] = useCreateBlueprintMutation({
@ -42,7 +44,11 @@ export const CreateSaveAndBuildBtn = ({
return (
<DropdownList>
<DropdownItem onClick={onSaveAndBuild} ouiaId="wizard-create-build-btn">
<DropdownItem
onClick={onSaveAndBuild}
ouiaId="wizard-create-build-btn"
isDisabled={isDisabled}
>
Create blueprint and build image(s)
</DropdownItem>
</DropdownList>
@ -52,6 +58,7 @@ export const CreateSaveAndBuildBtn = ({
export const CreateSaveButton = ({
setIsOpen,
getBlueprintPayload,
isDisabled,
}: CreateDropdownProps) => {
const [createBlueprint, { isLoading }] = useCreateBlueprintMutation({
fixedCacheKey: 'createBlueprintKey',
@ -62,7 +69,11 @@ export const CreateSaveButton = ({
requestBody && createBlueprint({ createBlueprintRequest: requestBody });
};
return (
<MenuToggleAction onClick={onSave} id="wizard-create-save-btn">
<MenuToggleAction
onClick={onSave}
id="wizard-create-save-btn"
isDisabled={isDisabled}
>
<Flex display={{ default: 'inlineFlex' }}>
{isLoading && (
<FlexItem>

View file

@ -19,12 +19,14 @@ type EditDropdownProps = {
getBlueprintPayload: () => Promise<'' | CreateBlueprintRequest | undefined>;
setIsOpen: (isOpen: boolean) => void;
blueprintId: string;
isDisabled?: boolean;
};
export const EditSaveAndBuildBtn = ({
getBlueprintPayload,
setIsOpen,
blueprintId,
isDisabled,
}: EditDropdownProps) => {
const [buildBlueprint] = useComposeBlueprintMutation();
const [updateBlueprint] = useUpdateBlueprintMutation({
@ -44,7 +46,11 @@ export const EditSaveAndBuildBtn = ({
return (
<DropdownList>
<DropdownItem onClick={onSaveAndBuild} ouiaId="wizard-edit-build-btn">
<DropdownItem
onClick={onSaveAndBuild}
ouiaId="wizard-edit-build-btn"
isDisabled={isDisabled}
>
Save changes and build image(s)
</DropdownItem>
</DropdownList>
@ -55,6 +61,7 @@ export const EditSaveButton = ({
setIsOpen,
getBlueprintPayload,
blueprintId,
isDisabled,
}: EditDropdownProps) => {
const [updateBlueprint, { isLoading }] = useUpdateBlueprintMutation({
fixedCacheKey: 'updateBlueprintKey',
@ -66,7 +73,11 @@ export const EditSaveButton = ({
updateBlueprint({ id: blueprintId, createBlueprintRequest: requestBody });
};
return (
<MenuToggleAction onClick={onSave} id="wizard-edit-save-btn">
<MenuToggleAction
onClick={onSave}
id="wizard-edit-save-btn"
isDisabled={isDisabled}
>
<Flex display={{ default: 'inlineFlex' }}>
{isLoading && (
<FlexItem>

View file

@ -15,11 +15,12 @@ import { useNavigate, useParams } from 'react-router-dom';
import { CreateSaveAndBuildBtn, CreateSaveButton } from './CreateDropdown';
import { EditSaveAndBuildBtn, EditSaveButton } from './EditDropdown';
import { useServerStore } from '../../../../../store/hooks';
import { useServerStore, useAppSelector } from '../../../../../store/hooks';
import {
useCreateBlueprintMutation,
useUpdateBlueprintMutation,
} from '../../../../../store/imageBuilderApi';
import { selectIsValid } from '../../../../../store/wizardSlice';
import { resolveRelPath } from '../../../../../Utilities/path';
import { mapRequestFromState } from '../../../utilities/requestMapper';
@ -40,6 +41,7 @@ const ReviewWizardFooter = () => {
setIsOpen(!isOpen);
};
const navigate = useNavigate();
const isValid = useAppSelector(selectIsValid);
useEffect(() => {
if (isUpdateSuccess || isCreateSuccess) {
@ -68,6 +70,7 @@ const ReviewWizardFooter = () => {
ref={toggleRef}
onClick={onToggleClick}
isExpanded={isOpen}
isDisabled={!isValid}
splitButtonOptions={{
variant: 'action',
items: composeId
@ -77,6 +80,7 @@ const ReviewWizardFooter = () => {
getBlueprintPayload={getBlueprintPayload}
setIsOpen={setIsOpen}
blueprintId={composeId}
isDisabled={!isValid}
/>,
]
: [
@ -84,6 +88,7 @@ const ReviewWizardFooter = () => {
key="wizard-create-save-btn"
getBlueprintPayload={getBlueprintPayload}
setIsOpen={setIsOpen}
isDisabled={!isValid}
/>,
],
}}
@ -99,11 +104,13 @@ const ReviewWizardFooter = () => {
getBlueprintPayload={getBlueprintPayload}
setIsOpen={setIsOpen}
blueprintId={composeId}
isDisabled={!isValid}
/>
) : (
<CreateSaveAndBuildBtn
getBlueprintPayload={getBlueprintPayload}
setIsOpen={setIsOpen}
isDisabled={!isValid}
/>
)}
</Dropdown>