|
|
|
@ -143,6 +143,13 @@ const REQUIRED_NETWORKS: NetworkInput[] = [ |
|
|
|
|
const BASE_INPUT_COUNT = 2; |
|
|
|
|
const MAX_INTERFACES_PER_NETWORK = 2; |
|
|
|
|
const PER_NETWORK_INPUT_COUNT = 3; |
|
|
|
|
const INPUT_TEST_IDS = { |
|
|
|
|
dnsCSV: 'domainNameServerCSV', |
|
|
|
|
gateway: 'gateway', |
|
|
|
|
networkName: (prefix: string) => `${prefix}Name`, |
|
|
|
|
networkIPAddress: (prefix: string) => `${prefix}IPAddress`, |
|
|
|
|
networkSubnet: (prefix: string) => `${prefix}SubnetMask`, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const NETWORK_INTERFACE_TEMPLATE = Array.from( |
|
|
|
|
{ length: MAX_INTERFACES_PER_NETWORK }, |
|
|
|
@ -265,6 +272,8 @@ const NetworkForm: FC<{ |
|
|
|
|
setNetworkInterfaceInputMap: Dispatch< |
|
|
|
|
SetStateAction<NetworkInterfaceInputMap> |
|
|
|
|
>; |
|
|
|
|
testAllInputs: (...excludeTestIds: string[]) => boolean; |
|
|
|
|
toggleSubmitDisabled?: ToggleSubmitDisabledFunction; |
|
|
|
|
}> = ({ |
|
|
|
|
createDropMouseUpHandler, |
|
|
|
|
getNetworkTypeCount, |
|
|
|
@ -276,6 +285,8 @@ const NetworkForm: FC<{ |
|
|
|
|
optionalNetworkInputsLength, |
|
|
|
|
setNetworkInputs, |
|
|
|
|
setNetworkInterfaceInputMap, |
|
|
|
|
testAllInputs, |
|
|
|
|
toggleSubmitDisabled, |
|
|
|
|
}) => { |
|
|
|
|
const theme = useTheme(); |
|
|
|
|
const breakpointMedium = useMediaQuery(theme.breakpoints.up('md')); |
|
|
|
@ -286,9 +297,23 @@ const NetworkForm: FC<{ |
|
|
|
|
|
|
|
|
|
const { inputUUID, interfaces, ipAddress, subnetMask, type } = networkInput; |
|
|
|
|
|
|
|
|
|
const inputTestPrefix = `network${networkIndex}`; |
|
|
|
|
const inputTestPrefix = useMemo( |
|
|
|
|
() => `network${networkIndex}`, |
|
|
|
|
[networkIndex], |
|
|
|
|
); |
|
|
|
|
const ipAddressInputTestId = useMemo( |
|
|
|
|
() => INPUT_TEST_IDS.networkIPAddress(inputTestPrefix), |
|
|
|
|
[inputTestPrefix], |
|
|
|
|
); |
|
|
|
|
const subnetMaskInputTestId = useMemo( |
|
|
|
|
() => INPUT_TEST_IDS.networkSubnet(inputTestPrefix), |
|
|
|
|
[inputTestPrefix], |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
const isNetworkOptional = networkIndex < optionalNetworkInputsLength; |
|
|
|
|
const isNetworkOptional = useMemo( |
|
|
|
|
() => networkIndex < optionalNetworkInputsLength, |
|
|
|
|
[networkIndex, optionalNetworkInputsLength], |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
networkInput.ipAddressInputRef = ipAddressInputRef; |
|
|
|
|
networkInput.subnetMaskInputRef = subnetMaskInputRef; |
|
|
|
@ -417,10 +442,19 @@ const NetworkForm: FC<{ |
|
|
|
|
inputLabelProps={{ isNotifyRequired: true }} |
|
|
|
|
label="IP address" |
|
|
|
|
onChange={({ target: { value } }) => { |
|
|
|
|
testInput({ |
|
|
|
|
inputs: { [`${inputTestPrefix}IPAddress`]: { value } }, |
|
|
|
|
const isLocalValid = testInput({ |
|
|
|
|
inputs: { |
|
|
|
|
[ipAddressInputTestId]: { |
|
|
|
|
value, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
tests: inputTests, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
toggleSubmitDisabled?.call( |
|
|
|
|
null, |
|
|
|
|
isLocalValid && testAllInputs(ipAddressInputTestId), |
|
|
|
|
); |
|
|
|
|
}} |
|
|
|
|
value={ipAddress} |
|
|
|
|
/> |
|
|
|
@ -434,10 +468,17 @@ const NetworkForm: FC<{ |
|
|
|
|
inputLabelProps={{ isNotifyRequired: true }} |
|
|
|
|
label="Subnet mask" |
|
|
|
|
onChange={({ target: { value } }) => { |
|
|
|
|
testInput({ |
|
|
|
|
inputs: { [`${inputTestPrefix}SubnetMask`]: { value } }, |
|
|
|
|
const isLocalValid = testInput({ |
|
|
|
|
inputs: { |
|
|
|
|
[subnetMaskInputTestId]: { value }, |
|
|
|
|
}, |
|
|
|
|
tests: inputTests, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
toggleSubmitDisabled?.call( |
|
|
|
|
null, |
|
|
|
|
isLocalValid && testAllInputs(subnetMaskInputTestId), |
|
|
|
|
); |
|
|
|
|
}} |
|
|
|
|
value={subnetMask} |
|
|
|
|
/> |
|
|
|
@ -449,10 +490,15 @@ const NetworkForm: FC<{ |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
NetworkForm.defaultProps = { createDropMouseUpHandler: undefined }; |
|
|
|
|
NetworkForm.defaultProps = { |
|
|
|
|
createDropMouseUpHandler: undefined, |
|
|
|
|
toggleSubmitDisabled: undefined, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
(networkInitFormProps, ref) => { |
|
|
|
|
const NetworkInitForm = forwardRef< |
|
|
|
|
NetworkInitFormForwardRefContent, |
|
|
|
|
{ toggleSubmitDisabled?: (testResult: boolean) => void } |
|
|
|
|
>(({ toggleSubmitDisabled }, ref) => { |
|
|
|
|
const [dragMousePosition, setDragMousePosition] = useState<{ |
|
|
|
|
x: number; |
|
|
|
|
y: number; |
|
|
|
@ -541,8 +587,9 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
|
|
|
|
|
const inputTests: InputTestBatches = useMemo(() => { |
|
|
|
|
const tests: InputTestBatches = { |
|
|
|
|
domainNameServerCSV: { |
|
|
|
|
[INPUT_TEST_IDS.dnsCSV]: { |
|
|
|
|
defaults: { |
|
|
|
|
getValue: () => dnsCSVInputRef.current.getValue?.call(null), |
|
|
|
|
onSuccess: () => { |
|
|
|
|
setDomainNameServerCSVInputMessage(undefined); |
|
|
|
|
}, |
|
|
|
@ -552,7 +599,7 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
onFailure: () => { |
|
|
|
|
setDomainNameServerCSVInputMessage({ |
|
|
|
|
children: |
|
|
|
|
'Domain name servers should be a comma-separated list of IPv4 addresses.', |
|
|
|
|
'Domain name servers should be a comma-separated list of IPv4 addresses without trailing comma(s).', |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
test: ({ value }) => REP_IPV4_CSV.test(value as string), |
|
|
|
@ -560,8 +607,9 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
{ test: testNotBlank }, |
|
|
|
|
], |
|
|
|
|
}, |
|
|
|
|
gateway: { |
|
|
|
|
[INPUT_TEST_IDS.gateway]: { |
|
|
|
|
defaults: { |
|
|
|
|
getValue: () => gatewayInputRef.current.getValue?.call(null), |
|
|
|
|
onSuccess: () => { |
|
|
|
|
setGatewayInputMessage(undefined); |
|
|
|
|
}, |
|
|
|
@ -580,17 +628,19 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
}, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
networkInputs.forEach(({ name }, networkIndex) => { |
|
|
|
|
networkInputs.forEach(({ ipAddress, name, subnetMask }, networkIndex) => { |
|
|
|
|
const inputTestPrefix = `network${networkIndex}`; |
|
|
|
|
|
|
|
|
|
tests[`${inputTestPrefix}Name`] = { |
|
|
|
|
tests[INPUT_TEST_IDS.networkName(inputTestPrefix)] = { |
|
|
|
|
defaults: { value: name }, |
|
|
|
|
tests: [{ test: testNotBlank }], |
|
|
|
|
}; |
|
|
|
|
tests[`${inputTestPrefix}IPAddress`] = { |
|
|
|
|
tests[INPUT_TEST_IDS.networkIPAddress(inputTestPrefix)] = { |
|
|
|
|
defaults: { |
|
|
|
|
onSuccess: () => { |
|
|
|
|
setNetworkIPAddressInputMessage(networkIndex, undefined); |
|
|
|
|
}, |
|
|
|
|
value: ipAddress, |
|
|
|
|
}, |
|
|
|
|
tests: [ |
|
|
|
|
{ |
|
|
|
@ -604,11 +654,12 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
{ test: testNotBlank }, |
|
|
|
|
], |
|
|
|
|
}; |
|
|
|
|
tests[`${inputTestPrefix}SubnetMask`] = { |
|
|
|
|
tests[INPUT_TEST_IDS.networkSubnet(inputTestPrefix)] = { |
|
|
|
|
defaults: { |
|
|
|
|
onSuccess: () => { |
|
|
|
|
setNetworkSubnetMaskInputMessage(networkIndex, undefined); |
|
|
|
|
}, |
|
|
|
|
value: subnetMask, |
|
|
|
|
}, |
|
|
|
|
tests: [ |
|
|
|
|
{ |
|
|
|
@ -633,6 +684,15 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
setNetworkSubnetMaskInputMessage, |
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
const testAllInputs = useCallback( |
|
|
|
|
(...excludeTestIds: string[]) => |
|
|
|
|
testInput({ |
|
|
|
|
excludeTestIds, |
|
|
|
|
isIgnoreOnCallbacks: true, |
|
|
|
|
tests: inputTests, |
|
|
|
|
}), |
|
|
|
|
[inputTests], |
|
|
|
|
); |
|
|
|
|
const clearNetworkInterfaceHeld = useCallback(() => { |
|
|
|
|
setNetworkInterfaceHeld(undefined); |
|
|
|
|
}, []); |
|
|
|
@ -791,8 +851,7 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
type, |
|
|
|
|
networkIndex, |
|
|
|
|
)}`,
|
|
|
|
|
subnetMask: |
|
|
|
|
subnetMaskInputRef?.current.getValue?.call(null) ?? '', |
|
|
|
|
subnetMask: subnetMaskInputRef?.current.getValue?.call(null) ?? '', |
|
|
|
|
type, |
|
|
|
|
}), |
|
|
|
|
), |
|
|
|
@ -907,6 +966,8 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
optionalNetworkInputsLength, |
|
|
|
|
setNetworkInputs, |
|
|
|
|
setNetworkInterfaceInputMap, |
|
|
|
|
testAllInputs, |
|
|
|
|
toggleSubmitDisabled, |
|
|
|
|
}} |
|
|
|
|
/> |
|
|
|
|
); |
|
|
|
@ -923,10 +984,15 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
id="network-init-gateway" |
|
|
|
|
inputLabelProps={{ isNotifyRequired: true }} |
|
|
|
|
onChange={({ target: { value } }) => { |
|
|
|
|
testInput({ |
|
|
|
|
inputs: { gateway: { value } }, |
|
|
|
|
const isLocalValid = testInput({ |
|
|
|
|
inputs: { [INPUT_TEST_IDS.gateway]: { value } }, |
|
|
|
|
tests: inputTests, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
toggleSubmitDisabled?.call( |
|
|
|
|
null, |
|
|
|
|
isLocalValid && testAllInputs(INPUT_TEST_IDS.gateway), |
|
|
|
|
); |
|
|
|
|
}} |
|
|
|
|
label="Gateway" |
|
|
|
|
/> |
|
|
|
@ -939,10 +1005,15 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
id="network-init-dns-csv" |
|
|
|
|
inputLabelProps={{ isNotifyRequired: true }} |
|
|
|
|
onChange={({ target: { value } }) => { |
|
|
|
|
testInput({ |
|
|
|
|
inputs: { domainNameServerCSV: { value } }, |
|
|
|
|
const isLocalValid = testInput({ |
|
|
|
|
inputs: { [INPUT_TEST_IDS.dnsCSV]: { value } }, |
|
|
|
|
tests: inputTests, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
toggleSubmitDisabled?.call( |
|
|
|
|
null, |
|
|
|
|
isLocalValid && testAllInputs(INPUT_TEST_IDS.dnsCSV), |
|
|
|
|
); |
|
|
|
|
}} |
|
|
|
|
label="Domain name server(s)" |
|
|
|
|
/> |
|
|
|
@ -960,9 +1031,9 @@ const NetworkInitForm = forwardRef<NetworkInitFormForwardRefContent>( |
|
|
|
|
</MUIBox> |
|
|
|
|
</MUIBox> |
|
|
|
|
); |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
NetworkInitForm.defaultProps = { toggleSubmitDisabled: undefined }; |
|
|
|
|
NetworkInitForm.displayName = 'NetworkInitForm'; |
|
|
|
|
|
|
|
|
|
export type { |
|
|
|
|