diff --git a/striker-ui/components/ManageManifest/AddManifestInputGroup.tsx b/striker-ui/components/ManageManifest/AddManifestInputGroup.tsx index 7617f204..774c9c11 100644 --- a/striker-ui/components/ManageManifest/AddManifestInputGroup.tsx +++ b/striker-ui/components/ManageManifest/AddManifestInputGroup.tsx @@ -1,5 +1,6 @@ -import { ReactElement, useState } from 'react'; +import { ReactElement, useMemo, useState } from 'react'; +import AnvilHostConfigInputGroup from './AnvilHostConfigInputGroup'; import AnvilIdInputGroup, { INPUT_ID_ANVIL_ID_DOMAIN, INPUT_ID_ANVIL_ID_PREFIX, @@ -12,7 +13,7 @@ import AnvilNetworkConfigInputGroup, { } from './AnvilNetworkConfigInputGroup'; import FlexBox from '../FlexBox'; -const DEFAULT_NETWORKS: ManifestNetworkList = { +const DEFAULT_NETWORK_LIST: ManifestNetworkList = { bcn1: { networkMinIp: '', networkNumber: 1, @@ -45,23 +46,36 @@ const AddManifestInputGroup = < }, >({ formUtils, - previous: { networkConfig: previousNetworkConfig = {} } = {}, + previous: { + hostConfig: previousHostConfig = {}, + networkConfig: previousNetworkConfig = {}, + } = {}, }: AddManifestInputGroupProps): ReactElement => { - const { networks: previousNetworkList = DEFAULT_NETWORKS } = + const { networks: previousNetworkList = DEFAULT_NETWORK_LIST } = previousNetworkConfig; const [networkList, setNetworkList] = useState(previousNetworkList); + const networkListEntries = useMemo( + () => Object.entries(networkList), + [networkList], + ); + return ( + ); }; diff --git a/striker-ui/components/ManageManifest/AnvilHostConfigInputGroup.tsx b/striker-ui/components/ManageManifest/AnvilHostConfigInputGroup.tsx new file mode 100644 index 00000000..d755395c --- /dev/null +++ b/striker-ui/components/ManageManifest/AnvilHostConfigInputGroup.tsx @@ -0,0 +1,103 @@ +import { ReactElement, useMemo } from 'react'; + +import AnvilHostInputGroup from './AnvilHostInputGroup'; +import Grid from '../Grid'; + +const INPUT_ID_PREFIX_ANVIL_HOST_CONFIG = 'anvil-host-config-input'; + +const INPUT_GROUP_ID_PREFIX_ANVIL_HOST_CONFIG = `${INPUT_ID_PREFIX_ANVIL_HOST_CONFIG}-group`; +const INPUT_GROUP_CELL_ID_PREFIX_ANVIL_HOST_CONFIG = `${INPUT_GROUP_ID_PREFIX_ANVIL_HOST_CONFIG}-cell`; + +const DEFAULT_HOST_LIST: ManifestHostList = { + node1: { + fences: { + fence1: { fenceName: 'ex_pdu01', fencePort: 0 }, + fence2: { fenceName: 'ex_pdu02', fencePort: 0 }, + }, + hostNumber: 1, + hostType: 'node', + upses: { + ups1: { isPowerHost: true, upsName: 'ex_ups01' }, + ups2: { isPowerHost: false, upsName: 'ex_ups02' }, + }, + }, + node2: { + hostNumber: 2, + hostType: 'node', + }, + dr1: { + hostNumber: 1, + hostType: 'dr', + }, +}; + +const AnvilHostConfigInputGroup = ({ + formUtils, + networkListEntries, + previous: { hosts: previousHostList = DEFAULT_HOST_LIST } = {}, +}: AnvilHostConfigInputGroupProps): ReactElement => { + const hostListEntries = useMemo( + () => Object.entries(previousHostList), + [previousHostList], + ); + + const hostNetworkList = useMemo( + () => + networkListEntries.reduce( + (previous, [networkId, { networkNumber, networkType }]) => { + previous[networkId] = { + networkIp: '', + networkNumber, + networkType, + }; + + return previous; + }, + {}, + ), + [networkListEntries], + ); + + const hostListGridLayout = useMemo( + () => + hostListEntries.reduce( + (previous, [hostId, previousHostArgs]) => { + const { + hostNumber, + hostType, + networks = hostNetworkList, + }: ManifestHost = previousHostArgs; + + const cellId = `${INPUT_GROUP_CELL_ID_PREFIX_ANVIL_HOST_CONFIG}-${hostId}`; + + const hostLabel = `${hostType} ${hostNumber}`; + + previous[cellId] = { + children: ( + + ), + md: 3, + sm: 2, + }; + + return previous; + }, + {}, + ), + [formUtils, hostListEntries, hostNetworkList], + ); + + return ( + + ); +}; + +export default AnvilHostConfigInputGroup; diff --git a/striker-ui/components/ManageManifest/AnvilHostInputGroup.tsx b/striker-ui/components/ManageManifest/AnvilHostInputGroup.tsx index ddefa929..fd955138 100644 --- a/striker-ui/components/ManageManifest/AnvilHostInputGroup.tsx +++ b/striker-ui/components/ManageManifest/AnvilHostInputGroup.tsx @@ -2,6 +2,7 @@ import { ReactElement, useMemo } from 'react'; import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES'; +import FlexBox from '../FlexBox'; import Grid from '../Grid'; import InputWithRef from '../InputWithRef'; import OutlinedInputWithLabel from '../OutlinedInputWithLabel'; @@ -13,9 +14,9 @@ import { } from '../../lib/test_input'; import { BodyText } from '../Text'; -const INPUT_ID_PREFIX_ANVIL_HOST_CONFIG = 'anvil-host-config-input'; +const INPUT_ID_PREFIX_ANVIL_HOST = 'anvil-host-input'; -const INPUT_CELL_ID_PREFIX_ANVIL_HOST_CONFIG = `${INPUT_ID_PREFIX_ANVIL_HOST_CONFIG}-cell`; +const INPUT_CELL_ID_PREFIX_ANVIL_HOST = `${INPUT_ID_PREFIX_ANVIL_HOST}-cell`; const AnvilHostInputGroup = ({ formUtils: { @@ -25,148 +26,194 @@ const AnvilHostInputGroup = ({ setMsgSetter, }, hostLabel, - previous: { fences = {}, networks = {}, upses = {} } = {}, + previous: { + fences: fenceList = {}, + networks: networkList = {}, + upses: upsList = {}, + } = {}, }: AnvilHostInputGroupProps): ReactElement => { - const gridLayout = useMemo(() => { - let result: GridLayout = {}; + const fenceListEntries = useMemo( + () => Object.entries(fenceList), + [fenceList], + ); - result = Object.entries(networks).reduce( - (previous, [networkId, { networkIp, networkNumber, networkType }]) => { - const idPostfix = `${networkId}-ip`; + const networkListEntries = useMemo( + () => Object.entries(networkList), + [networkList], + ); - const cellId = `${INPUT_CELL_ID_PREFIX_ANVIL_HOST_CONFIG}-${idPostfix}`; + const upsListEntries = useMemo(() => Object.entries(upsList), [upsList]); - const inputId = `${INPUT_ID_PREFIX_ANVIL_HOST_CONFIG}-${idPostfix}`; - const inputLabel = `${NETWORK_TYPES[networkType]} ${networkNumber}`; + const fenceListGridLayout = useMemo( + () => + fenceListEntries.reduce( + (previous, [fenceId, { fenceName, fencePort }]) => { + const idPostfix = `${fenceId}-port`; - setMsgSetter(inputId); + const cellId = `${INPUT_CELL_ID_PREFIX_ANVIL_HOST}-${idPostfix}`; - previous[cellId] = { - children: ( - - } - inputTestBatch={buildIPAddressTestBatch( - inputLabel, - () => { - msgSetters[inputId](); - }, - { onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, - (message) => { - msgSetters[inputId]({ - children: message, - }); - }, - )} - onFirstRender={buildInputFirstRenderFunction(inputId)} - required - /> - ), - }; + const inputId = `${INPUT_ID_PREFIX_ANVIL_HOST}-${idPostfix}`; + const inputLabel = fenceName; - return previous; - }, - result, - ); + setMsgSetter(inputId); - result = Object.entries(fences).reduce( - (previous, [fenceId, { fenceName, fencePort }]) => { - const idPostfix = `${fenceId}-port`; + previous[cellId] = { + children: ( + + } + inputTestBatch={buildNumberTestBatch( + inputLabel, + () => { + msgSetters[inputId](); + }, + { onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, + (message) => { + msgSetters[inputId]({ + children: message, + }); + }, + )} + onFirstRender={buildInputFirstRenderFunction(inputId)} + required + valueType="number" + /> + ), + }; - const cellId = `${INPUT_CELL_ID_PREFIX_ANVIL_HOST_CONFIG}-${idPostfix}`; + return previous; + }, + {}, + ), + [ + buildFinishInputTestBatchFunction, + buildInputFirstRenderFunction, + fenceListEntries, + msgSetters, + setMsgSetter, + ], + ); - const inputId = `${INPUT_ID_PREFIX_ANVIL_HOST_CONFIG}-${idPostfix}`; - const inputLabel = fenceName; + const networkListGridLayout = useMemo( + () => + networkListEntries.reduce( + (previous, [networkId, { networkIp, networkNumber, networkType }]) => { + const idPostfix = `${networkId}-ip`; - setMsgSetter(inputId); + const cellId = `${INPUT_CELL_ID_PREFIX_ANVIL_HOST}-${idPostfix}`; - previous[cellId] = { - children: ( - - } - inputTestBatch={buildNumberTestBatch( - inputLabel, - () => { - msgSetters[inputId](); - }, - { onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, - (message) => { - msgSetters[inputId]({ - children: message, - }); - }, - )} - required - valueType="number" - /> - ), - }; + const inputId = `${INPUT_ID_PREFIX_ANVIL_HOST}-${idPostfix}`; + const inputLabel = `${NETWORK_TYPES[networkType]} ${networkNumber}`; - return previous; - }, - result, - ); + setMsgSetter(inputId); - result = Object.entries(upses).reduce( - (previous, [upsId, { isPowerHost, upsName }]) => { - const idPostfix = `${upsId}-power-host`; + previous[cellId] = { + children: ( + + } + inputTestBatch={buildIPAddressTestBatch( + inputLabel, + () => { + msgSetters[inputId](); + }, + { onFinishBatch: buildFinishInputTestBatchFunction(inputId) }, + (message) => { + msgSetters[inputId]({ + children: message, + }); + }, + )} + onFirstRender={buildInputFirstRenderFunction(inputId)} + required + /> + ), + }; - const cellId = `${INPUT_CELL_ID_PREFIX_ANVIL_HOST_CONFIG}-${idPostfix}`; + return previous; + }, + {}, + ), + [ + networkListEntries, + setMsgSetter, + buildFinishInputTestBatchFunction, + buildInputFirstRenderFunction, + msgSetters, + ], + ); - const inputId = `${INPUT_ID_PREFIX_ANVIL_HOST_CONFIG}-${idPostfix}`; + const upsListGridLayout = useMemo( + () => + upsListEntries.reduce( + (previous, [upsId, { isPowerHost, upsName }]) => { + const idPostfix = `${upsId}-power-host`; - previous[cellId] = { - children: ( - - } - valueType="boolean" - /> - ), - }; + const cellId = `${INPUT_CELL_ID_PREFIX_ANVIL_HOST}-${idPostfix}`; - return previous; - }, - result, - ); + const inputId = `${INPUT_ID_PREFIX_ANVIL_HOST}-${idPostfix}`; - return result; - }, [ - buildFinishInputTestBatchFunction, - buildInputFirstRenderFunction, - setMsgSetter, - fences, - msgSetters, - networks, - upses, - ]); + previous[cellId] = { + children: ( + + } + valueType="boolean" + /> + ), + }; + + return previous; + }, + {}, + ), + [upsListEntries], + ); return ( - + {hostLabel} - + + + {Boolean(fenceListEntries.length || upsListEntries.length) && ( + + )} + ); }; +export { INPUT_ID_PREFIX_ANVIL_HOST }; + export default AnvilHostInputGroup; diff --git a/striker-ui/components/ManageManifest/AnvilNetworkConfigInputGroup.tsx b/striker-ui/components/ManageManifest/AnvilNetworkConfigInputGroup.tsx index 332276f8..63ea5d8a 100644 --- a/striker-ui/components/ManageManifest/AnvilNetworkConfigInputGroup.tsx +++ b/striker-ui/components/ManageManifest/AnvilNetworkConfigInputGroup.tsx @@ -37,7 +37,7 @@ const AnvilNetworkConfigInputGroup = < }, >({ formUtils, - networkList, + networkListEntries, previous: { dnsCsv: previousDnsCsv, mtu: previousMtu, @@ -51,11 +51,6 @@ const AnvilNetworkConfigInputGroup = < msgSetters, } = formUtils; - const networkListEntries = useMemo( - () => Object.entries(networkList), - [networkList], - ); - const getNetworkNumber = useCallback( ( type: string, diff --git a/striker-ui/types/ManageManifest.d.ts b/striker-ui/types/ManageManifest.d.ts index aac4dd01..8aa911ec 100644 --- a/striker-ui/types/ManageManifest.d.ts +++ b/striker-ui/types/ManageManifest.d.ts @@ -23,6 +23,36 @@ type ManifestNetworkList = { [networkId: string]: ManifestNetwork; }; +type ManifestHostNetworkList = { + [networkId: string]: { + networkIp: string; + networkNumber: number; + networkType: string; + }; +}; + +type ManifestHost = { + fences?: { + [fenceId: string]: { + fenceName: string; + fencePort: number; + }; + }; + hostNumber: number; + hostType: string; + networks?: ManifestHostNetworkList; + upses?: { + [upsId: string]: { + isPowerHost: boolean; + upsName: string; + }; + }; +}; + +type ManifestHostList = { + [hostId: string]: ManifestHost; +}; + type AnvilNetworkEventHandlerPreviousArgs = { networkId: string; } & Pick; @@ -68,34 +98,13 @@ type AnvilNetworkInputGroupProps = }; type AnvilHostInputGroupOptionalProps = { - previous?: { - fences?: { - [fenceId: string]: { - fenceName: string; - fencePort: number; - }; - }; - networks?: { - [networkId: string]: { - networkIp: string; - networkNumber: number; - networkType: string; - }; - }; - upses?: { - [upsId: string]: { - isPowerHost: boolean; - upsName: string; - }; - }; - }; + previous?: Pick; }; type AnvilHostInputGroupProps = AnvilHostInputGroupOptionalProps & { formUtils: FormUtils; hostLabel: string; - idPrefix: string; }; type AnvilNetworkConfigInputGroupOptionalProps = { @@ -111,15 +120,28 @@ type AnvilNetworkConfigInputGroupOptionalProps = { type AnvilNetworkConfigInputGroupProps = AnvilNetworkConfigInputGroupOptionalProps & { formUtils: FormUtils; - networkList: ManifestNetworkList; + networkListEntries: Array<[string, ManifestNetwork]>; setNetworkList: import('react').Dispatch< import('react').SetStateAction >; }; +type AnvilHostConfigInputGroupOptionalProps = { + previous?: { + hosts?: ManifestHostList; + }; +}; + +type AnvilHostConfigInputGroupProps = + AnvilHostConfigInputGroupOptionalProps & { + formUtils: FormUtils; + networkListEntries: Array<[string, ManifestNetwork]>; + }; + type AddManifestInputGroupOptionalProps = { previous?: { networkConfig?: AnvilNetworkConfigInputGroupOptionalProps['previous']; + hostConfig?: AnvilHostConfigInputGroupOptionalProps['previous']; }; };