2022-10-21 23:17:06 +00:00
|
|
|
/*
|
|
|
|
* Vencord, a modification for Discord's desktop app
|
|
|
|
* Copyright (c) 2022 Vendicated and contributors
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2023-05-05 23:36:00 +00:00
|
|
|
import { useSettings } from "@api/Settings";
|
2022-11-28 12:58:14 +00:00
|
|
|
import { ErrorCard } from "@components/ErrorCard";
|
|
|
|
import { Flex } from "@components/Flex";
|
|
|
|
import { Link } from "@components/Link";
|
2023-03-01 20:35:08 +00:00
|
|
|
import { Margins } from "@utils/margins";
|
2023-05-05 23:36:00 +00:00
|
|
|
import { classes } from "@utils/misc";
|
2023-04-03 23:16:29 +00:00
|
|
|
import { relaunch } from "@utils/native";
|
2023-05-05 23:36:00 +00:00
|
|
|
import { useAwaiter } from "@utils/react";
|
2023-05-02 00:50:51 +00:00
|
|
|
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
|
2023-03-01 20:35:08 +00:00
|
|
|
import { Alerts, Button, Card, Forms, Parser, React, Switch, Toasts } from "@webpack/common";
|
2022-11-28 12:37:55 +00:00
|
|
|
|
2022-10-23 21:23:52 +00:00
|
|
|
import gitHash from "~git-hash";
|
2022-10-22 16:18:41 +00:00
|
|
|
|
2023-05-11 23:40:43 +00:00
|
|
|
import { SettingsTab, wrapTab } from "./shared";
|
|
|
|
|
2022-09-30 22:42:50 +00:00
|
|
|
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!",
|
2022-10-02 00:46:41 +00:00
|
|
|
body: (
|
|
|
|
<ErrorCard>
|
|
|
|
{err.split("\n").map(line => <div>{Parser.parse(line)}</div>)}
|
|
|
|
</ErrorCard>
|
|
|
|
)
|
2022-09-30 22:42:50 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
finally {
|
|
|
|
dispatcher(false);
|
|
|
|
}
|
|
|
|
};
|
2022-10-08 18:36:57 +00:00
|
|
|
}
|
2022-09-30 22:42:50 +00:00
|
|
|
|
2022-10-05 15:09:37 +00:00
|
|
|
interface CommonProps {
|
|
|
|
repo: string;
|
|
|
|
repoPending: boolean;
|
|
|
|
}
|
2022-10-01 20:09:20 +00:00
|
|
|
|
2023-01-03 01:30:54 +00:00
|
|
|
function HashLink({ repo, hash, disabled = false }: { repo: string, hash: string, disabled?: boolean; }) {
|
|
|
|
return <Link href={`${repo}/commit/${hash}`} disabled={disabled}>
|
|
|
|
{hash}
|
|
|
|
</Link>;
|
|
|
|
}
|
|
|
|
|
2022-10-05 15:09:37 +00:00
|
|
|
function Changes({ updates, repo, repoPending }: CommonProps & { updates: typeof changes; }) {
|
2022-09-30 22:42:50 +00:00
|
|
|
return (
|
2022-10-05 15:09:37 +00:00
|
|
|
<Card style={{ padding: ".5em" }}>
|
|
|
|
{updates.map(({ hash, author, message }) => (
|
|
|
|
<div>
|
2023-01-03 01:30:54 +00:00
|
|
|
<code><HashLink {...{ repo, hash }} disabled={repoPending} /></code>
|
2022-10-05 15:09:37 +00:00
|
|
|
<span style={{
|
|
|
|
marginLeft: "0.5em",
|
|
|
|
color: "var(--text-normal)"
|
|
|
|
}}>{message} - {author}</span>
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</Card>
|
|
|
|
);
|
|
|
|
}
|
2022-09-30 22:42:50 +00:00
|
|
|
|
2022-10-05 15:09:37 +00:00
|
|
|
function Updatable(props: CommonProps) {
|
|
|
|
const [updates, setUpdates] = React.useState(changes);
|
|
|
|
const [isChecking, setIsChecking] = React.useState(false);
|
|
|
|
const [isUpdating, setIsUpdating] = React.useState(false);
|
2022-10-01 20:09:20 +00:00
|
|
|
|
2022-10-18 07:57:32 +00:00
|
|
|
const isOutdated = (updates?.length ?? 0) > 0;
|
2022-10-01 20:09:20 +00:00
|
|
|
|
2022-10-05 15:09:37 +00:00
|
|
|
return (
|
|
|
|
<>
|
2022-10-02 00:46:41 +00:00
|
|
|
{!updates && updateError ? (
|
|
|
|
<>
|
|
|
|
<Forms.FormText>Failed to check updates. Check the console for more info</Forms.FormText>
|
|
|
|
<ErrorCard style={{ padding: "1em" }}>
|
|
|
|
<p>{updateError.stderr || updateError.stdout || "An unknown error occurred"}</p>
|
|
|
|
</ErrorCard>
|
|
|
|
</>
|
2022-10-05 15:09:37 +00:00
|
|
|
) : (
|
2023-03-01 20:35:08 +00:00
|
|
|
<Forms.FormText className={Margins.bottom8}>
|
2022-10-05 15:09:37 +00:00
|
|
|
{isOutdated ? `There are ${updates.length} Updates` : "Up to Date!"}
|
|
|
|
</Forms.FormText>
|
2022-10-01 20:09:20 +00:00
|
|
|
)}
|
2022-09-30 22:42:50 +00:00
|
|
|
|
2022-10-05 15:09:37 +00:00
|
|
|
{isOutdated && <Changes updates={updates} {...props} />}
|
|
|
|
|
2023-03-01 20:35:08 +00:00
|
|
|
<Flex className={classes(Margins.bottom8, Margins.top8)}>
|
2022-10-01 20:09:20 +00:00
|
|
|
{isOutdated && <Button
|
2022-09-30 22:42:50 +00:00
|
|
|
size={Button.Sizes.SMALL}
|
|
|
|
disabled={isUpdating || isChecking}
|
|
|
|
onClick={withDispatcher(setIsUpdating, async () => {
|
|
|
|
if (await update()) {
|
2022-10-01 20:14:57 +00:00
|
|
|
setUpdates([]);
|
2022-09-30 22:42:50 +00:00
|
|
|
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() {
|
2023-04-09 02:04:02 +00:00
|
|
|
relaunch();
|
2022-09-30 22:42:50 +00:00
|
|
|
r();
|
|
|
|
},
|
|
|
|
onCancel: r
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
})}
|
|
|
|
>
|
2022-10-01 20:09:20 +00:00
|
|
|
Update Now
|
|
|
|
</Button>}
|
2022-09-30 22:42:50 +00:00
|
|
|
<Button
|
|
|
|
size={Button.Sizes.SMALL}
|
|
|
|
disabled={isUpdating || isChecking}
|
|
|
|
onClick={withDispatcher(setIsChecking, async () => {
|
2022-10-01 20:09:20 +00:00
|
|
|
const outdated = await checkForUpdates();
|
|
|
|
if (outdated) {
|
2022-09-30 22:42:50 +00:00
|
|
|
setUpdates(changes);
|
|
|
|
} else {
|
2022-10-01 20:14:57 +00:00
|
|
|
setUpdates([]);
|
2022-10-01 20:09:20 +00:00
|
|
|
Toasts.show({
|
|
|
|
message: "No updates found!",
|
|
|
|
id: Toasts.genId(),
|
|
|
|
type: Toasts.Type.MESSAGE,
|
|
|
|
options: {
|
|
|
|
position: Toasts.Position.BOTTOM
|
|
|
|
}
|
|
|
|
});
|
2022-09-30 22:42:50 +00:00
|
|
|
}
|
|
|
|
})}
|
|
|
|
>
|
2022-10-01 20:09:20 +00:00
|
|
|
Check for Updates
|
2022-09-30 22:42:50 +00:00
|
|
|
</Button>
|
|
|
|
</Flex>
|
2022-10-05 15:09:37 +00:00
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function Newer(props: CommonProps) {
|
|
|
|
return (
|
|
|
|
<>
|
2023-03-01 20:35:08 +00:00
|
|
|
<Forms.FormText className={Margins.bottom8}>
|
2022-10-05 15:09:37 +00:00
|
|
|
Your local copy has more recent commits. Please stash or reset them.
|
|
|
|
</Forms.FormText>
|
|
|
|
<Changes {...props} updates={changes} />
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-10-16 15:15:15 +00:00
|
|
|
function Updater() {
|
2023-03-19 09:21:26 +00:00
|
|
|
const settings = useSettings(["notifyAboutUpdates", "autoUpdate", "autoUpdateNotification"]);
|
2023-01-24 00:42:57 +00:00
|
|
|
|
2022-12-02 15:43:37 +00:00
|
|
|
const [repo, err, repoPending] = useAwaiter(getRepo, { fallbackValue: "Loading..." });
|
2022-10-05 15:09:37 +00:00
|
|
|
|
|
|
|
React.useEffect(() => {
|
|
|
|
if (err)
|
|
|
|
UpdateLogger.error("Failed to retrieve repo", err);
|
|
|
|
}, [err]);
|
|
|
|
|
|
|
|
const commonProps: CommonProps = {
|
|
|
|
repo,
|
|
|
|
repoPending
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
2023-05-11 23:40:43 +00:00
|
|
|
<SettingsTab title="Vencord Updater">
|
2023-01-24 00:42:57 +00:00
|
|
|
<Forms.FormTitle tag="h5">Updater Settings</Forms.FormTitle>
|
|
|
|
<Switch
|
|
|
|
value={settings.notifyAboutUpdates}
|
|
|
|
onChange={(v: boolean) => settings.notifyAboutUpdates = v}
|
2023-03-19 09:21:26 +00:00
|
|
|
note="Shows a notification on startup"
|
2023-01-24 00:42:57 +00:00
|
|
|
disabled={settings.autoUpdate}
|
|
|
|
>
|
|
|
|
Get notified about new updates
|
|
|
|
</Switch>
|
|
|
|
<Switch
|
|
|
|
value={settings.autoUpdate}
|
|
|
|
onChange={(v: boolean) => settings.autoUpdate = v}
|
|
|
|
note="Automatically update Vencord without confirmation prompt"
|
|
|
|
>
|
|
|
|
Automatically update
|
|
|
|
</Switch>
|
2023-03-19 09:21:26 +00:00
|
|
|
<Switch
|
|
|
|
value={settings.autoUpdateNotification}
|
|
|
|
onChange={(v: boolean) => settings.autoUpdateNotification = v}
|
|
|
|
note="Shows a notification when Vencord automatically updates"
|
|
|
|
disabled={!settings.autoUpdate}
|
|
|
|
>
|
|
|
|
Get notified when an automatic update completes
|
|
|
|
</Switch>
|
2023-01-24 00:42:57 +00:00
|
|
|
|
2022-10-05 15:09:37 +00:00
|
|
|
<Forms.FormTitle tag="h5">Repo</Forms.FormTitle>
|
|
|
|
|
2023-04-08 21:28:12 +00:00
|
|
|
<Forms.FormText className="vc-text-selectable">
|
|
|
|
{repoPending
|
|
|
|
? repo
|
|
|
|
: err
|
|
|
|
? "Failed to retrieve - check console"
|
|
|
|
: (
|
|
|
|
<Link href={repo}>
|
|
|
|
{repo.split("/").slice(-2).join("/")}
|
|
|
|
</Link>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
{" "}(<HashLink hash={gitHash} repo={repo} disabled={repoPending} />)
|
|
|
|
</Forms.FormText>
|
2022-10-05 15:09:37 +00:00
|
|
|
|
2023-03-01 20:35:08 +00:00
|
|
|
<Forms.FormDivider className={Margins.top8 + " " + Margins.bottom8} />
|
2022-10-05 15:09:37 +00:00
|
|
|
|
|
|
|
<Forms.FormTitle tag="h5">Updates</Forms.FormTitle>
|
|
|
|
|
|
|
|
{isNewer ? <Newer {...commonProps} /> : <Updatable {...commonProps} />}
|
2023-05-11 23:40:43 +00:00
|
|
|
</SettingsTab>
|
2022-09-30 22:42:50 +00:00
|
|
|
);
|
2022-10-16 15:15:15 +00:00
|
|
|
}
|
|
|
|
|
2023-08-25 12:15:02 +00:00
|
|
|
export default IS_UPDATER_DISABLED ? null : wrapTab(Updater, "Updater");
|