diff --git a/src/api/SwaggerApi.js b/src/api/SwaggerApi.js index c4b25b3f9e68469e51d3af2bd6f12e76b21680c9..773589bce32f24e3debb362e85bc4b4979505558 100644 --- a/src/api/SwaggerApi.js +++ b/src/api/SwaggerApi.js @@ -797,6 +797,16 @@ export function unpackUpdateIoc(updateIoc) { return d; } +export function unpackUndeployInDb(deployment) { + return { ...deployment }; +} + +export function useUndeployInDb(id, onError) { + const api = useContext(apiContext); + const method = useCallAndUnpack(api.apis.Deployments.unDeployInDb, unpackUndeployInDb) + const boundMethod = useCallback(method.bind(null, { iocId: id }), [id]) + return useAsync({ fcn: boundMethod, call: false, onError: onError }); +} export function useAnnouncements() { const api = useContext(apiContext); const method = useCallAndUnpack(api.apis.Broadcasts.fetchAnnouncements, unpackAnnouncement) diff --git a/src/components/IOC/AdministerUndeployment.js b/src/components/IOC/AdministerUndeployment.js new file mode 100644 index 0000000000000000000000000000000000000000..fc2b660325ad664b2ce14f43f771cf73bb98952c --- /dev/null +++ b/src/components/IOC/AdministerUndeployment.js @@ -0,0 +1,113 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { useHistory } from "react-router-dom"; +import { makeStyles } from '@material-ui/core/styles'; +import { Button, Typography, Grid, Tooltip } from "@material-ui/core"; +import { theme } from "../../style/Theme"; +import { useUndeployInDb } from '../../api/SwaggerApi'; +import { SimpleAccordion } from "../common/Accordion/SimpleAccordion"; +import { ConfirmationDialog } from "../dialog/ConfirmationDialog"; +import { SimpleModal } from "../../components/common/SimpleModal/SimpleModal"; +import { Alert } from "@material-ui/lab"; +import AccessControl from '../auth/AccessControl'; + +const useStyles = makeStyles({ + undeployButton: { + backgroundColor: '#aa2e25', + color: '#FFFFFF', + "&:disabled": { + backgroundColor: '#e0e0e0', + color: '#afaba6', + }, + "&:hover": { + backgroundColor: '#6c0000', + color: '#FFFFFF', + } + }, +}); + +export default function AdministerUndeployment({ ioc, buttonDisabled }) { + + const classes = useStyles(theme); + + const history = useHistory(); + + function onError(message) { + setError(message); + } + + //for the dialog + const [error, setError] = useState(); + const [adHocDialogOpen, setAdHocDialogOpen] = useState(false); + const [adHocDialogTitle, setAdHocDiatlogTitle] = useState(); + const [adHocDialogDescription, setAdHocDialogDescription] = useState(); + const callbackRef = useRef(); + + const [response, undeployIOC] = useUndeployInDb(ioc.id, onError); + + //Setting up dialog properties + const openUndeployModal = () => { + setAdHocDiatlogTitle("Administratively 'undeploy' IOC"); + setAdHocDialogDescription( + <> + <Typography style={{ display: 'inline-block' }}>Are you sure want to administer IOC as undeployed </Typography> + <Typography style={{ fontFamily: "monospace", display: 'inline-block' }}> {ioc.namingName}? </Typography> + </>); + callbackRef.current = undeployIoc; + setAdHocDialogOpen(true); + } + + //what to do when "undeploying" the IOC + const undeployIoc = async () => { + undeployIOC(); + } + + useEffect(() => + { + if (response) { + history.goBack(); + } + }, [response, history]); + + let iocIsDeployed = ioc.activeDeployment && !ioc.activeDeployment.undeployment; + + let disabledButtonTitle = ""; + if (buttonDisabled || ioc.operationInProgress) { + disabledButtonTitle = "There is an ongoing operation, you cannot 'undeploy' the IOC right now"; + } else { + if (!iocIsDeployed) { + disabledButtonTitle = "IOC is not deployed, you cannot 'undeploy' it" + } + } + + return ( + <> + <AccessControl allowedRoles={["DeploymentToolAdmin"]} + renderNoAccess={() => + <></> + }> + <> + <SimpleModal open={adHocDialogOpen} setOpen={setAdHocDialogOpen}> + <ConfirmationDialog open={adHocDialogOpen} setOpen={setAdHocDialogOpen} title={adHocDialogTitle} description={adHocDialogDescription} callback={callbackRef.current} /> + </SimpleModal> + + <SimpleAccordion summary="Change deployment status to not deployed (e.g. if IOC has been manually removed)" defaultExpanded> + <Grid container spacing={1}> + {error ? + <Grid item xs={12}> + <Alert severity="error">{error}</Alert> + </Grid> + : <></>} + <Grid item xs={12}> + <Tooltip title={disabledButtonTitle}> + <span> + <Button className={classes.undeployButton} onClick={openUndeployModal} disabled={buttonDisabled || ioc.operationInProgress || !iocIsDeployed} >SET DEPLOYMENT STATE TO NOT DEPLOYED</Button> + </span> + </Tooltip> + </Grid> + </Grid> + </SimpleAccordion> + </> + </AccessControl> + </> + ) +} \ No newline at end of file diff --git a/src/components/IOC/IOCAdmin.js b/src/components/IOC/IOCAdmin.js index 7e84b7dc0df62585a40e8c8b4742c0c285b9f303..c75614616cce47b420133cde2a888465f7bc9cf3 100644 --- a/src/components/IOC/IOCAdmin.js +++ b/src/components/IOC/IOCAdmin.js @@ -1,4 +1,5 @@ import React from 'react'; +import AdministerUndeployment from './AdministerUndeployment'; import IOCDelete from './IOCDelete'; import IOCDetailAdmin from './IOCDetailAdmin'; @@ -7,6 +8,7 @@ export default function IOCAdmin({ ioc, getIOC, resetTab, buttonDisabled }) { return ( <> <IOCDetailAdmin ioc={ioc} getIOC={getIOC} resetTab={resetTab} buttonDisabled={buttonDisabled}/> + <AdministerUndeployment ioc={ioc} buttonDisabled={buttonDisabled} /> <IOCDelete ioc={ioc} buttonDisabled={buttonDisabled} /> </> ); diff --git a/src/components/IOC/IOCDetailAdmin.js b/src/components/IOC/IOCDetailAdmin.js index daca4dc53dd7aec6e9271bd1c55d1df7f05e934a..75157e3154fc2f1ab9d750932d132d2e432d7f47 100644 --- a/src/components/IOC/IOCDetailAdmin.js +++ b/src/components/IOC/IOCDetailAdmin.js @@ -84,20 +84,31 @@ export default function IOCDetailAdmin({ ioc, getIOC, resetTab, buttonDisabled } } }, [uioc, getIOC, resetTab]); + let iocIsDeployed = ioc.activeDeployment && !ioc.activeDeployment.undeployment; + + let nameDisabledTitle = ""; + if (iocIsDeployed) { + nameDisabledTitle = "IOC cannot be renamed while deployed - please undeploy first" + } + function nameAutocomplete(disabled) { - return( - <Autocomplete - className={classes.textField} - autoHighlight - id="namingName" - options={names} - defaultValue={name} - getOptionLabel={(option) => { console.log(option?.name); return option?.name }} - renderInput={(params) => <TextField {...params} label="IOC name" variant="outlined" required />} - onChange={(event, value, reason) => {setName(value); setError(null);}} - onInputChange={(event, value, reason) => { event && onNameKeyUp(event.nativeEvent) }} - disabled={disabled} - /> + return ( + <Tooltip title={nameDisabledTitle}> + <span> + <Autocomplete + className={classes.textField} + autoHighlight + id="namingName" + options={names} + defaultValue={name} + getOptionLabel={(option) => { console.log(option?.name); return option?.name }} + renderInput={(params) => <TextField {...params} label="IOC name" variant="outlined" required />} + onChange={(event, value, reason) => { setName(value); setError(null); }} + onInputChange={(event, value, reason) => { event && onNameKeyUp(event.nativeEvent) }} + disabled={disabled} + /> + </span> + </Tooltip> ); } @@ -133,7 +144,7 @@ export default function IOCDetailAdmin({ ioc, getIOC, resetTab, buttonDisabled } <AccessControl allowedRoles={["DeploymentToolAdmin"]} renderNoAccess={() => nameAutocomplete(true)} > - {nameAutocomplete(false)} + {nameAutocomplete(iocIsDeployed)} </AccessControl> <Autocomplete