mirror of
https://github.com/coaidev/coai.git
synced 2025-06-03 20:30:19 +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";
|
import axios from "axios";
|
||||||
|
|
||||||
export const version: string = "3.2.2";
|
export const version: string = "3.2.3";
|
||||||
export const deploy: boolean = true;
|
export const deploy: boolean = true;
|
||||||
export let rest_api: string = "http://localhost:8094";
|
export let rest_api: string = "http://localhost:8094";
|
||||||
export let ws_api: string = "ws://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",
|
"copied-description": "API key has been copied to clipboard",
|
||||||
"learn-more": "Learn more",
|
"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: {
|
cn: {
|
||||||
@ -310,6 +317,13 @@ const resources = {
|
|||||||
"copied-description": "API 密钥已复制到剪贴板",
|
"copied-description": "API 密钥已复制到剪贴板",
|
||||||
"learn-more": "了解更多",
|
"learn-more": "了解更多",
|
||||||
},
|
},
|
||||||
|
service: {
|
||||||
|
"title": "发现新版本",
|
||||||
|
"description": "发现新版本,是否立即更新?",
|
||||||
|
"update": "更新",
|
||||||
|
"offline-title": "离线模式",
|
||||||
|
"offline": "应用当前处于离线状态。",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ru: {
|
ru: {
|
||||||
@ -469,6 +483,13 @@ const resources = {
|
|||||||
"copied-description": "Ключ API скопирован в буфер обмена",
|
"copied-description": "Ключ API скопирован в буфер обмена",
|
||||||
"learn-more": "Узнать больше",
|
"learn-more": "Узнать больше",
|
||||||
},
|
},
|
||||||
|
service: {
|
||||||
|
"title": "Доступна новая версия",
|
||||||
|
"description": "Доступна новая версия. Хотите обновить сейчас?",
|
||||||
|
"update": "Обновить",
|
||||||
|
"offline-title": "Режим оффлайн",
|
||||||
|
"offline": "Приложение в настоящее время находится в автономном режиме.",
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -5,11 +5,12 @@ import "./conf.ts";
|
|||||||
import "./i18n.ts";
|
import "./i18n.ts";
|
||||||
import "./assets/main.less";
|
import "./assets/main.less";
|
||||||
import "./assets/globals.less";
|
import "./assets/globals.less";
|
||||||
import "./service.ts";
|
|
||||||
import "./conf.ts";
|
import "./conf.ts";
|
||||||
|
import ReloadPrompt from "./components/ReloadService.tsx";
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
<ReloadPrompt />
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>,
|
</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"],
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
"types": [
|
||||||
|
"vite-plugin-pwa/react",
|
||||||
|
"./types/*.d.ts",
|
||||||
|
],
|
||||||
|
|
||||||
/* Bundler mode */
|
/* Bundler mode */
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
@ -25,5 +29,5 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
},
|
},
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }],
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user