|
|
@ -23,7 +23,7 @@ import { |
|
|
|
import Autocomplete from './Autocomplete'; |
|
|
|
import Autocomplete from './Autocomplete'; |
|
|
|
import ContainedButton, { ContainedButtonProps } from './ContainedButton'; |
|
|
|
import ContainedButton, { ContainedButtonProps } from './ContainedButton'; |
|
|
|
import MenuItem from './MenuItem'; |
|
|
|
import MenuItem from './MenuItem'; |
|
|
|
import MessageBox from './MessageBox'; |
|
|
|
import MessageBox, { MessageBoxProps } from './MessageBox'; |
|
|
|
import OutlinedInput from './OutlinedInput'; |
|
|
|
import OutlinedInput from './OutlinedInput'; |
|
|
|
import OutlinedInputLabel from './OutlinedInputLabel'; |
|
|
|
import OutlinedInputLabel from './OutlinedInputLabel'; |
|
|
|
import OutlinedInputWithLabel, { |
|
|
|
import OutlinedInputWithLabel, { |
|
|
@ -34,6 +34,8 @@ import Select, { SelectProps } from './Select'; |
|
|
|
import Slider, { SliderProps } from './Slider'; |
|
|
|
import Slider, { SliderProps } from './Slider'; |
|
|
|
import { BodyText, HeaderText } from './Text'; |
|
|
|
import { BodyText, HeaderText } from './Text'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type InputMessage = Partial<Pick<MessageBoxProps, 'type' | 'text'>>; |
|
|
|
|
|
|
|
|
|
|
|
type SelectItem<SelectItemValueType = string> = { |
|
|
|
type SelectItem<SelectItemValueType = string> = { |
|
|
|
displayValue?: SelectItemValueType; |
|
|
|
displayValue?: SelectItemValueType; |
|
|
|
value: SelectItemValueType; |
|
|
|
value: SelectItemValueType; |
|
|
@ -148,9 +150,10 @@ type FilterAnvilsFunction = ( |
|
|
|
|
|
|
|
|
|
|
|
type VirtualDiskStates = { |
|
|
|
type VirtualDiskStates = { |
|
|
|
maxes: bigint[]; |
|
|
|
maxes: bigint[]; |
|
|
|
inputErrors: Array<string | undefined>; |
|
|
|
|
|
|
|
inputMaxes: string[]; |
|
|
|
inputMaxes: string[]; |
|
|
|
|
|
|
|
inputSizeMessages: Array<InputMessage | undefined>; |
|
|
|
inputSizes: string[]; |
|
|
|
inputSizes: string[]; |
|
|
|
|
|
|
|
inputStorageGroupUUIDMessages: Array<InputMessage | undefined>; |
|
|
|
inputStorageGroupUUIDs: string[]; |
|
|
|
inputStorageGroupUUIDs: string[]; |
|
|
|
inputUnits: DataSizeUnit[]; |
|
|
|
inputUnits: DataSizeUnit[]; |
|
|
|
sizes: bigint[]; |
|
|
|
sizes: bigint[]; |
|
|
@ -175,8 +178,18 @@ type TestArgs = { |
|
|
|
value: bigint | number | string; |
|
|
|
value: bigint | number | string; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
type TestInputFunction = (inputs: { |
|
|
|
type InputTest = { |
|
|
|
[id: string]: Partial<TestArgs>; |
|
|
|
onFailure?: (args: TestArgs) => void; |
|
|
|
|
|
|
|
onSuccess?: () => void; |
|
|
|
|
|
|
|
test: (args: TestArgs) => boolean; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type TestInputFunction = (options?: { |
|
|
|
|
|
|
|
inputs?: { |
|
|
|
|
|
|
|
[id: string]: Partial<TestArgs>; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
isContinueOnFailure?: boolean; |
|
|
|
|
|
|
|
isIgnoreOnCallbacks?: boolean; |
|
|
|
}) => boolean; |
|
|
|
}) => boolean; |
|
|
|
|
|
|
|
|
|
|
|
const MOCK_DATA = { |
|
|
|
const MOCK_DATA = { |
|
|
@ -361,8 +374,8 @@ const DATA_SIZE_UNIT_SELECT_ITEMS: SelectItem<DataSizeUnit>[] = [ |
|
|
|
{ value: 'TB' }, |
|
|
|
{ value: 'TB' }, |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
const createErrorMessage = (error?: string) => |
|
|
|
const createInputMessage = ({ text, type }: Partial<MessageBoxProps> = {}) => |
|
|
|
error && <MessageBox sx={{ marginTop: '.4em' }} type="error" text={error} />; |
|
|
|
text && <MessageBox {...{ sx: { marginTop: '.4em' }, text, type }} />; |
|
|
|
|
|
|
|
|
|
|
|
const createOutlinedSelect = ( |
|
|
|
const createOutlinedSelect = ( |
|
|
|
id: string, |
|
|
|
id: string, |
|
|
@ -372,6 +385,7 @@ const createOutlinedSelect = ( |
|
|
|
checkItem, |
|
|
|
checkItem, |
|
|
|
disableItem, |
|
|
|
disableItem, |
|
|
|
hideItem, |
|
|
|
hideItem, |
|
|
|
|
|
|
|
messageBoxProps, |
|
|
|
selectProps, |
|
|
|
selectProps, |
|
|
|
isCheckableItems = selectProps?.multiple, |
|
|
|
isCheckableItems = selectProps?.multiple, |
|
|
|
}: { |
|
|
|
}: { |
|
|
@ -379,6 +393,7 @@ const createOutlinedSelect = ( |
|
|
|
disableItem?: (value: string) => boolean; |
|
|
|
disableItem?: (value: string) => boolean; |
|
|
|
hideItem?: (value: string) => boolean; |
|
|
|
hideItem?: (value: string) => boolean; |
|
|
|
isCheckableItems?: boolean; |
|
|
|
isCheckableItems?: boolean; |
|
|
|
|
|
|
|
messageBoxProps?: Partial<MessageBoxProps>; |
|
|
|
selectProps?: Partial<SelectProps>; |
|
|
|
selectProps?: Partial<SelectProps>; |
|
|
|
} = {}, |
|
|
|
} = {}, |
|
|
|
): JSX.Element => ( |
|
|
|
): JSX.Element => ( |
|
|
@ -410,6 +425,7 @@ const createOutlinedSelect = ( |
|
|
|
</MenuItem> |
|
|
|
</MenuItem> |
|
|
|
))} |
|
|
|
))} |
|
|
|
</Select> |
|
|
|
</Select> |
|
|
|
|
|
|
|
{createInputMessage(messageBoxProps)} |
|
|
|
</FormControl> |
|
|
|
</FormControl> |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -436,12 +452,12 @@ const createOutlinedInputWithSelect = ( |
|
|
|
label: string, |
|
|
|
label: string, |
|
|
|
selectItems: SelectItem[], |
|
|
|
selectItems: SelectItem[], |
|
|
|
{ |
|
|
|
{ |
|
|
|
error, |
|
|
|
messageBoxProps, |
|
|
|
inputWithLabelProps, |
|
|
|
inputWithLabelProps, |
|
|
|
selectProps, |
|
|
|
selectProps, |
|
|
|
}: { |
|
|
|
}: { |
|
|
|
error?: string; |
|
|
|
|
|
|
|
inputWithLabelProps?: Partial<OutlinedInputWithLabelProps>; |
|
|
|
inputWithLabelProps?: Partial<OutlinedInputWithLabelProps>; |
|
|
|
|
|
|
|
messageBoxProps?: Partial<MessageBoxProps>; |
|
|
|
selectProps?: Partial<SelectProps>; |
|
|
|
selectProps?: Partial<SelectProps>; |
|
|
|
} = {}, |
|
|
|
} = {}, |
|
|
|
) => ( |
|
|
|
) => ( |
|
|
@ -468,7 +484,7 @@ const createOutlinedInputWithSelect = ( |
|
|
|
selectProps, |
|
|
|
selectProps, |
|
|
|
})} |
|
|
|
})} |
|
|
|
</Box> |
|
|
|
</Box> |
|
|
|
{createErrorMessage(error)} |
|
|
|
{createInputMessage(messageBoxProps)} |
|
|
|
</Box> |
|
|
|
</Box> |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
@ -885,9 +901,11 @@ const createVirtualDiskForm = ( |
|
|
|
const { maxVirtualDiskSizes } = updateLimits({ virtualDisks }); |
|
|
|
const { maxVirtualDiskSizes } = updateLimits({ virtualDisks }); |
|
|
|
|
|
|
|
|
|
|
|
testInput({ |
|
|
|
testInput({ |
|
|
|
[`vd${vdIndex}Size`]: { |
|
|
|
inputs: { |
|
|
|
max: maxVirtualDiskSizes?.[vdIndex], |
|
|
|
[`vd${vdIndex}Size`]: { |
|
|
|
value: cvsValue, |
|
|
|
max: maxVirtualDiskSizes?.[vdIndex], |
|
|
|
|
|
|
|
value: cvsValue, |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
}; |
|
|
@ -940,61 +958,66 @@ const createVirtualDiskForm = ( |
|
|
|
'sizes', |
|
|
|
'sizes', |
|
|
|
).toString()}, Max: ${get('maxes').toString()}`}
|
|
|
|
).toString()}, Max: ${get('maxes').toString()}`}
|
|
|
|
/> |
|
|
|
/> |
|
|
|
{createOutlinedInputWithSelect( |
|
|
|
<Box sx={{ display: 'flex', flexDirection: 'column' }}> |
|
|
|
`ps-virtual-disk-size-${vdIndex}`, |
|
|
|
{createOutlinedInputWithSelect( |
|
|
|
'Virtual disk size', |
|
|
|
`ps-virtual-disk-size-${vdIndex}`, |
|
|
|
DATA_SIZE_UNIT_SELECT_ITEMS, |
|
|
|
'Virtual disk size', |
|
|
|
{ |
|
|
|
DATA_SIZE_UNIT_SELECT_ITEMS, |
|
|
|
inputWithLabelProps: { |
|
|
|
{ |
|
|
|
inputProps: { |
|
|
|
inputWithLabelProps: { |
|
|
|
endAdornment: createMaxValueButton( |
|
|
|
inputProps: { |
|
|
|
`${get('inputMaxes')} ${get('inputUnits')}`, |
|
|
|
endAdornment: createMaxValueButton( |
|
|
|
{ |
|
|
|
`${get('inputMaxes')} ${get('inputUnits')}`, |
|
|
|
onButtonClick: () => { |
|
|
|
{ |
|
|
|
set('inputSizes', get('inputMaxes')); |
|
|
|
onButtonClick: () => { |
|
|
|
changeVDSize(get('maxes')); |
|
|
|
set('inputSizes', get('inputMaxes')); |
|
|
|
|
|
|
|
changeVDSize(get('maxes')); |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
|
|
|
|
handleVDSizeChange({ value }); |
|
|
|
}, |
|
|
|
}, |
|
|
|
), |
|
|
|
type: 'number', |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
value: get('inputSizes'), |
|
|
|
handleVDSizeChange({ value }); |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
type: 'number', |
|
|
|
|
|
|
|
value: get('inputSizes'), |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
selectProps: { |
|
|
|
selectProps: { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
const selectedUnit = value as DataSizeUnit; |
|
|
|
const selectedUnit = value as DataSizeUnit; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleVDSizeChange({ unit: selectedUnit }); |
|
|
|
handleVDSizeChange({ unit: selectedUnit }); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
value: get('inputUnits'), |
|
|
|
}, |
|
|
|
}, |
|
|
|
value: get('inputUnits'), |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
)} |
|
|
|
)} |
|
|
|
{createInputMessage(get('inputSizeMessages'))} |
|
|
|
{createOutlinedSelect( |
|
|
|
</Box> |
|
|
|
`ps-storage-group-${vdIndex}`, |
|
|
|
<Box sx={{ display: 'flex', flexDirection: 'column' }}> |
|
|
|
'Storage group', |
|
|
|
{createOutlinedSelect( |
|
|
|
storageGroupSelectItems, |
|
|
|
`ps-storage-group-${vdIndex}`, |
|
|
|
{ |
|
|
|
'Storage group', |
|
|
|
disableItem: (value) => |
|
|
|
storageGroupSelectItems, |
|
|
|
!( |
|
|
|
{ |
|
|
|
includeStorageGroupUUIDs.includes(value) && |
|
|
|
disableItem: (value) => |
|
|
|
get('sizes') <= storageGroupUUIDMapToFree[value] |
|
|
|
!( |
|
|
|
), |
|
|
|
includeStorageGroupUUIDs.includes(value) && |
|
|
|
selectProps: { |
|
|
|
get('sizes') <= storageGroupUUIDMapToFree[value] |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
), |
|
|
|
const selectedStorageGroupUUID = value as string; |
|
|
|
selectProps: { |
|
|
|
|
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
|
|
|
|
const selectedStorageGroupUUID = value as string; |
|
|
|
|
|
|
|
|
|
|
|
handleVDStorageGroupChange(selectedStorageGroupUUID); |
|
|
|
handleVDStorageGroupChange(selectedStorageGroupUUID); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
value: get('inputStorageGroupUUIDs'), |
|
|
|
|
|
|
|
onClearIndicatorClick: () => handleVDStorageGroupChange(''), |
|
|
|
}, |
|
|
|
}, |
|
|
|
value: get('inputStorageGroupUUIDs'), |
|
|
|
|
|
|
|
onClearIndicatorClick: () => handleVDStorageGroupChange(''), |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
)} |
|
|
|
)} |
|
|
|
{createInputMessage(get('inputStorageGroupUUIDMessages'))} |
|
|
|
{createErrorMessage(get('inputErrors'))} |
|
|
|
</Box> |
|
|
|
</Box> |
|
|
|
</Box> |
|
|
|
); |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
@ -1002,46 +1025,51 @@ const createVirtualDiskForm = ( |
|
|
|
const addVirtualDisk = ({ |
|
|
|
const addVirtualDisk = ({ |
|
|
|
existingVirtualDisks: virtualDisks = { |
|
|
|
existingVirtualDisks: virtualDisks = { |
|
|
|
maxes: [], |
|
|
|
maxes: [], |
|
|
|
inputErrors: [], |
|
|
|
|
|
|
|
inputMaxes: [], |
|
|
|
inputMaxes: [], |
|
|
|
|
|
|
|
inputSizeMessages: [], |
|
|
|
inputSizes: [], |
|
|
|
inputSizes: [], |
|
|
|
|
|
|
|
inputStorageGroupUUIDMessages: [], |
|
|
|
inputStorageGroupUUIDs: [], |
|
|
|
inputStorageGroupUUIDs: [], |
|
|
|
inputUnits: [], |
|
|
|
inputUnits: [], |
|
|
|
sizes: [], |
|
|
|
sizes: [], |
|
|
|
}, |
|
|
|
}, |
|
|
|
max = BIGINT_ZERO, |
|
|
|
max = BIGINT_ZERO, |
|
|
|
inputError = undefined, |
|
|
|
|
|
|
|
inputMax = '0', |
|
|
|
inputMax = '0', |
|
|
|
inputSize = '', |
|
|
|
inputSize = '', |
|
|
|
|
|
|
|
inputSizeMessage = undefined, |
|
|
|
inputStorageGroupUUID = '', |
|
|
|
inputStorageGroupUUID = '', |
|
|
|
|
|
|
|
inputStorageGroupUUIDMessage = undefined, |
|
|
|
inputUnit = 'B', |
|
|
|
inputUnit = 'B', |
|
|
|
setVirtualDisks, |
|
|
|
setVirtualDisks, |
|
|
|
size = BIGINT_ZERO, |
|
|
|
size = BIGINT_ZERO, |
|
|
|
}: { |
|
|
|
}: { |
|
|
|
existingVirtualDisks?: VirtualDiskStates; |
|
|
|
existingVirtualDisks?: VirtualDiskStates; |
|
|
|
max?: bigint; |
|
|
|
max?: bigint; |
|
|
|
inputError?: string | undefined; |
|
|
|
|
|
|
|
inputMax?: string; |
|
|
|
inputMax?: string; |
|
|
|
inputSize?: string; |
|
|
|
inputSize?: string; |
|
|
|
|
|
|
|
inputSizeMessage?: InputMessage | undefined; |
|
|
|
inputStorageGroupUUID?: string; |
|
|
|
inputStorageGroupUUID?: string; |
|
|
|
|
|
|
|
inputStorageGroupUUIDMessage?: InputMessage | undefined; |
|
|
|
inputUnit?: DataSizeUnit; |
|
|
|
inputUnit?: DataSizeUnit; |
|
|
|
setVirtualDisks?: Dispatch<SetStateAction<VirtualDiskStates>>; |
|
|
|
setVirtualDisks?: Dispatch<SetStateAction<VirtualDiskStates>>; |
|
|
|
size?: bigint; |
|
|
|
size?: bigint; |
|
|
|
} = {}) => { |
|
|
|
} = {}) => { |
|
|
|
const { |
|
|
|
const { |
|
|
|
maxes, |
|
|
|
maxes, |
|
|
|
inputErrors, |
|
|
|
|
|
|
|
inputMaxes, |
|
|
|
inputMaxes, |
|
|
|
|
|
|
|
inputSizeMessages, |
|
|
|
inputSizes, |
|
|
|
inputSizes, |
|
|
|
|
|
|
|
inputStorageGroupUUIDMessages, |
|
|
|
inputStorageGroupUUIDs, |
|
|
|
inputStorageGroupUUIDs, |
|
|
|
inputUnits, |
|
|
|
inputUnits, |
|
|
|
sizes, |
|
|
|
sizes, |
|
|
|
} = virtualDisks; |
|
|
|
} = virtualDisks; |
|
|
|
|
|
|
|
|
|
|
|
maxes.push(max); |
|
|
|
maxes.push(max); |
|
|
|
inputErrors.push(inputError); |
|
|
|
|
|
|
|
inputMaxes.push(inputMax); |
|
|
|
inputMaxes.push(inputMax); |
|
|
|
|
|
|
|
inputSizeMessages.push(inputSizeMessage); |
|
|
|
inputSizes.push(inputSize); |
|
|
|
inputSizes.push(inputSize); |
|
|
|
|
|
|
|
inputStorageGroupUUIDMessages.push(inputStorageGroupUUIDMessage); |
|
|
|
inputStorageGroupUUIDs.push(inputStorageGroupUUID); |
|
|
|
inputStorageGroupUUIDs.push(inputStorageGroupUUID); |
|
|
|
inputUnits.push(inputUnit); |
|
|
|
inputUnits.push(inputUnit); |
|
|
|
sizes.push(size); |
|
|
|
sizes.push(size); |
|
|
@ -1076,14 +1104,14 @@ const ProvisionServerDialog = ({ |
|
|
|
|
|
|
|
|
|
|
|
const [inputCPUCoresValue, setInputCPUCoresValue] = useState<number>(1); |
|
|
|
const [inputCPUCoresValue, setInputCPUCoresValue] = useState<number>(1); |
|
|
|
const [inputCPUCoresMax, setInputCPUCoresMax] = useState<number>(0); |
|
|
|
const [inputCPUCoresMax, setInputCPUCoresMax] = useState<number>(0); |
|
|
|
const [inputCPUCoresError, setInputCPUCoresError] = useState< |
|
|
|
const [inputCPUCoresMessage, setInputCPUCoresMessage] = useState< |
|
|
|
string | undefined |
|
|
|
InputMessage | undefined |
|
|
|
>(); |
|
|
|
>(); |
|
|
|
|
|
|
|
|
|
|
|
const [memory, setMemory] = useState<bigint>(BIGINT_ZERO); |
|
|
|
const [memory, setMemory] = useState<bigint>(BIGINT_ZERO); |
|
|
|
const [memoryMax, setMemoryMax] = useState<bigint>(BIGINT_ZERO); |
|
|
|
const [memoryMax, setMemoryMax] = useState<bigint>(BIGINT_ZERO); |
|
|
|
const [inputMemoryError, setInputMemoryError] = useState< |
|
|
|
const [inputMemoryMessage, setInputMemoryMessage] = useState< |
|
|
|
string | undefined |
|
|
|
InputMessage | undefined |
|
|
|
>(); |
|
|
|
>(); |
|
|
|
const [inputMemoryMax, setInputMemoryMax] = useState<string>('0'); |
|
|
|
const [inputMemoryMax, setInputMemoryMax] = useState<string>('0'); |
|
|
|
const [inputMemoryValue, setInputMemoryValue] = useState<string>(''); |
|
|
|
const [inputMemoryValue, setInputMemoryValue] = useState<string>(''); |
|
|
@ -1095,10 +1123,17 @@ const ProvisionServerDialog = ({ |
|
|
|
|
|
|
|
|
|
|
|
const [inputInstallISOFileUUID, setInputInstallISOFileUUID] = |
|
|
|
const [inputInstallISOFileUUID, setInputInstallISOFileUUID] = |
|
|
|
useState<string>(''); |
|
|
|
useState<string>(''); |
|
|
|
|
|
|
|
const [inputInstallISOMessage, setInputInstallISOMessage] = useState< |
|
|
|
|
|
|
|
InputMessage | undefined |
|
|
|
|
|
|
|
>(); |
|
|
|
const [inputDriverISOFileUUID, setInputDriverISOFileUUID] = |
|
|
|
const [inputDriverISOFileUUID, setInputDriverISOFileUUID] = |
|
|
|
useState<string>(''); |
|
|
|
useState<string>(''); |
|
|
|
|
|
|
|
const [inputDriverISOMessage] = useState<InputMessage | undefined>(); |
|
|
|
|
|
|
|
|
|
|
|
const [inputAnvilValue, setInputAnvilValue] = useState<string>(''); |
|
|
|
const [inputAnvilValue, setInputAnvilValue] = useState<string>(''); |
|
|
|
|
|
|
|
const [inputAnvilMessage, setInputAnvilMessage] = useState< |
|
|
|
|
|
|
|
InputMessage | undefined |
|
|
|
|
|
|
|
>(); |
|
|
|
|
|
|
|
|
|
|
|
const [includeAnvilUUIDs, setIncludeAnvilUUIDs] = useState<string[]>([]); |
|
|
|
const [includeAnvilUUIDs, setIncludeAnvilUUIDs] = useState<string[]>([]); |
|
|
|
const [includeFileUUIDs, setIncludeFileUUIDs] = useState<string[]>([]); |
|
|
|
const [includeFileUUIDs, setIncludeFileUUIDs] = useState<string[]>([]); |
|
|
@ -1180,11 +1215,13 @@ const ProvisionServerDialog = ({ |
|
|
|
// 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: TestInputFunction = (inputs: { |
|
|
|
const testInput: TestInputFunction = ({ |
|
|
|
[id: string]: Partial<TestArgs>; |
|
|
|
inputs, |
|
|
|
}): boolean => { |
|
|
|
isContinueOnFailure, |
|
|
|
const testNotBlank = ({ value }: TestArgs) => value !== ''; |
|
|
|
isIgnoreOnCallbacks, |
|
|
|
const testMax = ({ max, min }: TestArgs) => max >= min; |
|
|
|
} = {}): boolean => { |
|
|
|
|
|
|
|
const testNotBlank = ({ value }: Pick<TestArgs, 'value'>) => value !== ''; |
|
|
|
|
|
|
|
const testMax = ({ max, min }: Pick<TestArgs, 'max' | 'min'>) => max >= min; |
|
|
|
const testRange = ({ max, min, value }: TestArgs) => |
|
|
|
const testRange = ({ max, min, value }: TestArgs) => |
|
|
|
value >= min && value <= max; |
|
|
|
value >= min && value <= max; |
|
|
|
|
|
|
|
|
|
|
@ -1193,11 +1230,9 @@ const ProvisionServerDialog = ({ |
|
|
|
defaults: TestArgs & { |
|
|
|
defaults: TestArgs & { |
|
|
|
onSuccess: () => void; |
|
|
|
onSuccess: () => void; |
|
|
|
}; |
|
|
|
}; |
|
|
|
tests: Array<{ |
|
|
|
onFinishBatch?: () => void; |
|
|
|
onFailure?: (args: TestArgs) => void; |
|
|
|
optionalTests?: Array<InputTest>; |
|
|
|
onSuccess?: () => void; |
|
|
|
tests: Array<InputTest>; |
|
|
|
test: (args: TestArgs) => boolean; |
|
|
|
|
|
|
|
}>; |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
} = { |
|
|
|
} = { |
|
|
|
cpuCores: { |
|
|
|
cpuCores: { |
|
|
@ -1205,22 +1240,26 @@ const ProvisionServerDialog = ({ |
|
|
|
max: inputCPUCoresMax, |
|
|
|
max: inputCPUCoresMax, |
|
|
|
min: inputCPUCoresMin, |
|
|
|
min: inputCPUCoresMin, |
|
|
|
onSuccess: () => { |
|
|
|
onSuccess: () => { |
|
|
|
setInputCPUCoresError(''); |
|
|
|
setInputCPUCoresMessage(undefined); |
|
|
|
}, |
|
|
|
}, |
|
|
|
value: inputCPUCoresValue, |
|
|
|
value: inputCPUCoresValue, |
|
|
|
}, |
|
|
|
}, |
|
|
|
tests: [ |
|
|
|
tests: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
onFailure: () => { |
|
|
|
onFailure: () => { |
|
|
|
setInputCPUCoresError('Non available.'); |
|
|
|
setInputCPUCoresMessage({ |
|
|
|
|
|
|
|
text: 'Non available.', |
|
|
|
|
|
|
|
type: 'error', |
|
|
|
|
|
|
|
}); |
|
|
|
}, |
|
|
|
}, |
|
|
|
test: testMax, |
|
|
|
test: testMax, |
|
|
|
}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
{ |
|
|
|
onFailure: ({ max, min }) => { |
|
|
|
onFailure: ({ max, min }) => { |
|
|
|
setInputCPUCoresError( |
|
|
|
setInputCPUCoresMessage({ |
|
|
|
`The number of CPU cores is expected to be between ${min} and ${max}.`, |
|
|
|
text: `The number of CPU cores is expected to be between ${min} and ${max}.`, |
|
|
|
); |
|
|
|
type: 'error', |
|
|
|
|
|
|
|
}); |
|
|
|
}, |
|
|
|
}, |
|
|
|
test: testRange, |
|
|
|
test: testRange, |
|
|
|
}, |
|
|
|
}, |
|
|
@ -1231,56 +1270,89 @@ const ProvisionServerDialog = ({ |
|
|
|
max: memoryMax, |
|
|
|
max: memoryMax, |
|
|
|
min: 1, |
|
|
|
min: 1, |
|
|
|
onSuccess: () => { |
|
|
|
onSuccess: () => { |
|
|
|
setInputMemoryError(''); |
|
|
|
setInputMemoryMessage(undefined); |
|
|
|
}, |
|
|
|
}, |
|
|
|
value: memory, |
|
|
|
value: memory, |
|
|
|
}, |
|
|
|
}, |
|
|
|
tests: [ |
|
|
|
tests: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
onFailure: () => { |
|
|
|
onFailure: () => { |
|
|
|
setInputMemoryError('Non available.'); |
|
|
|
setInputMemoryMessage({ text: 'Non available.', type: 'error' }); |
|
|
|
}, |
|
|
|
}, |
|
|
|
test: testMax, |
|
|
|
test: testMax, |
|
|
|
}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
{ |
|
|
|
onFailure: ({ max, min }) => { |
|
|
|
onFailure: ({ max, min }) => { |
|
|
|
setInputMemoryError( |
|
|
|
setInputMemoryMessage({ |
|
|
|
`Memory is expected to be between ${min} B and ${max} B.`, |
|
|
|
text: `Memory is expected to be between ${min} B and ${max} B.`, |
|
|
|
); |
|
|
|
type: 'error', |
|
|
|
|
|
|
|
}); |
|
|
|
}, |
|
|
|
}, |
|
|
|
test: testRange, |
|
|
|
test: testRange, |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
], |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
installISO: { |
|
|
|
|
|
|
|
defaults: { |
|
|
|
|
|
|
|
max: 0, |
|
|
|
|
|
|
|
min: 0, |
|
|
|
|
|
|
|
onSuccess: () => { |
|
|
|
|
|
|
|
setInputInstallISOMessage(undefined); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
value: inputInstallISOFileUUID, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
tests: [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
test: testNotBlank, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
anvil: { |
|
|
|
|
|
|
|
defaults: { |
|
|
|
|
|
|
|
max: 0, |
|
|
|
|
|
|
|
min: 0, |
|
|
|
|
|
|
|
onSuccess: () => { |
|
|
|
|
|
|
|
setInputAnvilMessage(undefined); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
value: inputAnvilValue, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
tests: [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
test: testNotBlank, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
}, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
virtualDisks.inputErrors.forEach((error, vdIndex) => { |
|
|
|
virtualDisks.inputSizeMessages.forEach((error, vdIndex) => { |
|
|
|
const defaultOnSuccess = () => { |
|
|
|
|
|
|
|
virtualDisks.inputErrors[vdIndex] = undefined; |
|
|
|
|
|
|
|
setVirtualDisks({ ...virtualDisks }); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tests[`vd${vdIndex}Size`] = { |
|
|
|
tests[`vd${vdIndex}Size`] = { |
|
|
|
defaults: { |
|
|
|
defaults: { |
|
|
|
max: virtualDisks.maxes[vdIndex], |
|
|
|
max: virtualDisks.maxes[vdIndex], |
|
|
|
min: 1, |
|
|
|
min: 1, |
|
|
|
onSuccess: defaultOnSuccess, |
|
|
|
onSuccess: () => { |
|
|
|
|
|
|
|
virtualDisks.inputSizeMessages[vdIndex] = undefined; |
|
|
|
|
|
|
|
}, |
|
|
|
value: virtualDisks.sizes[vdIndex], |
|
|
|
value: virtualDisks.sizes[vdIndex], |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
onFinishBatch: () => { |
|
|
|
|
|
|
|
setVirtualDisks({ ...virtualDisks }); |
|
|
|
|
|
|
|
}, |
|
|
|
tests: [ |
|
|
|
tests: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
onFailure: () => { |
|
|
|
onFailure: () => { |
|
|
|
virtualDisks.inputErrors[vdIndex] = 'Non available.'; |
|
|
|
virtualDisks.inputSizeMessages[vdIndex] = { |
|
|
|
setVirtualDisks({ ...virtualDisks }); |
|
|
|
text: 'Non available.', |
|
|
|
|
|
|
|
type: 'error', |
|
|
|
|
|
|
|
}; |
|
|
|
}, |
|
|
|
}, |
|
|
|
test: testMax, |
|
|
|
test: testMax, |
|
|
|
}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
{ |
|
|
|
onFailure: ({ max, min }) => { |
|
|
|
onFailure: ({ max, min }) => { |
|
|
|
virtualDisks.inputErrors[ |
|
|
|
virtualDisks.inputSizeMessages[vdIndex] = { |
|
|
|
vdIndex |
|
|
|
text: `Virtual disk ${vdIndex} size is expected to be between ${min} B and ${max} B.`, |
|
|
|
] = `Virtual disk ${vdIndex} size is expected to be between ${min} B and ${max} B.`; |
|
|
|
type: 'error', |
|
|
|
setVirtualDisks({ ...virtualDisks }); |
|
|
|
}; |
|
|
|
}, |
|
|
|
}, |
|
|
|
test: testRange, |
|
|
|
test: testRange, |
|
|
|
}, |
|
|
|
}, |
|
|
@ -1291,24 +1363,37 @@ const ProvisionServerDialog = ({ |
|
|
|
defaults: { |
|
|
|
defaults: { |
|
|
|
max: 0, |
|
|
|
max: 0, |
|
|
|
min: 0, |
|
|
|
min: 0, |
|
|
|
onSuccess: defaultOnSuccess, |
|
|
|
onSuccess: () => { |
|
|
|
|
|
|
|
virtualDisks.inputStorageGroupUUIDMessages[vdIndex] = undefined; |
|
|
|
|
|
|
|
}, |
|
|
|
value: virtualDisks.inputStorageGroupUUIDs[vdIndex], |
|
|
|
value: virtualDisks.inputStorageGroupUUIDs[vdIndex], |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
onFinishBatch: () => { |
|
|
|
|
|
|
|
setVirtualDisks({ ...virtualDisks }); |
|
|
|
|
|
|
|
}, |
|
|
|
tests: [ |
|
|
|
tests: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
onFailure: () => { |
|
|
|
|
|
|
|
virtualDisks.inputErrors[ |
|
|
|
|
|
|
|
vdIndex |
|
|
|
|
|
|
|
] = `Virtual disk ${vdIndex} storage group shouldn't be blank.`; |
|
|
|
|
|
|
|
setVirtualDisks({ ...virtualDisks }); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
test: testNotBlank, |
|
|
|
test: testNotBlank, |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
], |
|
|
|
}; |
|
|
|
}; |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
return Object.keys(inputs).every((id: string) => { |
|
|
|
const testsToRun = |
|
|
|
|
|
|
|
inputs ?? |
|
|
|
|
|
|
|
Object.keys(tests).reduce< |
|
|
|
|
|
|
|
Exclude< |
|
|
|
|
|
|
|
Exclude<Parameters<TestInputFunction>[0], undefined>['inputs'], |
|
|
|
|
|
|
|
undefined |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
>((reduceContainer, id: string) => { |
|
|
|
|
|
|
|
reduceContainer[id] = {}; |
|
|
|
|
|
|
|
return reduceContainer; |
|
|
|
|
|
|
|
}, {}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let allResult = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object.keys(testsToRun).every((id: string) => { |
|
|
|
const { |
|
|
|
const { |
|
|
|
defaults: { |
|
|
|
defaults: { |
|
|
|
max: dMax, |
|
|
|
max: dMax, |
|
|
@ -1316,23 +1401,59 @@ const ProvisionServerDialog = ({ |
|
|
|
onSuccess: dOnSuccess, |
|
|
|
onSuccess: dOnSuccess, |
|
|
|
value: dValue, |
|
|
|
value: dValue, |
|
|
|
}, |
|
|
|
}, |
|
|
|
tests: group, |
|
|
|
onFinishBatch: dOnFinishBatch, |
|
|
|
|
|
|
|
optionalTests, |
|
|
|
|
|
|
|
tests: requiredTests, |
|
|
|
} = tests[id]; |
|
|
|
} = tests[id]; |
|
|
|
const { max = dMax, min = dMin, value = dValue } = inputs[id]; |
|
|
|
const { max = dMax, min = dMin, value = dValue } = testsToRun[id]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let cbFinishBatch; |
|
|
|
|
|
|
|
let setOnResult: (test?: Partial<InputTest>) => { |
|
|
|
|
|
|
|
cbFailure: InputTest['onFailure']; |
|
|
|
|
|
|
|
cbSuccess: InputTest['onSuccess']; |
|
|
|
|
|
|
|
} = () => ({ cbFailure: undefined, cbSuccess: undefined }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!isIgnoreOnCallbacks) { |
|
|
|
|
|
|
|
cbFinishBatch = dOnFinishBatch; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setOnResult = ({ onFailure, onSuccess }: Partial<InputTest> = {}) => ({ |
|
|
|
|
|
|
|
cbFailure: onFailure, |
|
|
|
|
|
|
|
cbSuccess: onSuccess, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return group.every(({ onFailure, onSuccess = dOnSuccess, test }) => { |
|
|
|
const runTest: (test: InputTest) => boolean = ({ |
|
|
|
|
|
|
|
onFailure, |
|
|
|
|
|
|
|
onSuccess = dOnSuccess, |
|
|
|
|
|
|
|
test, |
|
|
|
|
|
|
|
}) => { |
|
|
|
const args = { max, min, value }; |
|
|
|
const args = { max, min, value }; |
|
|
|
const result: boolean = test(args); |
|
|
|
const singleResult: boolean = test(args); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { cbFailure, cbSuccess } = setOnResult({ onFailure, onSuccess }); |
|
|
|
|
|
|
|
|
|
|
|
if (result) { |
|
|
|
if (singleResult) { |
|
|
|
onSuccess?.call(null); |
|
|
|
cbSuccess?.call(null); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
onFailure?.call(null, args); |
|
|
|
allResult = singleResult; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cbFailure?.call(null, args); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
return singleResult; |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Don't need to pass optional tests for input to be valid.
|
|
|
|
|
|
|
|
optionalTests?.forEach(runTest); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const requiredTestsResult = requiredTests.every(runTest); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cbFinishBatch?.call(null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return requiredTestsResult || isContinueOnFailure; |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return allResult; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const changeMemory = ({ |
|
|
|
const changeMemory = ({ |
|
|
@ -1346,7 +1467,7 @@ const ProvisionServerDialog = ({ |
|
|
|
memory: cmValue, |
|
|
|
memory: cmValue, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
testInput({ memory: { max: maxMemory, value: cmValue } }); |
|
|
|
testInput({ inputs: { memory: { max: maxMemory, value: cmValue } } }); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleInputMemoryValueChange = ({ |
|
|
|
const handleInputMemoryValueChange = ({ |
|
|
@ -1462,7 +1583,7 @@ const ProvisionServerDialog = ({ |
|
|
|
> |
|
|
|
> |
|
|
|
<OutlinedInputWithLabel id="ps-server-name" label="Server name" /> |
|
|
|
<OutlinedInputWithLabel id="ps-server-name" label="Server name" /> |
|
|
|
{createOutlinedSlider('ps-cpu-cores', 'CPU cores', inputCPUCoresValue, { |
|
|
|
{createOutlinedSlider('ps-cpu-cores', 'CPU cores', inputCPUCoresValue, { |
|
|
|
error: inputCPUCoresError, |
|
|
|
messageBoxProps: inputCPUCoresMessage, |
|
|
|
sliderProps: { |
|
|
|
sliderProps: { |
|
|
|
onChange: (value) => { |
|
|
|
onChange: (value) => { |
|
|
|
const newCPUCoresValue = value as number; |
|
|
|
const newCPUCoresValue = value as number; |
|
|
@ -1475,7 +1596,9 @@ const ProvisionServerDialog = ({ |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
testInput({ |
|
|
|
testInput({ |
|
|
|
cpuCores: { max: newCPUCoresMax, value: newCPUCoresValue }, |
|
|
|
inputs: { |
|
|
|
|
|
|
|
cpuCores: { max: newCPUCoresMax, value: newCPUCoresValue }, |
|
|
|
|
|
|
|
}, |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
@ -1491,7 +1614,7 @@ const ProvisionServerDialog = ({ |
|
|
|
'Memory', |
|
|
|
'Memory', |
|
|
|
DATA_SIZE_UNIT_SELECT_ITEMS, |
|
|
|
DATA_SIZE_UNIT_SELECT_ITEMS, |
|
|
|
{ |
|
|
|
{ |
|
|
|
error: inputMemoryError, |
|
|
|
messageBoxProps: inputMemoryMessage, |
|
|
|
inputWithLabelProps: { |
|
|
|
inputWithLabelProps: { |
|
|
|
inputProps: { |
|
|
|
inputProps: { |
|
|
|
endAdornment: createMaxValueButton( |
|
|
|
endAdornment: createMaxValueButton( |
|
|
@ -1539,6 +1662,7 @@ const ProvisionServerDialog = ({ |
|
|
|
{ |
|
|
|
{ |
|
|
|
disableItem: (value) => value === inputDriverISOFileUUID, |
|
|
|
disableItem: (value) => value === inputDriverISOFileUUID, |
|
|
|
hideItem: (value) => !includeFileUUIDs.includes(value), |
|
|
|
hideItem: (value) => !includeFileUUIDs.includes(value), |
|
|
|
|
|
|
|
messageBoxProps: inputInstallISOMessage, |
|
|
|
selectProps: { |
|
|
|
selectProps: { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
const newInstallISOFileUUID = value as string; |
|
|
|
const newInstallISOFileUUID = value as string; |
|
|
@ -1558,6 +1682,7 @@ const ProvisionServerDialog = ({ |
|
|
|
{ |
|
|
|
{ |
|
|
|
disableItem: (value) => value === inputInstallISOFileUUID, |
|
|
|
disableItem: (value) => value === inputInstallISOFileUUID, |
|
|
|
hideItem: (value) => !includeFileUUIDs.includes(value), |
|
|
|
hideItem: (value) => !includeFileUUIDs.includes(value), |
|
|
|
|
|
|
|
messageBoxProps: inputDriverISOMessage, |
|
|
|
selectProps: { |
|
|
|
selectProps: { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
const newDriverISOFileUUID = value as string; |
|
|
|
const newDriverISOFileUUID = value as string; |
|
|
@ -1572,6 +1697,7 @@ const ProvisionServerDialog = ({ |
|
|
|
)} |
|
|
|
)} |
|
|
|
{createOutlinedSelect('ps-anvil', 'Anvil', anvilSelectItems, { |
|
|
|
{createOutlinedSelect('ps-anvil', 'Anvil', anvilSelectItems, { |
|
|
|
disableItem: (value) => !includeAnvilUUIDs.includes(value), |
|
|
|
disableItem: (value) => !includeAnvilUUIDs.includes(value), |
|
|
|
|
|
|
|
messageBoxProps: inputAnvilMessage, |
|
|
|
selectProps: { |
|
|
|
selectProps: { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
const newAnvilUUID: string = value as string; |
|
|
|
const newAnvilUUID: string = value as string; |
|
|
@ -1599,7 +1725,9 @@ const ProvisionServerDialog = ({ |
|
|
|
width: '100%', |
|
|
|
width: '100%', |
|
|
|
}} |
|
|
|
}} |
|
|
|
> |
|
|
|
> |
|
|
|
<ContainedButton>Provision</ContainedButton> |
|
|
|
<ContainedButton disabled={!testInput({ isIgnoreOnCallbacks: true })}> |
|
|
|
|
|
|
|
Provision |
|
|
|
|
|
|
|
</ContainedButton> |
|
|
|
</Box> |
|
|
|
</Box> |
|
|
|
</Dialog> |
|
|
|
</Dialog> |
|
|
|
); |
|
|
|
); |
|
|
|