fix(striker-ui): add confirm before provision server

main
Tsu-ba-me 3 years ago
parent 5856502c67
commit 3936060208
  1. 136
      striker-ui/components/ProvisionServerDialog.tsx

@ -8,6 +8,7 @@ import {
} from 'react'; } from 'react';
import { Box, Dialog, DialogProps, InputAdornment } from '@mui/material'; import { Box, Dialog, DialogProps, InputAdornment } from '@mui/material';
import { DataSizeUnit } from 'format-data-size'; import { DataSizeUnit } from 'format-data-size';
import { v4 as uuidv4 } from 'uuid';
import Autocomplete from './Autocomplete'; import Autocomplete from './Autocomplete';
import ContainedButton, { ContainedButtonProps } from './ContainedButton'; import ContainedButton, { ContainedButtonProps } from './ContainedButton';
@ -29,6 +30,7 @@ import {
} from '../types/TestInputFunction'; } from '../types/TestInputFunction';
import { BodyText, HeaderText } from './Text'; import { BodyText, HeaderText } from './Text';
import OutlinedLabeledInputWithSelect from './OutlinedLabeledInputWithSelect'; import OutlinedLabeledInputWithSelect from './OutlinedLabeledInputWithSelect';
import ConfirmDialog from './ConfirmDialog';
type InputMessage = Partial<Pick<MessageBoxProps, 'type' | 'text'>>; type InputMessage = Partial<Pick<MessageBoxProps, 'type' | 'text'>>;
@ -119,6 +121,10 @@ type AnvilUUIDMapToData = {
[uuid: string]: OrganizedAnvilDetailMetadataForProvisionServer; [uuid: string]: OrganizedAnvilDetailMetadataForProvisionServer;
}; };
type FileUUIDMapToData = {
[uuid: string]: FileMetadataForProvisionServer;
};
type StorageGroupUUIDMapToData = { type StorageGroupUUIDMapToData = {
[uuid: string]: OrganizedStorageGroupMetadataForProvisionServer; [uuid: string]: OrganizedStorageGroupMetadataForProvisionServer;
}; };
@ -149,13 +155,14 @@ type FilterAnvilsFunction = (
}; };
type VirtualDiskStates = { type VirtualDiskStates = {
maxes: bigint[]; stateIds: string[];
inputMaxes: string[]; inputMaxes: string[];
inputSizeMessages: Array<InputMessage | undefined>; inputSizeMessages: Array<InputMessage | undefined>;
inputSizes: string[]; inputSizes: string[];
inputStorageGroupUUIDMessages: Array<InputMessage | undefined>; inputStorageGroupUUIDMessages: Array<InputMessage | undefined>;
inputStorageGroupUUIDs: string[]; inputStorageGroupUUIDs: string[];
inputUnits: DataSizeUnit[]; inputUnits: DataSizeUnit[];
maxes: bigint[];
sizes: bigint[]; sizes: bigint[];
}; };
@ -428,13 +435,14 @@ const createSelectItemDisplay = ({
); );
const organizeAnvils = (data: AnvilDetailMetadataForProvisionServer[]) => { const organizeAnvils = (data: AnvilDetailMetadataForProvisionServer[]) => {
const anvilFiles: Record<string, FileMetadataForProvisionServer> = {}; const allFiles: Record<string, FileMetadataForProvisionServer> = {};
const result = data.reduce<{ const result = data.reduce<{
anvils: OrganizedAnvilDetailMetadataForProvisionServer[]; anvils: OrganizedAnvilDetailMetadataForProvisionServer[];
anvilSelectItems: SelectItem[]; anvilSelectItems: SelectItem[];
anvilUUIDMapToData: AnvilUUIDMapToData; anvilUUIDMapToData: AnvilUUIDMapToData;
files: FileMetadataForProvisionServer[]; files: FileMetadataForProvisionServer[];
fileSelectItems: SelectItem[]; fileSelectItems: SelectItem[];
fileUUIDMapToData: FileUUIDMapToData;
storageGroups: OrganizedStorageGroupMetadataForProvisionServer[]; storageGroups: OrganizedStorageGroupMetadataForProvisionServer[];
storageGroupSelectItems: SelectItem[]; storageGroupSelectItems: SelectItem[];
storageGroupUUIDMapToData: StorageGroupUUIDMapToData; storageGroupUUIDMapToData: StorageGroupUUIDMapToData;
@ -516,7 +524,7 @@ const organizeAnvils = (data: AnvilDetailMetadataForProvisionServer[]) => {
fileUUIDs.push(fileUUID); fileUUIDs.push(fileUUID);
anvilFiles[fileUUID] = file; allFiles[fileUUID] = file;
}); });
const resultAnvil = { const resultAnvil = {
@ -581,18 +589,20 @@ const organizeAnvils = (data: AnvilDetailMetadataForProvisionServer[]) => {
anvilUUIDMapToData: {}, anvilUUIDMapToData: {},
files: [], files: [],
fileSelectItems: [], fileSelectItems: [],
fileUUIDMapToData: {},
storageGroups: [], storageGroups: [],
storageGroupSelectItems: [], storageGroupSelectItems: [],
storageGroupUUIDMapToData: {}, storageGroupUUIDMapToData: {},
}, },
); );
Object.values(anvilFiles).forEach((distinctFile) => { Object.values(allFiles).forEach((distinctFile) => {
result.files.push(distinctFile); result.files.push(distinctFile);
result.fileSelectItems.push({ result.fileSelectItems.push({
displayValue: distinctFile.fileName, displayValue: distinctFile.fileName,
value: distinctFile.fileUUID, value: distinctFile.fileUUID,
}); });
result.fileUUIDMapToData[distinctFile.fileUUID] = distinctFile;
}); });
return result; return result;
@ -863,7 +873,7 @@ const createVirtualDiskForm = (
return ( return (
<Box <Box
key={`ps-virtual-disk-${vdIndex}`} key={`ps-virtual-disk-${get('stateIds')}`}
sx={{ sx={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
@ -952,54 +962,59 @@ const createVirtualDiskForm = (
const addVirtualDisk = ({ const addVirtualDisk = ({
existingVirtualDisks: virtualDisks = { existingVirtualDisks: virtualDisks = {
maxes: [], stateIds: [],
inputMaxes: [], inputMaxes: [],
inputSizeMessages: [], inputSizeMessages: [],
inputSizes: [], inputSizes: [],
inputStorageGroupUUIDMessages: [], inputStorageGroupUUIDMessages: [],
inputStorageGroupUUIDs: [], inputStorageGroupUUIDs: [],
inputUnits: [], inputUnits: [],
maxes: [],
sizes: [], sizes: [],
}, },
max = BIGINT_ZERO, stateId = uuidv4(),
inputMax = '0', inputMax = '0',
inputSize = '', inputSize = '',
inputSizeMessage = undefined, inputSizeMessage = undefined,
inputStorageGroupUUID = '', inputStorageGroupUUID = '',
inputStorageGroupUUIDMessage = undefined, inputStorageGroupUUIDMessage = undefined,
inputUnit = INITIAL_DATA_SIZE_UNIT, inputUnit = INITIAL_DATA_SIZE_UNIT,
max = BIGINT_ZERO,
setVirtualDisks, setVirtualDisks,
size = BIGINT_ZERO, size = BIGINT_ZERO,
}: { }: {
existingVirtualDisks?: VirtualDiskStates; existingVirtualDisks?: VirtualDiskStates;
max?: bigint; stateId?: string;
inputMax?: string; inputMax?: string;
inputSize?: string; inputSize?: string;
inputSizeMessage?: InputMessage | undefined; inputSizeMessage?: InputMessage | undefined;
inputStorageGroupUUID?: string; inputStorageGroupUUID?: string;
inputStorageGroupUUIDMessage?: InputMessage | undefined; inputStorageGroupUUIDMessage?: InputMessage | undefined;
inputUnit?: DataSizeUnit; inputUnit?: DataSizeUnit;
max?: bigint;
setVirtualDisks?: Dispatch<SetStateAction<VirtualDiskStates>>; setVirtualDisks?: Dispatch<SetStateAction<VirtualDiskStates>>;
size?: bigint; size?: bigint;
} = {}) => { } = {}) => {
const { const {
maxes, stateIds,
inputMaxes, inputMaxes,
inputSizeMessages, inputSizeMessages,
inputSizes, inputSizes,
inputStorageGroupUUIDMessages, inputStorageGroupUUIDMessages,
inputStorageGroupUUIDs, inputStorageGroupUUIDs,
inputUnits, inputUnits,
maxes,
sizes, sizes,
} = virtualDisks; } = virtualDisks;
maxes.push(max); stateIds.push(stateId);
inputMaxes.push(inputMax); inputMaxes.push(inputMax);
inputSizeMessages.push(inputSizeMessage); inputSizeMessages.push(inputSizeMessage);
inputSizes.push(inputSize); inputSizes.push(inputSize);
inputStorageGroupUUIDMessages.push(inputStorageGroupUUIDMessage); inputStorageGroupUUIDMessages.push(inputStorageGroupUUIDMessage);
inputStorageGroupUUIDs.push(inputStorageGroupUUID); inputStorageGroupUUIDs.push(inputStorageGroupUUID);
inputUnits.push(inputUnit); inputUnits.push(inputUnit);
maxes.push(max);
sizes.push(size); sizes.push(size);
setVirtualDisks?.call(null, { ...virtualDisks }); setVirtualDisks?.call(null, { ...virtualDisks });
@ -1020,6 +1035,9 @@ const ProvisionServerDialog = ({
>([]); >([]);
const [anvilUUIDMapToData, setAnvilUUIDMapToData] = const [anvilUUIDMapToData, setAnvilUUIDMapToData] =
useState<AnvilUUIDMapToData>({}); useState<AnvilUUIDMapToData>({});
const [fileUUIDMapToData, setFileUUIDMapToData] = useState<FileUUIDMapToData>(
{},
);
const [storageGroupUUIDMapToData, setStorageGroupUUIDMapToData] = const [storageGroupUUIDMapToData, setStorageGroupUUIDMapToData] =
useState<StorageGroupUUIDMapToData>({}); useState<StorageGroupUUIDMapToData>({});
@ -1084,6 +1102,9 @@ const ProvisionServerDialog = ({
string[] string[]
>([]); >([]);
const [isOpenProvisionConfirmDialog, setIsOpenProvisionConfirmDialog] =
useState<boolean>(false);
const inputTests: InputTestBatches = { const inputTests: InputTestBatches = {
serverName: { serverName: {
defaults: { defaults: {
@ -1433,12 +1454,14 @@ const ProvisionServerDialog = ({
anvilSelectItems: ueAnvilSelectItems, anvilSelectItems: ueAnvilSelectItems,
anvilUUIDMapToData: ueAnvilUUIDMapToData, anvilUUIDMapToData: ueAnvilUUIDMapToData,
fileSelectItems: ueFileSelectItems, fileSelectItems: ueFileSelectItems,
fileUUIDMapToData: ueFileUUIDMapToData,
storageGroupSelectItems: ueStorageGroupSelectItems, storageGroupSelectItems: ueStorageGroupSelectItems,
storageGroupUUIDMapToData: ueStorageGroupUUIDMapToData, storageGroupUUIDMapToData: ueStorageGroupUUIDMapToData,
} = organizeAnvils(data.anvils); } = organizeAnvils(data.anvils);
setAllAnvils(ueAllAnvils); setAllAnvils(ueAllAnvils);
setAnvilUUIDMapToData(ueAnvilUUIDMapToData); setAnvilUUIDMapToData(ueAnvilUUIDMapToData);
setFileUUIDMapToData(ueFileUUIDMapToData);
setStorageGroupUUIDMapToData(ueStorageGroupUUIDMapToData); setStorageGroupUUIDMapToData(ueStorageGroupUUIDMapToData);
setAnvilSelectItems(ueAnvilSelectItems); setAnvilSelectItems(ueAnvilSelectItems);
@ -1463,6 +1486,7 @@ const ProvisionServerDialog = ({
}, [initLimits]); }, [initLimits]);
return ( return (
<>
<Dialog <Dialog
{...{ {...{
fullWidth: true, fullWidth: true,
@ -1507,7 +1531,11 @@ const ProvisionServerDialog = ({
messageBoxProps={inputServerNameMessage} messageBoxProps={inputServerNameMessage}
/> />
</Box> </Box>
{createOutlinedSlider('ps-cpu-cores', 'CPU cores', inputCPUCoresValue, { {createOutlinedSlider(
'ps-cpu-cores',
'CPU cores',
inputCPUCoresValue,
{
messageBoxProps: inputCPUCoresMessage, messageBoxProps: inputCPUCoresMessage,
sliderProps: { sliderProps: {
onChange: (value) => { onChange: (value) => {
@ -1522,7 +1550,10 @@ const ProvisionServerDialog = ({
testInput({ testInput({
inputs: { inputs: {
cpuCores: { max: newCPUCoresMax, value: newCPUCoresValue }, cpuCores: {
max: newCPUCoresMax,
value: newCPUCoresValue,
},
}, },
}); });
} }
@ -1530,7 +1561,8 @@ const ProvisionServerDialog = ({
max: inputCPUCoresMax, max: inputCPUCoresMax,
min: inputCPUCoresMin, min: inputCPUCoresMin,
}, },
})} },
)}
<OutlinedLabeledInputWithSelect <OutlinedLabeledInputWithSelect
id="ps-memory" id="ps-memory"
label="Memory" label="Memory"
@ -1568,7 +1600,7 @@ const ProvisionServerDialog = ({
}, },
}} }}
/> />
{virtualDisks.maxes.map((max, vdIndex) => {virtualDisks.stateIds.map((vdStateId, vdIndex) =>
createVirtualDiskForm( createVirtualDiskForm(
virtualDisks, virtualDisks,
vdIndex, vdIndex,
@ -1614,7 +1646,8 @@ const ProvisionServerDialog = ({
handleInputDriverISOFileUUIDChange(newDriverISOFileUUID); handleInputDriverISOFileUUIDChange(newDriverISOFileUUID);
}, },
onClearIndicatorClick: () => handleInputDriverISOFileUUIDChange(''), onClearIndicatorClick: () =>
handleInputDriverISOFileUUIDChange(''),
value: inputDriverISOFileUUID, value: inputDriverISOFileUUID,
}} }}
/> />
@ -1646,8 +1679,10 @@ const ProvisionServerDialog = ({
<Autocomplete <Autocomplete
id="ps-optimize-for-os" id="ps-optimize-for-os"
extendRenderInput={({ inputLabelProps = {} }) => { extendRenderInput={({ inputLabelProps = {} }) => {
inputLabelProps.isNotifyRequired = inputOptimizeForOSValue === null; inputLabelProps.isNotifyRequired =
inputOptimizeForOSValue === null;
}} }}
isOptionEqualToValue={(option, value) => option.key === value.key}
label="Optimize for OS" label="Optimize for OS"
messageBoxProps={inputOptimizeForOSMessage} messageBoxProps={inputOptimizeForOSMessage}
noOptionsText="No matching OS" noOptionsText="No matching OS"
@ -1668,11 +1703,78 @@ const ProvisionServerDialog = ({
width: '100%', width: '100%',
}} }}
> >
<ContainedButton disabled={!testInput({ isIgnoreOnCallbacks: true })}> <ContainedButton
disabled={!testInput({ isIgnoreOnCallbacks: true })}
onClick={() => {
setIsOpenProvisionConfirmDialog(true);
}}
>
Provision Provision
</ContainedButton> </ContainedButton>
</Box> </Box>
</Dialog> </Dialog>
{isOpenProvisionConfirmDialog && (
<ConfirmDialog
actionProceedText="Provision"
content={
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<BodyText
text={`Server ${inputServerNameValue} will be created on anvil node pair ${anvilUUIDMapToData[inputAnvilValue].anvilName} with the following properties:`}
/>
<BodyText text={`CPU: ${inputCPUCoresValue} core(s)`} />
<BodyText
text={`Memory: ${inputMemoryValue} ${inputMemoryUnit}`}
/>
{virtualDisks.stateIds.map((vdStateId, vdIndex) => (
<BodyText
key={`ps-virtual-disk-${vdStateId}-summary`}
text={`Virtual disk ${vdIndex}: ${
virtualDisks.inputSizes[vdIndex]
} ${virtualDisks.inputUnits[vdIndex]} on ${
storageGroupUUIDMapToData[
virtualDisks.inputStorageGroupUUIDs[vdIndex]
].storageGroupName
}`}
/>
))}
<BodyText
text={`Install ISO: ${fileUUIDMapToData[inputInstallISOFileUUID].fileName}`}
/>
<BodyText
text={`Driver ISO: ${
fileUUIDMapToData[inputDriverISOFileUUID]?.fileName ?? 'none'
}`}
/>
<BodyText
text={`Optimize for OS: ${inputOptimizeForOSValue?.label}`}
/>
</Box>
}
dialogProps={{ open: isOpenProvisionConfirmDialog }}
onCancel={() => {
setIsOpenProvisionConfirmDialog(false);
}}
onProceed={() => {
// const requestBody = {
// serverName: inputServerNameValue,
// cpuCores: inputCPUCoresValue,
// memory,
// virtualDisks: virtualDisks.stateIds.map((vdStateId, vdIndex) => ({
// size: virtualDisks.sizes[vdIndex],
// storageGroupUUID: virtualDisks.inputStorageGroupUUIDs[vdIndex],
// })),
// installISOFileUUID: inputInstallISOFileUUID,
// driverISOFileUUID: inputDriverISOFileUUID,
// anvilUUID: inputAnvilValue,
// optimizeForOS: inputOptimizeForOSValue?.key,
// };
setIsOpenProvisionConfirmDialog(false);
}}
titleText={`Provision ${inputServerNameValue}?`}
/>
)}
</>
); );
}; };

Loading…
Cancel
Save