mirror of
https://github.com/coaidev/coai.git
synced 2025-05-29 09:50:16 +09:00
add service worker auto update prompt
This commit is contained in:
parent
b431754d71
commit
c346c06804
53
app/src/components/ReloadService.tsx
Normal file
53
app/src/components/ReloadService.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { useRegisterSW } from 'virtual:pwa-register/react'
|
||||
import {version} from "../conf.ts";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {useToast} from "./ui/use-toast.ts";
|
||||
import {useEffect} from "react";
|
||||
import {ToastAction} from "./ui/toast.tsx";
|
||||
|
||||
function ReloadPrompt() {
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
|
||||
const {
|
||||
offlineReady: [offlineReady, setOfflineReady],
|
||||
needRefresh: [needRefresh, setNeedRefresh],
|
||||
updateServiceWorker,
|
||||
} = useRegisterSW({
|
||||
onRegisteredSW() {
|
||||
console.debug(`[service] service worker registered (version ${version})`);
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.log(`[service] service worker registration failed: ${error.message}`);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (offlineReady) {
|
||||
toast({
|
||||
title: t('service.offline-title'),
|
||||
description: t('service.offline'),
|
||||
})
|
||||
}
|
||||
|
||||
if (needRefresh) {
|
||||
toast({
|
||||
title: t('service.title'),
|
||||
description: t('service.description'),
|
||||
action: (
|
||||
<ToastAction altText={t('service.update')} onClick={() => updateServiceWorker(true)}>
|
||||
{t('service.update')}
|
||||
</ToastAction>
|
||||
),
|
||||
});
|
||||
|
||||
setOfflineReady(false);
|
||||
setNeedRefresh(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
||||
export default ReloadPrompt;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import axios from "axios";
|
||||
|
||||
export const version: string = "3.2.2";
|
||||
export const version: string = "3.2.3";
|
||||
export const deploy: boolean = true;
|
||||
export let rest_api: string = "http://localhost:8094";
|
||||
export let ws_api: string = "ws://localhost:8094";
|
||||
|
@ -162,6 +162,13 @@ const resources = {
|
||||
"copied-description": "API key has been copied to clipboard",
|
||||
"learn-more": "Learn more",
|
||||
},
|
||||
service: {
|
||||
"title": "New Version Available",
|
||||
"description": "A new version is available. Do you want to update now?",
|
||||
"update": "Update",
|
||||
"offline-title": "Offline Mode",
|
||||
"offline": "App is currently offline.",
|
||||
}
|
||||
},
|
||||
},
|
||||
cn: {
|
||||
@ -310,6 +317,13 @@ const resources = {
|
||||
"copied-description": "API 密钥已复制到剪贴板",
|
||||
"learn-more": "了解更多",
|
||||
},
|
||||
service: {
|
||||
"title": "发现新版本",
|
||||
"description": "发现新版本,是否立即更新?",
|
||||
"update": "更新",
|
||||
"offline-title": "离线模式",
|
||||
"offline": "应用当前处于离线状态。",
|
||||
}
|
||||
},
|
||||
},
|
||||
ru: {
|
||||
@ -469,6 +483,13 @@ const resources = {
|
||||
"copied-description": "Ключ API скопирован в буфер обмена",
|
||||
"learn-more": "Узнать больше",
|
||||
},
|
||||
service: {
|
||||
"title": "Доступна новая версия",
|
||||
"description": "Доступна новая версия. Хотите обновить сейчас?",
|
||||
"update": "Обновить",
|
||||
"offline-title": "Режим оффлайн",
|
||||
"offline": "Приложение в настоящее время находится в автономном режиме.",
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -5,11 +5,12 @@ import "./conf.ts";
|
||||
import "./i18n.ts";
|
||||
import "./assets/main.less";
|
||||
import "./assets/globals.less";
|
||||
import "./service.ts";
|
||||
import "./conf.ts";
|
||||
import ReloadPrompt from "./components/ReloadService.tsx";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
<ReloadPrompt />
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
@ -1,24 +0,0 @@
|
||||
// @ts-ignore
|
||||
import { registerSW } from "virtual:pwa-register";
|
||||
import { version } from "./conf.ts";
|
||||
|
||||
export const updateSW = registerSW({
|
||||
onRegisteredSW(url: string, registration: ServiceWorkerRegistration) {
|
||||
if (!(!registration.installing && navigator)) return;
|
||||
if ("connection" in navigator && !navigator.onLine) return;
|
||||
|
||||
console.debug(
|
||||
"[service] checking for update (current version: %s)",
|
||||
version,
|
||||
);
|
||||
fetch(url, {
|
||||
headers: { "Service-Worker": "script", "Cache-Control": "no-cache" },
|
||||
cache: "no-store",
|
||||
}).then(async (resp) => {
|
||||
if (resp?.status === 200) {
|
||||
await registration.update();
|
||||
if (registration.onupdatefound) console.debug("[service] update found");
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
15
app/src/types/service.d.ts
vendored
Normal file
15
app/src/types/service.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
declare module 'virtual:pwa-register/react' {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
|
||||
// @ts-expect-error ignore when React is not installed
|
||||
import type { Dispatch, SetStateAction } from 'react'
|
||||
import type { RegisterSWOptions } from 'vite-plugin-pwa/types'
|
||||
|
||||
export type { RegisterSWOptions }
|
||||
|
||||
export function useRegisterSW(options?: RegisterSWOptions): {
|
||||
needRefresh: [boolean, Dispatch<SetStateAction<boolean>>]
|
||||
offlineReady: [boolean, Dispatch<SetStateAction<boolean>>]
|
||||
updateServiceWorker: (reloadPage?: boolean) => Promise<void>
|
||||
onRegistered: (registration: ServiceWorkerRegistration) => void
|
||||
}
|
||||
}
|
@ -5,6 +5,10 @@
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vite-plugin-pwa/react",
|
||||
"./types/*.d.ts",
|
||||
],
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
@ -25,5 +29,5 @@
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
"references": [{ "path": "./tsconfig.node.json" }],
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user