|
|
@ -1,97 +1,101 @@ |
|
|
|
import { useEffect, useState } from 'react'; |
|
|
|
import { useEffect, useState } from 'react'; |
|
|
|
|
|
|
|
import { Dialog, DialogProps, FormControl, FormGroup } from '@mui/material'; |
|
|
|
import { |
|
|
|
import { |
|
|
|
Box, |
|
|
|
dSize as baseDSize, |
|
|
|
Dialog, |
|
|
|
DataSizeUnit, |
|
|
|
DialogProps, |
|
|
|
FormatDataSizeOptions, |
|
|
|
FormControl, |
|
|
|
FormatDataSizeInputValue, |
|
|
|
FormGroup, |
|
|
|
} from 'format-data-size'; |
|
|
|
} from '@mui/material'; |
|
|
|
|
|
|
|
import { dSize, dSizeStr } from 'format-data-size'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import MenuItem from './MenuItem'; |
|
|
|
import MenuItem from './MenuItem'; |
|
|
|
import OutlinedInput from './OutlinedInput'; |
|
|
|
import OutlinedInput, { OutlinedInputProps } from './OutlinedInput'; |
|
|
|
import OutlinedInputLabel from './OutlinedInputLabel'; |
|
|
|
import OutlinedInputLabel from './OutlinedInputLabel'; |
|
|
|
import { Panel, PanelHeader } from './Panels'; |
|
|
|
import { Panel, PanelHeader } from './Panels'; |
|
|
|
import Select from './Select'; |
|
|
|
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'; |
|
|
|
|
|
|
|
import ContainedButton from './ContainedButton'; |
|
|
|
|
|
|
|
|
|
|
|
type ProvisionServerDialogProps = { |
|
|
|
type ProvisionServerDialogProps = { |
|
|
|
dialogProps: DialogProps; |
|
|
|
dialogProps: DialogProps; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const BIGINT_ZERO = BigInt(0); |
|
|
|
type HostMetadataForProvisionServerHost = { |
|
|
|
|
|
|
|
hostUUID: string; |
|
|
|
const createOutlinedInput = (id: string, label: string): JSX.Element => ( |
|
|
|
hostName: string; |
|
|
|
<FormControl> |
|
|
|
hostCPUCores: number; |
|
|
|
<OutlinedInputLabel {...{ htmlFor: id }}>{label}</OutlinedInputLabel> |
|
|
|
hostMemory: string; |
|
|
|
<OutlinedInput {...{ id, label }} /> |
|
|
|
}; |
|
|
|
</FormControl> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const createOutlinedSelect = ( |
|
|
|
|
|
|
|
id: string, |
|
|
|
|
|
|
|
label: string | undefined, |
|
|
|
|
|
|
|
value: string, |
|
|
|
|
|
|
|
selectItems: string[][] | string[], |
|
|
|
|
|
|
|
): JSX.Element => ( |
|
|
|
|
|
|
|
<FormControl> |
|
|
|
|
|
|
|
{label && ( |
|
|
|
|
|
|
|
<OutlinedInputLabel {...{ htmlFor: id }}>{label}</OutlinedInputLabel> |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
<Select {...{ id, input: <OutlinedInput {...{ label }} />, value }}> |
|
|
|
|
|
|
|
{selectItems.map((item) => { |
|
|
|
|
|
|
|
let itemValue; |
|
|
|
|
|
|
|
let itemDisplayValue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item instanceof Array) { |
|
|
|
type ServerMetadataForProvisionServer = { |
|
|
|
[itemValue, itemDisplayValue] = item; |
|
|
|
serverUUID: string; |
|
|
|
} else { |
|
|
|
serverName: string; |
|
|
|
itemValue = item; |
|
|
|
serverCPUCores: number; |
|
|
|
itemDisplayValue = item; |
|
|
|
serverMemory: string; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
type StorageGroupMetadataForProvisionServer = { |
|
|
|
<MenuItem key={`${id}-${itemValue}`} value={itemValue}> |
|
|
|
storageGroupUUID: string; |
|
|
|
{itemDisplayValue} |
|
|
|
storageGroupName: string; |
|
|
|
</MenuItem> |
|
|
|
storageGroupSize: string; |
|
|
|
); |
|
|
|
storageGroupFree: string; |
|
|
|
})} |
|
|
|
}; |
|
|
|
</Select> |
|
|
|
|
|
|
|
</FormControl> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const createOutlinedSlider = ( |
|
|
|
type FileMetadataForProvisionServer = { |
|
|
|
id: string, |
|
|
|
fileUUID: string; |
|
|
|
label: string, |
|
|
|
fileName: string; |
|
|
|
sliderProps?: Partial<SliderProps>, |
|
|
|
}; |
|
|
|
): JSX.Element => ( |
|
|
|
|
|
|
|
<FormControl> |
|
|
|
|
|
|
|
<Slider |
|
|
|
|
|
|
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
|
|
|
|
|
|
{...{ |
|
|
|
|
|
|
|
isAllowTextInput: true, |
|
|
|
|
|
|
|
label, |
|
|
|
|
|
|
|
labelId: `${id}-label`, |
|
|
|
|
|
|
|
value: 1, |
|
|
|
|
|
|
|
...sliderProps, |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</FormControl> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ProvisionServerDialog = ({ |
|
|
|
type AnvilDetailMetadataForProvisionServer = { |
|
|
|
dialogProps: { open }, |
|
|
|
anvilUUID: string; |
|
|
|
}: ProvisionServerDialogProps): JSX.Element => { |
|
|
|
anvilName: string; |
|
|
|
const [sliderMaxAvailableCPUCores, setSliderMaxAvailableCPUCores] = |
|
|
|
anvilTotalCPUCores: number; |
|
|
|
useState<number>(0); |
|
|
|
anvilTotalMemory: string; |
|
|
|
const [sliderMaxAvailableMemory, setSliderMaxAvailableMemory] = |
|
|
|
anvilTotalAllocatedCPUCores: number; |
|
|
|
useState<number>(0); |
|
|
|
anvilTotalAllocatedMemory: string; |
|
|
|
|
|
|
|
anvilTotalAvailableCPUCores: number; |
|
|
|
|
|
|
|
anvilTotalAvailableMemory: string; |
|
|
|
|
|
|
|
hosts: Array<HostMetadataForProvisionServerHost>; |
|
|
|
|
|
|
|
servers: Array<ServerMetadataForProvisionServer>; |
|
|
|
|
|
|
|
storageGroups: Array<StorageGroupMetadataForProvisionServer>; |
|
|
|
|
|
|
|
files: Array<FileMetadataForProvisionServer>; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const [memory, setMemory] = useState<bigint>(BIGINT_ZERO); |
|
|
|
type OrganizedAnvilDetailMetadataForProvisionServer = Omit< |
|
|
|
const [memoryUnit, setMemoryUnit] = useState<string>(''); |
|
|
|
AnvilDetailMetadataForProvisionServer, |
|
|
|
|
|
|
|
| 'anvilTotalMemory' |
|
|
|
|
|
|
|
| 'anvilTotalAllocatedMemory' |
|
|
|
|
|
|
|
| 'anvilTotalAvailableMemory' |
|
|
|
|
|
|
|
| 'hosts' |
|
|
|
|
|
|
|
| 'servers' |
|
|
|
|
|
|
|
| 'storageGroups' |
|
|
|
|
|
|
|
> & { |
|
|
|
|
|
|
|
anvilTotalMemory: bigint; |
|
|
|
|
|
|
|
anvilTotalAllocatedMemory: bigint; |
|
|
|
|
|
|
|
anvilTotalAvailableMemory: bigint; |
|
|
|
|
|
|
|
anvilMaxAvailableStorage: bigint; |
|
|
|
|
|
|
|
hosts: Array< |
|
|
|
|
|
|
|
Omit<HostMetadataForProvisionServerHost, 'hostMemory'> & { |
|
|
|
|
|
|
|
hostMemory: bigint; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
>; |
|
|
|
|
|
|
|
servers: Array< |
|
|
|
|
|
|
|
Omit<ServerMetadataForProvisionServer, 'serverMemory'> & { |
|
|
|
|
|
|
|
serverMemory: bigint; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
>; |
|
|
|
|
|
|
|
storageGroups: Array< |
|
|
|
|
|
|
|
Omit< |
|
|
|
|
|
|
|
StorageGroupMetadataForProvisionServer, |
|
|
|
|
|
|
|
'storageGroupSize' | 'storageGroupFree' |
|
|
|
|
|
|
|
> & { |
|
|
|
|
|
|
|
storageGroupSize: bigint; |
|
|
|
|
|
|
|
storageGroupFree: bigint; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
>; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const data = { |
|
|
|
const MOCK_DATA = { |
|
|
|
anvils: [ |
|
|
|
anvils: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
anvilUUID: 'ad590bcb-24e1-4592-8cd1-9cd6229b7bf2', |
|
|
|
anvilUUID: 'ad590bcb-24e1-4592-8cd1-9cd6229b7bf2', |
|
|
@ -175,7 +179,20 @@ const ProvisionServerDialog = ({ |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
], |
|
|
|
servers: [], |
|
|
|
servers: [], |
|
|
|
storageGroups: [], |
|
|
|
storageGroups: [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
storageGroupUUID: '271651b0-c064-401b-9391-549bbced2383', |
|
|
|
|
|
|
|
storageGroupName: 'Mock storage group 1', |
|
|
|
|
|
|
|
storageGroupSize: '274651414528', |
|
|
|
|
|
|
|
storageGroupFree: '85882568704', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
storageGroupUUID: '271651b0-c064-401b-9391-549bbced2383', |
|
|
|
|
|
|
|
storageGroupName: 'Mock storage group 2', |
|
|
|
|
|
|
|
storageGroupSize: '205988560896', |
|
|
|
|
|
|
|
storageGroupFree: '171765137408', |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
], |
|
|
|
files: [ |
|
|
|
files: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
fileUUID: '5d6fc6d9-03f8-40ec-9bff-38e31b3a5bc5', |
|
|
|
fileUUID: '5d6fc6d9-03f8-40ec-9bff-38e31b3a5bc5', |
|
|
@ -213,27 +230,189 @@ const ProvisionServerDialog = ({ |
|
|
|
], |
|
|
|
], |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const { maxAvailableCPUCores, maxAvailableMemory } = data.anvils.reduce<{ |
|
|
|
const BIGINT_ZERO = BigInt(0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const DATA_SIZE_UNITS: DataSizeUnit[] = [ |
|
|
|
|
|
|
|
'B', |
|
|
|
|
|
|
|
'KiB', |
|
|
|
|
|
|
|
'MiB', |
|
|
|
|
|
|
|
'GiB', |
|
|
|
|
|
|
|
'TiB', |
|
|
|
|
|
|
|
'kB', |
|
|
|
|
|
|
|
'MB', |
|
|
|
|
|
|
|
'GB', |
|
|
|
|
|
|
|
'TB', |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const createOutlinedInput = ( |
|
|
|
|
|
|
|
id: string, |
|
|
|
|
|
|
|
label: string, |
|
|
|
|
|
|
|
inputProps?: Partial<OutlinedInputProps>, |
|
|
|
|
|
|
|
): JSX.Element => ( |
|
|
|
|
|
|
|
<FormControl> |
|
|
|
|
|
|
|
<OutlinedInputLabel {...{ htmlFor: id }}>{label}</OutlinedInputLabel> |
|
|
|
|
|
|
|
{/* eslint-disable-next-line react/jsx-props-no-spreading */} |
|
|
|
|
|
|
|
<OutlinedInput {...{ id, label, ...inputProps }} /> |
|
|
|
|
|
|
|
</FormControl> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const createOutlinedSelect = ( |
|
|
|
|
|
|
|
id: string, |
|
|
|
|
|
|
|
label: string | undefined, |
|
|
|
|
|
|
|
selectItems: [string, string][] | string[], |
|
|
|
|
|
|
|
selectProps?: Partial<SelectProps>, |
|
|
|
|
|
|
|
): JSX.Element => ( |
|
|
|
|
|
|
|
<FormControl> |
|
|
|
|
|
|
|
{label && ( |
|
|
|
|
|
|
|
<OutlinedInputLabel {...{ htmlFor: id }}>{label}</OutlinedInputLabel> |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
<Select |
|
|
|
|
|
|
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
|
|
|
|
|
|
{...{ |
|
|
|
|
|
|
|
id, |
|
|
|
|
|
|
|
input: <OutlinedInput {...{ label }} />, |
|
|
|
|
|
|
|
...selectProps, |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
{selectItems.map((item) => { |
|
|
|
|
|
|
|
let itemValue; |
|
|
|
|
|
|
|
let itemDisplayValue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item instanceof Array) { |
|
|
|
|
|
|
|
[itemValue, itemDisplayValue] = item; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
itemValue = item; |
|
|
|
|
|
|
|
itemDisplayValue = item; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
<MenuItem key={`${id}-${itemValue}`} value={itemValue}> |
|
|
|
|
|
|
|
{itemDisplayValue} |
|
|
|
|
|
|
|
</MenuItem> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
})} |
|
|
|
|
|
|
|
</Select> |
|
|
|
|
|
|
|
</FormControl> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const createOutlinedSlider = ( |
|
|
|
|
|
|
|
id: string, |
|
|
|
|
|
|
|
label: string, |
|
|
|
|
|
|
|
value: number, |
|
|
|
|
|
|
|
sliderProps?: Partial<SliderProps>, |
|
|
|
|
|
|
|
): JSX.Element => ( |
|
|
|
|
|
|
|
<FormControl> |
|
|
|
|
|
|
|
<Slider |
|
|
|
|
|
|
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
|
|
|
|
|
|
{...{ |
|
|
|
|
|
|
|
isAllowTextInput: true, |
|
|
|
|
|
|
|
label, |
|
|
|
|
|
|
|
labelId: `${id}-label`, |
|
|
|
|
|
|
|
value, |
|
|
|
|
|
|
|
...sliderProps, |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</FormControl> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const createOutlinedInputWithSelect = ( |
|
|
|
|
|
|
|
id: string, |
|
|
|
|
|
|
|
label: string, |
|
|
|
|
|
|
|
selectItems: [string, string][] | string[], |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
inputProps, |
|
|
|
|
|
|
|
selectProps, |
|
|
|
|
|
|
|
}: { |
|
|
|
|
|
|
|
inputProps?: Partial<OutlinedInputProps>; |
|
|
|
|
|
|
|
selectProps?: Partial<SelectProps>; |
|
|
|
|
|
|
|
} = {}, |
|
|
|
|
|
|
|
) => ( |
|
|
|
|
|
|
|
<FormControl |
|
|
|
|
|
|
|
sx={{ |
|
|
|
|
|
|
|
display: 'flex', |
|
|
|
|
|
|
|
flexDirection: 'row', |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'& > :first-child': { |
|
|
|
|
|
|
|
flexGrow: 1, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
{createOutlinedInput(id, label, inputProps)} |
|
|
|
|
|
|
|
{createOutlinedSelect( |
|
|
|
|
|
|
|
`${id}-nested-select`, |
|
|
|
|
|
|
|
undefined, |
|
|
|
|
|
|
|
selectItems, |
|
|
|
|
|
|
|
selectProps, |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
</FormControl> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const organizeAnvils = ( |
|
|
|
|
|
|
|
data: AnvilDetailMetadataForProvisionServer[], |
|
|
|
|
|
|
|
): OrganizedAnvilDetailMetadataForProvisionServer[] => |
|
|
|
|
|
|
|
data.map((anvil) => { |
|
|
|
|
|
|
|
const anvilMaxAvailableStorage = anvil.storageGroups.reduce<bigint>( |
|
|
|
|
|
|
|
(reducedStorageGroupFree, { storageGroupFree }) => { |
|
|
|
|
|
|
|
const convertedStorageGroupFree = BigInt(storageGroupFree); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return convertedStorageGroupFree > reducedStorageGroupFree |
|
|
|
|
|
|
|
? convertedStorageGroupFree |
|
|
|
|
|
|
|
: reducedStorageGroupFree; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
BIGINT_ZERO, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
|
|
...anvil, |
|
|
|
|
|
|
|
anvilTotalMemory: BigInt(anvil.anvilTotalMemory), |
|
|
|
|
|
|
|
anvilTotalAllocatedMemory: BigInt(anvil.anvilTotalAllocatedMemory), |
|
|
|
|
|
|
|
anvilTotalAvailableMemory: BigInt(anvil.anvilTotalAvailableMemory), |
|
|
|
|
|
|
|
anvilMaxAvailableStorage, |
|
|
|
|
|
|
|
hosts: anvil.hosts.map((host) => ({ |
|
|
|
|
|
|
|
...host, |
|
|
|
|
|
|
|
hostMemory: BigInt(host.hostMemory), |
|
|
|
|
|
|
|
})), |
|
|
|
|
|
|
|
servers: anvil.servers.map((server) => ({ |
|
|
|
|
|
|
|
...server, |
|
|
|
|
|
|
|
serverMemory: BigInt(server.serverMemory), |
|
|
|
|
|
|
|
})), |
|
|
|
|
|
|
|
storageGroups: anvil.storageGroups.map((storageGroup) => ({ |
|
|
|
|
|
|
|
...storageGroup, |
|
|
|
|
|
|
|
storageGroupSize: BigInt(storageGroup.storageGroupSize), |
|
|
|
|
|
|
|
storageGroupFree: BigInt(storageGroup.storageGroupFree), |
|
|
|
|
|
|
|
})), |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getMaxAvailableValues = ( |
|
|
|
|
|
|
|
anvils: OrganizedAnvilDetailMetadataForProvisionServer[], |
|
|
|
|
|
|
|
) => |
|
|
|
|
|
|
|
anvils.reduce<{ |
|
|
|
maxAvailableCPUCores: number; |
|
|
|
maxAvailableCPUCores: number; |
|
|
|
maxAvailableMemory: bigint; |
|
|
|
maxAvailableMemory: bigint; |
|
|
|
|
|
|
|
maxAvailableVirtualDiskSize: bigint; |
|
|
|
}>( |
|
|
|
}>( |
|
|
|
( |
|
|
|
( |
|
|
|
reducedValues, |
|
|
|
reducedValues, |
|
|
|
{ anvilTotalAvailableCPUCores, anvilTotalAvailableMemory }, |
|
|
|
{ |
|
|
|
) => { |
|
|
|
anvilTotalAvailableCPUCores, |
|
|
|
const convertedAnvilTotalAvailableMemory = BigInt( |
|
|
|
|
|
|
|
anvilTotalAvailableMemory, |
|
|
|
anvilTotalAvailableMemory, |
|
|
|
); |
|
|
|
anvilMaxAvailableStorage, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
) => { |
|
|
|
reducedValues.maxAvailableCPUCores = Math.max( |
|
|
|
reducedValues.maxAvailableCPUCores = Math.max( |
|
|
|
anvilTotalAvailableCPUCores, |
|
|
|
anvilTotalAvailableCPUCores, |
|
|
|
reducedValues.maxAvailableCPUCores, |
|
|
|
reducedValues.maxAvailableCPUCores, |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (anvilTotalAvailableMemory > reducedValues.maxAvailableMemory) { |
|
|
|
|
|
|
|
reducedValues.maxAvailableMemory = anvilTotalAvailableMemory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ( |
|
|
|
if ( |
|
|
|
convertedAnvilTotalAvailableMemory > reducedValues.maxAvailableMemory |
|
|
|
anvilMaxAvailableStorage > reducedValues.maxAvailableVirtualDiskSize |
|
|
|
) { |
|
|
|
) { |
|
|
|
reducedValues.maxAvailableMemory = convertedAnvilTotalAvailableMemory; |
|
|
|
reducedValues.maxAvailableVirtualDiskSize = anvilMaxAvailableStorage; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return reducedValues; |
|
|
|
return reducedValues; |
|
|
@ -241,30 +420,116 @@ const ProvisionServerDialog = ({ |
|
|
|
{ |
|
|
|
{ |
|
|
|
maxAvailableCPUCores: 0, |
|
|
|
maxAvailableCPUCores: 0, |
|
|
|
maxAvailableMemory: BIGINT_ZERO, |
|
|
|
maxAvailableMemory: BIGINT_ZERO, |
|
|
|
|
|
|
|
maxAvailableVirtualDiskSize: BIGINT_ZERO, |
|
|
|
}, |
|
|
|
}, |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const optimizeOSList = data.osList.map((keyValuePair) => |
|
|
|
const dSize = ( |
|
|
|
keyValuePair.split(','), |
|
|
|
valueToFormat: FormatDataSizeInputValue, |
|
|
|
); |
|
|
|
{ |
|
|
|
|
|
|
|
fromUnit, |
|
|
|
|
|
|
|
onFailure, |
|
|
|
|
|
|
|
onSuccess, |
|
|
|
|
|
|
|
precision, |
|
|
|
|
|
|
|
toUnit, |
|
|
|
|
|
|
|
}: FormatDataSizeOptions & { |
|
|
|
|
|
|
|
onFailure?: (error?: unknown, value?: string, unit?: DataSizeUnit) => void; |
|
|
|
|
|
|
|
onSuccess?: { |
|
|
|
|
|
|
|
bigint?: (value: bigint, unit: DataSizeUnit) => void; |
|
|
|
|
|
|
|
number?: (value: number, unit: DataSizeUnit) => void; |
|
|
|
|
|
|
|
string?: (value: string, unit: DataSizeUnit) => void; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
} = {}, |
|
|
|
|
|
|
|
) => { |
|
|
|
|
|
|
|
const formatted = baseDSize(valueToFormat, { |
|
|
|
|
|
|
|
fromUnit, |
|
|
|
|
|
|
|
precision, |
|
|
|
|
|
|
|
toUnit, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (formatted) { |
|
|
|
setSliderMaxAvailableCPUCores(maxAvailableCPUCores); |
|
|
|
const { value, unit } = formatted; |
|
|
|
|
|
|
|
|
|
|
|
const formattedMaxAvailableMemory = dSize(maxAvailableMemory, { |
|
|
|
try { |
|
|
|
precision: 2, |
|
|
|
onSuccess?.bigint?.call(null, BigInt(value), unit); |
|
|
|
}); |
|
|
|
onSuccess?.number?.call(null, parseFloat(value), unit); |
|
|
|
|
|
|
|
onSuccess?.string?.call(null, value, unit); |
|
|
|
|
|
|
|
} catch (convertValueToTypeError) { |
|
|
|
|
|
|
|
onFailure?.call(null, convertValueToTypeError, value, unit); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
onFailure?.call(null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
console.dir(formattedMaxAvailableMemory, { depth: null }); |
|
|
|
const filterAnvils = ( |
|
|
|
|
|
|
|
organizedAnvils: OrganizedAnvilDetailMetadataForProvisionServer[], |
|
|
|
|
|
|
|
cpuCores: number, |
|
|
|
|
|
|
|
memory: bigint, |
|
|
|
|
|
|
|
virtualDiskSize: bigint, |
|
|
|
|
|
|
|
) => |
|
|
|
|
|
|
|
organizedAnvils |
|
|
|
|
|
|
|
.filter((anvil) => { |
|
|
|
|
|
|
|
const isEnoughCPUCores = cpuCores <= anvil.anvilTotalAvailableCPUCores; |
|
|
|
|
|
|
|
const isEnoughMemory = memory <= anvil.anvilTotalAvailableMemory; |
|
|
|
|
|
|
|
const isEnoughStorage = virtualDiskSize <= anvil.anvilMaxAvailableStorage; |
|
|
|
|
|
|
|
|
|
|
|
if (formattedMaxAvailableMemory) { |
|
|
|
return isEnoughCPUCores && isEnoughMemory && isEnoughStorage; |
|
|
|
setSliderMaxAvailableMemory( |
|
|
|
}) |
|
|
|
parseFloat(formattedMaxAvailableMemory.value), |
|
|
|
.map(({ anvilUUID, anvilName }) => [anvilUUID, anvilName]); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setMemoryUnit(formattedMaxAvailableMemory.unit); |
|
|
|
/** |
|
|
|
} |
|
|
|
* 1. Fetch anvils detail for provision server from the back-end. |
|
|
|
}, [maxAvailableCPUCores, maxAvailableMemory]); |
|
|
|
* 2. Get the max values for CPU cores, memory, and virtual disk size. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ProvisionServerDialog = ({ |
|
|
|
|
|
|
|
dialogProps: { open }, |
|
|
|
|
|
|
|
}: ProvisionServerDialogProps): JSX.Element => { |
|
|
|
|
|
|
|
const [sliderCPUCoresMax, setSliderCPUCoresMax] = useState<number>(0); |
|
|
|
|
|
|
|
// const [sliderMemoryMax, setSliderMemoryMax] = useState<number>(0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [cpuCoresValue, setCPUCoresValue] = useState<number>(1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [memoryValue, setMemoryValue] = useState<bigint>(BIGINT_ZERO); |
|
|
|
|
|
|
|
const [inputMemoryValue, setInputMemoryValue] = useState<string>(''); |
|
|
|
|
|
|
|
const [inputMemoryUnit, setInputMemoryUnit] = useState<DataSizeUnit>('B'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [virtualDiskSizeValue, setVirtualDiskSizeValue] = |
|
|
|
|
|
|
|
useState<bigint>(BIGINT_ZERO); |
|
|
|
|
|
|
|
const [inputVirtualDiskSizeValue, setInputVirtualDiskSizeValue] = |
|
|
|
|
|
|
|
useState<string>(''); |
|
|
|
|
|
|
|
const [inputVirtualDiskSizeUnit, setInputVirtualDiskSizeUnit] = |
|
|
|
|
|
|
|
useState<DataSizeUnit>('B'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// const [storageGroupUUID, setStorageGroupUUID] = useState<string>('');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const data = MOCK_DATA; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const organizedAnvils = organizeAnvils(data.anvils); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { |
|
|
|
|
|
|
|
maxAvailableCPUCores, |
|
|
|
|
|
|
|
maxAvailableMemory, |
|
|
|
|
|
|
|
maxAvailableVirtualDiskSize, |
|
|
|
|
|
|
|
} = getMaxAvailableValues(organizedAnvils); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// const optimizeOSList = data.osList.map((keyValuePair) =>
|
|
|
|
|
|
|
|
// keyValuePair.split(','),
|
|
|
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
setSliderCPUCoresMax(maxAvailableCPUCores); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dSize(maxAvailableMemory, { |
|
|
|
|
|
|
|
onSuccess: { |
|
|
|
|
|
|
|
number: (value, unit) => { |
|
|
|
|
|
|
|
setSliderMemoryMax(value); |
|
|
|
|
|
|
|
setInputMemoryUnit(unit); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, [maxAvailableCPUCores, maxAvailableMemory, maxAvailableVirtualDiskSize]); |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<Dialog |
|
|
|
<Dialog |
|
|
@ -281,42 +546,103 @@ const ProvisionServerDialog = ({ |
|
|
|
</PanelHeader> |
|
|
|
</PanelHeader> |
|
|
|
<FormGroup> |
|
|
|
<FormGroup> |
|
|
|
{createOutlinedInput('ps-server-name', 'Server name')} |
|
|
|
{createOutlinedInput('ps-server-name', 'Server name')} |
|
|
|
{createOutlinedSlider('ps-cpu-cores', 'CPU cores', { |
|
|
|
{createOutlinedSlider('ps-cpu-cores', 'CPU cores', cpuCoresValue, { |
|
|
|
sliderProps: { max: sliderMaxAvailableCPUCores, min: 1 }, |
|
|
|
sliderProps: { |
|
|
|
|
|
|
|
onChange: (event, value) => { |
|
|
|
|
|
|
|
setCPUCoresValue(value as number); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
max: sliderCPUCoresMax, |
|
|
|
|
|
|
|
min: 1, |
|
|
|
|
|
|
|
}, |
|
|
|
})} |
|
|
|
})} |
|
|
|
<BodyText text={`Memory: ${memory.toString()}`} /> |
|
|
|
<BodyText text={`Memory: ${memoryValue.toString()}`} /> |
|
|
|
<Box |
|
|
|
{createOutlinedInputWithSelect('ps-memory', 'Memory', DATA_SIZE_UNITS, { |
|
|
|
sx={{ |
|
|
|
inputProps: { |
|
|
|
display: 'flex', |
|
|
|
type: 'number', |
|
|
|
flexDirection: 'row', |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
|
|
|
|
setInputMemoryValue(value); |
|
|
|
|
|
|
|
|
|
|
|
'& > :first-child': { |
|
|
|
dSize(value, { |
|
|
|
flexGrow: 1, |
|
|
|
fromUnit: inputMemoryUnit, |
|
|
|
|
|
|
|
onSuccess: { |
|
|
|
|
|
|
|
bigint: (newValue) => { |
|
|
|
|
|
|
|
setMemoryValue(newValue); |
|
|
|
}, |
|
|
|
}, |
|
|
|
}} |
|
|
|
}, |
|
|
|
> |
|
|
|
precision: 0, |
|
|
|
{createOutlinedSlider('ps-memory', 'Memory', { |
|
|
|
toUnit: 'B', |
|
|
|
sliderProps: { |
|
|
|
}); |
|
|
|
max: sliderMaxAvailableMemory, |
|
|
|
}, |
|
|
|
min: 1, |
|
|
|
value: inputMemoryValue, |
|
|
|
onChange: (event, newValue) => { |
|
|
|
}, |
|
|
|
console.log(`newValue=${newValue}`); |
|
|
|
selectProps: { |
|
|
|
|
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
|
|
|
|
const selectedUnit = value as DataSizeUnit; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setInputMemoryUnit(selectedUnit); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dSize(inputMemoryValue, { |
|
|
|
|
|
|
|
fromUnit: selectedUnit, |
|
|
|
|
|
|
|
onSuccess: { |
|
|
|
|
|
|
|
bigint: (newValue) => { |
|
|
|
|
|
|
|
setMemoryValue(newValue); |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
precision: 0, |
|
|
|
|
|
|
|
toUnit: 'B', |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
value: inputMemoryUnit, |
|
|
|
|
|
|
|
}, |
|
|
|
})} |
|
|
|
})} |
|
|
|
{createOutlinedSelect('ps-memory-unit', undefined, memoryUnit, [ |
|
|
|
<BodyText |
|
|
|
'B', |
|
|
|
text={`Virtual disk size: ${virtualDiskSizeValue.toString()}`} |
|
|
|
'KiB', |
|
|
|
/> |
|
|
|
'kB', |
|
|
|
{createOutlinedInputWithSelect( |
|
|
|
'MiB', |
|
|
|
'ps-virtual-disk-size', |
|
|
|
'MB', |
|
|
|
'Virtual disk size', |
|
|
|
'GiB', |
|
|
|
DATA_SIZE_UNITS, |
|
|
|
'GB', |
|
|
|
{ |
|
|
|
'TiB', |
|
|
|
inputProps: { |
|
|
|
'TB', |
|
|
|
type: 'number', |
|
|
|
])} |
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
</Box> |
|
|
|
setInputVirtualDiskSizeValue(value); |
|
|
|
{/* {createOutlinedSlider('ps-memory', 'Memory')} |
|
|
|
|
|
|
|
|
|
|
|
dSize(value, { |
|
|
|
|
|
|
|
fromUnit: inputVirtualDiskSizeUnit, |
|
|
|
|
|
|
|
onSuccess: { |
|
|
|
|
|
|
|
bigint: (newValue) => { |
|
|
|
|
|
|
|
setVirtualDiskSizeValue(newValue); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
precision: 0, |
|
|
|
|
|
|
|
toUnit: 'B', |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
value: inputVirtualDiskSizeValue, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
selectProps: { |
|
|
|
|
|
|
|
onChange: ({ target: { value } }) => { |
|
|
|
|
|
|
|
const selectedUnit = value as DataSizeUnit; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setInputVirtualDiskSizeUnit(selectedUnit); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
dSize(inputVirtualDiskSizeValue, { |
|
|
|
|
|
|
|
fromUnit: selectedUnit, |
|
|
|
|
|
|
|
onSuccess: { |
|
|
|
|
|
|
|
bigint: (newValue) => { |
|
|
|
|
|
|
|
setVirtualDiskSizeValue(newValue); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
precision: 0, |
|
|
|
|
|
|
|
toUnit: 'B', |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
value: inputVirtualDiskSizeUnit, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
)} |
|
|
|
|
|
|
|
{/* |
|
|
|
{createOutlinedSelect('ps-storage-group', 'Storage group', [ |
|
|
|
{createOutlinedSelect('ps-storage-group', 'Storage group', [ |
|
|
|
['b594f417-852a-4bd4-a215-fae32d226b0b', 'Storage group 1'], |
|
|
|
['b594f417-852a-4bd4-a215-fae32d226b0b', 'Storage group 1'], |
|
|
|
])} |
|
|
|
])} |
|
|
@ -328,7 +654,19 @@ const ProvisionServerDialog = ({ |
|
|
|
'Optimize for OS', |
|
|
|
'Optimize for OS', |
|
|
|
optimizeOSList, |
|
|
|
optimizeOSList, |
|
|
|
)} */} |
|
|
|
)} */} |
|
|
|
|
|
|
|
{filterAnvils( |
|
|
|
|
|
|
|
organizedAnvils, |
|
|
|
|
|
|
|
cpuCoresValue, |
|
|
|
|
|
|
|
memoryValue, |
|
|
|
|
|
|
|
virtualDiskSizeValue, |
|
|
|
|
|
|
|
).map(([anvilUUID, anvilName]) => ( |
|
|
|
|
|
|
|
<BodyText |
|
|
|
|
|
|
|
key={`ps-filtered-anvils-${anvilUUID}`} |
|
|
|
|
|
|
|
text={`${anvilUUID},${anvilName}`} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
))} |
|
|
|
</FormGroup> |
|
|
|
</FormGroup> |
|
|
|
|
|
|
|
<ContainedButton>Provision</ContainedButton> |
|
|
|
</Dialog> |
|
|
|
</Dialog> |
|
|
|
); |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|