fix(striker-ui): enable add/remove networks

main
Tsu-ba-me 2 years ago
parent 45a0d1a6c8
commit b269770d3a
  1. 152
      striker-ui/components/ManageManifest/AnvilNetworkConfigInputGroup.tsx
  2. 47
      striker-ui/components/ManageManifest/AnvilNetworkInputGroup.tsx
  3. 35
      striker-ui/types/ManageManifest.d.ts

@ -1,9 +1,10 @@
import { ReactElement, useMemo } from 'react';
import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES';
import { ReactElement, useCallback, useMemo, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
import AnvilNetworkInputGroup from './AnvilNetworkInputGroup';
import buildObjectStateSetterCallback from '../../lib/buildObjectStateSetterCallback';
import Grid from '../Grid';
import IconButton from '../IconButton';
import InputWithRef from '../InputWithRef';
import OutlinedInputWithLabel from '../OutlinedInputWithLabel';
import { buildNumberTestBatch } from '../../lib/test_input';
@ -20,7 +21,7 @@ const INPUT_LABEL_ANVIL_NETWORK_CONFIG_DNS = 'DNS';
const INPUT_LABEL_ANVIL_NETWORK_CONFIG_MTU = 'MTU';
const INPUT_LABEL_ANVIL_NETWORK_CONFIG_NTP = 'NTP';
const DEFAULT_NETWORKS: { [networkId: string]: AnvilNetworkConfigNetwork } = {
const DEFAULT_NETWORKS: AnvilNetworkConfigNetworkList = {
bcn1: {
networkMinIp: '',
networkNumber: 1,
@ -41,6 +42,8 @@ const DEFAULT_NETWORKS: { [networkId: string]: AnvilNetworkConfigNetwork } = {
},
};
const isIfn = (type: string) => type === 'ifn';
const AnvilNetworkConfigInputGroup = <
M extends MapToInputTestID & {
[K in
@ -53,7 +56,7 @@ const AnvilNetworkConfigInputGroup = <
previous: {
dnsCsv: previousDnsCsv,
mtu: previousMtu,
networks = DEFAULT_NETWORKS,
networks: previousNetworks = DEFAULT_NETWORKS,
ntpCsv: previousNtpCsv,
} = {},
}: AnvilNetworkConfigInputGroupProps<M>): ReactElement => {
@ -63,19 +66,119 @@ const AnvilNetworkConfigInputGroup = <
msgSetters,
} = formUtils;
const [networkList, setNetworkList] =
useState<AnvilNetworkConfigNetworkList>(previousNetworks);
const networkListArray = useMemo(
() => Object.entries(networkList),
[networkList],
);
const getNetworkNumber = useCallback(
(
type: string,
{
input = networkListArray,
end = networkListArray.length,
}: {
input?: Array<[string, AnvilNetworkConfigNetwork]>;
end?: number;
} = {},
) => {
let netNum = 0;
input.every(([, { networkType }], networkIndex) => {
if (networkType === type) {
netNum += 1;
}
return networkIndex < end;
});
return netNum;
},
[networkListArray],
);
const buildNetwork = useCallback(
({
networkMinIp = '',
networkSubnetMask = '',
networkType = 'ifn',
// Params that depend on others.
networkGateway = isIfn(networkType) ? '' : undefined,
networkNumber = getNetworkNumber(networkType) + 1,
}: Partial<AnvilNetworkConfigNetwork> = {}): {
network: AnvilNetworkConfigNetwork;
networkId: string;
} => ({
network: {
networkGateway,
networkMinIp,
networkNumber,
networkSubnetMask,
networkType,
},
networkId: uuidv4(),
}),
[getNetworkNumber],
);
const setNetwork = useCallback(
(key: string, value?: AnvilNetworkConfigNetwork) =>
setNetworkList(buildObjectStateSetterCallback(key, value)),
[],
);
const removeNetwork = useCallback<AnvilNetworkCloseHandler>(
({ networkId: rmId, networkType: rmType }) => {
let isIdMatch = false;
let networkNumber = 0;
const newList = networkListArray.reduce<AnvilNetworkConfigNetworkList>(
(previous, [networkId, networkValue]) => {
const { networkType } = networkValue;
if (networkId === rmId) {
isIdMatch = true;
} else {
if (networkType === rmType) {
networkNumber += 1;
}
if (isIdMatch) {
previous[networkId] = {
...networkValue,
networkNumber,
};
} else {
previous[networkId] = networkValue;
}
}
return previous;
},
{},
);
setNetworkList(newList);
},
[networkListArray],
);
const networksGridLayout = useMemo<GridLayout>(() => {
let result: GridLayout = {};
result = Object.entries(networks).reduce<GridLayout>(
result = networkListArray.reduce<GridLayout>(
(
previous,
[
networkId,
{
networkGateway: previousGateway,
networkMinIp: previousMinIp,
networkGateway,
networkMinIp,
networkNumber,
networkSubnetMask: previousSubnetMask,
networkSubnetMask,
networkType,
},
],
@ -89,9 +192,8 @@ const AnvilNetworkConfigInputGroup = <
const inputMinIpId = `${inputIdPrefix}-min-ip`;
const inputSubnetMaskId = `${inputIdPrefix}-subnet-mask`;
const networkName = `${NETWORK_TYPES[networkType]} ${networkNumber}`;
const isShowGateway = networkType === 'ifn';
const isFirstNetwork = networkNumber === 1;
const isShowGateway = isIfn(networkType);
previous[cellId] = {
children: (
@ -101,12 +203,16 @@ const AnvilNetworkConfigInputGroup = <
inputGatewayId={inputGatewayId}
inputMinIpId={inputMinIpId}
inputSubnetMaskId={inputSubnetMaskId}
networkName={networkName}
networkId={networkId}
networkNumber={networkNumber}
networkType={networkType}
onClose={removeNetwork}
previous={{
gateway: previousGateway,
minIp: previousMinIp,
subnetMask: previousSubnetMask,
gateway: networkGateway,
minIp: networkMinIp,
subnetMask: networkSubnetMask,
}}
showCloseButton={!isFirstNetwork}
showGateway={isShowGateway}
/>
),
@ -120,13 +226,25 @@ const AnvilNetworkConfigInputGroup = <
);
return result;
}, [formUtils, networks]);
}, [formUtils, networkListArray, removeNetwork]);
return (
<Grid
columns={{ xs: 1, sm: 2, md: 3 }}
layout={{
...networksGridLayout,
'anvil-network-config-cell-add-network': {
children: (
<IconButton
mapPreset="add"
onClick={() => {
const { network: newNet, networkId: newNetId } = buildNetwork();
setNetwork(newNetId, newNet);
}}
/>
),
},
'anvil-network-config-input-cell-dns': {
children: (
<InputWithRef

@ -1,5 +1,7 @@
import { ReactElement, ReactNode, useEffect, useMemo } from 'react';
import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES';
import Grid from '../Grid';
import IconButton from '../IconButton';
import InputWithRef from '../InputWithRef';
@ -22,14 +24,23 @@ const AnvilNetworkInputGroup = <M extends MapToInputTestID>({
inputMinIpLabel = 'IP address',
inputSubnetMaskId,
inputSubnetMaskLabel = 'Subnet mask',
networkName,
networkId,
networkNumber,
networkType,
onClose,
previous: {
gateway: previousGateway,
minIp: previousIpAddress,
subnetMask: previousSubnetMask,
} = {},
showCloseButton: isShowCloseButton,
showGateway: isShowGateway,
}: AnvilNetworkInputGroupProps<M>): ReactElement => {
const networkName = useMemo(
() => `${NETWORK_TYPES[networkType]} ${networkNumber}`,
[networkNumber, networkType],
);
const inputCellGatewayId = useMemo(
() => `${idPrefix}-input-cell-gateway`,
[idPrefix],
@ -45,6 +56,26 @@ const AnvilNetworkInputGroup = <M extends MapToInputTestID>({
[isShowGateway],
);
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;
@ -74,6 +105,7 @@ const AnvilNetworkInputGroup = <M extends MapToInputTestID>({
});
},
)}
onFirstRender={buildInputFirstRenderFunction(inputGatewayId)}
required={isShowGateway}
/>
);
@ -88,6 +120,7 @@ const AnvilNetworkInputGroup = <M extends MapToInputTestID>({
previousGateway,
networkName,
buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction,
msgSetters,
]);
@ -100,18 +133,8 @@ const AnvilNetworkInputGroup = <M extends MapToInputTestID>({
<InnerPanel mv={0}>
<InnerPanelHeader>
<BodyText>{networkName}</BodyText>
<IconButton
mapPreset="close"
iconProps={{ fontSize: 'small' }}
sx={{
padding: '.2em',
position: 'absolute',
right: '-.6rem',
top: '-.2rem',
}}
/>
{closeButtonElement}
</InnerPanelHeader>
<InnerPanelBody>
<Grid
layout={{

@ -11,16 +11,35 @@ type AnvilIdInputGroupProps<M extends MapToInputTestID> =
formUtils: FormUtils<M>;
};
type AnvilNetworkConfigNetwork = {
networkGateway?: string;
networkMinIp: string;
networkNumber: number;
networkSubnetMask: string;
networkType: string;
};
type AnvilNetworkConfigNetworkList = {
[networkId: string]: AnvilNetworkConfigNetwork;
};
type AnvilNetworkCloseHandler = (
args: { networkId: string } & Pick<AnvilNetworkConfigNetwork, 'networkType'>,
...handlerArgs: Parameters<IconButtonMouseEventHandler>
) => ReturnType<IconButtonMouseEventHandler>;
type AnvilNetworkInputGroupOptionalProps = {
inputGatewayId?: string;
inputGatewayLabel?: string;
inputMinIpLabel?: string;
inputSubnetMaskLabel?: string;
onClose?: AnvilNetworkCloseHandler;
previous?: {
gateway?: string;
minIp?: string;
subnetMask?: string;
};
showCloseButton?: boolean;
showGateway?: boolean;
};
@ -30,7 +49,9 @@ type AnvilNetworkInputGroupProps<M extends MapToInputTestID> =
idPrefix: string;
inputMinIpId: string;
inputSubnetMaskId: string;
networkName: string;
networkId: string;
networkNumber: number;
networkType: string;
};
type AnvilHostInputGroupOptionalProps = {
@ -64,22 +85,12 @@ type AnvilHostInputGroupProps<M extends MapToInputTestID> =
idPrefix: string;
};
type AnvilNetworkConfigNetwork = {
networkGateway?: string;
networkMinIp: string;
networkNumber: number;
networkSubnetMask: string;
networkType: string;
};
type AnvilNetworkConfigInputGroupOptionalProps = {
previous?: {
dnsCsv?: string;
/** Max Transmission Unit (MTU); unit: bytes */
mtu?: number;
networks?: {
[networkId: string]: AnvilNetworkConfigNetwork;
};
networks?: AnvilNetworkConfigNetworkList;
ntpCsv?: string;
};
};

Loading…
Cancel
Save