import { Assignment as AssignmentIcon } from '@mui/icons-material'; import { Grid } from '@mui/material'; import { useRouter } from 'next/router'; import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import API_BASE_URL from '../lib/consts/API_BASE_URL'; import { BLACK } from '../lib/consts/DEFAULT_THEME'; import api from '../lib/api'; import ConfirmDialog from './ConfirmDialog'; import ContainedButton from './ContainedButton'; import FlexBox from './FlexBox'; import GeneralInitForm, { GeneralInitFormForwardedRefContent, GeneralInitFormValues, } from './GeneralInitForm'; import handleAPIError from '../lib/handleAPIError'; import IconButton from './IconButton'; import IconWithIndicator, { IconWithIndicatorForwardedRefContent, } from './IconWithIndicator'; import JobSummary, { JobSummaryForwardedRefContent } from './JobSummary'; import Link from './Link'; import MessageBox, { Message } from './MessageBox'; import NetworkInitForm, { NetworkInitFormForwardedRefContent, NetworkInitFormValues, } from './NetworkInitForm'; import { Panel, PanelHeader } from './Panels'; import Spinner from './Spinner'; import { BodyText, HeaderText, InlineMonoText, MonoText } from './Text'; const StrikerInitForm: FC = () => { const { isReady, query: { re }, } = useRouter(); const [submitMessage, setSubmitMessage] = useState(); const [requestBody, setRequestBody] = useState< (GeneralInitFormValues & NetworkInitFormValues) | undefined >(); const [isOpenConfirm, setIsOpenConfirm] = useState(false); const [isDisableSubmit, setIsDisableSubmit] = useState(true); const [isGeneralInitFormValid, setIsGeneralInitFormValid] = useState(false); const [isNetworkInitFormValid, setIsNetworkInitFormValid] = useState(false); const [isSubmittingForm, setIsSubmittingForm] = useState(false); const [hostNumber, setHostNumber] = useState(); const [hostDetail, setHostDetail] = useState(); // Make sure the fetch for host detail only happens once. const allowGetHostDetail = useRef(true); const generalInitFormRef = useRef({}); const networkInitFormRef = useRef({}); const jobIconRef = useRef({}); const jobSummaryRef = useRef({}); const [panelTitle, setPanelTitle] = useState('Loading...'); const reconfig = useMemo(() => Boolean(re), [re]); const buildSubmitSection = useMemo( () => isSubmittingForm ? ( ) : ( { setRequestBody({ ...(generalInitFormRef.current.get?.call(null) ?? {}), ...(networkInitFormRef.current.get?.call(null) ?? { networks: [], }), }); setIsOpenConfirm(true); }} > Initialize ), [isDisableSubmit, isSubmittingForm], ); const toggleSubmitDisabled = useCallback((...testResults: boolean[]) => { setIsDisableSubmit(!testResults.every((testResult) => testResult)); }, []); useEffect(() => { if (!isReady) return; if (!reconfig) { setPanelTitle('Initialize striker'); return; } if (!allowGetHostDetail.current) return; allowGetHostDetail.current = false; api .get('/host/local') .then(({ data }) => { setHostDetail(data); setPanelTitle(`Reconfigure ${data.shortHostName}`); }) .catch((error) => { const emsg = handleAPIError(error); emsg.children = <>Failed to get host detail data. {emsg.children}; setSubmitMessage(emsg); }); }, [isReady, reconfig, setHostDetail]); return ( <> {panelTitle} { jobSummaryRef.current.setAnchor?.call(null, currentTarget); jobSummaryRef.current.setOpen?.call(null, true); }} variant="normal" > { setHostNumber(value); }} ref={generalInitFormRef} toggleSubmitDisabled={(testResult) => { if (testResult !== isGeneralInitFormValid) { setIsGeneralInitFormValid(testResult); toggleSubmitDisabled(testResult, isNetworkInitFormValid); } }} /> { if (testResult !== isNetworkInitFormValid) { setIsNetworkInitFormValid(testResult); toggleSubmitDisabled(isGeneralInitFormValid, testResult); } }} /> {submitMessage && ( setSubmitMessage(undefined)} /> )} {buildSubmitSection} Organization name {requestBody?.organizationName} Organization prefix {requestBody?.organizationPrefix} Striker number {requestBody?.hostNumber} Domain name {requestBody?.domainName} Host name {requestBody?.hostName} Networks {requestBody?.networks.map( ({ inputUUID, interfaces, ipAddress, name, subnetMask, type, typeCount, }) => ( {name} ( {`${type.toUpperCase()}${typeCount}`} ) {interfaces.map((iface, ifaceIndex) => { let key = `network-confirm-${inputUUID}-interface${ifaceIndex}`; let ifaceName = 'none'; if (iface) { const { networkInterfaceName, networkInterfaceUUID } = iface; key = `${key}-${networkInterfaceUUID}`; ifaceName = networkInterfaceName; } return ( {`Link ${ifaceIndex + 1}`} {ifaceName} ); })} {`${ipAddress}/${subnetMask}`} ), )} Gateway {requestBody?.gateway} Gateway network {requestBody?.gatewayInterface?.toUpperCase()} Domain name server(s) {requestBody?.dns} } dialogProps={{ open: isOpenConfirm }} onCancelAppend={() => { setIsOpenConfirm(false); }} onProceedAppend={() => { setSubmitMessage(undefined); setIsSubmittingForm(true); setIsOpenConfirm(false); api .put('/init', requestBody) .then(() => { setIsSubmittingForm(false); setSubmitMessage({ children: reconfig ? ( <>Successfully initiated reconfiguration. ) : ( <> Successfully registered the configuration job! You can check the progress at the top right icon. Once the job completes, you can access the{' '} login page . ), type: 'info', }); }) .catch((error) => { const errorMessage = handleAPIError(error); setSubmitMessage(errorMessage); setIsSubmittingForm(false); }); }} titleText="Confirm striker initialization" /> `${API_BASE_URL}/init/job?start=${epoch}`} onFetchSuccessAppend={(jobs) => { jobIconRef.current.indicate?.call(null, Object.keys(jobs).length > 0); }} ref={jobSummaryRef} /> ); }; export default StrikerInitForm;