in frontend/src/old-pages/Configure/Queues/MultiInstanceComputeResource.tsx [54:364]
export function ComputeResource({
index,
queueIndex,
computeResource,
canUseEFA,
}: any) {
const parentPath = useMemo(() => [...queuesPath, queueIndex], [queueIndex])
const computeResources: MultiInstanceComputeResource[] = useState([
...parentPath,
'ComputeResources',
])
const path = useMemo(
() => [...parentPath, 'ComputeResources', index],
[index, parentPath],
)
const errorsPath = [...queuesErrorsPath, queueIndex, 'computeResource', index]
const typeError = useState([...errorsPath, 'type'])
const instanceTypePath = useMemo(() => [...path, 'Instances'], [path])
const instances: ComputeResourceInstance[] = useState(instanceTypePath) || []
const memoryBasedSchedulingEnabledPath = [
'app',
'wizard',
'config',
'Scheduling',
'SlurmSettings',
'EnableMemoryBasedScheduling',
]
const enableMemoryBasedScheduling = useState(memoryBasedSchedulingEnabledPath)
const multithreadingDisabledPath = useMemo(
() => [...path, 'DisableSimultaneousMultithreading'],
[path],
)
const multithreadingDisabled = useState(multithreadingDisabledPath)
const efaInstances = new Set<string>(useState(['aws', 'efa_instance_types']))
const enableEFA = useState([...path, 'Efa', 'Enabled']) || false
const enablePlacementGroupPath = useMemo(
() => [...parentPath, 'Networking', 'PlacementGroup', 'Enabled'],
[parentPath],
)
const minCount = useState([...path, 'MinCount'])
const maxCount = useState([...path, 'MaxCount'])
const instanceGroups = useInstanceGroups()
const instanceOptions = useMemo(
() =>
Object.keys(instanceGroups).map(groupName => {
return {
label: groupName,
options: instanceGroups[groupName].map((instance: InstanceType) => ({
label: instance.type,
tags: instance.tags,
value: instance.type,
})),
}
}),
[instanceGroups],
)
const {t} = useTranslation()
const remove = () => {
setState(
[...parentPath, 'ComputeResources'],
[
...computeResources.slice(0, index),
...computeResources.slice(index + 1),
],
)
}
const setMinCount = (staticCount: any) => {
const dynamicCount = maxCount - minCount
if (staticCount > 0)
setState([...path, 'MinCount'], !isNaN(staticCount) ? staticCount : 0)
else clearState([...path, 'MinCount'])
setState(
[...path, 'MaxCount'],
(!isNaN(staticCount) ? staticCount : 0) +
(!isNaN(dynamicCount) ? dynamicCount : 0),
)
}
const setMaxCount = (dynamicCount: any) => {
const staticCount = minCount
setState(
[...path, 'MaxCount'],
(!isNaN(staticCount) ? staticCount : 0) +
(!isNaN(dynamicCount) ? dynamicCount : 0),
)
}
const setSchedulableMemory = (
schedulableMemoryPath: string[],
schedulableMemory: string,
) => {
let schedulableMemoryNumber = parseInt(schedulableMemory)
if (enableMemoryBasedScheduling && !isNaN(schedulableMemoryNumber)) {
setState(schedulableMemoryPath, schedulableMemoryNumber)
} else {
clearState(schedulableMemoryPath)
}
}
const setDisableHT = useCallback(
(disable: any) => {
if (disable) setState(multithreadingDisabledPath, disable)
else clearState(multithreadingDisabledPath)
},
[multithreadingDisabledPath],
)
const setEnableEFA = useCallback(
(enable: any) => {
if (enable) {
setState([...path, 'Efa', 'Enabled'], enable)
setState(enablePlacementGroupPath, enable)
} else {
clearState([...path, 'Efa'])
clearState(enablePlacementGroupPath)
}
},
[enablePlacementGroupPath, path],
)
const hpcInstanceSelected = isHpcInstanceSelected(instances)
useEffect(() => {
if (!canUseEFA) {
setEnableEFA(false)
}
}, [canUseEFA, setEnableEFA])
useEffect(() => {
if (hpcInstanceSelected) {
setDisableHT(false)
}
}, [hpcInstanceSelected, setDisableHT])
const setInstances: NonCancelableEventHandler<MultiselectProps.MultiselectChangeDetail> =
useCallback(
({detail}) => {
const selectedInstances = (detail.selectedOptions.map(option => ({
InstanceType: option.value,
})) || []) as ComputeResourceInstance[]
setState(instanceTypePath, selectedInstances)
if (!allInstancesSupportEFA(selectedInstances, efaInstances)) {
setEnableEFA(false)
}
},
[efaInstances, instanceTypePath, setEnableEFA],
)
const initialCapacityReservationTarget = useState([...path, 'CapacityReservationTarget']) || {}
const [odcrCbOption, setOdcrCbOption] = React.useState(
initialCapacityReservationTarget.CapacityReservationId
? 'capacityReservationId'
: initialCapacityReservationTarget.CapacityReservationResourceGroupArn
? 'capacityReservationResourceGroupArn'
: 'none'
)
const [odcrCbInput, setOdcrCbInput] = React.useState(
initialCapacityReservationTarget.CapacityReservationId ||
initialCapacityReservationTarget.CapacityReservationResourceGroupArn ||
''
)
useEffect(() => {
if (odcrCbOption === 'none') {
clearState([...path, 'CapacityReservationTarget'])
} else {
const updateData = {
CapacityReservationId: odcrCbOption === 'capacityReservationId' ? odcrCbInput : undefined,
CapacityReservationResourceGroupArn: odcrCbOption === 'capacityReservationResourceGroupArn' ? odcrCbInput : undefined,
}
setState([...path, 'CapacityReservationTarget'], updateData)
if (odcrCbOption === 'capacityReservationId') {
clearState(instanceTypePath)
}
}
}, [odcrCbOption, odcrCbInput, path, instanceTypePath])
return (
<SpaceBetween direction="vertical" size="s">
<div className={componentsStyle['space-between-wrap']}>
<TextContent>
<h4>
{t('wizard.queues.computeResource.name', {
index: index + 1,
crName: computeResource.Name,
})}
</h4>
</TextContent>
{computeResources.length > 1 && (
<Button onClick={remove}>
{t(
'wizard.queues.computeResource.removeComputeResourceButton.label',
)}
</Button>
)}
</div>
<ColumnLayout columns={2}>
<SpaceBetween direction="horizontal" size="l">
<FormField label={t('wizard.queues.computeResource.staticNodes')}>
<Input
value={computeResource.MinCount || 0}
type="number"
onChange={({detail}) => setMinCount(parseInt(detail.value))}
/>
</FormField>
<FormField label={t('wizard.queues.computeResource.dynamicNodes')}>
<Input
value={Math.max(
(computeResource.MaxCount || 0) -
(computeResource.MinCount || 0),
0,
).toString()}
type="number"
onChange={({detail}) => setMaxCount(parseInt(detail.value))}
/>
</FormField>
</SpaceBetween>
{/* Render the instance type selection field only when 'capacityReservationId' is not selected */}
{odcrCbOption !== 'capacityReservationId' && (
<FormField
label={t('wizard.queues.computeResource.instanceType.label')}
errorText={typeError}
>
<Multiselect
selectedOptions={instances.map(instance => ({
value: instance.InstanceType,
label: instance.InstanceType,
}))}
placeholder={t(
'wizard.queues.computeResource.instanceType.placeholder.multiple',
)}
tokenLimit={3}
onChange={setInstances}
options={instanceOptions}
filteringType="auto"
/>
</FormField>
)}
{enableMemoryBasedScheduling && (
<HelpTextInput
name={t('wizard.queues.schedulableMemory.name')}
path={path}
errorsPath={errorsPath}
configKey={'SchedulableMemory'}
onChange={({detail}) =>
setSchedulableMemory([...path, 'SchedulableMemory'], detail.value)
}
description={t('wizard.queues.schedulableMemory.description')}
placeholder={t('wizard.queues.schedulableMemory.placeholder')}
help={t('wizard.queues.schedulableMemory.help')}
type="number"
/>
)}
</ColumnLayout>
<SpaceBetween direction="vertical" size="s">
<OdcrCbSelect
selectedOption={odcrCbOption}
onChange={({detail}) => {
setOdcrCbOption(detail.selectedOption.value)
if (detail.selectedOption.value === 'none') {
setOdcrCbInput('')
}
}}
inputValue={odcrCbInput}
onInputChange={({detail}) => setOdcrCbInput(detail.value)}
/>
<CheckboxWithHelpPanel
checked={multithreadingDisabled}
disabled={hpcInstanceSelected}
onChange={_e => {
setDisableHT(!multithreadingDisabled)
}}
helpPanel={
<TitleDescriptionHelpPanel
title={t(
'wizard.queues.computeResource.disableHT.helpPanel.title',
)}
description={t(
'wizard.queues.computeResource.disableHT.helpPanel.description',
)}
/>
}
>
<Trans i18nKey="wizard.queues.computeResource.disableHT.label" />
</CheckboxWithHelpPanel>
<Checkbox
disabled={
!allInstancesSupportEFA(instances, efaInstances) || !canUseEFA
}
checked={enableEFA}
onChange={_e => {
setEnableEFA(!enableEFA)
}}
>
<Trans i18nKey="wizard.queues.computeResource.enableEfa" />
</Checkbox>
</SpaceBetween>
</SpaceBetween>
)
}