V2Wizrad: fix validation at file system step (HMS-3733)
this commit fix validation when usr choose duplicate mount point andwhen there is no root partition
This commit is contained in:
parent
92fbb8babf
commit
698d21df42
5 changed files with 117 additions and 4 deletions
|
|
@ -11,6 +11,7 @@ import { useNavigate, useSearchParams } from 'react-router-dom';
|
|||
|
||||
import DetailsStep from './steps/Details';
|
||||
import FileSystemStep from './steps/FileSystem';
|
||||
import { FileSystemStepFooter } from './steps/FileSystem/FileSystemConfiguration';
|
||||
import ImageOutputStep from './steps/ImageOutput';
|
||||
import OscapStep from './steps/Oscap';
|
||||
import PackagesStep from './steps/Packages';
|
||||
|
|
@ -260,7 +261,7 @@ const CreateImageWizard = ({ startStepIndex = 1 }: CreateImageWizardProps) => {
|
|||
<WizardStep
|
||||
name="File system configuration"
|
||||
id="step-file-system"
|
||||
footer={<CustomWizardFooter disableNext={false} />}
|
||||
footer={<FileSystemStepFooter />}
|
||||
>
|
||||
<FileSystemStep />
|
||||
</WizardStep>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
Alert,
|
||||
|
|
@ -8,6 +8,8 @@ import {
|
|||
TextContent,
|
||||
TextInput,
|
||||
TextVariants,
|
||||
useWizardContext,
|
||||
WizardFooterWrapper,
|
||||
} from '@patternfly/react-core';
|
||||
import { Select, SelectOption } from '@patternfly/react-core/deprecated';
|
||||
import {
|
||||
|
|
@ -29,9 +31,16 @@ import {
|
|||
removePartition,
|
||||
selectPartitions,
|
||||
changePartitionUnit,
|
||||
setIsNextButtonTouched,
|
||||
selectIsNextButtonTouched,
|
||||
selectFileSystemPartitionMode,
|
||||
} from '../../../../store/wizardSlice';
|
||||
import UsrSubDirectoriesDisabled from '../../UsrSubDirectoriesDisabled';
|
||||
import { ValidatedTextInput } from '../../ValidatedTextInput';
|
||||
import {
|
||||
getDuplicateMountPoints,
|
||||
isFileSystemConfigValid,
|
||||
} from '../../validators';
|
||||
|
||||
export type Partition = {
|
||||
id: string;
|
||||
|
|
@ -40,12 +49,58 @@ export type Partition = {
|
|||
unit: Units;
|
||||
};
|
||||
|
||||
export const FileSystemStepFooter = () => {
|
||||
const { goToNextStep, goToPrevStep, close } = useWizardContext();
|
||||
const [isValid, setIsValid] = useState(false);
|
||||
const dispatch = useAppDispatch();
|
||||
const [isNextDisabled, setNextDisabled] = useState(false);
|
||||
const fileSystemPartitionMode = useAppSelector((state) =>
|
||||
selectFileSystemPartitionMode(state)
|
||||
);
|
||||
const partitions = useAppSelector((state) => selectPartitions(state));
|
||||
|
||||
const onValidate = () => {
|
||||
dispatch(setIsNextButtonTouched(false));
|
||||
if (!isValid) {
|
||||
setNextDisabled(true);
|
||||
} else {
|
||||
goToNextStep();
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (
|
||||
fileSystemPartitionMode === 'automatic' ||
|
||||
isFileSystemConfigValid(partitions)
|
||||
) {
|
||||
setIsValid(true);
|
||||
} else setIsValid(false);
|
||||
setNextDisabled(false);
|
||||
dispatch(setIsNextButtonTouched(true));
|
||||
}, [partitions, fileSystemPartitionMode, dispatch]);
|
||||
return (
|
||||
<WizardFooterWrapper>
|
||||
<Button onClick={onValidate} isDisabled={isNextDisabled}>
|
||||
Next
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={goToPrevStep}>
|
||||
Back
|
||||
</Button>
|
||||
<Button ouiaId="wizard-cancel-btn" variant="link" onClick={close}>
|
||||
Cancel
|
||||
</Button>
|
||||
</WizardFooterWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const FileSystemConfiguration = () => {
|
||||
const partitions = useAppSelector((state) => selectPartitions(state));
|
||||
const environments = useAppSelector((state) => selectImageTypes(state));
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const isNextButtonPristine = useAppSelector((state) =>
|
||||
selectIsNextButtonTouched(state)
|
||||
);
|
||||
const handleAddPartition = () => {
|
||||
const id = uuidv4();
|
||||
dispatch(
|
||||
|
|
@ -66,6 +121,17 @@ const FileSystemConfiguration = () => {
|
|||
{partitions?.find((partition) =>
|
||||
partition?.mountpoint?.includes('/usr')
|
||||
) && <UsrSubDirectoriesDisabled />}
|
||||
{!isNextButtonPristine &&
|
||||
getDuplicateMountPoints(partitions)?.length !== 0 &&
|
||||
getDuplicateMountPoints(partitions)?.length !== undefined && (
|
||||
<div>
|
||||
<Alert
|
||||
isInline
|
||||
variant="warning"
|
||||
title="Duplicate mount points: All mount points must be unique. Remove the duplicate or choose a new mount point."
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<TextContent>
|
||||
<Text>
|
||||
Create partitions for your image by defining mount points and minimum
|
||||
|
|
@ -167,16 +233,29 @@ const getSuffix = (mountpoint: string) => {
|
|||
|
||||
const Row = ({ partition }: RowPropTypes) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const partitions = useAppSelector((state) => selectPartitions(state));
|
||||
const handleRemovePartition = (id: string) => {
|
||||
dispatch(removePartition(id));
|
||||
};
|
||||
const isNextButtonPristine = useAppSelector((state) =>
|
||||
selectIsNextButtonTouched(state)
|
||||
);
|
||||
const duplicates = getDuplicateMountPoints(partitions);
|
||||
|
||||
return (
|
||||
<Tr>
|
||||
<Td />
|
||||
<Td width={20}>
|
||||
<Td className="pf-m-width-20">
|
||||
<MountpointPrefix partition={partition} />
|
||||
{!isNextButtonPristine &&
|
||||
duplicates.indexOf(partition.mountpoint) !== -1 && (
|
||||
<Alert
|
||||
variant="danger"
|
||||
isInline
|
||||
isPlain
|
||||
title="Duplicate mount point."
|
||||
/>
|
||||
)}
|
||||
</Td>
|
||||
{partition.mountpoint !== '/' &&
|
||||
!partition.mountpoint.startsWith('/boot') &&
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ export const mapRequestToState = (request: BlueprintResponse): wizardState => {
|
|||
fileSystem: {
|
||||
mode: 'automatic',
|
||||
partitions: [],
|
||||
isNextButtonTouched: true,
|
||||
},
|
||||
|
||||
architecture: request.image_requests[0].architecture,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { Partition } from './steps/FileSystem/FileSystemConfiguration';
|
||||
|
||||
export const isAwsAccountIdValid = (awsAccountId: string | undefined) => {
|
||||
return (
|
||||
awsAccountId !== undefined &&
|
||||
|
|
@ -38,3 +40,23 @@ export const isBlueprintNameValid = (blueprintName: string) =>
|
|||
export const isBlueprintDescriptionValid = (blueprintDescription: string) => {
|
||||
return blueprintDescription.length <= 250;
|
||||
};
|
||||
export const isFileSystemConfigValid = (partitions: Partition[]) => {
|
||||
const duplicates = getDuplicateMountPoints(partitions);
|
||||
return duplicates.length === 0;
|
||||
};
|
||||
export const getDuplicateMountPoints = (partitions: Partition[]): string[] => {
|
||||
const mountPointSet: Set<string> = new Set();
|
||||
const duplicates: string[] = [];
|
||||
if (!partitions) {
|
||||
return [];
|
||||
}
|
||||
for (const partition of partitions) {
|
||||
const mountPoint = partition.mountpoint;
|
||||
if (mountPointSet.has(mountPoint)) {
|
||||
duplicates.push(mountPoint);
|
||||
} else {
|
||||
mountPointSet.add(mountPoint);
|
||||
}
|
||||
}
|
||||
return duplicates;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ export type wizardState = {
|
|||
fileSystem: {
|
||||
mode: FileSystemPartitionMode;
|
||||
partitions: Partition[];
|
||||
isNextButtonTouched: boolean;
|
||||
};
|
||||
repositories: {
|
||||
customRepositories: CustomRepository[];
|
||||
|
|
@ -130,6 +131,7 @@ const initialState: wizardState = {
|
|||
fileSystem: {
|
||||
mode: 'automatic',
|
||||
partitions: [],
|
||||
isNextButtonTouched: true,
|
||||
},
|
||||
repositories: {
|
||||
customRepositories: [],
|
||||
|
|
@ -233,6 +235,9 @@ export const selectEnabledServices = (state: RootState) => {
|
|||
export const selectFileSystemPartitionMode = (state: RootState) => {
|
||||
return state.wizard.fileSystem.mode;
|
||||
};
|
||||
export const selectIsNextButtonTouched = (state: RootState) => {
|
||||
return state.wizard.fileSystem.isNextButtonTouched;
|
||||
};
|
||||
|
||||
export const selectPartitions = (state: RootState) => {
|
||||
return state.wizard.fileSystem.partitions;
|
||||
|
|
@ -379,6 +384,10 @@ export const wizardSlice = createSlice({
|
|||
) => {
|
||||
state.fileSystem.partitions = action.payload;
|
||||
},
|
||||
setIsNextButtonTouched: (state, action: PayloadAction<boolean>) => {
|
||||
state.fileSystem.isNextButtonTouched = action.payload;
|
||||
},
|
||||
|
||||
changeFileSystemPartitionMode: (
|
||||
state,
|
||||
action: PayloadAction<FileSystemPartitionMode>
|
||||
|
|
@ -489,6 +498,7 @@ export const {
|
|||
changeDisabledServices,
|
||||
changeEnabledServices,
|
||||
changeFileSystemConfiguration,
|
||||
setIsNextButtonTouched,
|
||||
changeFileSystemPartitionMode,
|
||||
addPartition,
|
||||
removePartition,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue