import gitHash from "git-hash"; import { changes, checkForUpdates, getRepo, rebuild, update, UpdateLogger } from "../utils/updater"; import { React, Forms, Button, Margins, Alerts, Card, Parser, Toasts } from '../webpack/common'; import { Flex } from "./Flex"; import { useAwaiter } from '../utils/misc'; import { Link } from "./Link"; import ErrorBoundary from "./ErrorBoundary"; function withDispatcher(dispatcher: React.Dispatch<React.SetStateAction<boolean>>, action: () => any) { return async () => { dispatcher(true); try { await action(); } catch (e: any) { UpdateLogger.error("Failed to update", e); if (!e) { var err = "An unknown error occurred (error is undefined).\nPlease try again."; } else if (e.code && e.cmd) { const { code, path, cmd, stderr } = e; if (code === "ENOENT") var err = `Command \`${path}\` not found.\nPlease install it and try again`; else { var err = `An error occured while running \`${cmd}\`:\n`; err += stderr || `Code \`${code}\`. See the console for more info`; } } else { var err = "An unknown error occurred. See the console for more info."; } Alerts.show({ title: "Oops!", body: err.split("\n").map(line => <div>{Parser.parse(line)}</div>) }); } finally { dispatcher(false); } }; }; export default ErrorBoundary.wrap(function Updater() { const [repo, err, repoPending] = useAwaiter(getRepo, "Loading..."); const [isChecking, setIsChecking] = React.useState(false); const [isUpdating, setIsUpdating] = React.useState(false); const [updates, setUpdates] = React.useState(changes); React.useEffect(() => { if (err) UpdateLogger.error("Failed to retrieve repo", err); }, [err]); const isOutdated = updates.length > 0; return ( <Forms.FormSection tag="h1" title="Vencord Updater"> <Forms.FormTitle tag="h5">Repo</Forms.FormTitle> <Forms.FormText>{repoPending ? repo : err ? "Failed to retrieve - check console" : ( <Link href={repo}> {repo.split("/").slice(-2).join("/")} </Link> )} ({gitHash})</Forms.FormText> <Forms.FormDivider /> <Forms.FormTitle tag="h5">Updates</Forms.FormTitle> <Forms.FormText className={Margins.marginBottom8}> {updates.length ? `There are ${updates.length} Updates` : "Up to Date!"} </Forms.FormText> {updates.length > 0 && ( <Card style={{ padding: ".5em" }}> {updates.map(({ hash, author, message }) => ( <div> <Link href={`${repo}/commit/${hash}`} disabled={repoPending}> <code>{hash}</code> </Link> <span style={{ marginLeft: "0.5em", color: "var(--text-normal)" }}>{message} - {author}</span> </div> ))} </Card> )} <Flex className={`${Margins.marginBottom8} ${Margins.marginTop8}`}> {isOutdated && <Button size={Button.Sizes.SMALL} disabled={isUpdating || isChecking} onClick={withDispatcher(setIsUpdating, async () => { if (await update()) { const needFullRestart = await rebuild(); await new Promise<void>(r => { Alerts.show({ title: "Update Success!", body: "Successfully updated. Restart now to apply the changes?", confirmText: "Restart", cancelText: "Not now!", onConfirm() { if (needFullRestart) window.DiscordNative.app.relaunch(); else location.reload(); r(); }, onCancel: r }); }); } })} > Update Now </Button>} <Button size={Button.Sizes.SMALL} disabled={isUpdating || isChecking} onClick={withDispatcher(setIsChecking, async () => { const outdated = await checkForUpdates(); if (outdated) { setUpdates(changes); } else { Toasts.show({ message: "No updates found!", id: Toasts.genId(), type: Toasts.Type.MESSAGE, options: { position: Toasts.Position.BOTTOM } }); } })} > Check for Updates </Button> </Flex> </Forms.FormSection> ); });