frontend/app/PremiereVersionChange/PremiereVersionChange.tsx (288 lines of code) (raw):

import React, { useEffect, useState } from "react"; import { Helmet } from "react-helmet"; import { Button, Grid, LinearProgress, Link, Paper, Typography, } from "@material-ui/core"; import { RouteComponentProps } from "react-router-dom"; import { parse } from "query-string"; import { lookupProjectFile, lookupVersion, performConversion, } from "./VersionChangeService"; import { CheckCircle, Error } from "@material-ui/icons"; import { useHistory } from "react-router"; import { getFileStorageMetadata, getOpenUrl, } from "../ProjectEntryList/helpers"; import { useGuardianStyles } from "~/misc/utils"; const largestSupportedFile = 10485760; //don't try to convert anything bigger than 10meg, it's unreliable interface PremiereVersionChangeParams { project: string; requiredVersion: string; } const PremiereVersionChange: React.FC<RouteComponentProps> = (props) => { const classes = useGuardianStyles(); const [loading, setLoading] = useState(true); const [lastError, setLastError] = useState<string | undefined>(undefined); const [projectName, setProjectName] = useState(""); const [requiredVersion, setRequiredVersion] = useState(""); const [targetVersionName, setTargetVersionName] = useState(""); const [fileId, setFileId] = useState<number | undefined>(undefined); const [fileSize, setFileSize] = useState<number | undefined>(undefined); const [failedLarge, setFailedLarge] = useState(false); const [conversionInProgress, setConversionInProgress] = useState(false); const [newOpenUrl, setNewOpenUrl] = useState<string | undefined>(undefined); const [popupBlocked, setPopupBlocked] = useState(false); const history = useHistory(); useEffect(() => { try { const parsedParams = (parse( props.location.search ) as unknown) as PremiereVersionChangeParams; if ( parsedParams.project == undefined || parsedParams.requiredVersion == undefined ) { setLastError( "invalid arguments, missing either project or requiredVersion" ); return; } setProjectName(parsedParams.project); setRequiredVersion(parsedParams.requiredVersion); } catch (err) { console.error("Could not parse url parameters: ", err); setLastError(err.toString()); setLoading(false); } }, []); useEffect(() => { if (requiredVersion != "") { lookupVersion(requiredVersion) .then((result) => setTargetVersionName(result.name)) .catch((err) => setLastError(err)) .finally(() => setLoading(false)); } }, [requiredVersion]); useEffect(() => { if (projectName != "") { lookupProjectFile(projectName) .then((fileEntry) => setFileId(fileEntry.id)) .catch((err) => setLastError(err)) .finally(() => setLoading(false)); } }, [projectName]); useEffect(() => { if (!!fileId) { setLoading(true); getFileStorageMetadata(fileId) .then((meta) => { console.log("Got file metadata of ", meta, " for ", fileId); const sizeString = meta.get("size"); const sizeNum = sizeString ? parseInt(sizeString, 10) : undefined; console.log("File size is ", sizeNum); setFileSize(sizeNum); }) .catch((err) => { console.error( "Could not get file storage metadata for ", fileId, ": ", err ); }) .finally(() => setLoading(false)); } }, [fileId]); /** * User does not want to continue. If the window was opened directly then close it, otherwise go back to the root page. */ const goBack = () => { if (document.referrer == "") { console.log("Page was opened directly"); window.close(); } else { history.push("/"); } }; const forceOpenUrl = () => `pluto:openproject:${projectName}?premiereVersion=${requiredVersion}&force=true`; /** * User wants to open the project anyway. Ask plutohelperagent to do so. */ const forceOpen = () => { window.open(forceOpenUrl(), "_blank"); }; /** * User wants to convert the project */ const startConversion = async () => { setConversionInProgress(true); //this will disable the controlling buttons if (fileId && requiredVersion) { try { const updatedFile = await performConversion(fileId, requiredVersion); const openUrl = await getOpenUrl(updatedFile, -1); setNewOpenUrl(openUrl); setConversionInProgress(false); } catch (err) { if (err == "The target file is already at the requested version") { setLastError("No update was required"); setNewOpenUrl(forceOpenUrl); setConversionInProgress(false); } else { console.error(err); if (fileSize && fileSize > largestSupportedFile) { setFailedLarge(true); } if (typeof err == "string") { setLastError(err); } else { setLastError(err.toString()); } setConversionInProgress(false); } } } else { console.error( "either fileId or requiredVersion was not set, can't start a conversion" ); } }; /** * try to open the new file once we have it */ useEffect(() => { if (newOpenUrl && newOpenUrl !== "") { const newWindow = window.open(newOpenUrl, "_blank"); if (!newWindow) { setPopupBlocked(true); } else { // Successfully opened a new window, close this one. window.close(); } } }, [newOpenUrl]); return ( <> <Helmet> <title>Change Premiere project version</title> </Helmet> <Paper elevation={3}> <Typography variant="h2" style={{ textAlign: "center" }}> Change Premiere project's version </Typography> {loading || conversionInProgress ? <LinearProgress /> : undefined} {failedLarge ? ( <Typography className={classes.centered}> This project is too large to be automatically updated to a newer version of Adobe Premiere by Pluto. Please contact multimediatech@theguardian.com for assistance. <br /> <br /> If you need to open this urgently then make sure you choose the "Open Anyway" button. As the project opens, Premiere Pro will request you to rename the project file. Make sure you remove the "_1" bit that is added to the end of the filename and click save. Then let it overwrite when prompted. </Typography> ) : undefined} {lastError ? ( <Typography className={classes.centered}> <Error className={classes.error} style={{ verticalAlign: "bottom", marginRight: "0.2em" }} /> {lastError} </Typography> ) : undefined} {!lastError && projectName && requiredVersion && targetVersionName ? ( <Typography className={classes.centered}> In order to successfully open this project on your workstation, it must be updated to the Premiere version {targetVersionName} ( {requiredVersion}) format. <br /> Click 'Update it' below to automatically complete this process. The existing project will be backed up in the system and the new version will be opened in Premiere. <br /> If you have any issues with the converted project, please contact Multimediatech who can restore the old version for you. </Typography> ) : undefined} {!lastError && fileId && requiredVersion && !newOpenUrl ? ( <Grid container spacing={3} justifyContent="space-around" className={classes.buttonContainer} > <Grid item> <Button variant="contained" color="secondary" onClick={startConversion} disabled={conversionInProgress} > Update it </Button> </Grid> <Grid item> <Button variant="outlined" onClick={forceOpen} disabled={conversionInProgress} > Open anyway </Button> </Grid> <Grid item> <Button variant="outlined" onClick={goBack} disabled={conversionInProgress} > Don't try to open it </Button> </Grid> </Grid> ) : undefined} {popupBlocked ? ( <Grid container direction="column" spacing={2}> <Grid item style={{ marginLeft: "auto", marginRight: "auto", width: "100px", }} > <CheckCircle className={classes.success} /> </Grid> <Grid item> <Typography className={classes.centered} style={{ fontWeight: "bold", fontSize: "1.5em" }} > Ready to go! Please click{" "} <Button variant="contained" color="primary" onClick={() => { const newWindow = window.open(newOpenUrl); if (newWindow) { window.close(); } }} style={{ cursor: "pointer" }} > here </Button>{" "} to open project </Typography> </Grid> </Grid> ) : undefined} {newOpenUrl || lastError ? ( <Typography className={classes.centered}> You can now close this tab </Typography> ) : undefined} </Paper> </> ); }; export default PremiereVersionChange;