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.
395 lines
12 KiB
395 lines
12 KiB
import { debounce } from 'lodash'; |
|
import { ReactElement, ReactNode, useMemo } from 'react'; |
|
|
|
import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES'; |
|
|
|
import Grid from '../Grid'; |
|
import IconButton from '../IconButton'; |
|
import InputWithRef from '../InputWithRef'; |
|
import OutlinedInputWithLabel from '../OutlinedInputWithLabel'; |
|
import { InnerPanel, InnerPanelBody, InnerPanelHeader } from '../Panels'; |
|
import SelectWithLabel from '../SelectWithLabel'; |
|
import { buildIPAddressTestBatch } from '../../lib/test_input'; |
|
|
|
const INPUT_ID_PREFIX_AN_NETWORK = 'an-network-input'; |
|
|
|
const INPUT_CELL_ID_PREFIX_AN = `${INPUT_ID_PREFIX_AN_NETWORK}-cell`; |
|
|
|
const MAP_TO_AN_INPUT_HANDLER: MapToManifestFormInputHandler = { |
|
gateway: (container, input) => { |
|
const { |
|
dataset: { networkId = '' }, |
|
value, |
|
} = input; |
|
const { |
|
networkConfig: { networks }, |
|
} = container; |
|
|
|
networks[networkId].networkGateway = value; |
|
}, |
|
minip: (container, input) => { |
|
const { |
|
dataset: { networkId = '' }, |
|
value, |
|
} = input; |
|
const { |
|
networkConfig: { networks }, |
|
} = container; |
|
|
|
networks[networkId].networkMinIp = value; |
|
}, |
|
network: (container, input) => { |
|
const { |
|
dataset: { networkId = '', networkNumber: rawNn = '', networkType = '' }, |
|
} = input; |
|
const { |
|
networkConfig: { networks }, |
|
} = container; |
|
const networkNumber = Number.parseInt(rawNn, 10); |
|
|
|
networks[networkId] = { |
|
networkNumber, |
|
networkType, |
|
} as ManifestNetwork; |
|
}, |
|
subnetmask: (container, input) => { |
|
const { |
|
dataset: { networkId = '' }, |
|
value, |
|
} = input; |
|
const { |
|
networkConfig: { networks }, |
|
} = container; |
|
|
|
networks[networkId].networkSubnetMask = value; |
|
}, |
|
}; |
|
|
|
const buildInputIdANGateway = (networkId: string): string => |
|
`${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}-gateway`; |
|
|
|
const buildInputIdANMinIp = (networkId: string): string => |
|
`${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}-min-ip`; |
|
|
|
const buildInputIdANNetworkType = (networkId: string): string => |
|
`${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}-network-type`; |
|
|
|
const buildInputIdANSubnetMask = (networkId: string): string => |
|
`${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}-subnet-mask`; |
|
|
|
const AnNetworkInputGroup = <M extends MapToInputTestID>({ |
|
debounceWait = 500, |
|
formUtils: { |
|
buildFinishInputTestBatchFunction, |
|
buildInputFirstRenderFunction, |
|
buildInputUnmountFunction, |
|
setMessage, |
|
}, |
|
inputGatewayLabel = 'Gateway', |
|
inputMinIpLabel = 'IP address', |
|
inputSubnetMaskLabel = 'Subnet mask', |
|
networkId, |
|
networkNumber, |
|
networkType, |
|
networkTypeOptions, |
|
onClose, |
|
onNetworkGatewayChange, |
|
onNetworkMinIpChange, |
|
onNetworkSubnetMaskChange, |
|
onNetworkTypeChange, |
|
previous: { |
|
gateway: previousGateway, |
|
minIp: previousIpAddress, |
|
subnetMask: previousSubnetMask, |
|
} = {}, |
|
readonlyNetworkName: isReadonlyNetworkName, |
|
showCloseButton: isShowCloseButton, |
|
showGateway: isShowGateway, |
|
}: AnNetworkInputGroupProps<M>): ReactElement => { |
|
const networkName = useMemo( |
|
() => `${NETWORK_TYPES[networkType]} ${networkNumber}`, |
|
[networkNumber, networkType], |
|
); |
|
|
|
const inputCellIdGateway = useMemo( |
|
() => `${INPUT_CELL_ID_PREFIX_AN}-${networkId}-gateway`, |
|
[networkId], |
|
); |
|
const inputCellIdIp = useMemo( |
|
() => `${INPUT_CELL_ID_PREFIX_AN}-${networkId}-ip`, |
|
[networkId], |
|
); |
|
const inputCellIdSubnetMask = useMemo( |
|
() => `${INPUT_CELL_ID_PREFIX_AN}-${networkId}-subnet-mask`, |
|
[networkId], |
|
); |
|
|
|
const inputIdANNetwork = useMemo( |
|
() => `${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}`, |
|
[networkId], |
|
); |
|
|
|
const inputIdGateway = useMemo( |
|
() => buildInputIdANGateway(networkId), |
|
[networkId], |
|
); |
|
const inputIdMinIp = useMemo( |
|
() => buildInputIdANMinIp(networkId), |
|
[networkId], |
|
); |
|
const inputIdNetworkType = useMemo( |
|
() => buildInputIdANNetworkType(networkId), |
|
[networkId], |
|
); |
|
const inputIdSubnetMask = useMemo( |
|
() => buildInputIdANSubnetMask(networkId), |
|
[networkId], |
|
); |
|
|
|
const inputCellGatewayDisplay = useMemo( |
|
() => (isShowGateway ? undefined : 'none'), |
|
[isShowGateway], |
|
); |
|
|
|
const debounceNetworkGatewayChangeHandler = useMemo( |
|
() => |
|
onNetworkGatewayChange && debounce(onNetworkGatewayChange, debounceWait), |
|
[debounceWait, onNetworkGatewayChange], |
|
); |
|
|
|
const debounceNetworkMinIpChangeHandler = useMemo( |
|
() => onNetworkMinIpChange && debounce(onNetworkMinIpChange, debounceWait), |
|
[debounceWait, onNetworkMinIpChange], |
|
); |
|
|
|
const debounceNetworkSubnetMaskChangeHandler = useMemo( |
|
() => |
|
onNetworkSubnetMaskChange && |
|
debounce(onNetworkSubnetMaskChange, debounceWait), |
|
[debounceWait, onNetworkSubnetMaskChange], |
|
); |
|
|
|
const closeButtonElement = useMemo<ReactNode>( |
|
() => |
|
isShowCloseButton && ( |
|
<IconButton |
|
mapPreset="close" |
|
iconProps={{ fontSize: 'small' }} |
|
onClick={(...args) => { |
|
onClose?.call(null, { networkId, networkType }, ...args); |
|
}} |
|
sx={{ |
|
padding: '.2em', |
|
position: 'absolute', |
|
right: '-.6rem', |
|
top: '-.2rem', |
|
}} |
|
/> |
|
), |
|
[isShowCloseButton, networkId, networkType, onClose], |
|
); |
|
|
|
const inputGatewayElement = useMemo<ReactNode>(() => { |
|
let result: ReactNode; |
|
|
|
if (isShowGateway && inputIdGateway) { |
|
result = ( |
|
<InputWithRef |
|
createInputOnChangeHandlerOptions={{ |
|
postSet: (...args) => |
|
debounceNetworkGatewayChangeHandler?.call( |
|
null, |
|
{ networkId, networkType }, |
|
...args, |
|
), |
|
}} |
|
input={ |
|
<OutlinedInputWithLabel |
|
baseInputProps={{ |
|
'data-handler': 'gateway', |
|
'data-network-id': networkId, |
|
}} |
|
id={inputIdGateway} |
|
label={inputGatewayLabel} |
|
value={previousGateway} |
|
/> |
|
} |
|
inputTestBatch={buildIPAddressTestBatch( |
|
`${networkName} ${inputGatewayLabel}`, |
|
() => { |
|
setMessage(inputIdGateway); |
|
}, |
|
{ |
|
onFinishBatch: buildFinishInputTestBatchFunction(inputIdGateway), |
|
}, |
|
(message) => { |
|
setMessage(inputIdGateway, { children: message }); |
|
}, |
|
)} |
|
onFirstRender={buildInputFirstRenderFunction(inputIdGateway)} |
|
onUnmount={buildInputUnmountFunction(inputIdGateway)} |
|
required={isShowGateway} |
|
/> |
|
); |
|
} |
|
|
|
return result; |
|
}, [ |
|
isShowGateway, |
|
inputIdGateway, |
|
networkId, |
|
inputGatewayLabel, |
|
previousGateway, |
|
networkName, |
|
buildFinishInputTestBatchFunction, |
|
buildInputFirstRenderFunction, |
|
buildInputUnmountFunction, |
|
debounceNetworkGatewayChangeHandler, |
|
networkType, |
|
setMessage, |
|
]); |
|
|
|
return ( |
|
<InnerPanel mv={0}> |
|
<InnerPanelHeader> |
|
<InputWithRef |
|
input={ |
|
<SelectWithLabel |
|
id={inputIdNetworkType} |
|
isReadOnly={isReadonlyNetworkName} |
|
onChange={(...args) => { |
|
onNetworkTypeChange?.call( |
|
null, |
|
{ networkId, networkType }, |
|
...args, |
|
); |
|
}} |
|
selectItems={networkTypeOptions} |
|
selectProps={{ |
|
renderValue: () => networkName, |
|
}} |
|
value={networkType} |
|
/> |
|
} |
|
/> |
|
{closeButtonElement} |
|
</InnerPanelHeader> |
|
<InnerPanelBody> |
|
<input |
|
hidden |
|
id={inputIdANNetwork} |
|
readOnly |
|
data-handler="network" |
|
data-network-id={networkId} |
|
data-network-number={networkNumber} |
|
data-network-type={networkType} |
|
/> |
|
<Grid |
|
columns={{ xs: 1, sm: 2, md: 3 }} |
|
layout={{ |
|
[inputCellIdIp]: { |
|
children: ( |
|
<InputWithRef |
|
createInputOnChangeHandlerOptions={{ |
|
postSet: (...args) => |
|
debounceNetworkMinIpChangeHandler?.call( |
|
null, |
|
{ networkId, networkType }, |
|
...args, |
|
), |
|
}} |
|
input={ |
|
<OutlinedInputWithLabel |
|
baseInputProps={{ |
|
'data-handler': 'minip', |
|
'data-network-id': networkId, |
|
}} |
|
id={inputIdMinIp} |
|
label={inputMinIpLabel} |
|
value={previousIpAddress} |
|
/> |
|
} |
|
inputTestBatch={buildIPAddressTestBatch( |
|
`${networkName} ${inputMinIpLabel}`, |
|
() => { |
|
setMessage(inputIdMinIp); |
|
}, |
|
{ |
|
onFinishBatch: |
|
buildFinishInputTestBatchFunction(inputIdMinIp), |
|
}, |
|
(message) => { |
|
setMessage(inputIdMinIp, { children: message }); |
|
}, |
|
)} |
|
onFirstRender={buildInputFirstRenderFunction(inputIdMinIp)} |
|
onUnmount={buildInputUnmountFunction(inputIdMinIp)} |
|
required |
|
/> |
|
), |
|
}, |
|
[inputCellIdSubnetMask]: { |
|
children: ( |
|
<InputWithRef |
|
createInputOnChangeHandlerOptions={{ |
|
postSet: (...args) => |
|
debounceNetworkSubnetMaskChangeHandler?.call( |
|
null, |
|
{ networkId, networkType }, |
|
...args, |
|
), |
|
}} |
|
input={ |
|
<OutlinedInputWithLabel |
|
baseInputProps={{ |
|
'data-handler': 'subnetmask', |
|
'data-network-id': networkId, |
|
}} |
|
id={inputIdSubnetMask} |
|
label={inputSubnetMaskLabel} |
|
value={previousSubnetMask} |
|
/> |
|
} |
|
inputTestBatch={buildIPAddressTestBatch( |
|
`${networkName} ${inputSubnetMaskLabel}`, |
|
() => { |
|
setMessage(inputIdSubnetMask); |
|
}, |
|
{ |
|
onFinishBatch: |
|
buildFinishInputTestBatchFunction(inputIdSubnetMask), |
|
}, |
|
(message) => { |
|
setMessage(inputIdSubnetMask, { children: message }); |
|
}, |
|
)} |
|
onFirstRender={buildInputFirstRenderFunction( |
|
inputIdSubnetMask, |
|
)} |
|
onUnmount={buildInputUnmountFunction(inputIdSubnetMask)} |
|
required |
|
/> |
|
), |
|
}, |
|
[inputCellIdGateway]: { |
|
children: inputGatewayElement, |
|
display: inputCellGatewayDisplay, |
|
}, |
|
}} |
|
spacing="1em" |
|
/> |
|
</InnerPanelBody> |
|
</InnerPanel> |
|
); |
|
}; |
|
|
|
export { |
|
INPUT_ID_PREFIX_AN_NETWORK, |
|
MAP_TO_AN_INPUT_HANDLER, |
|
buildInputIdANGateway, |
|
buildInputIdANMinIp, |
|
buildInputIdANNetworkType, |
|
buildInputIdANSubnetMask, |
|
}; |
|
|
|
export default AnNetworkInputGroup;
|
|
|