fix(striker-ui): suggest default BCN, SN, IFN IPs for each subnode in create manifest

main
Tsu-ba-me 1 year ago
parent 2b90bf3a9f
commit 8b6b1a64a8
  1. 17
      striker-ui/components/ManageManifest/AddManifestInputGroup.tsx
  2. 53
      striker-ui/components/ManageManifest/AnHostConfigInputGroup.tsx
  3. 203
      striker-ui/components/ManageManifest/AnIdInputGroup.tsx
  4. 31
      striker-ui/components/ManageManifest/AnNetworkConfigInputGroup.tsx
  5. 49
      striker-ui/components/ManageManifest/AnNetworkInputGroup.tsx
  6. 7
      striker-ui/components/ManageManifest/ManageManifestPanel.tsx
  7. 30
      striker-ui/types/ManageManifest.d.ts

@ -57,6 +57,10 @@ const AddManifestInputGroup = <
const { networks: previousNetworkList = DEFAULT_NETWORK_LIST } = const { networks: previousNetworkList = DEFAULT_NETWORK_LIST } =
previousNetworkConfig; previousNetworkConfig;
const [anSequence, setAnSequence] = useState<number>(
previousAnId?.sequence ?? 0,
);
const [networkList, setNetworkList] = const [networkList, setNetworkList] =
useState<ManifestNetworkList>(previousNetworkList); useState<ManifestNetworkList>(previousNetworkList);
@ -67,7 +71,17 @@ const AddManifestInputGroup = <
return ( return (
<FlexBox> <FlexBox>
<AnIdInputGroup formUtils={formUtils} previous={previousAnId} /> <AnIdInputGroup
formUtils={formUtils}
onSequenceChange={(event) => {
const {
target: { value },
} = event;
setAnSequence(Number(value));
}}
previous={previousAnId}
/>
<AnNetworkConfigInputGroup <AnNetworkConfigInputGroup
formUtils={formUtils} formUtils={formUtils}
networkListEntries={networkListEntries} networkListEntries={networkListEntries}
@ -75,6 +89,7 @@ const AddManifestInputGroup = <
setNetworkList={setNetworkList} setNetworkList={setNetworkList}
/> />
<AnHostConfigInputGroup <AnHostConfigInputGroup
anSequence={anSequence}
formUtils={formUtils} formUtils={formUtils}
knownFences={knownFences} knownFences={knownFences}
knownUpses={knownUpses} knownUpses={knownUpses}

@ -1,3 +1,4 @@
import { Netmask } from 'netmask';
import { ReactElement, useMemo } from 'react'; import { ReactElement, useMemo } from 'react';
import AnHostInputGroup from './AnHostInputGroup'; import AnHostInputGroup from './AnHostInputGroup';
@ -19,7 +20,39 @@ const DEFAULT_HOST_LIST: ManifestHostList = {
}, },
}; };
const guessHostIpOnNetwork = ({
anSeq,
minIp,
offset3 = 10,
step3 = 2,
subnetMask,
subSeq,
}: {
anSeq: number;
minIp: string;
offset3?: number;
step3?: number;
subnetMask: string;
subSeq: number;
}): string => {
try {
const block = new Netmask(`${minIp}/${subnetMask}`);
if (block.bitmask !== 16) {
return `${block.base.replace(/\.0/g, '')}.`;
}
const third = (anSeq - 1) * step3 + offset3;
const fourth = subSeq;
return minIp.replace(/^((\d+\.){2})\d+\.\d+$/, `$1${third}.${fourth}`);
} catch (error) {
return '';
}
};
const AnHostConfigInputGroup = <M extends MapToInputTestID>({ const AnHostConfigInputGroup = <M extends MapToInputTestID>({
anSequence,
formUtils, formUtils,
knownFences = {}, knownFences = {},
knownUpses = {}, knownUpses = {},
@ -64,10 +97,25 @@ const AnHostConfigInputGroup = <M extends MapToInputTestID>({
{}, {},
); );
const networks = networkListEntries.reduce<ManifestHostNetworkList>( const networks = networkListEntries.reduce<ManifestHostNetworkList>(
(networkList, [networkId, { networkNumber, networkType }]) => { (
const { [networkId]: { networkIp = '' } = {} } = networkList,
[
networkId,
{ networkMinIp, networkNumber, networkSubnetMask, networkType },
],
) => {
let { [networkId]: { networkIp = '' } = {} } =
previousNetworkList; previousNetworkList;
if (!networkIp) {
networkIp = guessHostIpOnNetwork({
anSeq: anSequence,
minIp: networkMinIp,
subnetMask: networkSubnetMask,
subSeq: hostNumber,
});
}
networkList[networkId] = { networkList[networkId] = {
networkIp, networkIp,
networkNumber, networkNumber,
@ -110,6 +158,7 @@ const AnHostConfigInputGroup = <M extends MapToInputTestID>({
{}, {},
), ),
[ [
anSequence,
formUtils, formUtils,
hostListEntries, hostListEntries,
knownFenceListValues, knownFenceListValues,

@ -1,4 +1,5 @@
import { ReactElement } from 'react'; import { debounce } from 'lodash';
import { ReactElement, useMemo } from 'react';
import Grid from '../Grid'; import Grid from '../Grid';
import InputWithRef from '../InputWithRef'; import InputWithRef from '../InputWithRef';
@ -26,109 +27,123 @@ const AnIdInputGroup = <
| typeof INPUT_ID_AI_SEQUENCE]: string; | typeof INPUT_ID_AI_SEQUENCE]: string;
}, },
>({ >({
debounceWait = 500,
formUtils: { formUtils: {
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
setMessage, setMessage,
}, },
onSequenceChange,
previous: { previous: {
domain: previousDomain, domain: previousDomain,
prefix: previousPrefix, prefix: previousPrefix,
sequence: previousSequence, sequence: previousSequence,
} = {}, } = {},
}: AnIdInputGroupProps<M>): ReactElement => ( }: AnIdInputGroupProps<M>): ReactElement => {
<Grid const debounceSequenceChangeHandler = useMemo(
columns={{ xs: 1, sm: 2, md: 3 }} () => onSequenceChange && debounce(onSequenceChange, debounceWait),
layout={{ [debounceWait, onSequenceChange],
'an-id-input-cell-prefix': { );
children: (
<InputWithRef return (
input={ <Grid
<OutlinedInputWithLabel columns={{ xs: 1, sm: 2, md: 3 }}
id={INPUT_ID_AI_PREFIX} layout={{
label={INPUT_LABEL_AI_PREFIX} 'an-id-input-cell-prefix': {
value={previousPrefix} children: (
/> <InputWithRef
} input={
inputTestBatch={buildPeacefulStringTestBatch( <OutlinedInputWithLabel
INPUT_LABEL_AI_PREFIX, id={INPUT_ID_AI_PREFIX}
() => { label={INPUT_LABEL_AI_PREFIX}
setMessage(INPUT_ID_AI_PREFIX); value={previousPrefix}
}, />
{ }
onFinishBatch: inputTestBatch={buildPeacefulStringTestBatch(
buildFinishInputTestBatchFunction(INPUT_ID_AI_PREFIX), INPUT_LABEL_AI_PREFIX,
}, () => {
(message) => { setMessage(INPUT_ID_AI_PREFIX);
setMessage(INPUT_ID_AI_PREFIX, { children: message }); },
}, {
)} onFinishBatch:
onFirstRender={buildInputFirstRenderFunction(INPUT_ID_AI_PREFIX)} buildFinishInputTestBatchFunction(INPUT_ID_AI_PREFIX),
required },
/> (message) => {
), setMessage(INPUT_ID_AI_PREFIX, { children: message });
}, },
'an-id-input-cell-domain': { )}
children: ( onFirstRender={buildInputFirstRenderFunction(INPUT_ID_AI_PREFIX)}
<InputWithRef required
input={ />
<OutlinedInputWithLabel ),
id={INPUT_ID_AI_DOMAIN} },
label={INPUT_LABEL_AI_DOMAIN} 'an-id-input-cell-domain': {
value={previousDomain} children: (
/> <InputWithRef
} input={
inputTestBatch={buildPeacefulStringTestBatch( <OutlinedInputWithLabel
INPUT_LABEL_AI_DOMAIN, id={INPUT_ID_AI_DOMAIN}
() => { label={INPUT_LABEL_AI_DOMAIN}
setMessage(INPUT_ID_AI_DOMAIN); value={previousDomain}
}, />
{ }
onFinishBatch: inputTestBatch={buildPeacefulStringTestBatch(
buildFinishInputTestBatchFunction(INPUT_ID_AI_DOMAIN), INPUT_LABEL_AI_DOMAIN,
}, () => {
(message) => { setMessage(INPUT_ID_AI_DOMAIN);
setMessage(INPUT_ID_AI_DOMAIN, { children: message }); },
}, {
)} onFinishBatch:
onFirstRender={buildInputFirstRenderFunction(INPUT_ID_AI_DOMAIN)} buildFinishInputTestBatchFunction(INPUT_ID_AI_DOMAIN),
required },
/> (message) => {
), setMessage(INPUT_ID_AI_DOMAIN, { children: message });
}, },
'an-id-input-cell-sequence': { )}
children: ( onFirstRender={buildInputFirstRenderFunction(INPUT_ID_AI_DOMAIN)}
<InputWithRef required
input={ />
<OutlinedInputWithLabel ),
id={INPUT_ID_AI_SEQUENCE} },
label={INPUT_LABEL_AI_SEQUENCE} 'an-id-input-cell-sequence': {
value={previousSequence} children: (
/> <InputWithRef
} createInputOnChangeHandlerOptions={{
inputTestBatch={buildNumberTestBatch( postSet: debounceSequenceChangeHandler,
INPUT_LABEL_AI_SEQUENCE, }}
() => { input={
setMessage(INPUT_ID_AI_SEQUENCE); <OutlinedInputWithLabel
}, id={INPUT_ID_AI_SEQUENCE}
{ label={INPUT_LABEL_AI_SEQUENCE}
onFinishBatch: value={previousSequence}
buildFinishInputTestBatchFunction(INPUT_ID_AI_SEQUENCE), />
}, }
(message) => { inputTestBatch={buildNumberTestBatch(
setMessage(INPUT_ID_AI_SEQUENCE, { children: message }); INPUT_LABEL_AI_SEQUENCE,
}, () => {
)} setMessage(INPUT_ID_AI_SEQUENCE);
onFirstRender={buildInputFirstRenderFunction(INPUT_ID_AI_SEQUENCE)} },
required {
valueType="number" onFinishBatch:
/> buildFinishInputTestBatchFunction(INPUT_ID_AI_SEQUENCE),
), },
}, (message) => {
}} setMessage(INPUT_ID_AI_SEQUENCE, { children: message });
spacing="1em" },
/> )}
); onFirstRender={buildInputFirstRenderFunction(
INPUT_ID_AI_SEQUENCE,
)}
required
valueType="number"
/>
),
},
}}
spacing="1em"
/>
);
};
export { INPUT_ID_AI_DOMAIN, INPUT_ID_AI_PREFIX, INPUT_ID_AI_SEQUENCE }; export { INPUT_ID_AI_DOMAIN, INPUT_ID_AI_PREFIX, INPUT_ID_AI_SEQUENCE };

@ -124,6 +124,26 @@ const AnNetworkConfigInputGroup = <
[setNetworkList], [setNetworkList],
); );
const setNetworkProp = useCallback(
<P extends keyof ManifestNetwork>(
nkey: string,
pkey: P,
value: ManifestNetwork[P],
) =>
setNetworkList((previous) => {
const nyu = { ...previous };
const { [nkey]: nw } = nyu;
if (nw) {
nw[pkey] = value;
}
return nyu;
}),
[setNetworkList],
);
const handleNetworkTypeChange = useCallback<AnNetworkTypeChangeEventHandler>( const handleNetworkTypeChange = useCallback<AnNetworkTypeChangeEventHandler>(
( (
{ networkId: targetId, networkType: previousType }, { networkId: targetId, networkType: previousType },
@ -243,6 +263,14 @@ const AnNetworkConfigInputGroup = <
networkType={networkType} networkType={networkType}
networkTypeOptions={networkTypeOptions} networkTypeOptions={networkTypeOptions}
onClose={handleNetworkRemove} onClose={handleNetworkRemove}
onNetworkMinIpChange={(
{ networkId: nid },
{ target: { value } },
) => setNetworkProp(nid, 'networkMinIp', value)}
onNetworkSubnetMaskChange={(
{ networkId: nid },
{ target: { value } },
) => setNetworkProp(nid, 'networkSubnetMask', value)}
onNetworkTypeChange={handleNetworkTypeChange} onNetworkTypeChange={handleNetworkTypeChange}
previous={{ previous={{
gateway: networkGateway, gateway: networkGateway,
@ -265,11 +293,12 @@ const AnNetworkConfigInputGroup = <
return result; return result;
}, [ }, [
formUtils,
networkListEntries, networkListEntries,
formUtils,
networkTypeOptions, networkTypeOptions,
handleNetworkRemove, handleNetworkRemove,
handleNetworkTypeChange, handleNetworkTypeChange,
setNetworkProp,
]); ]);
return ( return (

@ -1,3 +1,4 @@
import { debounce } from 'lodash';
import { ReactElement, ReactNode, useMemo } from 'react'; import { ReactElement, ReactNode, useMemo } from 'react';
import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES'; import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES';
@ -77,6 +78,7 @@ const buildInputIdANSubnetMask = (networkId: string): string =>
`${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}-subnet-mask`; `${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}-subnet-mask`;
const AnNetworkInputGroup = <M extends MapToInputTestID>({ const AnNetworkInputGroup = <M extends MapToInputTestID>({
debounceWait = 500,
formUtils: { formUtils: {
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
@ -91,6 +93,9 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
networkType, networkType,
networkTypeOptions, networkTypeOptions,
onClose, onClose,
onNetworkGatewayChange,
onNetworkMinIpChange,
onNetworkSubnetMaskChange,
onNetworkTypeChange, onNetworkTypeChange,
previous: { previous: {
gateway: previousGateway, gateway: previousGateway,
@ -146,6 +151,24 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
[isShowGateway], [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>( const closeButtonElement = useMemo<ReactNode>(
() => () =>
isShowCloseButton && ( isShowCloseButton && (
@ -172,6 +195,14 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
if (isShowGateway && inputIdGateway) { if (isShowGateway && inputIdGateway) {
result = ( result = (
<InputWithRef <InputWithRef
createInputOnChangeHandlerOptions={{
postSet: (...args) =>
debounceNetworkGatewayChangeHandler?.call(
null,
{ networkId, networkType },
...args,
),
}}
input={ input={
<OutlinedInputWithLabel <OutlinedInputWithLabel
baseInputProps={{ baseInputProps={{
@ -213,6 +244,8 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
buildFinishInputTestBatchFunction, buildFinishInputTestBatchFunction,
buildInputFirstRenderFunction, buildInputFirstRenderFunction,
buildInputUnmountFunction, buildInputUnmountFunction,
debounceNetworkGatewayChangeHandler,
networkType,
setMessage, setMessage,
]); ]);
@ -256,6 +289,14 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
[inputCellIdIp]: { [inputCellIdIp]: {
children: ( children: (
<InputWithRef <InputWithRef
createInputOnChangeHandlerOptions={{
postSet: (...args) =>
debounceNetworkMinIpChangeHandler?.call(
null,
{ networkId, networkType },
...args,
),
}}
input={ input={
<OutlinedInputWithLabel <OutlinedInputWithLabel
baseInputProps={{ baseInputProps={{
@ -289,6 +330,14 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
[inputCellIdSubnetMask]: { [inputCellIdSubnetMask]: {
children: ( children: (
<InputWithRef <InputWithRef
createInputOnChangeHandlerOptions={{
postSet: (...args) =>
debounceNetworkSubnetMaskChangeHandler?.call(
null,
{ networkId, networkType },
...args,
),
}}
input={ input={
<OutlinedInputWithLabel <OutlinedInputWithLabel
baseInputProps={{ baseInputProps={{

@ -47,6 +47,8 @@ import useFormUtils from '../../hooks/useFormUtils';
import useIsFirstRender from '../../hooks/useIsFirstRender'; import useIsFirstRender from '../../hooks/useIsFirstRender';
import useProtectedState from '../../hooks/useProtectedState'; import useProtectedState from '../../hooks/useProtectedState';
const REQ_BODY_MAX_DEPTH = 6;
const getFormData = ( const getFormData = (
...[{ target }]: DivFormEventHandlerParameters ...[{ target }]: DivFormEventHandlerParameters
): APIBuildManifestRequestBody => { ): APIBuildManifestRequestBody => {
@ -262,7 +264,7 @@ const ManageManifestPanel: FC = () => {
setConfirmDialogProps({ setConfirmDialogProps({
actionProceedText: 'Add', actionProceedText: 'Add',
content: <FormSummary entries={body} />, content: <FormSummary entries={body} maxDepth={REQ_BODY_MAX_DEPTH} />,
onProceedAppend: () => { onProceedAppend: () => {
submitForm({ submitForm({
body, body,
@ -311,7 +313,7 @@ const ManageManifestPanel: FC = () => {
setConfirmDialogProps({ setConfirmDialogProps({
actionProceedText: 'Edit', actionProceedText: 'Edit',
content: <FormSummary entries={body} />, content: <FormSummary entries={body} maxDepth={REQ_BODY_MAX_DEPTH} />,
onProceedAppend: () => { onProceedAppend: () => {
submitForm({ submitForm({
body, body,
@ -605,6 +607,7 @@ const ManageManifestPanel: FC = () => {
{...confirmDialogProps} {...confirmDialogProps}
ref={confirmDialogRef} ref={confirmDialogRef}
scrollContent scrollContent
wide
/> />
</> </>
); );

@ -74,6 +74,10 @@ type MapToManifestFormInputHandler = Record<string, ManifestFormInputHandler>;
/** ---------- Component types ---------- */ /** ---------- Component types ---------- */
type AnIdInputGroupOptionalProps = { type AnIdInputGroupOptionalProps = {
debounceWait?: number;
onSequenceChange?: import('react').ChangeEventHandler<
HTMLInputElement | HTMLTextAreaElement
>;
previous?: Partial<ManifestAnId>; previous?: Partial<ManifestAnId>;
}; };
@ -86,21 +90,32 @@ type AnNetworkEventHandlerPreviousArgs = {
networkId: string; networkId: string;
} & Pick<ManifestNetwork, 'networkType'>; } & Pick<ManifestNetwork, 'networkType'>;
type AnNetworkCloseEventHandler = ( type AnNetworkChangeEventHandler<Handler> = (
args: AnNetworkEventHandlerPreviousArgs, args: AnNetworkEventHandlerPreviousArgs,
...handlerArgs: Parameters<IconButtonMouseEventHandler> ...handlerArgs: Parameters<Handler>
) => ReturnType<IconButtonMouseEventHandler>; ) => ReturnType<Handler>;
type AnNetworkTypeChangeEventHandler = ( type AnNetworkCloseEventHandler =
args: AnNetworkEventHandlerPreviousArgs, AnNetworkChangeEventHandler<IconButtonMouseEventHandler>;
...handlerArgs: Parameters<SelectChangeEventHandler>
) => ReturnType<SelectChangeEventHandler>; type AnNetworkTypeChangeEventHandler =
AnNetworkChangeEventHandler<SelectChangeEventHandler>;
type AnNetworkInputGroupOptionalProps = { type AnNetworkInputGroupOptionalProps = {
debounceWait?: number;
inputGatewayLabel?: string; inputGatewayLabel?: string;
inputMinIpLabel?: string; inputMinIpLabel?: string;
inputSubnetMaskLabel?: string; inputSubnetMaskLabel?: string;
onClose?: AnNetworkCloseEventHandler; onClose?: AnNetworkCloseEventHandler;
onNetworkGatewayChange?: AnNetworkChangeEventHandler<
import('react').ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>
>;
onNetworkMinIpChange?: AnNetworkChangeEventHandler<
import('react').ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>
>;
onNetworkSubnetMaskChange?: AnNetworkChangeEventHandler<
import('react').ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>
>;
onNetworkTypeChange?: AnNetworkTypeChangeEventHandler; onNetworkTypeChange?: AnNetworkTypeChangeEventHandler;
previous?: { previous?: {
gateway?: string; gateway?: string;
@ -155,6 +170,7 @@ type AnHostConfigInputGroupOptionalProps = {
type AnHostConfigInputGroupProps<M extends MapToInputTestID> = type AnHostConfigInputGroupProps<M extends MapToInputTestID> =
AnHostConfigInputGroupOptionalProps & { AnHostConfigInputGroupOptionalProps & {
anSequence: number;
formUtils: FormUtils<M>; formUtils: FormUtils<M>;
networkListEntries: Array<[string, ManifestNetwork]>; networkListEntries: Array<[string, ManifestNetwork]>;
}; };

Loading…
Cancel
Save