import { useState, useEffect, useCallback, useMemo, SetStateAction, Dispatch } from "react"; import { ConfirmationDialog } from "@ess-ics/ce-ui-common"; import { Box, Button, Typography, Grid, Tooltip, TextField, CircularProgress, Autocomplete } from "@mui/material"; import { AccessControl } from "../../auth/AccessControl"; import { useTypingTimer } from "../../../hooks/useTypingTimer"; import { HostInfoWithId, IocDetails, useLazyListHostsQuery } from "../../../store/deployApi"; import { useUpdateActiveDeploymentHostMutation } from "../../../store/enhancedApi"; import { useCustomSnackbar } from "../../common/snackbar"; import { getErrorState } from "../../common/Alerts/AlertsData"; interface ChangeHostAdminProps { ioc: IocDetails; buttonDisabled: boolean; setButtonDisabled: Dispatch<SetStateAction<boolean>>; } export const ChangeHostAdmin = ({ ioc, buttonDisabled, setButtonDisabled }: ChangeHostAdminProps) => { const initHost = useMemo( () => ({ fqdn: ioc?.activeDeployment?.host?.fqdn, hostId: ioc?.activeDeployment?.host?.hostId }), [ioc?.activeDeployment?.host] ); const [host, setHost] = useState<HostInfoWithId | null>(initHost); const [open, setOpen] = useState(false); const { value: query, onKeyUp: onHostKeyUp } = useTypingTimer({ interval: 500 }); const { showSuccess } = useCustomSnackbar(); const [getHosts, { data: hosts, isLoading: loadingHosts }] = useLazyListHostsQuery(); const [updateHost, { isLoading, data: updatedIoc, error: updateHostError }] = useUpdateActiveDeploymentHostMutation(); const noModification = useCallback( () => !host || host?.hostId === ioc?.activeDeployment?.host?.hostId, [host, ioc] ); const onClose = useCallback(() => { setOpen(false); setHost(initHost); }, [setOpen, initHost]); const onConfirm = useCallback(() => { if (ioc.id) { setButtonDisabled(true); updateHost({ iocId: ioc.id, updateHostRequest: { hostId: host?.hostId } }) .unwrap() .then(() => { showSuccess("IOC host changed successfully"); setButtonDisabled(false); }) .catch(() => { setButtonDisabled(false); }); } }, [updateHost, ioc, host?.hostId, setButtonDisabled, showSuccess]); useEffect(() => { if (updatedIoc) { setHost({ // Schema change related. Wait until all files have been migrated fqdn: updatedIoc?.activeDeployment?.host?.fqdn, hostId: updatedIoc?.activeDeployment?.host?.hostId }); setButtonDisabled(false); } }, [updatedIoc, setButtonDisabled]); useEffect(() => { getHosts({ text: `${query}` }); }, [query, getHosts]); let disabledButtonTitle = ""; if (buttonDisabled || ioc.operationInProgress) { disabledButtonTitle = "There is an ongoing operation, you cannot 'undeploy' the IOC right now"; } else { if (!ioc.activeDeployment) { disabledButtonTitle = "IOC has no active deployment"; } } return ( <> <AccessControl allowedRoles={["DeploymentToolAdmin"]} renderNoAccess={() => <></>} > <ConfirmationDialog title={ <Typography variant="h2" marginY={1} > Administratively change host </Typography> } content={ <> <Typography component="span"> Are you sure you want to update the IOC to be specified as deployed on <Typography component="span" fontFamily="monospace" > {" "} {host?.fqdn} </Typography>{" "} ? </Typography> </> } confirmText="Modify Host" cancelText="Cancel" open={open} onCancel={onClose} onClose={onClose} onConfirm={onConfirm} isLoading={isLoading} error={updateHostError && getErrorState(updateHostError).message} /> <Box sx={{ pt: 2 }}> <Typography sx={{ my: 2.5 }} component="h2" variant="h3" > Change deployment host (e.g. if host has been replaced in NetBox) </Typography> <Grid container spacing={1} > <Grid item xs={12} > <Autocomplete autoHighlight id="host" options={query ? (hosts?.netBoxHosts ?? []) : []} loading={loadingHosts} clearOnBlur={false} value={host} getOptionLabel={(option) => { return option?.fqdn ?? ""; }} renderInput={(params) => ( <TextField {...params} label="host" variant="outlined" required InputProps={{ ...params.InputProps, endAdornment: ( <> {loadingHosts ? ( <CircularProgress color="inherit" size={20} /> ) : null} {params.InputProps.endAdornment} </> ) }} /> )} onChange={(_event, value: HostInfoWithId | null) => { setHost(value); }} onInputChange={(event) => { if (event) { onHostKeyUp(event as React.KeyboardEvent<HTMLInputElement>); } }} autoSelect filterOptions={(options) => options} /> </Grid> <Grid item xs={12} > <Tooltip title={disabledButtonTitle}> <span> <Button color="primary" variant="contained" onClick={() => setOpen(true)} disabled={ buttonDisabled || ioc.operationInProgress || !ioc.activeDeployment || isLoading || noModification() } > Change host </Button> </span> </Tooltip> </Grid> </Grid> </Box> </AccessControl> </> ); };