From f21830293e84ab4fd435484640bc389edc2a4d9a Mon Sep 17 00:00:00 2001 From: Kalvin Chau Date: Tue, 29 Sep 2026 14:10:25 -0700 Subject: [PATCH 1/3] feat(updates): show installed version in Software Updates settings Preview and release builds inject their version at build time, so the native getVersion() is the runtime source of truth. Browser builds keep the plain subtitle. Signed-off-by: Kalvin Chau --- src/features/updates/UpdateSettings.test.tsx | 31 ++++++++++++++++++++ src/features/updates/UpdateSettings.tsx | 24 +++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/features/updates/UpdateSettings.test.tsx b/src/features/updates/UpdateSettings.test.tsx index ec27fcb7c..117665140 100644 --- a/src/features/updates/UpdateSettings.test.tsx +++ b/src/features/updates/UpdateSettings.test.tsx @@ -13,6 +13,13 @@ import { afterEach, expect, it, vi } from "vitest"; import { UpdateSettings } from "./UpdateSettings"; import { createUpdates, type UpdatePlatform, type Updates } from "./updates"; +const native = vi.hoisted(() => ({ + getVersion: vi.fn(async () => "1.2.3"), + isTauri: vi.fn(() => false), +})); +vi.mock("@tauri-apps/api/app", () => ({ getVersion: native.getVersion })); +vi.mock("@tauri-apps/api/core", () => ({ isTauri: native.isTauri })); + let updates: Updates | undefined; afterEach(() => { cleanup(); @@ -110,6 +117,30 @@ it("explains builds without automatic updates", async () => { expect(screen.getByRole("button", { name: "Check Again" })).toBeVisible(); }); +it("shows the installed version in the header", async () => { + native.isTauri.mockReturnValue(true); + try { + renderSettings({}); + expect( + await screen.findByText( + "Version 1.2.3. Keep Buzz up to date with the latest features and fixes.", + ), + ).toBeVisible(); + expect(native.getVersion).toHaveBeenCalledOnce(); + } finally { + native.isTauri.mockReturnValue(false); + } +}); + +it("keeps the plain subtitle when the native version is unavailable", async () => { + renderSettings({}); + expect( + screen.getByText( + "Keep Buzz up to date with the latest features and fixes.", + ), + ).toBeVisible(); +}); + function deferred() { let resolve!: (value: T) => void; let reject!: (reason: unknown) => void; diff --git a/src/features/updates/UpdateSettings.tsx b/src/features/updates/UpdateSettings.tsx index 0887901bb..e1bc710bb 100644 --- a/src/features/updates/UpdateSettings.tsx +++ b/src/features/updates/UpdateSettings.tsx @@ -1,4 +1,6 @@ -import { useEffect, useSyncExternalStore } from "react"; +import { useEffect, useState, useSyncExternalStore } from "react"; +import { getVersion } from "@tauri-apps/api/app"; +import { isTauri } from "@tauri-apps/api/core"; import { Button } from "../../shared/design-system/ui/Button"; import { Header } from "../../shared/design-system/ui/Header"; import type { Updates } from "./updates"; @@ -19,6 +21,20 @@ export function UpdateSettings({ () => (active ? updates.showInline() : undefined), [active, updates], ); + // Browser builds have no native version; leave it unset there. + const [version, setVersion] = useState(null); + useEffect(() => { + if (!isTauri()) return; + let cancelled = false; + getVersion() + .then((found) => { + if (!cancelled) setVersion(found); + }) + .catch(() => {}); + return () => { + cancelled = true; + }; + }, []); const pending = [ "checking", "available", @@ -50,7 +66,11 @@ export function UpdateSettings({

From 996ecefdb35059a08db2f4bfc94ad6e045c552a5 Mon Sep 17 00:00:00 2001 From: Kalvin Chau Date: Tue, 29 Sep 2026 14:12:38 -0700 Subject: [PATCH 2/3] style(updates): put installed version on its own line Signed-off-by: Kalvin Chau --- src/features/updates/UpdateSettings.test.tsx | 14 ++++++++++---- src/features/updates/UpdateSettings.tsx | 12 +++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/features/updates/UpdateSettings.test.tsx b/src/features/updates/UpdateSettings.test.tsx index 117665140..db0a5d435 100644 --- a/src/features/updates/UpdateSettings.test.tsx +++ b/src/features/updates/UpdateSettings.test.tsx @@ -121,11 +121,17 @@ it("shows the installed version in the header", async () => { native.isTauri.mockReturnValue(true); try { renderSettings({}); + const subtitle = await screen.findByText( + "Keep Buzz up to date with the latest features and fixes.", + ); + // The subtitle renders the version on its own line above the tagline. + const lineBreaks = subtitle.querySelectorAll("br"); + const text = subtitle.textContent ?? ""; + expect(lineBreaks).toHaveLength(1); + expect(text.startsWith("Version 1.2.3")).toBe(true); expect( - await screen.findByText( - "Version 1.2.3. Keep Buzz up to date with the latest features and fixes.", - ), - ).toBeVisible(); + text.endsWith("Keep Buzz up to date with the latest features and fixes."), + ).toBe(true); expect(native.getVersion).toHaveBeenCalledOnce(); } finally { native.isTauri.mockReturnValue(false); diff --git a/src/features/updates/UpdateSettings.tsx b/src/features/updates/UpdateSettings.tsx index e1bc710bb..7e9c497ea 100644 --- a/src/features/updates/UpdateSettings.tsx +++ b/src/features/updates/UpdateSettings.tsx @@ -67,9 +67,15 @@ export function UpdateSettings({ id="update-settings-title" title="Software Updates" subtitle={ - version - ? `Version ${version}. Keep Buzz up to date with the latest features and fixes.` - : "Keep Buzz up to date with the latest features and fixes." + version ? ( + <> + Version {version} +
+ Keep Buzz up to date with the latest features and fixes. + + ) : ( + "Keep Buzz up to date with the latest features and fixes." + ) } />

From 09973cc8027c2942146e00abae354318e3ba4f2b Mon Sep 17 00:00:00 2001 From: Kalvin Chau Date: Tue, 29 Sep 2026 14:13:21 -0700 Subject: [PATCH 3/3] test(updates): drop redundant plain-subtitle case Signed-off-by: Kalvin Chau --- src/features/updates/UpdateSettings.test.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/features/updates/UpdateSettings.test.tsx b/src/features/updates/UpdateSettings.test.tsx index db0a5d435..8eeea76fb 100644 --- a/src/features/updates/UpdateSettings.test.tsx +++ b/src/features/updates/UpdateSettings.test.tsx @@ -138,15 +138,6 @@ it("shows the installed version in the header", async () => { } }); -it("keeps the plain subtitle when the native version is unavailable", async () => { - renderSettings({}); - expect( - screen.getByText( - "Keep Buzz up to date with the latest features and fixes.", - ), - ).toBeVisible(); -}); - function deferred() { let resolve!: (value: T) => void; let reject!: (reason: unknown) => void;