From 0766a0f218f0979c97fdc9004aabaed1c847f491 Mon Sep 17 00:00:00 2001 From: blankll Date: Wed, 1 Jul 2026 00:03:31 +0800 Subject: [PATCH 1/5] feat: add floating update notification card with skip version support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add skipVersion persistence (localStorage) to skip specific versions - Add skipUpdate(), isRestarting state to useAppUpdater composable - Create UpdateNotification.vue — floating bottom-right card with progress bar and Skip/Later/Update Now actions (matches Dockit UX pattern) - Add i18n keys for notification UI in enUS and zhCN - Wire UpdateNotification into App.vue root template --- src/App.vue | 2 + src/components/UpdateNotification.vue | 173 ++++++++++++++++++++++++++ src/composables/useAppUpdater.ts | 57 ++++++--- src/lang/enUS.ts | 5 + src/lang/zhCN.ts | 5 + 5 files changed, 228 insertions(+), 14 deletions(-) create mode 100644 src/components/UpdateNotification.vue diff --git a/src/App.vue b/src/App.vue index 7e328de5..eb101911 100644 --- a/src/App.vue +++ b/src/App.vue @@ -5,6 +5,7 @@ import { storeToRefs } from 'pinia' import { onMounted, onUnmounted, watch } from 'vue' import { RouterView } from 'vue-router' import AppNotifications from '@/components/ui/notification/AppNotifications.vue' +import UpdateNotification from '@/components/UpdateNotification.vue' import { useAppUpdater } from '@/composables/useAppUpdater' import { useAccountStore } from '@/store/accountStore' import { useAppStore } from '@/store/appStore' @@ -41,4 +42,5 @@ onUnmounted(() => { diff --git a/src/components/UpdateNotification.vue b/src/components/UpdateNotification.vue new file mode 100644 index 00000000..4f2422a8 --- /dev/null +++ b/src/components/UpdateNotification.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/src/composables/useAppUpdater.ts b/src/composables/useAppUpdater.ts index bf698c2d..2883fa0a 100644 --- a/src/composables/useAppUpdater.ts +++ b/src/composables/useAppUpdater.ts @@ -1,10 +1,13 @@ import type { DownloadEvent, Update } from '@tauri-apps/plugin-updater' import { relaunch } from '@tauri-apps/plugin-process' import { check } from '@tauri-apps/plugin-updater' +import { useLocalStorage } from '@vueuse/core' import { computed, ref } from 'vue' import { useI18n } from 'vue-i18n' import { toast } from './useNotifications' +const skipVersion = useLocalStorage('sqlkit-skip-version', '') + export function useAppUpdater() { const { t } = useI18n() const updateAvailable = ref(false) @@ -12,6 +15,7 @@ export function useAppUpdater() { const isChecking = ref(false) const isDownloading = ref(false) const isInstalling = ref(false) + const isRestarting = ref(false) /** Accumulated downloaded bytes for the current update download */ const downloadedBytes = ref(0) @@ -32,7 +36,7 @@ export function useAppUpdater() { isChecking.value = true const update = await check() - if (update) { + if (update && update.version !== skipVersion.value) { updateAvailable.value = true updateInfo.value = update @@ -73,9 +77,16 @@ export function useAppUpdater() { isDownloading.value = true downloadedBytes.value = 0 contentLength.value = 0 - toast.info(t('updater.downloading')) - await updateInfo.value.downloadAndInstall((event: DownloadEvent) => { + // Re-check to get a fresh download URL + const freshUpdate = await check() + if (!freshUpdate) { + isDownloading.value = false + return + } + updateInfo.value = freshUpdate + + await freshUpdate.downloadAndInstall((event: DownloadEvent) => { if (event.event === 'Started') { contentLength.value = event.data.contentLength ?? 0 } @@ -85,30 +96,46 @@ export function useAppUpdater() { else if (event.event === 'Finished') { isDownloading.value = false isInstalling.value = true - toast.info(t('updater.installing')) } }) - - toast.success(t('updater.installed')) - - setTimeout(async () => { - await relaunch() - }, 1500) } catch (error) { console.error('Failed to install update:', error) toast.error(t('updater.installFailed'), { description: error instanceof Error ? error.message : String(error), }) - } - finally { isDownloading.value = false isInstalling.value = false - updateAvailable.value = false - updateInfo.value = null downloadedBytes.value = 0 contentLength.value = 0 + return } + + isRestarting.value = true + isInstalling.value = false + + const relaunchTimeout = setTimeout(() => { + isRestarting.value = false + }, 30000) + + try { + await relaunch() + } + catch { + clearTimeout(relaunchTimeout) + isRestarting.value = false + toast.error(t('updater.installFailed')) + } + } + + const skipUpdate = () => { + if (updateInfo.value) { + skipVersion.value = updateInfo.value.version + } + updateAvailable.value = false + updateInfo.value = null + downloadedBytes.value = 0 + contentLength.value = 0 } const dismissUpdate = () => { @@ -124,9 +151,11 @@ export function useAppUpdater() { isChecking, isDownloading, isInstalling, + isRestarting, downloadProgress, checkForUpdates, downloadAndInstall, + skipUpdate, dismissUpdate, } } diff --git a/src/lang/enUS.ts b/src/lang/enUS.ts index f899301c..f9ccd2bf 100644 --- a/src/lang/enUS.ts +++ b/src/lang/enUS.ts @@ -1409,6 +1409,11 @@ export const enUS = { installing: 'Installing update...', installed: 'Update installed. Restarting...', installFailed: 'Failed to install update', + skip: 'Skip This Version', + later: 'Later', + updateNow: 'Update Now', + restarting: 'Restarting...', + downloadingPercent: 'Downloading {percent}%', }, errors: { unexpected: 'Unexpected error: {error}', diff --git a/src/lang/zhCN.ts b/src/lang/zhCN.ts index b1a892a9..1aa306c2 100644 --- a/src/lang/zhCN.ts +++ b/src/lang/zhCN.ts @@ -1409,6 +1409,11 @@ export const zhCN = { installing: '正在安装更新...', installed: '更新已安装,正在重启...', installFailed: '安装更新失败', + skip: '跳过此版本', + later: '稍后', + updateNow: '立即更新', + restarting: '正在重启...', + downloadingPercent: '下载中 {percent}%', }, errors: { unexpected: '意外错误:{error}', From 58161e1e00e0254b306ff26e07843a80cab03fcd Mon Sep 17 00:00:00 2001 From: blankll Date: Wed, 1 Jul 2026 00:32:20 +0800 Subject: [PATCH 2/5] chore: pin windows-sys, windows-core, and socket2 transitive deps Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src-tauri/Cargo.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 71408a56..ff583ccb 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1709,7 +1709,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -2001,7 +2001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -2969,7 +2969,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.4", + "socket2 0.5.10", "system-configuration", "tokio", "tower-service", @@ -2989,7 +2989,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core 0.61.2", ] [[package]] @@ -3758,7 +3758,7 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4990,7 +4990,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.2", "rustls 0.23.40", - "socket2 0.6.4", + "socket2 0.5.10", "thiserror 2.0.18", "tokio", "tracing", @@ -5027,9 +5027,9 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.4", + "socket2 0.5.10", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -5631,7 +5631,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -5732,7 +5732,7 @@ dependencies = [ "security-framework 3.7.0", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -6306,7 +6306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7111,7 +7111,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -7640,7 +7640,7 @@ dependencies = [ "png 0.18.1", "serde", "thiserror 2.0.18", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -7680,7 +7680,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ "memoffset", "tempfile", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -8200,7 +8200,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] From 23b3f2d16776f50f011c425892fbebc212a123fd Mon Sep 17 00:00:00 2001 From: blankll Date: Wed, 1 Jul 2026 00:32:23 +0800 Subject: [PATCH 3/5] feat: add success color tokens to design system Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/assets/index.css | 8 ++++++++ uno.config.ts | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/assets/index.css b/src/assets/index.css index 8e97e989..c5296e56 100644 --- a/src/assets/index.css +++ b/src/assets/index.css @@ -15,6 +15,10 @@ --accent-foreground: 222.2 47.4% 11.2%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; + --success: 142.1 70.6% 35.5%; + --success-foreground: 0 0% 100%; + --success-muted: 138 76% 95%; + --success-border: 140 58% 85%; --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 220 13% 60%; @@ -43,6 +47,10 @@ --accent-foreground: 210 40% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 40% 98%; + --success: 142.1 70% 45%; + --success-foreground: 0 0% 100%; + --success-muted: 142 35% 16%; + --success-border: 142 30% 25%; --border: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%; --ring: 212.7 26.8% 68%; diff --git a/uno.config.ts b/uno.config.ts index 4c9b6bd6..40fa6bb7 100644 --- a/uno.config.ts +++ b/uno.config.ts @@ -43,6 +43,12 @@ export default defineConfig({ DEFAULT: 'hsl(var(--destructive))', foreground: 'hsl(var(--destructive-foreground))', }, + success: { + DEFAULT: 'hsl(var(--success))', + foreground: 'hsl(var(--success-foreground))', + muted: 'hsl(var(--success-muted))', + border: 'hsl(var(--success-border))', + }, muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))', @@ -105,5 +111,9 @@ export default defineConfig({ 'text-destructive', 'hover:bg-destructive/10', 'hover:text-destructive-foreground', + 'bg-success', + 'text-success', + 'border-success-border', + 'bg-success-muted', ], }) From 8a2087ff3889919699071e837c615b5718cd8213 Mon Sep 17 00:00:00 2001 From: blankll Date: Wed, 1 Jul 2026 00:32:26 +0800 Subject: [PATCH 4/5] refactor: use CSS variables for update notification and lift state to module scope Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/components/UpdateNotification.vue | 35 +++++++++++-------------- src/composables/useAppUpdater.ts | 37 +++++++++++++++------------ 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/components/UpdateNotification.vue b/src/components/UpdateNotification.vue index 4f2422a8..c4cae623 100644 --- a/src/components/UpdateNotification.vue +++ b/src/components/UpdateNotification.vue @@ -48,19 +48,15 @@ const buttonsDisabled = computed(() =>