You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
412 lines
12 KiB
412 lines
12 KiB
import { ReactElement, useMemo } from 'react'; |
|
|
|
import FlexBox from '../FlexBox'; |
|
import Grid from '../Grid'; |
|
import InputWithRef from '../InputWithRef'; |
|
import MessageBox from '../MessageBox'; |
|
import OutlinedInputWithLabel from '../OutlinedInputWithLabel'; |
|
import { InnerPanel, InnerPanelBody, InnerPanelHeader } from '../Panels'; |
|
import SwitchWithLabel from '../SwitchWithLabel'; |
|
import { |
|
buildIPAddressTestBatch, |
|
buildPeacefulStringTestBatch, |
|
} from '../../lib/test_input'; |
|
import { BodyText } from '../Text'; |
|
|
|
const INPUT_ID_PREFIX_AN_HOST = 'an-host-input'; |
|
|
|
const INPUT_CELL_ID_PREFIX_AH = `${INPUT_ID_PREFIX_AN_HOST}-cell`; |
|
|
|
const INPUT_LABEL_AH_IPMI_IP = 'IPMI IP'; |
|
|
|
const MAP_TO_AH_INPUT_HANDLER: MapToManifestFormInputHandler = { |
|
fence: (container, input) => { |
|
const { |
|
dataset: { hostId = '', fenceId = '', fenceName = '' }, |
|
value: fencePort, |
|
} = input; |
|
const { |
|
hostConfig: { |
|
hosts: { [hostId]: host }, |
|
}, |
|
} = container; |
|
const { fences = {} } = host; |
|
|
|
fences[fenceId] = { |
|
fenceName, |
|
fencePort, |
|
}; |
|
host.fences = fences; |
|
}, |
|
host: (container, input) => { |
|
const { |
|
dataset: { hostId = '', hostNumber: rawHostNumber = '', hostType = '' }, |
|
} = input; |
|
const hostNumber = Number.parseInt(rawHostNumber, 10); |
|
|
|
container.hostConfig.hosts[hostId] = { |
|
hostNumber, |
|
hostType, |
|
}; |
|
}, |
|
ipmi: (container, input) => { |
|
const { |
|
dataset: { hostId = '' }, |
|
value: ipmiIp, |
|
} = input; |
|
const { |
|
hostConfig: { |
|
hosts: { [hostId]: host }, |
|
}, |
|
} = container; |
|
|
|
host.ipmiIp = ipmiIp; |
|
}, |
|
network: (container, input) => { |
|
const { |
|
dataset: { |
|
hostId = '', |
|
networkId = '', |
|
networkNumber: rawNetworkNumber = '', |
|
networkType = '', |
|
}, |
|
value: networkIp, |
|
} = input; |
|
const { |
|
hostConfig: { |
|
hosts: { [hostId]: host }, |
|
}, |
|
} = container; |
|
const { networks = {} } = host; |
|
const networkNumber = Number.parseInt(rawNetworkNumber, 10); |
|
|
|
networks[networkId] = { |
|
networkIp, |
|
networkNumber, |
|
networkType, |
|
}; |
|
host.networks = networks; |
|
}, |
|
ups: (container, input) => { |
|
const { |
|
checked: isUsed, |
|
dataset: { hostId = '', upsId = '', upsName = '' }, |
|
} = input; |
|
const { |
|
hostConfig: { |
|
hosts: { [hostId]: host }, |
|
}, |
|
} = container; |
|
const { upses = {} } = host; |
|
|
|
upses[upsId] = { |
|
isUsed, |
|
upsName, |
|
}; |
|
host.upses = upses; |
|
}, |
|
}; |
|
|
|
const GRID_COLUMNS = { xs: 1, sm: 2, md: 3 }; |
|
const GRID_SPACING = '1em'; |
|
|
|
const buildInputIdAHFencePort = (hostId: string, fenceId: string): string => |
|
`${INPUT_ID_PREFIX_AN_HOST}-${hostId}-${fenceId}-port`; |
|
|
|
const buildInputIdAHIpmiIp = (hostId: string): string => |
|
`${INPUT_ID_PREFIX_AN_HOST}-${hostId}-ipmi-ip`; |
|
|
|
const buildInputIdAHNetworkIp = (hostId: string, networkId: string): string => |
|
`${INPUT_ID_PREFIX_AN_HOST}-${hostId}-${networkId}-ip`; |
|
|
|
const buildInputIdAHUpsPowerHost = (hostId: string, upsId: string): string => |
|
`${INPUT_ID_PREFIX_AN_HOST}-${hostId}-${upsId}-power-host`; |
|
|
|
const AnHostInputGroup = <M extends MapToInputTestID>({ |
|
formUtils: { |
|
buildFinishInputTestBatchFunction, |
|
buildInputFirstRenderFunction, |
|
buildInputUnmountFunction, |
|
setMessage, |
|
}, |
|
hostId, |
|
hostNumber, |
|
hostType, |
|
previous: { |
|
fences: fenceList = {}, |
|
ipmiIp: previousIpmiIp, |
|
networks: networkList = {}, |
|
upses: upsList = {}, |
|
} = {}, |
|
// Props that depend on others. |
|
hostLabel = `${hostType.replace('node', 'subnode')} ${hostNumber}`, |
|
}: AnHostInputGroupProps<M>): ReactElement => { |
|
const fenceListEntries = useMemo( |
|
() => Object.entries(fenceList), |
|
[fenceList], |
|
); |
|
const networkListEntries = useMemo( |
|
() => Object.entries(networkList), |
|
[networkList], |
|
); |
|
const upsListEntries = useMemo(() => Object.entries(upsList), [upsList]); |
|
|
|
const isShowUpsListGrid = useMemo( |
|
() => Boolean(upsListEntries.length), |
|
[upsListEntries.length], |
|
); |
|
|
|
const inputIdAHHost = useMemo( |
|
() => `${INPUT_ID_PREFIX_AN_HOST}-${hostId}`, |
|
[hostId], |
|
); |
|
const inputIdAHIpmiIp = useMemo(() => buildInputIdAHIpmiIp(hostId), [hostId]); |
|
|
|
const inputCellIdAHIpmiIp = useMemo( |
|
() => `${INPUT_CELL_ID_PREFIX_AH}-${hostId}-ipmi-ip`, |
|
[hostId], |
|
); |
|
|
|
const fenceListGridLayout = useMemo( |
|
() => |
|
fenceListEntries.reduce<GridLayout>( |
|
(previous, [fenceId, { fenceName, fencePort }]) => { |
|
const cellId = `${INPUT_CELL_ID_PREFIX_AH}-${hostId}-${fenceId}-port`; |
|
|
|
const inputId = buildInputIdAHFencePort(hostId, fenceId); |
|
const inputLabel = `Port on ${fenceName}`; |
|
|
|
previous[cellId] = { |
|
children: ( |
|
<InputWithRef |
|
input={ |
|
<OutlinedInputWithLabel |
|
baseInputProps={{ |
|
'data-handler': 'fence', |
|
'data-host-id': hostId, |
|
'data-fence-id': fenceId, |
|
'data-fence-name': fenceName, |
|
}} |
|
id={inputId} |
|
label={inputLabel} |
|
value={fencePort} |
|
/> |
|
} |
|
inputTestBatch={buildPeacefulStringTestBatch( |
|
`${hostId} ${inputLabel}`, |
|
() => { |
|
setMessage(inputId); |
|
}, |
|
{ onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, |
|
(message) => { |
|
setMessage(inputId, { children: message }); |
|
}, |
|
)} |
|
onFirstRender={buildInputFirstRenderFunction(inputId)} |
|
/> |
|
), |
|
}; |
|
|
|
return previous; |
|
}, |
|
{}, |
|
), |
|
[ |
|
buildFinishInputTestBatchFunction, |
|
buildInputFirstRenderFunction, |
|
fenceListEntries, |
|
hostId, |
|
setMessage, |
|
], |
|
); |
|
|
|
const networkListGridLayout = useMemo( |
|
() => |
|
networkListEntries.reduce<GridLayout>( |
|
(previous, [networkId, { networkIp, networkNumber, networkType }]) => { |
|
const cellId = `${INPUT_CELL_ID_PREFIX_AH}-${hostId}-${networkId}-ip`; |
|
|
|
const inputId = buildInputIdAHNetworkIp(hostId, networkId); |
|
const inputLabel = `${networkType.toUpperCase()} ${networkNumber} IP`; |
|
|
|
previous[cellId] = { |
|
children: ( |
|
<InputWithRef |
|
input={ |
|
<OutlinedInputWithLabel |
|
baseInputProps={{ |
|
'data-handler': 'network', |
|
'data-host-id': hostId, |
|
'data-network-id': networkId, |
|
'data-network-number': networkNumber, |
|
'data-network-type': networkType, |
|
}} |
|
id={inputId} |
|
label={inputLabel} |
|
value={networkIp} |
|
/> |
|
} |
|
inputTestBatch={buildIPAddressTestBatch( |
|
`${hostId} ${inputLabel}`, |
|
() => { |
|
setMessage(inputId); |
|
}, |
|
{ onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, |
|
(message) => { |
|
setMessage(inputId, { children: message }); |
|
}, |
|
)} |
|
onFirstRender={buildInputFirstRenderFunction(inputId)} |
|
onUnmount={buildInputUnmountFunction(inputId)} |
|
required |
|
/> |
|
), |
|
}; |
|
|
|
return previous; |
|
}, |
|
{}, |
|
), |
|
[ |
|
networkListEntries, |
|
hostId, |
|
buildFinishInputTestBatchFunction, |
|
buildInputFirstRenderFunction, |
|
buildInputUnmountFunction, |
|
setMessage, |
|
], |
|
); |
|
|
|
const upsListGridLayout = useMemo( |
|
() => |
|
upsListEntries.reduce<GridLayout>( |
|
(previous, [upsId, { isUsed, upsName }]) => { |
|
const cellId = `${INPUT_CELL_ID_PREFIX_AH}-${hostId}-${upsId}-power-host`; |
|
|
|
const inputId = buildInputIdAHUpsPowerHost(hostId, upsId); |
|
const inputLabel = `Uses ${upsName}`; |
|
|
|
previous[cellId] = { |
|
children: ( |
|
<InputWithRef |
|
input={ |
|
<SwitchWithLabel |
|
baseInputProps={{ |
|
'data-handler': 'ups', |
|
'data-host-id': hostId, |
|
'data-ups-id': upsId, |
|
'data-ups-name': upsName, |
|
}} |
|
checked={isUsed} |
|
id={inputId} |
|
label={inputLabel} |
|
/> |
|
} |
|
valueType="boolean" |
|
/> |
|
), |
|
}; |
|
|
|
return previous; |
|
}, |
|
{}, |
|
), |
|
[hostId, upsListEntries], |
|
); |
|
|
|
const upsListGrid = useMemo( |
|
() => |
|
isShowUpsListGrid && ( |
|
<Grid |
|
columns={GRID_COLUMNS} |
|
layout={upsListGridLayout} |
|
spacing={GRID_SPACING} |
|
/> |
|
), |
|
[isShowUpsListGrid, upsListGridLayout], |
|
); |
|
|
|
return ( |
|
<InnerPanel mv={0}> |
|
<InnerPanelHeader> |
|
<BodyText>{hostLabel}</BodyText> |
|
</InnerPanelHeader> |
|
<InnerPanelBody> |
|
<input |
|
hidden |
|
id={inputIdAHHost} |
|
readOnly |
|
data-handler="host" |
|
data-host-id={hostId} |
|
data-host-number={hostNumber} |
|
data-host-type={hostType} |
|
/> |
|
<FlexBox> |
|
<Grid |
|
columns={GRID_COLUMNS} |
|
layout={{ |
|
'fence-message': { |
|
children: ( |
|
<MessageBox> |
|
It is recommended to provide 2 fence device ports. |
|
</MessageBox> |
|
), |
|
width: '100%', |
|
xs: 0, |
|
}, |
|
...networkListGridLayout, |
|
[inputCellIdAHIpmiIp]: { |
|
children: ( |
|
<InputWithRef |
|
input={ |
|
<OutlinedInputWithLabel |
|
baseInputProps={{ |
|
'data-handler': 'ipmi', |
|
'data-host-id': hostId, |
|
}} |
|
id={inputIdAHIpmiIp} |
|
label={INPUT_LABEL_AH_IPMI_IP} |
|
value={previousIpmiIp} |
|
/> |
|
} |
|
inputTestBatch={buildIPAddressTestBatch( |
|
`${hostId} ${INPUT_LABEL_AH_IPMI_IP}`, |
|
() => { |
|
setMessage(inputIdAHIpmiIp); |
|
}, |
|
{ |
|
onFinishBatch: |
|
buildFinishInputTestBatchFunction(inputIdAHIpmiIp), |
|
}, |
|
(message) => { |
|
setMessage(inputIdAHIpmiIp, { children: message }); |
|
}, |
|
)} |
|
onFirstRender={buildInputFirstRenderFunction( |
|
inputIdAHIpmiIp, |
|
)} |
|
onUnmount={buildInputUnmountFunction(inputIdAHIpmiIp)} |
|
/> |
|
), |
|
}, |
|
...fenceListGridLayout, |
|
}} |
|
spacing={GRID_SPACING} |
|
/> |
|
{upsListGrid} |
|
</FlexBox> |
|
</InnerPanelBody> |
|
</InnerPanel> |
|
); |
|
}; |
|
|
|
export { |
|
INPUT_ID_PREFIX_AN_HOST, |
|
MAP_TO_AH_INPUT_HANDLER, |
|
buildInputIdAHFencePort, |
|
buildInputIdAHIpmiIp, |
|
buildInputIdAHNetworkIp, |
|
buildInputIdAHUpsPowerHost, |
|
}; |
|
|
|
export default AnHostInputGroup;
|
|
|