From 8161a07dba401f04dac93f861e6b2cffe53ab7e3 Mon Sep 17 00:00:00 2001
From: Vendicated <vendicated@riseup.net>
Date: Sat, 1 Oct 2022 00:42:50 +0200
Subject: Add in client updater, Notices API

---
 src/components/Updater.tsx | 128 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 src/components/Updater.tsx

(limited to 'src/components/Updater.tsx')

diff --git a/src/components/Updater.tsx b/src/components/Updater.tsx
new file mode 100644
index 0000000..e7b6d54
--- /dev/null
+++ b/src/components/Updater.tsx
@@ -0,0 +1,128 @@
+import gitHash from "git-hash";
+import { changes, checkForUpdates, getRepo, rebuild, update, UpdateLogger } from "../utils/updater";
+import { React, Forms, Button, Margins, Alerts, Card, Parser } from '../webpack/common';
+import { Flex } from "./Flex";
+import { useAwaiter } from '../utils/misc';
+import { Link } from "./Link";
+
+interface Props {
+    setIsOutdated(b: boolean): void;
+}
+
+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 function Updater(p: Props) {
+    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]);
+
+    return (
+        <>
+            <Forms.FormText>Repo: {repoPending ? repo : err ? "Failed to retrieve - check console" : (
+                <Link href={repo}>
+                    {repo.split("/").slice(-2).join("/")}
+                </Link>
+            )} ({gitHash})</Forms.FormText>
+
+            <Forms.FormText className={Margins.marginBottom8}>
+                There are {updates.length} Updates
+            </Forms.FormText>
+
+            <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}`}>
+                <Button
+                    size={Button.Sizes.SMALL}
+                    disabled={isUpdating || isChecking}
+                    onClick={withDispatcher(setIsUpdating, async () => {
+                        if (await update()) {
+                            p.setIsOutdated(false);
+                            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
+                </Button>
+                <Button
+                    size={Button.Sizes.SMALL}
+                    disabled={isUpdating || isChecking}
+                    onClick={withDispatcher(setIsChecking, async () => {
+                        const res = await checkForUpdates();
+                        if (res) {
+                            setUpdates(changes);
+                        } else {
+                            p.setIsOutdated(false);
+                        }
+                    })}
+                >
+                    Refresh
+                </Button>
+            </Flex>
+        </>
+    );
+}
-- 
cgit 

