From a67e4db4b2df921741221c6c237447a6793b465e Mon Sep 17 00:00:00 2001 From: tianma-if Date: Fri, 21 Aug 2026 21:27:13 +0800 Subject: [PATCH] feat(desktop): notify users of client updates --- apps/web/src/app/App.tsx | 2 + .../src/components/DesktopUpdateNotice.tsx | 83 +++++++++++++++++++ packages/shared/src/i18n/en-US.ts | 4 + packages/shared/src/i18n/zh-CN.ts | 4 + 4 files changed, 93 insertions(+) create mode 100644 apps/web/src/components/DesktopUpdateNotice.tsx diff --git a/apps/web/src/app/App.tsx b/apps/web/src/app/App.tsx index 37c3a552..9fbe24d8 100644 --- a/apps/web/src/app/App.tsx +++ b/apps/web/src/app/App.tsx @@ -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 = () => { } /> } /> + diff --git a/apps/web/src/components/DesktopUpdateNotice.tsx b/apps/web/src/components/DesktopUpdateNotice.tsx new file mode 100644 index 00000000..000428eb --- /dev/null +++ b/apps/web/src/components/DesktopUpdateNotice.tsx @@ -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(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 ( +
+
+ +
+
+ {t(downloaded ? "systemInfo.desktopUpdateReadyTitle" : "systemInfo.desktopUpdateAvailableTitle")} +
+
+ {t(downloaded ? "systemInfo.desktopUpdateReadyDescription" : "systemInfo.desktopUpdateAvailableDescription")} +
+ {failed ?
{t("systemInfo.desktopUpdateFailed")}
: null} + +
+ +
+
+ ); +}; diff --git a/packages/shared/src/i18n/en-US.ts b/packages/shared/src/i18n/en-US.ts index beb19209..6194a5dc 100644 --- a/packages/shared/src/i18n/en-US.ts +++ b/packages/shared/src/i18n/en-US.ts @@ -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, 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", diff --git a/packages/shared/src/i18n/zh-CN.ts b/packages/shared/src/i18n/zh-CN.ts index 7650428b..4d3fc1c6 100644 --- a/packages/shared/src/i18n/zh-CN.ts +++ b/packages/shared/src/i18n/zh-CN.ts @@ -608,6 +608,10 @@ export const zhCN = { releaseNotesUnavailable: "本次构建未包含更新摘要,可查看完整 Release 说明。", clientUpdatesNote: "桌面端可前往 Releases 下载更新,移动端请通过对应的应用商店更新。", viewReleaseNotes: "完整说明", + desktopUpdateAvailableTitle: "发现客户端新版本", + desktopUpdateAvailableDescription: "新版本已可下载并安装。", + desktopUpdateReadyTitle: "客户端更新已就绪", + desktopUpdateReadyDescription: "重启 EdgeEver 以完成更新。", desktopUpdateDownloading: "正在下载更新…", desktopUpdateReady: "更新已下载完成", desktopUpdateDownload: "下载更新",