fix(striker-ui): add edit manifest form

main
Tsu-ba-me 2 years ago
parent 18533ba0c8
commit 6aaa4f6237
  1. 17
      striker-ui/components/ManageManifest/AddManifestInputGroup.tsx
  2. 45
      striker-ui/components/ManageManifest/AnvilHostConfigInputGroup.tsx
  3. 6
      striker-ui/components/ManageManifest/AnvilIdInputGroup.tsx
  4. 39
      striker-ui/components/ManageManifest/EditManifestInputGroup.tsx
  5. 161
      striker-ui/components/ManageManifest/ManageManifestPanel.tsx
  6. 7
      striker-ui/types/APIManifest.d.ts
  7. 58
      striker-ui/types/ManageManifest.d.ts

@ -15,15 +15,15 @@ import FlexBox from '../FlexBox';
const DEFAULT_NETWORK_LIST: ManifestNetworkList = { const DEFAULT_NETWORK_LIST: ManifestNetworkList = {
bcn1: { bcn1: {
networkMinIp: '', networkMinIp: '10.201.0.0',
networkNumber: 1, networkNumber: 1,
networkSubnetMask: '', networkSubnetMask: '255.255.0.0',
networkType: 'bcn', networkType: 'bcn',
}, },
sn1: { sn1: {
networkMinIp: '', networkMinIp: '10.101.0.0',
networkNumber: 1, networkNumber: 1,
networkSubnetMask: '', networkSubnetMask: '255.255.0.0',
networkType: 'sn', networkType: 'sn',
}, },
ifn1: { ifn1: {
@ -46,9 +46,12 @@ const AddManifestInputGroup = <
}, },
>({ >({
formUtils, formUtils,
knownFences,
knownUpses,
previous: { previous: {
hostConfig: previousHostConfig = {}, hostConfig: previousHostConfig,
networkConfig: previousNetworkConfig = {}, networkConfig: previousNetworkConfig = {},
...previousAnId
} = {}, } = {},
}: AddManifestInputGroupProps<M>): ReactElement => { }: AddManifestInputGroupProps<M>): ReactElement => {
const { networks: previousNetworkList = DEFAULT_NETWORK_LIST } = const { networks: previousNetworkList = DEFAULT_NETWORK_LIST } =
@ -64,7 +67,7 @@ const AddManifestInputGroup = <
return ( return (
<FlexBox> <FlexBox>
<AnvilIdInputGroup formUtils={formUtils} /> <AnvilIdInputGroup formUtils={formUtils} previous={previousAnId} />
<AnvilNetworkConfigInputGroup <AnvilNetworkConfigInputGroup
formUtils={formUtils} formUtils={formUtils}
networkListEntries={networkListEntries} networkListEntries={networkListEntries}
@ -73,6 +76,8 @@ const AddManifestInputGroup = <
/> />
<AnvilHostConfigInputGroup <AnvilHostConfigInputGroup
formUtils={formUtils} formUtils={formUtils}
knownFences={knownFences}
knownUpses={knownUpses}
networkListEntries={networkListEntries} networkListEntries={networkListEntries}
previous={previousHostConfig} previous={previousHostConfig}
/> />

@ -39,23 +39,6 @@ const AnvilHostConfigInputGroup = <M extends MapToInputTestID>({
[knownUpses], [knownUpses],
); );
const hostNetworkList = useMemo(
() =>
networkListEntries.reduce<ManifestHostNetworkList>(
(previous, [networkId, { networkNumber, networkType }]) => {
previous[networkId] = {
networkIp: '',
networkNumber,
networkType,
};
return previous;
},
{},
),
[networkListEntries],
);
const hostListGridLayout = useMemo<GridLayout>( const hostListGridLayout = useMemo<GridLayout>(
() => () =>
hostListEntries.reduce<GridLayout>( hostListEntries.reduce<GridLayout>(
@ -64,7 +47,7 @@ const AnvilHostConfigInputGroup = <M extends MapToInputTestID>({
fences: previousFenceList = {}, fences: previousFenceList = {},
hostNumber, hostNumber,
hostType, hostType,
networks = hostNetworkList, networks: previousNetworkList = {},
upses: previousUpsList = {}, upses: previousUpsList = {},
}: ManifestHost = previousHostArgs; }: ManifestHost = previousHostArgs;
@ -72,23 +55,31 @@ const AnvilHostConfigInputGroup = <M extends MapToInputTestID>({
(fenceList, { fenceName }) => { (fenceList, { fenceName }) => {
const { fencePort = '' } = previousFenceList[fenceName] ?? {}; const { fencePort = '' } = previousFenceList[fenceName] ?? {};
fenceList[fenceName] = { fenceList[fenceName] = { fenceName, fencePort };
fenceName,
fencePort,
};
return fenceList; return fenceList;
}, },
{}, {},
); );
const networks = networkListEntries.reduce<ManifestHostNetworkList>(
(networkList, [networkId, { networkNumber, networkType }]) => {
const { networkIp = '' } = previousNetworkList[networkId] ?? {};
networkList[networkId] = {
networkIp,
networkNumber,
networkType,
};
return networkList;
},
{},
);
const upses = knownUpsListValues.reduce<ManifestHostUpsList>( const upses = knownUpsListValues.reduce<ManifestHostUpsList>(
(upsList, { upsName }) => { (upsList, { upsName }) => {
const { isUsed = true } = previousUpsList[upsName] ?? {}; const { isUsed = true } = previousUpsList[upsName] ?? {};
upsList[upsName] = { upsList[upsName] = { isUsed, upsName };
isUsed,
upsName,
};
return upsList; return upsList;
}, },
@ -117,9 +108,9 @@ const AnvilHostConfigInputGroup = <M extends MapToInputTestID>({
[ [
formUtils, formUtils,
hostListEntries, hostListEntries,
hostNetworkList,
knownFenceListValues, knownFenceListValues,
knownUpsListValues, knownUpsListValues,
networkListEntries,
], ],
); );

@ -30,9 +30,9 @@ const AnvilIdInputGroup = <
msgSetters, msgSetters,
}, },
previous: { previous: {
anvilIdDomain: previousDomain, domain: previousDomain,
anvilIdPrefix: previousPrefix, prefix: previousPrefix,
anvilIdSequence: previousSequence, sequence: previousSequence,
} = {}, } = {},
}: AnvilIdInputGroupProps<M>): ReactElement => ( }: AnvilIdInputGroupProps<M>): ReactElement => (
<Grid <Grid

@ -0,0 +1,39 @@
import { ReactElement } from 'react';
import {
INPUT_ID_ANVIL_ID_DOMAIN,
INPUT_ID_ANVIL_ID_PREFIX,
INPUT_ID_ANVIL_ID_SEQUENCE,
} from './AnvilIdInputGroup';
import {
INPUT_ID_ANVIL_NETWORK_CONFIG_DNS,
INPUT_ID_ANVIL_NETWORK_CONFIG_MTU,
INPUT_ID_ANVIL_NETWORK_CONFIG_NTP,
} from './AnvilNetworkConfigInputGroup';
import AddManifestInputGroup from './AddManifestInputGroup';
const EditManifestInputGroup = <
M extends {
[K in
| typeof INPUT_ID_ANVIL_ID_DOMAIN
| typeof INPUT_ID_ANVIL_ID_PREFIX
| typeof INPUT_ID_ANVIL_ID_SEQUENCE
| typeof INPUT_ID_ANVIL_NETWORK_CONFIG_DNS
| typeof INPUT_ID_ANVIL_NETWORK_CONFIG_MTU
| typeof INPUT_ID_ANVIL_NETWORK_CONFIG_NTP]: string;
},
>({
formUtils,
knownFences,
knownUpses,
previous,
}: EditManifestInputGroupProps<M>): ReactElement => (
<AddManifestInputGroup
formUtils={formUtils}
knownFences={knownFences}
knownUpses={knownUpses}
previous={previous}
/>
);
export default EditManifestInputGroup;

@ -1,5 +1,5 @@
import { PlayCircle } from '@mui/icons-material'; import { PlayCircle } from '@mui/icons-material';
import { FC, useMemo, useRef, useState } from 'react'; import { FC, useCallback, useMemo, useRef, useState } from 'react';
import API_BASE_URL from '../../lib/consts/API_BASE_URL'; import API_BASE_URL from '../../lib/consts/API_BASE_URL';
@ -14,9 +14,12 @@ import {
INPUT_ID_ANVIL_NETWORK_CONFIG_MTU, INPUT_ID_ANVIL_NETWORK_CONFIG_MTU,
INPUT_ID_ANVIL_NETWORK_CONFIG_NTP, INPUT_ID_ANVIL_NETWORK_CONFIG_NTP,
} from './AnvilNetworkConfigInputGroup'; } from './AnvilNetworkConfigInputGroup';
import api from '../../lib/api';
import ConfirmDialog from '../ConfirmDialog'; import ConfirmDialog from '../ConfirmDialog';
import EditManifestInputGroup from './EditManifestInputGroup';
import FlexBox from '../FlexBox'; import FlexBox from '../FlexBox';
import FormDialog from '../FormDialog'; import FormDialog from '../FormDialog';
import handleAPIError from '../../lib/handleAPIError';
import IconButton from '../IconButton'; import IconButton from '../IconButton';
import List from '../List'; import List from '../List';
import { MessageGroupForwardedRefContent } from '../MessageGroup'; import { MessageGroupForwardedRefContent } from '../MessageGroup';
@ -26,16 +29,32 @@ import Spinner from '../Spinner';
import { BodyText, HeaderText } from '../Text'; import { BodyText, HeaderText } from '../Text';
import useConfirmDialogProps from '../../hooks/useConfirmDialogProps'; import useConfirmDialogProps from '../../hooks/useConfirmDialogProps';
import useFormUtils from '../../hooks/useFormUtils'; import useFormUtils from '../../hooks/useFormUtils';
import useIsFirstRender from '../../hooks/useIsFirstRender';
import useProtectedState from '../../hooks/useProtectedState';
const ManageManifestPanel: FC = () => { const ManageManifestPanel: FC = () => {
const isFirstRender = useIsFirstRender();
const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent>({});
const formDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); const addManifestFormDialogRef = useRef<ConfirmDialogForwardedRefContent>({});
const editManifestFormDialogRef = useRef<ConfirmDialogForwardedRefContent>(
{},
);
const messageGroupRef = useRef<MessageGroupForwardedRefContent>({}); const messageGroupRef = useRef<MessageGroupForwardedRefContent>({});
const [confirmDialogProps] = useConfirmDialogProps(); const [confirmDialogProps] = useConfirmDialogProps();
const [formDialogProps, setFormDialogProps] = useConfirmDialogProps();
const [isEditManifests, setIsEditManifests] = useState<boolean>(false); const [isEditManifests, setIsEditManifests] = useState<boolean>(false);
const [isLoadingManifestDetail, setIsLoadingManifestDetail] =
useProtectedState<boolean>(true);
const [isLoadingManifestTemplate, setIsLoadingManifestTemplate] =
useState<boolean>(true);
const [manifestDetail, setManifestDetail] = useProtectedState<
APIManifestDetail | undefined
>(undefined);
const [manifestTemplate, setManifestTemplate] = useProtectedState<
APIManifestTemplate | undefined
>(undefined);
const { data: manifestOverviews, isLoading: isLoadingManifestOverviews } = const { data: manifestOverviews, isLoading: isLoadingManifestOverviews } =
periodicFetch<APIManifestOverviewList>(`${API_BASE_URL}/manifest`, { periodicFetch<APIManifestOverviewList>(`${API_BASE_URL}/manifest`, {
@ -55,13 +74,79 @@ const ManageManifestPanel: FC = () => {
); );
const { isFormInvalid } = formUtils; const { isFormInvalid } = formUtils;
const addAnvilManifestFormDialogProps = useMemo<ConfirmDialogProps>( const addManifestFormDialogProps = useMemo<ConfirmDialogProps>(() => {
() => ({ let domain: string | undefined;
let prefix: string | undefined;
let sequence: number | undefined;
let fences: APIManifestTemplateFenceList | undefined;
let upses: APIManifestTemplateUpsList | undefined;
if (manifestTemplate) {
({ domain, fences, prefix, sequence, upses } = manifestTemplate);
}
return {
actionProceedText: 'Add', actionProceedText: 'Add',
content: <AddManifestInputGroup formUtils={formUtils} />, content: (
titleText: 'Add a Anvil! manifest', <AddManifestInputGroup
}), formUtils={formUtils}
[formUtils], knownFences={fences}
knownUpses={upses}
previous={{ domain, prefix, sequence }}
/>
),
titleText: 'Add an install manifest',
};
}, [formUtils, manifestTemplate]);
const editManifestFormDialogProps = useMemo<ConfirmDialogProps>(() => {
let fences: APIManifestTemplateFenceList | undefined;
let manifestName: string | undefined;
let upses: APIManifestTemplateUpsList | undefined;
if (manifestTemplate) {
({ fences, upses } = manifestTemplate);
}
if (manifestDetail) {
({ name: manifestName } = manifestDetail);
}
return {
actionProceedText: 'Edit',
content: (
<EditManifestInputGroup
formUtils={formUtils}
knownFences={fences}
knownUpses={upses}
previous={manifestDetail}
/>
),
loading: isLoadingManifestDetail,
titleText: `Update install manifest ${manifestName}`,
};
}, [formUtils, isLoadingManifestDetail, manifestDetail, manifestTemplate]);
const getManifestDetail = useCallback(
(manifestUuid: string, finallyAppend?: () => void) => {
setIsLoadingManifestDetail(true);
api
.get<APIManifestDetail>(`manifest/${manifestUuid}`)
.then(({ data }) => {
data.uuid = manifestUuid;
setManifestDetail(data);
})
.catch((error) => {
handleAPIError(error);
})
.finally(() => {
setIsLoadingManifestDetail(false);
finallyAppend?.call(null);
});
},
[setIsLoadingManifestDetail, setManifestDetail],
); );
const listElement = useMemo( const listElement = useMemo(
@ -74,12 +159,19 @@ const ManageManifestPanel: FC = () => {
listEmpty="No manifest(s) registered." listEmpty="No manifest(s) registered."
listItems={manifestOverviews} listItems={manifestOverviews}
onAdd={() => { onAdd={() => {
setFormDialogProps(addAnvilManifestFormDialogProps); addManifestFormDialogRef.current.setOpen?.call(null, true);
formDialogRef.current.setOpen?.call(null, true);
}} }}
onEdit={() => { onEdit={() => {
setIsEditManifests((previous) => !previous); setIsEditManifests((previous) => !previous);
}} }}
onItemClick={({ manifestName, manifestUUID }) => {
setManifestDetail({
name: manifestName,
uuid: manifestUUID,
} as APIManifestDetail);
editManifestFormDialogRef.current.setOpen?.call(null, true);
getManifestDetail(manifestUUID);
}}
renderListItem={(manifestUUID, { manifestName }) => ( renderListItem={(manifestUUID, { manifestName }) => (
<FlexBox fullWidth row> <FlexBox fullWidth row>
<IconButton disabled={isEditManifests} variant="normal"> <IconButton disabled={isEditManifests} variant="normal">
@ -90,19 +182,33 @@ const ManageManifestPanel: FC = () => {
)} )}
/> />
), ),
[ [getManifestDetail, isEditManifests, manifestOverviews, setManifestDetail],
addAnvilManifestFormDialogProps,
isEditManifests,
manifestOverviews,
setFormDialogProps,
],
); );
const panelContent = useMemo( const panelContent = useMemo(
() => (isLoadingManifestOverviews ? <Spinner /> : listElement), () =>
[isLoadingManifestOverviews, listElement], isLoadingManifestTemplate || isLoadingManifestOverviews ? (
<Spinner />
) : (
listElement
),
[isLoadingManifestOverviews, isLoadingManifestTemplate, listElement],
); );
if (isFirstRender) {
api
.get<APIManifestTemplate>('/manifest/template')
.then(({ data }) => {
setManifestTemplate(data);
})
.catch((error) => {
handleAPIError(error);
})
.finally(() => {
setIsLoadingManifestTemplate(false);
});
}
return ( return (
<> <>
<Panel> <Panel>
@ -112,14 +218,15 @@ const ManageManifestPanel: FC = () => {
{panelContent} {panelContent}
</Panel> </Panel>
<FormDialog <FormDialog
{...formDialogProps} {...addManifestFormDialogProps}
ref={formDialogRef} disableProceed={isFormInvalid}
proceedButtonProps={{ disabled: isFormInvalid }} ref={addManifestFormDialogRef}
scrollBoxProps={{ scrollContent
paddingRight: '.4em', />
paddingTop: '.6em', <FormDialog
sx: { overflowX: 'hidden' }, {...editManifestFormDialogProps}
}} disableProceed={isFormInvalid}
ref={editManifestFormDialogRef}
scrollContent scrollContent
/> />
<ConfirmDialog {...confirmDialogProps} ref={confirmDialogRef} /> <ConfirmDialog {...confirmDialogProps} ref={confirmDialogRef} />

@ -7,6 +7,13 @@ type APIManifestOverviewList = {
[manifestUUID: string]: APIManifestOverview; [manifestUUID: string]: APIManifestOverview;
}; };
type APIManifestDetail = ManifestAnId & {
hostConfig: ManifestHostConfig;
name: string;
networkConfig: ManifestNetworkConfig;
uuid?: string;
};
type APIManifestTemplateFence = { type APIManifestTemplateFence = {
fenceName: string; fenceName: string;
fenceUUID: string; fenceUUID: string;

@ -1,14 +1,7 @@
type AnvilIdInputGroupOptionalProps = { type ManifestAnId = {
previous?: { domain: string;
anvilIdPrefix?: string; prefix: string;
anvilIdDomain?: string; sequence: number;
anvilIdSequence?: number;
};
};
type AnvilIdInputGroupProps<M extends MapToInputTestID> =
AnvilIdInputGroupOptionalProps & {
formUtils: FormUtils<M>;
}; };
type ManifestNetwork = { type ManifestNetwork = {
@ -23,6 +16,14 @@ type ManifestNetworkList = {
[networkId: string]: ManifestNetwork; [networkId: string]: ManifestNetwork;
}; };
type ManifestNetworkConfig = {
dnsCsv: string;
/** Max Transmission Unit (MTU); unit: bytes */
mtu: number;
networks: ManifestNetworkList;
ntpCsv: string;
};
type ManifestHostFenceList = { type ManifestHostFenceList = {
[fenceId: string]: { [fenceId: string]: {
fenceName: string; fenceName: string;
@ -57,6 +58,19 @@ type ManifestHostList = {
[hostId: string]: ManifestHost; [hostId: string]: ManifestHost;
}; };
type ManifestHostConfig = {
hosts: ManifestHostList;
};
type AnvilIdInputGroupOptionalProps = {
previous?: Partial<ManifestAnId>;
};
type AnvilIdInputGroupProps<M extends MapToInputTestID> =
AnvilIdInputGroupOptionalProps & {
formUtils: FormUtils<M>;
};
type AnvilNetworkEventHandlerPreviousArgs = { type AnvilNetworkEventHandlerPreviousArgs = {
networkId: string; networkId: string;
} & Pick<ManifestNetwork, 'networkType'>; } & Pick<ManifestNetwork, 'networkType'>;
@ -112,13 +126,7 @@ type AnvilHostInputGroupProps<M extends MapToInputTestID> =
}; };
type AnvilNetworkConfigInputGroupOptionalProps = { type AnvilNetworkConfigInputGroupOptionalProps = {
previous?: { previous?: Partial<ManifestNetworkConfig>;
dnsCsv?: string;
/** Max Transmission Unit (MTU); unit: bytes */
mtu?: number;
networks?: ManifestNetworkList;
ntpCsv?: string;
};
}; };
type AnvilNetworkConfigInputGroupProps<M extends MapToInputTestID> = type AnvilNetworkConfigInputGroupProps<M extends MapToInputTestID> =
@ -133,9 +141,7 @@ type AnvilNetworkConfigInputGroupProps<M extends MapToInputTestID> =
type AnvilHostConfigInputGroupOptionalProps = { type AnvilHostConfigInputGroupOptionalProps = {
knownFences?: APIManifestTemplateFenceList; knownFences?: APIManifestTemplateFenceList;
knownUpses?: APIManifestTemplateUpsList; knownUpses?: APIManifestTemplateUpsList;
previous?: { previous?: Partial<ManifestHostConfig>;
hosts?: ManifestHostList;
};
}; };
type AnvilHostConfigInputGroupProps<M extends MapToInputTestID> = type AnvilHostConfigInputGroupProps<M extends MapToInputTestID> =
@ -148,10 +154,9 @@ type AddManifestInputGroupOptionalProps = Pick<
AnvilHostConfigInputGroupOptionalProps, AnvilHostConfigInputGroupOptionalProps,
'knownFences' | 'knownUpses' 'knownFences' | 'knownUpses'
> & { > & {
previous?: { previous?: Partial<ManifestAnId> & {
anId?: AnvilIdInputGroupOptionalProps['previous']; hostConfig?: Partial<ManifestHostConfig>;
networkConfig?: AnvilNetworkConfigInputGroupOptionalProps['previous']; networkConfig?: Partial<ManifestNetworkConfig>;
hostConfig?: AnvilHostConfigInputGroupOptionalProps['previous'];
}; };
}; };
@ -159,3 +164,6 @@ type AddManifestInputGroupProps<M extends MapToInputTestID> =
AddManifestInputGroupOptionalProps & { AddManifestInputGroupOptionalProps & {
formUtils: FormUtils<M>; formUtils: FormUtils<M>;
}; };
type EditManifestInputGroupProps<M extends MapToInputTestID> =
AddManifestInputGroupProps<M>;

Loading…
Cancel
Save