import { styled } from '@mui/material'; import { ReactElement, useMemo, useRef } from 'react'; import INPUT_TYPES from '../../lib/consts/INPUT_TYPES'; import FlexBox from '../FlexBox'; import Grid from '../Grid'; import InputWithRef, { InputForwardedRefContent } from '../InputWithRef'; import OutlinedInputWithLabel from '../OutlinedInputWithLabel'; import SelectWithLabel from '../SelectWithLabel'; import { buildPeacefulStringTestBatch } from '../../lib/test_input'; import { BodyText, MonoText } from '../Text'; const INPUT_ID_PREFIX_RUN_MANIFEST = 'run-manifest-input'; const INPUT_ID_PREFIX_RM_HOST = `${INPUT_ID_PREFIX_RUN_MANIFEST}-host`; const INPUT_ID_RM_AN_DESCRIPTION = `${INPUT_ID_PREFIX_RUN_MANIFEST}-an-description`; const INPUT_ID_RM_AN_PASSWORD = `${INPUT_ID_PREFIX_RUN_MANIFEST}-an-password`; const INPUT_ID_RM_AN_CONFIRM_PASSWORD = `${INPUT_ID_PREFIX_RUN_MANIFEST}-an-confirm-password`; const INPUT_LABEL_RM_AN_DESCRIPTION = 'Description'; const INPUT_LABEL_RM_AN_PASSWORD = 'Password'; const INPUT_LABEL_RM_AN_CONFIRM_PASSWORD = 'Confirm password'; const MANIFEST_PARAM_NONE = '--'; const EndMono = styled(MonoText)({ justifyContent: 'end', }); const buildInputIdRMHost = (hostId: string): string => `${INPUT_ID_PREFIX_RM_HOST}-${hostId}`; const RunManifestInputGroup = ({ formUtils: { buildFinishInputTestBatchFunction, buildInputFirstRenderFunction, setMessage, }, knownFences = {}, knownHosts = {}, knownUpses = {}, previous: { domain: anDomain, hostConfig = {}, networkConfig = {} } = {}, }: RunManifestInputGroupProps): ReactElement => { const passwordRef = useRef>({}); 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(([, { 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.replace( 'node', 'subnode', )} ${hostNumber}`; headers[`run-manifest-column-header-cell-${hostId}`] = { children: {prettyId}, }; const inputId = buildInputIdRMHost(hostId); const inputLabel = `${prettyId} host`; hosts[`run-manifest-host-cell-${hostId}`] = { children: ( } inputTestBatch={buildPeacefulStringTestBatch( inputLabel, () => { setMessage(inputId); }, { onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, (message) => { setMessage(inputId, { children: message }); }, )} onFirstRender={buildInputFirstRenderFunction(inputId)} required /> ), }; hostNames[`run-manifest-new-host-name-cell-${hostId}`] = { children: ( {hostName}.{anDomain} ), }; return previous; }, { headers: { 'run-manifest-column-header-cell-offset': {}, }, hosts: { 'run-manifest-host-cell-header': { children: Uses host, }, }, hostNames: { 'run-manifest-new-host-name-cell-header': { children: New hostname, }, }, }, ), [ anDomain, buildFinishInputTestBatchFunction, buildInputFirstRenderFunction, hostListEntries, hostOptionList, setMessage, ], ); 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: {networkShortName}, }; hostListEntries.forEach(([hostId, { networks = {} }]) => { const { [networkId]: { networkIp: ip = MANIFEST_PARAM_NONE } = {}, } = networks; hostNetworks[`${idPrefix}-${hostId}-ip`] = { children: {ip}, }; }); const cellId = 'run-manifest-gateway-cell'; if (networkGateway && !gateway[cellId]) { gateway[cellId] = { children: {networkGateway}, }; } return previous; }, { gateway: { 'run-manifest-gateway-cell-header': { children: Gateway, }, }, hostNetworks: {}, }, ), [hostListEntries, networkListEntries], ); const hostFenceRowList = useMemo( () => knownFenceListEntries.reduce( (previous, [fenceUuid, { fenceName }]) => { const idPrefix = `run-manifest-fence-cell-${fenceUuid}`; previous[`${idPrefix}-header`] = { children: Port on {fenceName}, }; hostListEntries.forEach(([hostId, { fences = {} }]) => { const { [fenceName]: { fencePort = MANIFEST_PARAM_NONE } = {} } = fences; previous[`${idPrefix}-${hostId}-port`] = { children: {fencePort}, }; }); return previous; }, {}, ), [hostListEntries, knownFenceListEntries], ); const hostUpsRowList = useMemo( () => knownUpsListEntries.reduce( (previous, [upsUuid, { upsName }]) => { const idPrefix = `run-manifest-ups-cell-${upsUuid}`; previous[`${idPrefix}-header`] = { children: Uses {upsName}, }; hostListEntries.forEach(([hostId, { upses = {} }]) => { const { [upsName]: { isUsed = false } = {} } = upses; previous[`${idPrefix}-${hostId}-is-used`] = { children: {isUsed ? 'yes' : 'no'}, }; }); return previous; }, {}, ), [hostListEntries, knownUpsListEntries], ); const confirmPasswordProps = useMemo(() => { const inputTestBatch = buildPeacefulStringTestBatch( INPUT_LABEL_RM_AN_CONFIRM_PASSWORD, () => { setMessage(INPUT_ID_RM_AN_CONFIRM_PASSWORD); }, { onFinishBatch: buildFinishInputTestBatchFunction( INPUT_ID_RM_AN_CONFIRM_PASSWORD, ), }, (message) => { setMessage(INPUT_ID_RM_AN_CONFIRM_PASSWORD, { children: message }); }, ); const onFirstRender = buildInputFirstRenderFunction( INPUT_ID_RM_AN_CONFIRM_PASSWORD, ); inputTestBatch.tests.push({ onFailure: () => { setMessage(INPUT_ID_RM_AN_CONFIRM_PASSWORD, { children: <>Confirm password must match password., }); }, test: ({ value }) => passwordRef.current.getValue?.call(null) === value, }); return { inputTestBatch, onFirstRender, }; }, [ buildFinishInputTestBatchFunction, buildInputFirstRenderFunction, setMessage, ]); return ( } inputTestBatch={buildPeacefulStringTestBatch( INPUT_LABEL_RM_AN_DESCRIPTION, () => { setMessage(INPUT_ID_RM_AN_DESCRIPTION); }, { onFinishBatch: buildFinishInputTestBatchFunction( INPUT_ID_RM_AN_DESCRIPTION, ), }, (message) => { setMessage(INPUT_ID_RM_AN_DESCRIPTION, { children: message, }); }, )} onFirstRender={buildInputFirstRenderFunction( INPUT_ID_RM_AN_DESCRIPTION, )} required /> ), sm: 2, }, 'run-manifest-input-cell-an-password': { children: ( } inputTestBatch={buildPeacefulStringTestBatch( INPUT_LABEL_RM_AN_PASSWORD, () => { setMessage(INPUT_ID_RM_AN_PASSWORD); }, { onFinishBatch: buildFinishInputTestBatchFunction( INPUT_ID_RM_AN_PASSWORD, ), }, (message) => { setMessage(INPUT_ID_RM_AN_PASSWORD, { children: message }); }, )} onFirstRender={buildInputFirstRenderFunction( INPUT_ID_RM_AN_PASSWORD, )} ref={passwordRef} required /> ), }, 'run-manifest-input-cell-an-confirm-password': { children: ( } required {...confirmPasswordProps} /> ), }, }} spacing="1em" /> DNS, }, 'run-manifest-dns-csv-cell': { children: {dnsCsv}, }, 'run-manifest-ntp-csv-cell-header': { children: NTP, }, 'run-manifest-ntp-csv-cell': { children: {ntpCsv}, }, 'run-manifest-mtu-cell-header': { children: MTU, }, 'run-manifest-mtu-cell': { children: {mtu}, }, }} spacing="0.4em" /> ); }; export { INPUT_ID_RM_AN_CONFIRM_PASSWORD, INPUT_ID_RM_AN_DESCRIPTION, INPUT_ID_RM_AN_PASSWORD, buildInputIdRMHost, }; export default RunManifestInputGroup;