frontend/app/ProjectEntryList/BackupEntry.tsx (158 lines of code) (raw):

import React, { useEffect, useState } from "react"; import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, ListItem, ListItemIcon, ListItemText, Typography, } from "@material-ui/core"; import { FileCopy } from "@material-ui/icons"; import { getFileStorageMetadata } from "./helpers"; import { format, parseISO } from "date-fns"; import { DEFAULT_DATE_FORMAT } from "../../types/constants"; import SizeFormatter from "../common/SizeFormatter"; import { useGuardianStyles } from "~/misc/utils"; import axios from "axios"; import { SystemNotification, SystemNotifcationKind, } from "@guardian/pluto-headers"; interface BackupEntryProps { fileId: number; filepath: string; version: number; premiereVersion?: number; projectId?: number; } const BackupEntry: React.FC<BackupEntryProps> = (props) => { const classes = useGuardianStyles(); const [fileMeta, setFileMeta] = useState<Map<string, string>>(new Map()); const [loadError, setLoadError] = useState(false); const [openDialog, setOpenDialog] = useState(false); useEffect(() => { getFileStorageMetadata(props.fileId) .then((info) => { const maybeISOTime = info.get("lastModified"); if (maybeISOTime) { try { const d = parseISO(maybeISOTime); info.set("lastModified", format(d, DEFAULT_DATE_FORMAT)); } catch (err) { console.log(`Could not parse date value ${maybeISOTime}: ${err}`); } } setFileMeta(info); }) .catch((err) => { console.error("Could not load file information: ", err); setLoadError(true); }); }, [props.fileId]); const handleClickOpenDialog = () => { setOpenDialog(true); }; const handleCloseDialog = () => { setOpenDialog(false); }; const handleConfirmUpload = () => { handleCloseDialog(); handleRestore(); }; const handleRestore = async () => { try { const request = "/api/project/" + props.projectId + "/restore/" + props.version; const response = await axios.put(request, null, { headers: { "Content-Type": "application/json", }, }); console.log(response.data); SystemNotification.open( SystemNotifcationKind.Success, `${response.data.detail}` ); } catch (error) { console.error("Error restoring file:", error); SystemNotification.open( SystemNotifcationKind.Error, `Failed to restore project: ${error}` ); } }; return ( <ListItem> <ListItemIcon> <FileCopy /> </ListItemIcon> <ListItemText disableTypography={true}> <> <Typography className={classes.emphasis}>{props.filepath}</Typography> <Typography>Version {props.version}</Typography> {loadError ? ( <Typography variant="caption"> Could not load file information, see console for details </Typography> ) : ( <> <Typography variant="caption"> File size is <SizeFormatter bytes={fileMeta.get("size")} /> and was backed up at {fileMeta.get("lastModified")} </Typography> {props.premiereVersion ? ( <Typography variant="caption"> {" "} This is a Premiere project at internal version{" "} {props.premiereVersion} </Typography> ) : undefined} </> )} </> </ListItemText> <div> <Button color="secondary" variant="contained" onClick={handleClickOpenDialog} > Restore </Button> {/* Confirmation Dialog */} <Dialog open={openDialog} onClose={handleCloseDialog} aria-labelledby="update-file-dialog-title" aria-describedby="update-file-dialog-description" > <DialogTitle id="update-file-dialog-title"> Confirm Project File Restore </DialogTitle> <DialogContent> <DialogContentText id="update-file-dialog-description"> <strong> Are you sure you want to restore the project file? </strong> <br /> You are about to restore a backed up project file. This action will overwrite the current file. <br /> <br /> </DialogContentText> </DialogContent> <DialogActions> <Button onClick={handleCloseDialog} color="primary"> Cancel </Button> <Button onClick={handleConfirmUpload} color="primary" autoFocus> Proceed </Button> </DialogActions> </Dialog> </div> </ListItem> ); }; export default BackupEntry;