import { Grid } from '@mui/material'; import { FC, useMemo, useRef, useState } from 'react'; import API_BASE_URL from '../../lib/consts/API_BASE_URL'; import NETWORK_TYPES from '../../lib/consts/NETWORK_TYPES'; import api from '../../lib/api'; import ConfirmDialog from '../ConfirmDialog'; import FlexBox from '../FlexBox'; import handleAPIError from '../../lib/handleAPIError'; import List from '../List'; import MessageBox, { Message } from '../MessageBox'; import { ExpandablePanel } from '../Panels'; import periodicFetch from '../../lib/fetchers/periodicFetch'; import State from '../State'; import { BodyText, MonoText, SmallText } from '../Text'; import useProtect from '../../hooks/useProtect'; import useProtectedState from '../../hooks/useProtectedState'; const ConfigPeersForm: FC = ({ refreshInterval = 30000, }) => { const { protect } = useProtect(); const confirmDialogRef = useRef({}); const [apiMessage, setAPIMessage] = useProtectedState( undefined, protect, ); const [confirmDialogProps, setConfirmDialogProps] = useState({ actionProceedText: '', content: '', titleText: '', }); const [inboundConnections, setInboundConnections] = useProtectedState({}, protect); const [isEditPeerConnections, setIsEditPeerConnections] = useState(false); const [peerConnections, setPeerConnections] = useProtectedState({}, protect); const apiMessageElement = useMemo( () => apiMessage ? ( ) : undefined, [apiMessage], ); const { isLoading } = periodicFetch( `${API_BASE_URL}/host/connection`, { refreshInterval, onError: (error) => { setAPIMessage({ children: `Failed to get connection data. Error: ${error}`, type: 'error', }); }, onSuccess: ({ local: { inbound: { ipAddress: ipAddressList, port: dbPort, user: dbUser }, peer, }, }) => { setInboundConnections( Object.entries(ipAddressList).reduce( ( previous, [ipAddress, { networkLinkNumber, networkNumber, networkType }], ) => { previous[ipAddress] = { dbPort, dbUser, ipAddress, networkLinkNumber, networkNumber, networkType, }; return previous; }, {}, ), ); setPeerConnections( Object.entries(peer).reduce( ( previous, [ peerIPAddress, { hostUUID, isPing: isPingTest, port: peerDBPort, user: peerDBUser, }, ], ) => { previous[`${peerDBUser}@${peerIPAddress}:${peerDBPort}`] = { dbPort: peerDBPort, dbUser: peerDBUser, hostUUID, ipAddress: peerIPAddress, isPingTest, }; return previous; }, {}, ), ); }, }, ); return ( <> Configure striker peers} loading={isLoading} > No inbound connections found. } listItemKeyPrefix="config-peers-inbound-connection" listItems={inboundConnections} renderListItem={( ipAddress, { dbPort, dbUser, networkNumber, networkType }, ) => ( {`${dbUser}@${ipAddress}:${dbPort}`} {`${NETWORK_TYPES[networkType]} ${networkNumber}`} )} /> No peer connections found. } listItemKeyPrefix="config-peers-peer-connection" listItems={peerConnections} onDelete={() => { const pairs = Object.entries(peerConnections); const { body: deleteRequestBody, post: remainingPeerConnections, } = pairs.reduce<{ body: APIDeleteHostConnectionRequestBody; post: PeerConnectionList; }>( (previous, [key, value]) => { const { hostUUID, isChecked } = value; if (isChecked) { previous.body.local.push(hostUUID); } else { previous.post[key] = value; } return previous; }, { body: { local: [] }, post: {} }, ); const deleteCount = deleteRequestBody.local.length; if (deleteCount > 0) { setConfirmDialogProps({ actionProceedText: 'Delete', content: `The peer relationship between this striker and the selected ${deleteCount} host(s) will terminate. The removed peer(s) can be re-added later.`, onProceedAppend: () => { api .delete('/host/connection', { data: deleteRequestBody }) .then(() => { setPeerConnections(remainingPeerConnections); }) .catch((error) => { const emsg = handleAPIError(error); emsg.children = `Failed to delete peer connection(s). ${emsg.children}`; setAPIMessage(emsg); }); }, proceedColour: 'red', titleText: `Delete ${deleteCount} peer(s) from this striker?`, }); confirmDialogRef.current.setOpen?.call(null, true); } }} onEdit={() => { setIsEditPeerConnections((previous) => !previous); }} onItemCheckboxChange={(key, event, isChecked) => { peerConnections[key].isChecked = isChecked; setPeerConnections((previous) => ({ ...previous })); }} renderListItem={(peer, { isPingTest = false }) => ( {peer} )} /> {apiMessageElement} ); }; export default ConfigPeersForm;