|
|
|
@ -1,5 +1,5 @@ |
|
|
|
|
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'; |
|
|
|
|
|
|
|
|
@ -14,9 +14,12 @@ import { |
|
|
|
|
INPUT_ID_ANVIL_NETWORK_CONFIG_MTU, |
|
|
|
|
INPUT_ID_ANVIL_NETWORK_CONFIG_NTP, |
|
|
|
|
} from './AnvilNetworkConfigInputGroup'; |
|
|
|
|
import api from '../../lib/api'; |
|
|
|
|
import ConfirmDialog from '../ConfirmDialog'; |
|
|
|
|
import EditManifestInputGroup from './EditManifestInputGroup'; |
|
|
|
|
import FlexBox from '../FlexBox'; |
|
|
|
|
import FormDialog from '../FormDialog'; |
|
|
|
|
import handleAPIError from '../../lib/handleAPIError'; |
|
|
|
|
import IconButton from '../IconButton'; |
|
|
|
|
import List from '../List'; |
|
|
|
|
import { MessageGroupForwardedRefContent } from '../MessageGroup'; |
|
|
|
@ -26,16 +29,32 @@ import Spinner from '../Spinner'; |
|
|
|
|
import { BodyText, HeaderText } from '../Text'; |
|
|
|
|
import useConfirmDialogProps from '../../hooks/useConfirmDialogProps'; |
|
|
|
|
import useFormUtils from '../../hooks/useFormUtils'; |
|
|
|
|
import useIsFirstRender from '../../hooks/useIsFirstRender'; |
|
|
|
|
import useProtectedState from '../../hooks/useProtectedState'; |
|
|
|
|
|
|
|
|
|
const ManageManifestPanel: FC = () => { |
|
|
|
|
const isFirstRender = useIsFirstRender(); |
|
|
|
|
|
|
|
|
|
const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); |
|
|
|
|
const formDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); |
|
|
|
|
const addManifestFormDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); |
|
|
|
|
const editManifestFormDialogRef = useRef<ConfirmDialogForwardedRefContent>( |
|
|
|
|
{}, |
|
|
|
|
); |
|
|
|
|
const messageGroupRef = useRef<MessageGroupForwardedRefContent>({}); |
|
|
|
|
|
|
|
|
|
const [confirmDialogProps] = useConfirmDialogProps(); |
|
|
|
|
const [formDialogProps, setFormDialogProps] = useConfirmDialogProps(); |
|
|
|
|
|
|
|
|
|
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 } = |
|
|
|
|
periodicFetch<APIManifestOverviewList>(`${API_BASE_URL}/manifest`, { |
|
|
|
@ -55,13 +74,79 @@ const ManageManifestPanel: FC = () => { |
|
|
|
|
); |
|
|
|
|
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', |
|
|
|
|
content: <AddManifestInputGroup formUtils={formUtils} />, |
|
|
|
|
titleText: 'Add a Anvil! manifest', |
|
|
|
|
}), |
|
|
|
|
[formUtils], |
|
|
|
|
content: ( |
|
|
|
|
<AddManifestInputGroup |
|
|
|
|
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( |
|
|
|
@ -74,12 +159,19 @@ const ManageManifestPanel: FC = () => { |
|
|
|
|
listEmpty="No manifest(s) registered." |
|
|
|
|
listItems={manifestOverviews} |
|
|
|
|
onAdd={() => { |
|
|
|
|
setFormDialogProps(addAnvilManifestFormDialogProps); |
|
|
|
|
formDialogRef.current.setOpen?.call(null, true); |
|
|
|
|
addManifestFormDialogRef.current.setOpen?.call(null, true); |
|
|
|
|
}} |
|
|
|
|
onEdit={() => { |
|
|
|
|
setIsEditManifests((previous) => !previous); |
|
|
|
|
}} |
|
|
|
|
onItemClick={({ manifestName, manifestUUID }) => { |
|
|
|
|
setManifestDetail({ |
|
|
|
|
name: manifestName, |
|
|
|
|
uuid: manifestUUID, |
|
|
|
|
} as APIManifestDetail); |
|
|
|
|
editManifestFormDialogRef.current.setOpen?.call(null, true); |
|
|
|
|
getManifestDetail(manifestUUID); |
|
|
|
|
}} |
|
|
|
|
renderListItem={(manifestUUID, { manifestName }) => ( |
|
|
|
|
<FlexBox fullWidth row> |
|
|
|
|
<IconButton disabled={isEditManifests} variant="normal"> |
|
|
|
@ -90,19 +182,33 @@ const ManageManifestPanel: FC = () => { |
|
|
|
|
)} |
|
|
|
|
/> |
|
|
|
|
), |
|
|
|
|
[ |
|
|
|
|
addAnvilManifestFormDialogProps, |
|
|
|
|
isEditManifests, |
|
|
|
|
manifestOverviews, |
|
|
|
|
setFormDialogProps, |
|
|
|
|
], |
|
|
|
|
[getManifestDetail, isEditManifests, manifestOverviews, setManifestDetail], |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
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 ( |
|
|
|
|
<> |
|
|
|
|
<Panel> |
|
|
|
@ -112,14 +218,15 @@ const ManageManifestPanel: FC = () => { |
|
|
|
|
{panelContent} |
|
|
|
|
</Panel> |
|
|
|
|
<FormDialog |
|
|
|
|
{...formDialogProps} |
|
|
|
|
ref={formDialogRef} |
|
|
|
|
proceedButtonProps={{ disabled: isFormInvalid }} |
|
|
|
|
scrollBoxProps={{ |
|
|
|
|
paddingRight: '.4em', |
|
|
|
|
paddingTop: '.6em', |
|
|
|
|
sx: { overflowX: 'hidden' }, |
|
|
|
|
}} |
|
|
|
|
{...addManifestFormDialogProps} |
|
|
|
|
disableProceed={isFormInvalid} |
|
|
|
|
ref={addManifestFormDialogRef} |
|
|
|
|
scrollContent |
|
|
|
|
/> |
|
|
|
|
<FormDialog |
|
|
|
|
{...editManifestFormDialogProps} |
|
|
|
|
disableProceed={isFormInvalid} |
|
|
|
|
ref={editManifestFormDialogRef} |
|
|
|
|
scrollContent |
|
|
|
|
/> |
|
|
|
|
<ConfirmDialog {...confirmDialogProps} ref={confirmDialogRef} /> |
|
|
|
|