fix(striker-ui): get data from inputs in manage manifest forms

main
Tsu-ba-me 2 years ago
parent d402258b8a
commit 239138a8b1
  1. 6
      striker-ui/components/ManageManifest/AnHostConfigInputGroup.tsx
  2. 171
      striker-ui/components/ManageManifest/AnHostInputGroup.tsx
  3. 79
      striker-ui/components/ManageManifest/AnNetworkInputGroup.tsx
  4. 144
      striker-ui/components/ManageManifest/ManageManifestPanel.tsx
  5. 14
      striker-ui/types/APIManifest.d.ts
  6. 5
      striker-ui/types/ConfirmDialog.d.ts
  7. 15
      striker-ui/types/ManageManifest.d.ts

@ -10,12 +10,10 @@ const INPUT_GROUP_CELL_ID_PREFIX_AHC = `${INPUT_GROUP_ID_PREFIX_AHC}-cell`;
const DEFAULT_HOST_LIST: ManifestHostList = {
node1: {
hostName: '',
hostNumber: 1,
hostType: 'node',
},
node2: {
hostName: '',
hostNumber: 2,
hostType: 'node',
},
@ -89,14 +87,14 @@ const AnHostConfigInputGroup = <M extends MapToInputTestID>({
);
const cellId = `${INPUT_GROUP_CELL_ID_PREFIX_AHC}-${hostId}`;
const hostLabel = `${hostType} ${hostNumber}`;
previous[cellId] = {
children: (
<AnHostInputGroup
formUtils={formUtils}
hostId={hostId}
hostLabel={hostLabel}
hostNumber={hostNumber}
hostType={hostType}
previous={{ fences, networks, upses }}
/>
),

@ -18,6 +18,82 @@ const INPUT_ID_PREFIX_AN_HOST = 'an-host-input';
const INPUT_CELL_ID_PREFIX_AH = `${INPUT_ID_PREFIX_AN_HOST}-cell`;
const MAP_TO_AH_INPUT_HANDLER: MapToManifestFormInputHandler = {
fence: (container, input) => {
const {
dataset: { hostId = '', fenceId = '', fenceName = '' },
value: fencePort,
} = input;
const {
hostConfig: {
hosts: { [hostId]: host },
},
} = container;
const { fences = {} } = host;
fences[fenceId] = {
fenceName,
fencePort,
};
host.fences = fences;
},
host: (container, input) => {
const {
dataset: { hostId = '', hostNumber: rawHostNumber = '', hostType = '' },
} = input;
const hostNumber = Number.parseInt(rawHostNumber, 10);
container.hostConfig.hosts[hostId] = {
hostNumber,
hostType,
};
},
network: (container, input) => {
const {
dataset: {
hostId = '',
networkId = '',
networkNumber: rawNetworkNumber = '',
networkType = '',
},
value: networkIp,
} = input;
const {
hostConfig: {
hosts: { [hostId]: host },
},
} = container;
const { networks = {} } = host;
const networkNumber = Number.parseInt(rawNetworkNumber, 10);
networks[networkId] = {
networkIp,
networkNumber,
networkType,
};
host.networks = networks;
},
ups: (container, input) => {
const {
checked: isUsed,
dataset: { hostId = '', upsId = '', upsName = '' },
} = input;
const {
hostConfig: {
hosts: { [hostId]: host },
},
} = container;
const { upses = {} } = host;
upses[upsId] = {
isUsed,
upsName,
};
host.upses = upses;
},
};
const GRID_COLUMNS = { xs: 1, sm: 2, md: 3 };
const GRID_SPACING = '1em';
const buildInputIdAHFencePort = (hostId: string, fenceId: string): string =>
@ -37,12 +113,15 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
setMsgSetter,
},
hostId,
hostLabel,
hostNumber,
hostType,
previous: {
fences: fenceList = {},
networks: networkList = {},
upses: upsList = {},
} = {},
// Props that depend on others.
hostLabel = `${hostType} ${hostNumber}`,
}: AnHostInputGroupProps<M>): ReactElement => {
const fenceListEntries = useMemo(
() => Object.entries(fenceList),
@ -54,17 +133,14 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
);
const upsListEntries = useMemo(() => Object.entries(upsList), [upsList]);
const isShowFenceListGrid = useMemo(
() => Boolean(fenceListEntries.length),
[fenceListEntries.length],
);
const isShowUpsListGrid = useMemo(
() => Boolean(upsListEntries.length),
[upsListEntries.length],
);
const isShowFenceAndUpsListGrid = useMemo(
() => isShowFenceListGrid || isShowUpsListGrid,
[isShowFenceListGrid, isShowUpsListGrid],
const inputIdAHHost = useMemo(
() => `${INPUT_ID_PREFIX_AN_HOST}-${hostId}`,
[hostId],
);
const fenceListGridLayout = useMemo(
@ -83,6 +159,12 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
<InputWithRef
input={
<OutlinedInputWithLabel
baseInputProps={{
'data-handler': 'fence',
'data-host-id': hostId,
'data-fence-id': fenceId,
'data-fence-name': fenceName,
}}
id={inputId}
label={inputLabel}
value={fencePort}
@ -124,7 +206,7 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
(previous, [networkId, { networkIp, networkNumber, networkType }]) => {
const cellId = `${INPUT_CELL_ID_PREFIX_AH}-${networkId}-ip`;
const inputId = buildInputIdAHNetworkIp(hostId, networkIp);
const inputId = buildInputIdAHNetworkIp(hostId, networkId);
const inputLabel = `${NETWORK_TYPES[networkType]} ${networkNumber}`;
setMsgSetter(inputId);
@ -134,6 +216,13 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
<InputWithRef
input={
<OutlinedInputWithLabel
baseInputProps={{
'data-handler': 'network',
'data-host-id': hostId,
'data-network-id': networkId,
'data-network-number': networkNumber,
'data-network-type': networkType,
}}
id={inputId}
label={inputLabel}
value={networkIp}
@ -183,10 +272,15 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
<InputWithRef
input={
<SwitchWithLabel
baseInputProps={{
'data-handler': 'ups',
'data-host-id': hostId,
'data-ups-id': upsId,
'data-ups-name': upsName,
}}
checked={isUsed}
id={inputId}
label={inputLabel}
flexBoxProps={{ height: '3.5em' }}
/>
}
valueType="boolean"
@ -201,44 +295,43 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
[hostId, upsListEntries],
);
const upsListGrid = useMemo(
() =>
isShowUpsListGrid && (
<Grid
columns={GRID_COLUMNS}
layout={upsListGridLayout}
spacing={GRID_SPACING}
/>
),
[isShowUpsListGrid, upsListGridLayout],
);
return (
<InnerPanel mv={0}>
<InnerPanelHeader>
<BodyText>{hostLabel}</BodyText>
</InnerPanelHeader>
<InnerPanelBody>
<input
hidden
id={inputIdAHHost}
readOnly
data-handler="host"
data-host-id={hostId}
data-host-number={hostNumber}
data-host-type={hostType}
/>
<FlexBox>
<Grid
columns={{ xs: 1, sm: 2, md: 3 }}
layout={networkListGridLayout}
columns={GRID_COLUMNS}
layout={{
...networkListGridLayout,
...fenceListGridLayout,
}}
spacing={GRID_SPACING}
/>
{isShowFenceAndUpsListGrid && (
<Grid
columns={{ xs: 1, sm: 2 }}
layout={{
'an-host-fence-input-group': {
children: (
<Grid
columns={{ xs: 1, md: 2 }}
layout={fenceListGridLayout}
spacing={GRID_SPACING}
/>
),
},
'an-host-ups-input-group': {
children: (
<Grid
columns={{ xs: 1, md: 2 }}
layout={upsListGridLayout}
spacing={GRID_SPACING}
/>
),
},
}}
spacing={GRID_SPACING}
/>
)}
{upsListGrid}
</FlexBox>
</InnerPanelBody>
</InnerPanel>
@ -246,6 +339,8 @@ const AnHostInputGroup = <M extends MapToInputTestID>({
};
export {
INPUT_ID_PREFIX_AN_HOST,
MAP_TO_AH_INPUT_HANDLER,
buildInputIdAHFencePort,
buildInputIdAHNetworkIp,
buildInputIdAHUpsPowerHost,

@ -14,6 +14,56 @@ 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`;
@ -69,6 +119,11 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
[networkId],
);
const inputIdANNetwork = useMemo(
() => `${INPUT_ID_PREFIX_AN_NETWORK}-${networkId}`,
[networkId],
);
const inputGatewayId = useMemo(
() => buildInputIdANGateway(networkId),
[networkId],
@ -121,6 +176,10 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
<InputWithRef
input={
<OutlinedInputWithLabel
baseInputProps={{
'data-handler': 'gateway',
'data-network-id': networkId,
}}
id={inputGatewayId}
label={inputGatewayLabel}
value={previousGateway}
@ -151,6 +210,7 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
isShowGateway,
inputGatewayId,
setMsgSetter,
networkId,
inputGatewayLabel,
previousGateway,
networkName,
@ -190,6 +250,15 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
{closeButtonElement}
</InnerPanelHeader>
<InnerPanelBody>
<input
hidden
id={inputIdANNetwork}
readOnly
data-handler="network"
data-network-id={networkId}
data-network-number={networkNumber}
data-network-type={networkType}
/>
<Grid
layout={{
[inputCellIpId]: {
@ -197,6 +266,10 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
<InputWithRef
input={
<OutlinedInputWithLabel
baseInputProps={{
'data-handler': 'minip',
'data-network-id': networkId,
}}
id={inputMinIpId}
label={inputMinIpLabel}
value={previousIpAddress}
@ -227,6 +300,10 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
<InputWithRef
input={
<OutlinedInputWithLabel
baseInputProps={{
'data-handler': 'subnetmask',
'data-network-id': networkId,
}}
id={inputSubnetMaskId}
label={inputSubnetMaskLabel}
value={previousSubnetMask}
@ -249,6 +326,8 @@ const AnNetworkInputGroup = <M extends MapToInputTestID>({
};
export {
INPUT_ID_PREFIX_AN_NETWORK,
MAP_TO_AN_INPUT_HANDLER,
buildInputIdANGateway,
buildInputIdANMinIp,
buildInputIdANNetworkType,

@ -8,6 +8,14 @@ import {
INPUT_ID_AI_PREFIX,
INPUT_ID_AI_SEQUENCE,
} from './AnIdInputGroup';
import {
INPUT_ID_PREFIX_AN_HOST,
MAP_TO_AH_INPUT_HANDLER,
} from './AnHostInputGroup';
import {
INPUT_ID_PREFIX_AN_NETWORK,
MAP_TO_AN_INPUT_HANDLER,
} from './AnNetworkInputGroup';
import {
INPUT_ID_ANC_DNS,
INPUT_ID_ANC_MTU,
@ -25,6 +33,7 @@ import MessageGroup, { MessageGroupForwardedRefContent } from '../MessageGroup';
import { Panel, PanelHeader } from '../Panels';
import periodicFetch from '../../lib/fetchers/periodicFetch';
import RunManifestInputGroup, {
buildInputIdRMHost,
INPUT_ID_RM_AN_CONFIRM_PASSWORD,
INPUT_ID_RM_AN_DESCRIPTION,
INPUT_ID_RM_AN_PASSWORD,
@ -36,6 +45,99 @@ import useFormUtils from '../../hooks/useFormUtils';
import useIsFirstRender from '../../hooks/useIsFirstRender';
import useProtectedState from '../../hooks/useProtectedState';
const getFormData = (
...[{ target }]: DivFormEventHandlerParameters
): APIBuildManifestRequestBody => {
const { elements } = target as HTMLFormElement;
const { value: domain } = elements.namedItem(
INPUT_ID_AI_DOMAIN,
) as HTMLInputElement;
const { value: prefix } = elements.namedItem(
INPUT_ID_AI_PREFIX,
) as HTMLInputElement;
const { value: rawSequence } = elements.namedItem(
INPUT_ID_AI_SEQUENCE,
) as HTMLInputElement;
const { value: dnsCsv } = elements.namedItem(
INPUT_ID_ANC_DNS,
) as HTMLInputElement;
const { value: rawMtu } = elements.namedItem(
INPUT_ID_ANC_MTU,
) as HTMLInputElement;
const { value: ntpCsv } = elements.namedItem(
INPUT_ID_ANC_NTP,
) as HTMLInputElement;
const mtu = Number.parseInt(rawMtu, 10);
const sequence = Number.parseInt(rawSequence, 10);
return Object.values(elements).reduce<APIBuildManifestRequestBody>(
(previous, element) => {
const { id: inputId } = element;
if (RegExp(`^${INPUT_ID_PREFIX_AN_HOST}`).test(inputId)) {
const input = element as HTMLInputElement;
const {
dataset: { handler: key = '' },
} = input;
MAP_TO_AH_INPUT_HANDLER[key]?.call(null, previous, input);
} else if (RegExp(`^${INPUT_ID_PREFIX_AN_NETWORK}`).test(inputId)) {
const input = element as HTMLInputElement;
const {
dataset: { handler: key = '' },
} = input;
MAP_TO_AN_INPUT_HANDLER[key]?.call(null, previous, input);
}
return previous;
},
{
domain,
hostConfig: { hosts: {} },
networkConfig: {
dnsCsv,
mtu,
networks: {},
ntpCsv,
},
prefix,
sequence,
},
);
};
const getRunFormData = (
mdetailHosts: ManifestHostList,
...[{ target }]: DivFormEventHandlerParameters
): APIRunManifestRequestBody => {
const { elements } = target as HTMLFormElement;
const { value: description } = elements.namedItem(
INPUT_ID_RM_AN_DESCRIPTION,
) as HTMLInputElement;
const { value: password } = elements.namedItem(
INPUT_ID_RM_AN_PASSWORD,
) as HTMLInputElement;
const hosts = Object.entries(mdetailHosts).reduce<
APIRunManifestRequestBody['hosts']
>((previous, [hostId, { hostNumber, hostType }]) => {
const inputId = buildInputIdRMHost(hostId);
const { value: hostUuid } = elements.namedItem(inputId) as HTMLInputElement;
previous[hostId] = { hostNumber, hostType, hostUuid };
return previous;
}, {});
return { description, hosts, password };
};
const ManageManifestPanel: FC = () => {
const isFirstRender = useIsFirstRender();
@ -95,10 +197,11 @@ const ManageManifestPanel: FC = () => {
const { isFormInvalid: isRunFormInvalid } = runFormUtils;
const {
domain,
name: anName,
prefix,
sequence,
domain: mdetailDomain,
hostConfig: { hosts: mdetailHosts = {} } = {},
name: mdetailName,
prefix: mdetailPrefix,
sequence: mdetailSequence,
} = useMemo<Partial<APIManifestDetail>>(
() => manifestDetail ?? {},
[manifestDetail],
@ -115,12 +218,26 @@ const ManageManifestPanel: FC = () => {
formUtils={formUtils}
knownFences={knownFences}
knownUpses={knownUpses}
previous={{ domain, prefix, sequence }}
previous={{
domain: mdetailDomain,
prefix: mdetailPrefix,
sequence: mdetailSequence,
}}
/>
),
onSubmitAppend: (...args) => {
getFormData(...args);
},
titleText: 'Add an install manifest',
}),
[domain, formUtils, knownFences, knownUpses, prefix, sequence],
[
mdetailDomain,
formUtils,
knownFences,
knownUpses,
mdetailPrefix,
mdetailSequence,
],
);
const editManifestFormDialogProps = useMemo<ConfirmDialogProps>(
@ -134,15 +251,18 @@ const ManageManifestPanel: FC = () => {
previous={manifestDetail}
/>
),
onSubmitAppend: (...args) => {
getFormData(...args);
},
loading: isLoadingManifestDetail,
titleText: `Update install manifest ${anName}`,
titleText: `Update install manifest ${mdetailName}`,
}),
[
formUtils,
isLoadingManifestDetail,
knownFences,
knownUpses,
anName,
mdetailName,
manifestDetail,
],
);
@ -160,11 +280,15 @@ const ManageManifestPanel: FC = () => {
/>
),
loading: isLoadingManifestDetail,
titleText: `Run install manifest ${anName}`,
onSubmitAppend: (...args) => {
getRunFormData(mdetailHosts, ...args);
},
titleText: `Run install manifest ${mdetailName}`,
}),
[
anName,
mdetailName,
hostOverviews,
mdetailHosts,
isLoadingManifestDetail,
knownFences,
knownUpses,

@ -39,3 +39,17 @@ type APIManifestTemplate = {
sequence: number;
upses: APIManifestTemplateUpsList;
};
type APIBuildManifestRequestBody = Omit<APIManifestDetail, 'name' | 'uuid'>;
type APIRunManifestRequestBody = {
description: string;
hosts: {
[hostId: string]: {
hostNumber: number;
hostType: string;
hostUuid: string;
};
};
password: string;
};

@ -1,3 +1,6 @@
type DivFormEventHandler = import('react').FormEventHandler<HTMLDivElement>;
type DivFormEventHandlerParameters = Parameters<DivFormEventHandler>;
type ConfirmDialogOptionalProps = {
actionCancelText?: string;
closeOnProceed?: boolean;
@ -10,7 +13,7 @@ type ConfirmDialogOptionalProps = {
onActionAppend?: ContainedButtonProps['onClick'];
onProceedAppend?: ContainedButtonProps['onClick'];
onCancelAppend?: ContainedButtonProps['onClick'];
onSubmitAppend?: import('react').FormEventHandler<HTMLDivElement>;
onSubmitAppend?: DivFormEventHandler;
openInitially?: boolean;
preActionArea?: import('react').ReactNode;
proceedButtonProps?: ContainedButtonProps;

@ -48,7 +48,7 @@ type ManifestHostUpsList = {
type ManifestHost = {
fences?: ManifestHostFenceList;
hostName: string;
hostName?: string;
hostNumber: number;
hostType: string;
networks?: ManifestHostNetworkList;
@ -63,6 +63,15 @@ type ManifestHostConfig = {
hosts: ManifestHostList;
};
type ManifestFormInputHandler = (
container: APIBuildManifestRequestBody,
input: HTMLInputElement,
) => void;
type MapToManifestFormInputHandler = Record<string, ManifestFormInputHandler>;
/** ---------- Component types ---------- */
type AnIdInputGroupOptionalProps = {
previous?: Partial<ManifestAnId>;
};
@ -112,6 +121,7 @@ type AnNetworkInputGroupProps<M extends MapToInputTestID> =
};
type AnHostInputGroupOptionalProps = {
hostLabel?: string;
previous?: Pick<ManifestHost, 'fences' | 'networks' | 'upses'>;
};
@ -119,7 +129,8 @@ type AnHostInputGroupProps<M extends MapToInputTestID> =
AnHostInputGroupOptionalProps & {
formUtils: FormUtils<M>;
hostId: string;
hostLabel: string;
hostNumber: number;
hostType: string;
};
type AnNetworkConfigInputGroupOptionalProps = {

Loading…
Cancel
Save