diff --git a/src/api/SwaggerApi.js b/src/api/SwaggerApi.js index b1801af20e49fd2398b06a858e8cd8150441d745..db012c898027989cae629bfc0a84d6aead23f404 100644 --- a/src/api/SwaggerApi.js +++ b/src/api/SwaggerApi.js @@ -1100,6 +1100,24 @@ export function useUndeployInDb(id, onError) { const boundMethod = useCallback(method.bind(null, { ioc_id: id }), [id]); return useAsync({ fcn: boundMethod, call: false, onError: onError }); } + +export function unpackUpdateActiveDeploymentHost(ioc) { + return { ...ioc }; +} + +export function useUpdateActiveDeploymentHost(id, onError) { + const api = useContext(apiContext); + const method = useCallAndUnpack( + (body) => + api.apis.IOCs.updateActiveDeploymentHost( + { ioc_id: id }, + { requestBody: body } + ), + unpackUpdateActiveDeploymentHost + ); + return useAsync({ fcn: method, call: false, onError: onError }); +} + export function useAnnouncements() { const api = useContext(apiContext); const method = useCallAndUnpack( diff --git a/src/components/IOC/ChangeHostAdmin.js b/src/components/IOC/ChangeHostAdmin.js new file mode 100644 index 0000000000000000000000000000000000000000..a896052266b8eab96e583b0f92441a98253e468d --- /dev/null +++ b/src/components/IOC/ChangeHostAdmin.js @@ -0,0 +1,217 @@ +import React, { useState, useRef, useEffect, useCallback } from "react"; +import AccessControl from "../auth/AccessControl"; +import { SimpleAccordion } from "../common/Accordion/SimpleAccordion"; +import { + Button, + Typography, + Grid, + Tooltip, + TextField +} from "@material-ui/core"; +import { SimpleModal } from "../../components/common/SimpleModal/SimpleModal"; +import { ConfirmationDialog } from "../dialog/ConfirmationDialog"; +import { + useUpdateActiveDeploymentHost, + useCSEntrySearch +} from "../../api/SwaggerApi"; +import { Alert, Autocomplete } from "@material-ui/lab"; +import { useTypingTimer } from "../common/SearchBoxFilter/TypingTimer"; +import { transformHostQuery } from "../common/Helper"; + +export default function ChangeHostAdmin({ + ioc, + getIOC, + resetTab, + buttonDisabled +}) { + const initHost = { + csEntryHost: { + fqdn: ioc.activeDeployment.host.fqdn, + id: ioc.activeDeployment.host.csEntryId + } + }; + + const [hosts, getHosts] = useCSEntrySearch(); + const [host, setHost] = useState(initHost); + const [query, onHostKeyUp] = useTypingTimer({ interval: 500 }); + + function onError(message) { + setError(message); + } + + const noModification = useCallback( + () => !host || host.csEntryHost.id === ioc.activeDeployment.host.csEntryId, + [host, ioc] + ); + + // for the dialog + const [error, setError] = useState(); + const [adHocDialogOpen, setAdHocDialogOpen] = useState(false); + const [adHocDialogTitle, setAdHocDiatlogTitle] = useState(); + const [adHocDialogDescription, setAdHocDialogDescription] = useState(); + const callbackRef = useRef(); + + const [updatedIoc, updateHost] = useUpdateActiveDeploymentHost( + ioc.id, + onError + ); + const [comment, setComment] = useState(""); + + useEffect(() => { + if (updatedIoc) { + getIOC(); + resetTab(); + } + }, [updatedIoc, getIOC, resetTab]); + + useEffect( + () => getHosts({ query: transformHostQuery(`${query}`) }), + [query, getHosts] + ); + + const openModifyModal = () => { + setAdHocDiatlogTitle("Modifying deployment host"); + setAdHocDialogDescription( + <> + <Typography style={{ display: "inline-block" }}> + Are you sure want to modify deployment host of + </Typography> + <Typography + style={{ fontFamily: "monospace", display: "inline-block" }} + > + {" "} + {ioc.namingName}?{" "} + </Typography> + </> + ); + callbackRef.current = modifyHost; + setAdHocDialogOpen(true); + }; + + const modifyHost = () => { + updateHost({ + hostCSEntryId: host.csEntryHost.id, + comment: comment + }); + }; + + 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={() => <></>} + > + <> + <SimpleModal + open={adHocDialogOpen} + setOpen={setAdHocDialogOpen} + > + <ConfirmationDialog + open={adHocDialogOpen} + setOpen={setAdHocDialogOpen} + title={adHocDialogTitle} + description={adHocDialogDescription} + callback={callbackRef.current} + /> + </SimpleModal> + + <SimpleAccordion + summary="Change deployment host" + defaultExpanded + > + <Grid + container + spacing={1} + > + {error ? ( + <Grid + item + xs={12} + > + <Alert severity="error">{error}</Alert> + </Grid> + ) : ( + <></> + )} + <Grid + item + xs={12} + > + <Autocomplete + autoHighlight + id="host" + options={hosts.hostList} + defaultValue={initHost} + getOptionLabel={(option) => { + return option?.csEntryHost?.fqdn; + }} + renderInput={(params) => ( + <TextField + {...params} + label="host" + variant="outlined" + required + /> + )} + onChange={(event, value, reason) => { + setHost(value); + }} + onInputChange={(event, value, reason) => { + event && onHostKeyUp(event.nativeEvent); + }} + autoSelect + filterOptions={(options, state) => options} + /> + </Grid> + <Grid + item + xs={12} + > + <TextField + id="comment" + autoComplete="off" + label="Deployment comment" + variant="outlined" + onChange={(event) => setComment(event.target.value)} + fullWidth + /> + </Grid> + <Grid + item + xs={12} + > + <Tooltip title={disabledButtonTitle}> + <span> + <Button + color="primary" + variant="contained" + onClick={openModifyModal} + disabled={ + buttonDisabled || + ioc.operationInProgress || + !ioc.activeDeployment || + noModification() + } + > + CHANGE HOST + </Button> + </span> + </Tooltip> + </Grid> + </Grid> + </SimpleAccordion> + </> + </AccessControl> + </> + ); +} diff --git a/src/components/IOC/IOCAdmin.js b/src/components/IOC/IOCAdmin.js index da29d7ed978b23f8192a6355adb59734f06e5c46..9d981f51e1cd6d1916c2ba3d9212c75fbff2939b 100644 --- a/src/components/IOC/IOCAdmin.js +++ b/src/components/IOC/IOCAdmin.js @@ -2,6 +2,7 @@ import React from "react"; import AdministerUndeployment from "./AdministerUndeployment"; import IOCDelete from "./IOCDelete"; import IOCDetailAdmin from "./IOCDetailAdmin"; +import ChangeHostAdmin from "./ChangeHostAdmin"; export default function IOCAdmin({ ioc, getIOC, resetTab, buttonDisabled }) { return ( @@ -12,6 +13,14 @@ export default function IOCAdmin({ ioc, getIOC, resetTab, buttonDisabled }) { resetTab={resetTab} buttonDisabled={buttonDisabled} /> + {ioc.activeDeployment && ( + <ChangeHostAdmin + ioc={ioc} + getIOC={getIOC} + resetTab={resetTab} + buttonDisabled={buttonDisabled} + /> + )} <AdministerUndeployment ioc={ioc} buttonDisabled={buttonDisabled}