parent
2ca1277b3f
commit
c0189cba8d
3 changed files with 532 additions and 39 deletions
@ -0,0 +1,404 @@ |
||||
import { styled } from '@mui/material'; |
||||
import { ReactElement, useMemo } from 'react'; |
||||
import { buildPeacefulStringTestBatch } from '../../lib/test_input'; |
||||
|
||||
import FlexBox from '../FlexBox'; |
||||
import Grid from '../Grid'; |
||||
import InputWithRef from '../InputWithRef'; |
||||
import OutlinedInputWithLabel from '../OutlinedInputWithLabel'; |
||||
import SelectWithLabel from '../SelectWithLabel'; |
||||
import { BodyText, MonoText } from '../Text'; |
||||
|
||||
const INPUT_ID_PREFIX_RUN_MANIFEST = 'run-manifest-input'; |
||||
const INPUT_ID_PREFIX_HOST = `${INPUT_ID_PREFIX_RUN_MANIFEST}-host`; |
||||
|
||||
const INPUT_ID_AN_DESCRIPTION = `${INPUT_ID_PREFIX_RUN_MANIFEST}-an-description`; |
||||
const INPUT_ID_AN_PASSWORD = `${INPUT_ID_PREFIX_RUN_MANIFEST}-an-password`; |
||||
const INPUT_ID_AN_CONFIRM_PASSWORD = `${INPUT_ID_PREFIX_RUN_MANIFEST}-an-confirm-password`; |
||||
|
||||
const INPUT_LABEL_AN_DESCRIPTION = 'Description'; |
||||
const INPUT_LABEL_AN_PASSWORD = 'Password'; |
||||
const INPUT_LABEL_AN_CONFIRM_PASSWORD = 'Confirm password'; |
||||
|
||||
const MANIFEST_PARAM_NONE = '--'; |
||||
|
||||
const EndMono = styled(MonoText)({ |
||||
justifyContent: 'end', |
||||
}); |
||||
|
||||
const RunManifestInputGroup = <M extends MapToInputTestID>({ |
||||
formUtils: { |
||||
buildFinishInputTestBatchFunction, |
||||
buildInputFirstRenderFunction, |
||||
msgSetters, |
||||
setMsgSetter, |
||||
}, |
||||
knownFences = {}, |
||||
knownHosts = {}, |
||||
knownUpses = {}, |
||||
previous: { domain: anDomain, hostConfig = {}, networkConfig = {} } = {}, |
||||
}: RunManifestInputGroupProps<M>): ReactElement => { |
||||
const { hosts: initHostList = {} } = hostConfig; |
||||
const { |
||||
dnsCsv, |
||||
mtu, |
||||
networks: initNetworkList = {}, |
||||
ntpCsv = MANIFEST_PARAM_NONE, |
||||
} = networkConfig; |
||||
|
||||
const hostListEntries = useMemo( |
||||
() => Object.entries(initHostList), |
||||
[initHostList], |
||||
); |
||||
const knownFenceListEntries = useMemo( |
||||
() => Object.entries(knownFences), |
||||
[knownFences], |
||||
); |
||||
const knownHostListEntries = useMemo( |
||||
() => Object.entries(knownHosts), |
||||
[knownHosts], |
||||
); |
||||
const knownUpsListEntries = useMemo( |
||||
() => Object.entries(knownUpses), |
||||
[knownUpses], |
||||
); |
||||
const networkListEntries = useMemo( |
||||
() => Object.entries(initNetworkList), |
||||
[initNetworkList], |
||||
); |
||||
|
||||
const hostOptionList = useMemo( |
||||
() => |
||||
knownHostListEntries.map<SelectItem>(([, { hostName, hostUUID }]) => ({ |
||||
displayValue: hostName, |
||||
value: hostUUID, |
||||
})), |
||||
[knownHostListEntries], |
||||
); |
||||
|
||||
const { |
||||
headers: hostHeaderRow, |
||||
hosts: hostSelectRow, |
||||
hostNames: hostNewNameRow, |
||||
} = useMemo( |
||||
() => |
||||
hostListEntries.reduce<{ |
||||
headers: GridLayout; |
||||
hosts: GridLayout; |
||||
hostNames: GridLayout; |
||||
}>( |
||||
(previous, [hostId, { hostName, hostNumber, hostType }]) => { |
||||
const { headers, hosts, hostNames } = previous; |
||||
|
||||
const prettyId = `${hostType}${hostNumber}`; |
||||
|
||||
headers[`run-manifest-column-header-cell-${hostId}`] = { |
||||
children: <BodyText>{prettyId}</BodyText>, |
||||
}; |
||||
|
||||
const inputId = `${INPUT_ID_PREFIX_HOST}-${hostId}`; |
||||
const inputLabel = `${prettyId} host`; |
||||
|
||||
setMsgSetter(inputId); |
||||
|
||||
hosts[`run-manifest-host-cell-${hostId}`] = { |
||||
children: ( |
||||
<InputWithRef |
||||
input={ |
||||
<SelectWithLabel |
||||
id={inputId} |
||||
label={inputLabel} |
||||
selectItems={hostOptionList} |
||||
value="" |
||||
/> |
||||
} |
||||
inputTestBatch={buildPeacefulStringTestBatch( |
||||
inputLabel, |
||||
() => { |
||||
msgSetters[inputId](); |
||||
}, |
||||
{ onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, |
||||
(message) => { |
||||
msgSetters[inputId]({ children: message }); |
||||
}, |
||||
)} |
||||
onFirstRender={buildInputFirstRenderFunction(inputId)} |
||||
required |
||||
/> |
||||
), |
||||
}; |
||||
|
||||
hostNames[`run-manifest-new-host-name-cell-${hostId}`] = { |
||||
children: ( |
||||
<MonoText> |
||||
{hostName}.{anDomain} |
||||
</MonoText> |
||||
), |
||||
}; |
||||
|
||||
return previous; |
||||
}, |
||||
{ |
||||
headers: { |
||||
'run-manifest-column-header-cell-offset': {}, |
||||
}, |
||||
hosts: { |
||||
'run-manifest-host-cell-header': { |
||||
children: <BodyText>Uses host</BodyText>, |
||||
}, |
||||
}, |
||||
hostNames: { |
||||
'run-manifest-new-host-name-cell-header': { |
||||
children: <BodyText>New hostname</BodyText>, |
||||
}, |
||||
}, |
||||
}, |
||||
), |
||||
[ |
||||
anDomain, |
||||
buildFinishInputTestBatchFunction, |
||||
buildInputFirstRenderFunction, |
||||
hostListEntries, |
||||
hostOptionList, |
||||
msgSetters, |
||||
setMsgSetter, |
||||
], |
||||
); |
||||
|
||||
const { |
||||
gateway: defaultGatewayGridLayout, |
||||
hostNetworks: hostNetworkRowList, |
||||
} = useMemo( |
||||
() => |
||||
networkListEntries.reduce<{ |
||||
gateway: GridLayout; |
||||
hostNetworks: GridLayout; |
||||
}>( |
||||
( |
||||
previous, |
||||
[networkId, { networkGateway, networkNumber, networkType }], |
||||
) => { |
||||
const { gateway, hostNetworks } = previous; |
||||
|
||||
const idPrefix = `run-manifest-host-network-cell-${networkId}`; |
||||
|
||||
const networkShortName = `${networkType.toUpperCase()}${networkNumber}`; |
||||
|
||||
hostNetworks[`${idPrefix}-header`] = { |
||||
children: <BodyText>{networkShortName}</BodyText>, |
||||
}; |
||||
|
||||
hostListEntries.forEach(([hostId, { networks = {} }]) => { |
||||
const { |
||||
[networkId]: { networkIp: ip = MANIFEST_PARAM_NONE } = {}, |
||||
} = networks; |
||||
|
||||
hostNetworks[`${idPrefix}-${hostId}-ip`] = { |
||||
children: <MonoText>{ip}</MonoText>, |
||||
}; |
||||
}); |
||||
|
||||
const cellId = 'run-manifest-gateway-cell'; |
||||
|
||||
if (networkGateway && !gateway[cellId]) { |
||||
gateway[cellId] = { |
||||
children: <EndMono>{networkGateway}</EndMono>, |
||||
}; |
||||
} |
||||
|
||||
return previous; |
||||
}, |
||||
{ |
||||
gateway: { |
||||
'run-manifest-gateway-cell-header': { |
||||
children: <BodyText>Gateway</BodyText>, |
||||
}, |
||||
}, |
||||
hostNetworks: {}, |
||||
}, |
||||
), |
||||
[hostListEntries, networkListEntries], |
||||
); |
||||
|
||||
const hostFenceRowList = useMemo( |
||||
() => |
||||
knownFenceListEntries.reduce<GridLayout>( |
||||
(previous, [fenceUuid, { fenceName }]) => { |
||||
const idPrefix = `run-manifest-fence-cell-${fenceUuid}`; |
||||
|
||||
previous[`${idPrefix}-header`] = { |
||||
children: <BodyText>Port on {fenceName}</BodyText>, |
||||
}; |
||||
|
||||
hostListEntries.forEach(([hostId, { fences = {} }]) => { |
||||
const { [fenceName]: { fencePort = MANIFEST_PARAM_NONE } = {} } = |
||||
fences; |
||||
|
||||
previous[`${idPrefix}-${hostId}-port`] = { |
||||
children: <MonoText>{fencePort}</MonoText>, |
||||
}; |
||||
}); |
||||
|
||||
return previous; |
||||
}, |
||||
{}, |
||||
), |
||||
[hostListEntries, knownFenceListEntries], |
||||
); |
||||
|
||||
const hostUpsRowList = useMemo( |
||||
() => |
||||
knownUpsListEntries.reduce<GridLayout>( |
||||
(previous, [upsUuid, { upsName }]) => { |
||||
const idPrefix = `run-manifest-ups-cell-${upsUuid}`; |
||||
|
||||
previous[`${idPrefix}-header`] = { |
||||
children: <BodyText>Uses {upsName}</BodyText>, |
||||
}; |
||||
|
||||
hostListEntries.forEach(([hostId, { upses = {} }]) => { |
||||
const { [upsName]: { isUsed = false } = {} } = upses; |
||||
|
||||
previous[`${idPrefix}-${hostId}-is-used`] = { |
||||
children: <MonoText>{isUsed ? 'yes' : 'no'}</MonoText>, |
||||
}; |
||||
}); |
||||
|
||||
return previous; |
||||
}, |
||||
{}, |
||||
), |
||||
[hostListEntries, knownUpsListEntries], |
||||
); |
||||
|
||||
return ( |
||||
<FlexBox> |
||||
<Grid |
||||
columns={{ xs: 1, sm: 2 }} |
||||
layout={{ |
||||
'anvil-description-input-cell': { |
||||
children: ( |
||||
<InputWithRef |
||||
input={ |
||||
<OutlinedInputWithLabel |
||||
id={INPUT_ID_AN_DESCRIPTION} |
||||
label={INPUT_LABEL_AN_DESCRIPTION} |
||||
/> |
||||
} |
||||
inputTestBatch={buildPeacefulStringTestBatch( |
||||
INPUT_LABEL_AN_DESCRIPTION, |
||||
() => { |
||||
msgSetters[INPUT_ID_AN_DESCRIPTION](); |
||||
}, |
||||
{ |
||||
onFinishBatch: buildFinishInputTestBatchFunction( |
||||
INPUT_ID_AN_DESCRIPTION, |
||||
), |
||||
}, |
||||
(message) => { |
||||
msgSetters[INPUT_ID_AN_DESCRIPTION]({ children: message }); |
||||
}, |
||||
)} |
||||
onFirstRender={buildInputFirstRenderFunction( |
||||
INPUT_ID_AN_DESCRIPTION, |
||||
)} |
||||
required |
||||
/> |
||||
), |
||||
sm: 2, |
||||
}, |
||||
'anvil-password-input-cell': { |
||||
children: ( |
||||
<InputWithRef |
||||
input={ |
||||
<OutlinedInputWithLabel |
||||
id={INPUT_ID_AN_PASSWORD} |
||||
label={INPUT_LABEL_AN_PASSWORD} |
||||
/> |
||||
} |
||||
inputTestBatch={buildPeacefulStringTestBatch( |
||||
INPUT_LABEL_AN_PASSWORD, |
||||
() => { |
||||
msgSetters[INPUT_ID_AN_PASSWORD](); |
||||
}, |
||||
{ |
||||
onFinishBatch: |
||||
buildFinishInputTestBatchFunction(INPUT_ID_AN_PASSWORD), |
||||
}, |
||||
(message) => { |
||||
msgSetters[INPUT_ID_AN_PASSWORD]({ children: message }); |
||||
}, |
||||
)} |
||||
onFirstRender={buildInputFirstRenderFunction( |
||||
INPUT_ID_AN_PASSWORD, |
||||
)} |
||||
required |
||||
/> |
||||
), |
||||
}, |
||||
'anvil-confirm-password-input-cell': { |
||||
children: ( |
||||
<InputWithRef |
||||
input={ |
||||
<OutlinedInputWithLabel |
||||
id={INPUT_ID_AN_CONFIRM_PASSWORD} |
||||
label={INPUT_LABEL_AN_CONFIRM_PASSWORD} |
||||
/> |
||||
} |
||||
required |
||||
/> |
||||
), |
||||
}, |
||||
}} |
||||
spacing="1em" |
||||
/> |
||||
<Grid |
||||
alignItems="center" |
||||
columns={{ xs: hostListEntries.length + 1 }} |
||||
layout={{ |
||||
...hostHeaderRow, |
||||
...hostSelectRow, |
||||
...hostNewNameRow, |
||||
...hostNetworkRowList, |
||||
...hostFenceRowList, |
||||
...hostUpsRowList, |
||||
}} |
||||
columnSpacing="1em" |
||||
rowSpacing="0.4em" |
||||
/> |
||||
<Grid |
||||
columns={{ xs: 2 }} |
||||
layout={{ |
||||
...defaultGatewayGridLayout, |
||||
'run-manifest-dns-csv-cell-header': { |
||||
children: <BodyText>DNS</BodyText>, |
||||
}, |
||||
'run-manifest-dns-csv-cell': { |
||||
children: <EndMono>{dnsCsv}</EndMono>, |
||||
}, |
||||
'run-manifest-ntp-csv-cell-header': { |
||||
children: <BodyText>NTP</BodyText>, |
||||
}, |
||||
'run-manifest-ntp-csv-cell': { |
||||
children: <EndMono>{ntpCsv}</EndMono>, |
||||
}, |
||||
'run-manifest-mtu-cell-header': { |
||||
children: <BodyText>MTU</BodyText>, |
||||
}, |
||||
'run-manifest-mtu-cell': { |
||||
children: <EndMono>{mtu}</EndMono>, |
||||
}, |
||||
}} |
||||
spacing="0.4em" |
||||
/> |
||||
</FlexBox> |
||||
); |
||||
}; |
||||
|
||||
export { |
||||
INPUT_ID_AN_CONFIRM_PASSWORD, |
||||
INPUT_ID_AN_DESCRIPTION, |
||||
INPUT_ID_AN_PASSWORD, |
||||
}; |
||||
|
||||
export default RunManifestInputGroup; |
Loading…
Reference in new issue