feat(desktop): notify users of client updates
This commit is contained in:
1 parent
8645e84655
commit
a67e4db4b2
4 files changed
+93
No files matched your search
@@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { PwaUpdateNotice } from "@/components/PwaUpdateNotice";
|
||||
import { PwaInstallProvider } from "@/components/PwaInstallContext";
|
||||
import { PwaIosPrompt } from "@/components/PwaIosPrompt";
|
||||
import { DesktopUpdateNotice } from "@/components/DesktopUpdateNotice";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
api,
|
||||
@@ -229,6 +230,7 @@ export const App = () => {
|
||||
<Route path="/ai-prompts" element={<AuthenticatedWorkspace />} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
<DesktopUpdateNotice />
|
||||
<PwaUpdateNotice />
|
||||
<PwaIosPrompt />
|
||||
</PwaInstallProvider>
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import { useState } from "react";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { Download, LoaderCircle, RotateCcw, X } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
type DesktopUpdateState = "idle" | "available" | "downloaded";
|
||||
|
||||
const UPDATE_STATUS_QUERY_KEY = ["desktop-update-status"] as const;
|
||||
|
||||
export const DesktopUpdateNotice = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const bridge = window.edgeeverDesktop;
|
||||
const [dismissedState, setDismissedState] = useState<DesktopUpdateState | null>(null);
|
||||
|
||||
const statusQuery = useQuery({
|
||||
queryKey: UPDATE_STATUS_QUERY_KEY,
|
||||
queryFn: () => bridge!.updateStatus(),
|
||||
enabled: bridge?.isAvailable === true,
|
||||
refetchInterval: 5_000,
|
||||
retry: 1,
|
||||
});
|
||||
const downloadMutation = useMutation({
|
||||
mutationFn: () => bridge!.downloadUpdate(),
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: UPDATE_STATUS_QUERY_KEY });
|
||||
},
|
||||
});
|
||||
const installMutation = useMutation({
|
||||
mutationFn: () => bridge!.installUpdate(),
|
||||
});
|
||||
|
||||
const updateState = statusQuery.data?.state ?? "idle";
|
||||
const visible = bridge?.isAvailable === true && updateState !== "idle" && dismissedState !== updateState;
|
||||
if (!visible) return null;
|
||||
|
||||
const downloaded = updateState === "downloaded";
|
||||
const downloading = downloadMutation.isPending;
|
||||
const failed = downloadMutation.isError || installMutation.isError;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed bottom-5 right-5 z-[90] w-[min(22rem,calc(100vw-2rem))] animate-in slide-in-from-bottom-3 fade-in rounded-lg border border-emerald-200 bg-white/95 p-3 text-slate-900 shadow-[0_18px_48px_rgba(15,23,42,0.18)] backdrop-blur duration-300"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-emerald-50 text-emerald-700" aria-hidden="true">
|
||||
{downloading ? <LoaderCircle className="h-4 w-4 animate-spin" /> : downloaded ? <RotateCcw className="h-4 w-4" /> : <Download className="h-4 w-4" />}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-semibold leading-5">
|
||||
{t(downloaded ? "systemInfo.desktopUpdateReadyTitle" : "systemInfo.desktopUpdateAvailableTitle")}
|
||||
</div>
|
||||
<div className="mt-0.5 text-xs leading-5 text-slate-500">
|
||||
{t(downloaded ? "systemInfo.desktopUpdateReadyDescription" : "systemInfo.desktopUpdateAvailableDescription")}
|
||||
</div>
|
||||
{failed ? <div className="mt-1 text-xs font-medium text-rose-700" role="alert">{t("systemInfo.desktopUpdateFailed")}</div> : null}
|
||||
<Button
|
||||
className="mt-2"
|
||||
size="sm"
|
||||
variant="solid"
|
||||
disabled={downloading || installMutation.isPending}
|
||||
onClick={() => downloaded ? installMutation.mutate() : downloadMutation.mutate()}
|
||||
>
|
||||
{downloading
|
||||
? t("systemInfo.desktopUpdateDownloading")
|
||||
: t(downloaded ? "systemInfo.desktopUpdateRestart" : "systemInfo.desktopUpdateDownload")}
|
||||
</Button>
|
||||
</div>
|
||||
<button
|
||||
className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-slate-400 transition hover:bg-slate-100 hover:text-slate-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/70"
|
||||
type="button"
|
||||
aria-label={t("common.close")}
|
||||
onClick={() => setDismissedState(updateState)}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -608,6 +608,10 @@ export const enUS = {
|
||||
releaseNotesUnavailable: "This build does not include an update summary. You can view the full Release notes.",
|
||||
clientUpdatesNote: "Download desktop updates from <releases>Releases</releases>, or update mobile apps through the corresponding app store.",
|
||||
viewReleaseNotes: "Full notes",
|
||||
desktopUpdateAvailableTitle: "Client update available",
|
||||
desktopUpdateAvailableDescription: "A new version is ready to download and install.",
|
||||
desktopUpdateReadyTitle: "Client update ready",
|
||||
desktopUpdateReadyDescription: "Restart EdgeEver to finish updating.",
|
||||
desktopUpdateDownloading: "Downloading update…",
|
||||
desktopUpdateReady: "Update downloaded",
|
||||
desktopUpdateDownload: "Download update",
|
||||
|
||||
@@ -608,6 +608,10 @@ export const zhCN = {
|
||||
releaseNotesUnavailable: "本次构建未包含更新摘要,可查看完整 Release 说明。",
|
||||
clientUpdatesNote: "桌面端可前往 <releases>Releases</releases> 下载更新,移动端请通过对应的应用商店更新。",
|
||||
viewReleaseNotes: "完整说明",
|
||||
desktopUpdateAvailableTitle: "发现客户端新版本",
|
||||
desktopUpdateAvailableDescription: "新版本已可下载并安装。",
|
||||
desktopUpdateReadyTitle: "客户端更新已就绪",
|
||||
desktopUpdateReadyDescription: "重启 EdgeEver 以完成更新。",
|
||||
desktopUpdateDownloading: "正在下载更新…",
|
||||
desktopUpdateReady: "更新已下载完成",
|
||||
desktopUpdateDownload: "下载更新",
|
||||
|
||||
Reference in new issue
Block a user