fix(striker-ui): add validation for virtual disks

main
Tsu-ba-me 3 years ago
parent 559679f8a3
commit 97269e33c9
  1. 111
      striker-ui/components/ProvisionServerDialog.tsx

@ -148,6 +148,7 @@ type FilterAnvilsFunction = (
type VirtualDiskStates = { type VirtualDiskStates = {
maxes: bigint[]; maxes: bigint[];
inputErrors: Array<string | undefined>;
inputMaxes: string[]; inputMaxes: string[];
inputSizes: string[]; inputSizes: string[];
inputStorageGroupUUIDs: string[]; inputStorageGroupUUIDs: string[];
@ -171,9 +172,13 @@ type UpdateLimitsFunction = (options?: {
type TestArgs = { type TestArgs = {
max: bigint | number; max: bigint | number;
min: bigint | number; min: bigint | number;
value: bigint | number; value: bigint | number | string;
}; };
type TestInputFunction = (inputs: {
[id: string]: Partial<TestArgs>;
}) => boolean;
const MOCK_DATA = { const MOCK_DATA = {
anvils: [ anvils: [
{ {
@ -356,6 +361,9 @@ const DATA_SIZE_UNIT_SELECT_ITEMS: SelectItem<DataSizeUnit>[] = [
{ value: 'TB' }, { value: 'TB' },
]; ];
const createErrorMessage = (error?: string) =>
error && <MessageBox sx={{ marginTop: '.4em' }} type="error" text={error} />;
const createOutlinedSelect = ( const createOutlinedSelect = (
id: string, id: string,
label: string | undefined, label: string | undefined,
@ -460,9 +468,7 @@ const createOutlinedInputWithSelect = (
selectProps, selectProps,
})} })}
</Box> </Box>
{error && ( {createErrorMessage(error)}
<MessageBox sx={{ marginTop: '.4em' }} type="error" text={error} />
)}
</Box> </Box>
); );
@ -857,6 +863,7 @@ const createVirtualDiskForm = (
includeStorageGroupUUIDs: string[], includeStorageGroupUUIDs: string[],
updateLimits: UpdateLimitsFunction, updateLimits: UpdateLimitsFunction,
storageGroupUUIDMapToFree: StorageGroupUUIDMapToFree, storageGroupUUIDMapToFree: StorageGroupUUIDMapToFree,
testInput: TestInputFunction,
) => { ) => {
const get = <Key extends keyof VirtualDiskStates>( const get = <Key extends keyof VirtualDiskStates>(
key: Key, key: Key,
@ -874,7 +881,15 @@ const createVirtualDiskForm = (
const changeVDSize = (cvsValue: bigint = BIGINT_ZERO) => { const changeVDSize = (cvsValue: bigint = BIGINT_ZERO) => {
set('sizes', cvsValue); set('sizes', cvsValue);
updateLimits({ virtualDisks });
const { maxVirtualDiskSizes } = updateLimits({ virtualDisks });
testInput({
[`vd${vdIndex}Size`]: {
max: maxVirtualDiskSizes?.[vdIndex],
value: cvsValue,
},
});
}; };
const handleVDSizeChange = ({ const handleVDSizeChange = ({
@ -979,6 +994,7 @@ const createVirtualDiskForm = (
}, },
}, },
)} )}
{createErrorMessage(get('inputErrors'))}
</Box> </Box>
); );
}; };
@ -986,6 +1002,7 @@ const createVirtualDiskForm = (
const addVirtualDisk = ({ const addVirtualDisk = ({
existingVirtualDisks: virtualDisks = { existingVirtualDisks: virtualDisks = {
maxes: [], maxes: [],
inputErrors: [],
inputMaxes: [], inputMaxes: [],
inputSizes: [], inputSizes: [],
inputStorageGroupUUIDs: [], inputStorageGroupUUIDs: [],
@ -993,6 +1010,7 @@ const addVirtualDisk = ({
sizes: [], sizes: [],
}, },
max = BIGINT_ZERO, max = BIGINT_ZERO,
inputError = undefined,
inputMax = '0', inputMax = '0',
inputSize = '', inputSize = '',
inputStorageGroupUUID = '', inputStorageGroupUUID = '',
@ -1002,6 +1020,7 @@ const addVirtualDisk = ({
}: { }: {
existingVirtualDisks?: VirtualDiskStates; existingVirtualDisks?: VirtualDiskStates;
max?: bigint; max?: bigint;
inputError?: string | undefined;
inputMax?: string; inputMax?: string;
inputSize?: string; inputSize?: string;
inputStorageGroupUUID?: string; inputStorageGroupUUID?: string;
@ -1011,6 +1030,7 @@ const addVirtualDisk = ({
} = {}) => { } = {}) => {
const { const {
maxes, maxes,
inputErrors,
inputMaxes, inputMaxes,
inputSizes, inputSizes,
inputStorageGroupUUIDs, inputStorageGroupUUIDs,
@ -1019,6 +1039,7 @@ const addVirtualDisk = ({
} = virtualDisks; } = virtualDisks;
maxes.push(max); maxes.push(max);
inputErrors.push(inputError);
inputMaxes.push(inputMax); inputMaxes.push(inputMax);
inputSizes.push(inputSize); inputSizes.push(inputSize);
inputStorageGroupUUIDs.push(inputStorageGroupUUID); inputStorageGroupUUIDs.push(inputStorageGroupUUID);
@ -1152,13 +1173,17 @@ const ProvisionServerDialog = ({
return { return {
maxCPUCores, maxCPUCores,
maxMemory, maxMemory,
maxVirtualDiskSizes,
}; };
}; };
// The memorized version of updateLimits() should only be called during first render. // The memorized version of updateLimits() should only be called during first render.
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
const initLimits = useCallback(updateLimits, []); const initLimits = useCallback(updateLimits, []);
const testInput = (inputs: { [id: string]: Partial<TestArgs> }): boolean => { const testInput: TestInputFunction = (inputs: {
[id: string]: Partial<TestArgs>;
}): boolean => {
const testNotBlank = ({ value }: TestArgs) => value !== '';
const testMax = ({ max, min }: TestArgs) => max >= min; const testMax = ({ max, min }: TestArgs) => max >= min;
const testRange = ({ max, min, value }: TestArgs) => const testRange = ({ max, min, value }: TestArgs) =>
value >= min && value <= max; value >= min && value <= max;
@ -1169,7 +1194,7 @@ const ProvisionServerDialog = ({
onSuccess: () => void; onSuccess: () => void;
}; };
tests: Array<{ tests: Array<{
onFailure?: () => void; onFailure?: (args: TestArgs) => void;
onSuccess?: () => void; onSuccess?: () => void;
test: (args: TestArgs) => boolean; test: (args: TestArgs) => boolean;
}>; }>;
@ -1192,8 +1217,10 @@ const ProvisionServerDialog = ({
test: testMax, test: testMax,
}, },
{ {
onFailure: () => { onFailure: ({ max, min }) => {
setInputCPUCoresError('Out of range.'); setInputCPUCoresError(
`The number of CPU cores is expected to be between ${min} and ${max}.`,
);
}, },
test: testRange, test: testRange,
}, },
@ -1216,8 +1243,10 @@ const ProvisionServerDialog = ({
test: testMax, test: testMax,
}, },
{ {
onFailure: () => { onFailure: ({ max, min }) => {
setInputMemoryError('Out of range.'); setInputMemoryError(
`Memory is expected to be between ${min} B and ${max} B.`,
);
}, },
test: testRange, test: testRange,
}, },
@ -1225,6 +1254,60 @@ const ProvisionServerDialog = ({
}, },
}; };
virtualDisks.inputErrors.forEach((error, vdIndex) => {
const defaultOnSuccess = () => {
virtualDisks.inputErrors[vdIndex] = undefined;
setVirtualDisks({ ...virtualDisks });
};
tests[`vd${vdIndex}Size`] = {
defaults: {
max: virtualDisks.maxes[vdIndex],
min: 1,
onSuccess: defaultOnSuccess,
value: virtualDisks.sizes[vdIndex],
},
tests: [
{
onFailure: () => {
virtualDisks.inputErrors[vdIndex] = 'Non available.';
setVirtualDisks({ ...virtualDisks });
},
test: testMax,
},
{
onFailure: ({ max, min }) => {
virtualDisks.inputErrors[
vdIndex
] = `Virtual disk ${vdIndex} size is expected to be between ${min} B and ${max} B.`;
setVirtualDisks({ ...virtualDisks });
},
test: testRange,
},
],
};
tests[`vd${vdIndex}StorageGroup`] = {
defaults: {
max: 0,
min: 0,
onSuccess: defaultOnSuccess,
value: virtualDisks.inputStorageGroupUUIDs[vdIndex],
},
tests: [
{
onFailure: () => {
virtualDisks.inputErrors[
vdIndex
] = `Virtual disk ${vdIndex} storage group shouldn't be blank.`;
setVirtualDisks({ ...virtualDisks });
},
test: testNotBlank,
},
],
};
});
return Object.keys(inputs).every((id: string) => { return Object.keys(inputs).every((id: string) => {
const { const {
defaults: { defaults: {
@ -1238,12 +1321,13 @@ const ProvisionServerDialog = ({
const { max = dMax, min = dMin, value = dValue } = inputs[id]; const { max = dMax, min = dMin, value = dValue } = inputs[id];
return group.every(({ onFailure, onSuccess = dOnSuccess, test }) => { return group.every(({ onFailure, onSuccess = dOnSuccess, test }) => {
const result: boolean = test({ max, min, value }); const args = { max, min, value };
const result: boolean = test(args);
if (result) { if (result) {
onSuccess?.call(null); onSuccess?.call(null);
} else { } else {
onFailure?.call(null); onFailure?.call(null, args);
} }
return result; return result;
@ -1445,6 +1529,7 @@ const ProvisionServerDialog = ({
includeStorageGroupUUIDs, includeStorageGroupUUIDs,
updateLimits, updateLimits,
storageGroupUUIDMapToFree, storageGroupUUIDMapToFree,
testInput,
), ),
)} )}
{createOutlinedSelect( {createOutlinedSelect(

Loading…
Cancel
Save