mirror of
https://github.com/stoatchat/for-legacy-web.git
synced 2026-03-07 01:15:28 +00:00
feat: add auto-update and out-of-date indicator
This commit is contained in:
@@ -9,7 +9,7 @@ import { internalSubscribe } from "../../lib/eventEmitter";
|
||||
|
||||
import { useApplicationState } from "../../mobx/State";
|
||||
|
||||
import { updateSW } from "../../main";
|
||||
import { updateSW } from "../../updateWorker";
|
||||
import Tooltip from "./Tooltip";
|
||||
|
||||
let pendingUpdate = false;
|
||||
|
||||
47
src/context/modals/components/OutOfDate.tsx
Normal file
47
src/context/modals/components/OutOfDate.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Text } from "preact-i18n";
|
||||
|
||||
import { Modal } from "@revoltchat/ui";
|
||||
|
||||
import { noop, noopTrue } from "../../../lib/js";
|
||||
|
||||
import { APP_VERSION } from "../../../version";
|
||||
import { ModalProps } from "../types";
|
||||
|
||||
export default function OutOfDate({
|
||||
onClose,
|
||||
version,
|
||||
}: ModalProps<"out_of_date">) {
|
||||
return (
|
||||
<Modal
|
||||
title={<Text id="app.special.modals.out_of_date.title" />}
|
||||
description={
|
||||
<>
|
||||
<Text id="app.special.modals.out_of_date.description" />
|
||||
<br />
|
||||
<Text
|
||||
id="app.special.modals.out_of_date.version"
|
||||
fields={{ client: APP_VERSION, server: version }}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
actions={[
|
||||
{
|
||||
palette: "plain",
|
||||
onClick: noop,
|
||||
children: (
|
||||
<Text id="app.special.modals.out_of_date.attempting" />
|
||||
),
|
||||
},
|
||||
{
|
||||
palette: "plain-secondary",
|
||||
onClick: noopTrue,
|
||||
children: (
|
||||
<Text id="app.special.modals.out_of_date.ignore" />
|
||||
),
|
||||
},
|
||||
]}
|
||||
onClose={onClose}
|
||||
nonDismissable
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import { ulid } from "ulid";
|
||||
import MFAEnableTOTP from "./components/MFAEnableTOTP";
|
||||
import MFAFlow from "./components/MFAFlow";
|
||||
import MFARecovery from "./components/MFARecovery";
|
||||
import OutOfDate from "./components/OutOfDate";
|
||||
import Test from "./components/Test";
|
||||
import { Modal } from "./types";
|
||||
|
||||
@@ -120,5 +121,6 @@ export const modalController = new ModalControllerExtended({
|
||||
mfa_flow: MFAFlow,
|
||||
mfa_recovery: MFARecovery,
|
||||
mfa_enable_totp: MFAEnableTOTP,
|
||||
out_of_date: OutOfDate,
|
||||
test: Test,
|
||||
});
|
||||
|
||||
@@ -24,6 +24,10 @@ export type Modal = {
|
||||
secret: string;
|
||||
callback: (code?: string) => void;
|
||||
}
|
||||
| {
|
||||
type: "out_of_date";
|
||||
version: string;
|
||||
}
|
||||
| {
|
||||
type: "test";
|
||||
}
|
||||
|
||||
15
src/main.tsx
15
src/main.tsx
@@ -1,21 +1,8 @@
|
||||
import { registerSW } from "virtual:pwa-register";
|
||||
|
||||
import "./styles/index.scss";
|
||||
import { render } from "preact";
|
||||
|
||||
import { internalEmit } from "./lib/eventEmitter";
|
||||
|
||||
import { App } from "./pages/app";
|
||||
|
||||
export const updateSW = registerSW({
|
||||
onNeedRefresh() {
|
||||
internalEmit("PWA", "update");
|
||||
},
|
||||
onOfflineReady() {
|
||||
console.info("Ready to work offline.");
|
||||
// show a ready to work offline to user
|
||||
},
|
||||
});
|
||||
import "./updateWorker";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
render(<App />, document.getElementById("app")!);
|
||||
|
||||
64
src/updateWorker.ts
Normal file
64
src/updateWorker.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import semver from "semver";
|
||||
import { ulid } from "ulid";
|
||||
import { registerSW } from "virtual:pwa-register";
|
||||
|
||||
import { internalEmit } from "./lib/eventEmitter";
|
||||
|
||||
import { modalController } from "./context/modals";
|
||||
|
||||
import { APP_VERSION } from "./version";
|
||||
|
||||
const INTERVAL_HOUR = 36e5;
|
||||
|
||||
let forceUpdate = false;
|
||||
let registration: ServiceWorkerRegistration | undefined;
|
||||
|
||||
export const updateSW = registerSW({
|
||||
onNeedRefresh() {
|
||||
if (forceUpdate) {
|
||||
updateSW(true);
|
||||
} else {
|
||||
internalEmit("PWA", "update");
|
||||
}
|
||||
},
|
||||
onOfflineReady() {
|
||||
console.info("Ready to work offline.");
|
||||
// show a ready to work offline to user
|
||||
},
|
||||
onRegistered(r) {
|
||||
registration = r;
|
||||
|
||||
// Check for updates every hour
|
||||
setInterval(() => r!.update(), INTERVAL_HOUR);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Check whether the client is out of date
|
||||
*/
|
||||
async function checkVersion() {
|
||||
const { version } = (await fetch("https://api.revolt.chat/release").then(
|
||||
(res) => res.json(),
|
||||
)) as { version: string };
|
||||
|
||||
if (!semver.satisfies(APP_VERSION, version)) {
|
||||
// Let the worker know we should immediately refresh
|
||||
forceUpdate = true;
|
||||
|
||||
// Prompt service worker to update
|
||||
registration?.update();
|
||||
|
||||
// Push information that the client is out of date
|
||||
modalController.push({
|
||||
key: ulid(),
|
||||
type: "out_of_date",
|
||||
version,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.env.VITE_API_URL === "https://api.revolt.chat") {
|
||||
// Check for critical updates hourly
|
||||
checkVersion();
|
||||
setInterval(checkVersion, INTERVAL_HOUR);
|
||||
}
|
||||
Reference in New Issue
Block a user