export function ComputeResource()

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>
  )
}