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