frontend/app/generalinfocell.tsx (204 lines of code) (raw):
import React, { useEffect, useState } from "react";
import { useStyles } from "./mainpage";
import {
Button,
Dialog,
Grid,
LinearProgress,
makeStyles,
Typography,
} from "@material-ui/core";
import {
getLatestBuild,
getLatestMainlineBuild,
requestUpdate,
} from "./getbuilds";
import DockerImageName from "./dockerimagename";
import NeedsUpdate, { Updates } from "./needsupdate";
import clsx from "clsx";
import {
SystemNotification,
SystemNotifcationKind,
} from "@guardian/pluto-headers";
import { Error } from "@material-ui/icons";
interface GeneralInfoCellProps {
deploymentInfo: DeployedImageInfo;
gitRef?: string;
onUpdateInitiated?: () => void;
hideOn404?: boolean;
}
const localStyles = makeStyles((theme) => ({
inline: {
display: "inline",
},
warning: {
color: theme.palette.warning.dark,
},
updateDialog: {
padding: "1em",
},
}));
const GeneralInfoCell: React.FC<GeneralInfoCellProps> = (props) => {
const [masterBuild, setMasterBuild] =
useState<BuildInfo | undefined>(undefined);
const [loading, setLoading] = useState(true);
const [notFound, setNotFound] = useState(false);
const [showingDialog, setShowingDialog] = useState(false);
const [updateType, setUpdateType] = useState("");
const [failureMessage, setFailureMessage] =
useState<string | undefined>(undefined);
const classes = localStyles();
useEffect(() => {
const buildInfoPromise = props.gitRef
? getLatestBuild(props.deploymentInfo, props.gitRef)
: getLatestMainlineBuild(props.deploymentInfo);
buildInfoPromise
.then((info) => {
if (info) {
setMasterBuild(info);
} else {
setNotFound(true);
}
setLoading(false);
})
.catch((err) => {
setLoading(false);
console.error("Could not get master build info");
if (err.toString().includes("404")) {
if (!props.hideOn404) {
setFailureMessage(err.toString()); //don't set failure message if we are told to hide on 404
}
} else {
setFailureMessage(err.toString());
}
});
}, [props.deploymentInfo]);
const updateRequested = (updateType: string) => {
console.log("update requested: ", updateType);
setUpdateType(updateType);
setShowingDialog(true);
};
const handleDialogClose = () => {
setShowingDialog(false);
};
const performUpdate = () => {
setShowingDialog(false);
if (masterBuild?.built_image) {
requestUpdate(
masterBuild.built_image,
props.deploymentInfo.deploymentName
)
.then(() =>
props.onUpdateInitiated ? props.onUpdateInitiated() : null
)
.catch((err) => {
console.error(err);
SystemNotification.open(
SystemNotifcationKind.Error,
"Internal error occurred and the reqeust was not sent. See console for details."
);
});
} else {
SystemNotification.open(
SystemNotifcationKind.Error,
"Can't request update if there is no current build set"
);
}
};
return (
<>
{props.children}
{loading ? <LinearProgress variant="indeterminate" /> : null}
{failureMessage ? (
<Typography id="error-message">
<Error />
Could not determine available versions: {failureMessage}
</Typography>
) : null}
{masterBuild?.built_image ? (
<>
<NeedsUpdate
deployment={props.deploymentInfo}
available={masterBuild}
updateRequested={updateRequested}
/>
<Typography className={classes.inline}>Latest version is</Typography>
<DockerImageName image={masterBuild.built_image} />
<Typography className={classes.inline} id="build-date">
built at {masterBuild.ci_commit_timestamp}
</Typography>
</>
) : null}
{notFound ? (
<Typography>
No builds could be found. Is the deployment missing the
'gitlab-project-id' tag?
</Typography>
) : null}
{showingDialog && updateType == Updates.NotRequired ? (
<Dialog
classes={{ paper: classes.updateDialog }}
open={showingDialog}
onClose={handleDialogClose}
>
<Typography variant="h4">
Update {props.deploymentInfo.deploymentName}
</Typography>
<Typography>No update is required at the moment</Typography>
<hr />
<Button variant="outlined" onClick={handleDialogClose}>
Close
</Button>
</Dialog>
) : null}
{showingDialog && updateType == Updates.Downgrade ? (
<Dialog
classes={{ paper: classes.updateDialog }}
open={showingDialog}
onClose={handleDialogClose}
>
<Typography variant="h4">
Downgrade {props.deploymentInfo.deploymentName}
</Typography>
<Typography className={clsx(classes.inline, classes.warning)}>
WARNING
</Typography>
<Typography>
The currently running version is potentially later than the one you
are trying to deploy. Continuing may result in a loss of
functionality and could cause problems if any data schemas have been
updated in the later running version. Please ensure that you are
aware of the code differences between the versions before
continuing.
</Typography>
<hr />
<Grid container justify="space-between">
<Grid item>
<Button variant="outlined" onClick={handleDialogClose}>
Cancel
</Button>
</Grid>
<Grid item>
<Button variant="contained" onClick={performUpdate}>
Downgrade
</Button>
</Grid>
</Grid>
</Dialog>
) : null}
{showingDialog && updateType == Updates.Upgrade ? (
<Dialog
classes={{ paper: classes.updateDialog }}
open={showingDialog}
onClose={handleDialogClose}
>
<Typography variant="h4">
Upgrade {props.deploymentInfo.deploymentName}
</Typography>
<Typography>
The current deployment will be upgraded to the latest version from{" "}
{masterBuild?.ci_commit_ref_name}.
</Typography>
<Typography>
Please be aware that this might expect data schema changes or other
external changes that can't be managed through this app.
</Typography>
<Typography>
Please ensure that you are aware of any code differences between the
versions before continuing
</Typography>
{masterBuild?.ci_merge_request_project_url ? (
<Typography>
Merge request details are at{" "}
<a href={masterBuild.ci_merge_request_project_url}>
{masterBuild.ci_merge_request_project_url}
</a>
</Typography>
) : null}
<hr />
<Grid container justify="space-between">
<Grid item>
<Button variant="outlined" onClick={handleDialogClose}>
Cancel
</Button>
</Grid>
<Grid item>
<Button variant="contained" onClick={performUpdate}>
Upgrade
</Button>
</Grid>
</Grid>
</Dialog>
) : null}
</>
);
};
export default GeneralInfoCell;