|
|
|
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;
|