From 2fc3cdf331cf913c4ab8c729cb8ad80c3daafae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elberte=20Pl=C3=ADnio?= Date: Thu, 23 Jul 2026 17:25:09 -0300 Subject: [PATCH 1/4] feat(update): integrate shared studio update dialog behind flag Mount @pickforge/tauri-updater's shared controller and dialog element on PickGauge's main window when studioUpdateDialog is on (default off via @pickforge/flags); the legacy window.confirm flow in updater.ts is untouched while the flag is off. Eligibility excludes the floating capsule by Tauri window label and defers a hidden main window until its first focus event, preserving the existing checkForUpdatesWhenVisible deferral. Adds a dev-only ?updateDialogFixture= route for the available and downloading states, tree-shaken from production builds, since PickGauge has no visual-regression baseline harness. Refs pickforge/pickforge-platform#36 --- bun.lock | 6 ++ docs/releases/UNRELEASED.md | 21 +++++ package.json | 2 + src/App.svelte | 12 +++ src/lib/flags.test.ts | 16 ++++ src/lib/flags.ts | 25 ++++++ src/lib/updateDialog.test.ts | 139 +++++++++++++++++++++++++++++++++ src/lib/updateDialog.ts | 137 ++++++++++++++++++++++++++++++++ src/lib/updateDialogFixture.ts | 75 ++++++++++++++++++ src/main.ts | 65 ++++++++++----- 10 files changed, 479 insertions(+), 19 deletions(-) create mode 100644 src/lib/flags.test.ts create mode 100644 src/lib/flags.ts create mode 100644 src/lib/updateDialog.test.ts create mode 100644 src/lib/updateDialog.ts create mode 100644 src/lib/updateDialogFixture.ts diff --git a/bun.lock b/bun.lock index e2c707e..8dd965b 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,8 @@ "name": "pickgauge", "dependencies": { "@pickforge/brand": "0.2.1", + "@pickforge/flags": "^0.4.0", + "@pickforge/tauri-updater": "^0.12.0", "@tauri-apps/api": "^2.9.0", "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-updater": "^2.10.1", @@ -138,8 +140,12 @@ "@pickforge/brand": ["@pickforge/brand@0.2.1", "", { "dependencies": { "@fontsource/geist-mono": "^5.2.8", "@fontsource/geist-sans": "^5.2.5" } }, "sha512-8VASbOUFJKUkb2zVvqto7aPynyICISCMzrh8jMRcvovtKNpzbLMrZ2xS7eeIPQyVs5NRbJ0457Vb0HQC+sIhQQ=="], + "@pickforge/flags": ["@pickforge/flags@0.4.0", "", {}, "sha512-Z0nlxk3/0HXA7em8+ZQ+BV3jfF2U0E8uCdDPdyW2WdbMHe2pF7rgukTAIAyAZexEB3c7SATEYCbrnNsEd9V9Nw=="], + "@pickforge/tauri-release": ["@pickforge/tauri-release@0.3.0", "", { "bin": { "pickforge-tauri-release": "dist/cli.js" } }, "sha512-LTpsp6+zB9WU9eflvWH8tRFGNCJmiQW7ULYNnffQYCgfZ3fSqF33yDBKW38WdXdlyDBEcYpFnYjkw0+YnLob8Q=="], + "@pickforge/tauri-updater": ["@pickforge/tauri-updater@0.12.0", "", {}, "sha512-3q5SgSAJBV/ctpxFGKUvKOHZ6uIszhgO3BPajgA+BrffulARzrW9Uv4fXRy4TFWoV83LNlSy9GVnCi6dYWnJBw=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.61.0", "", { "os": "android", "cpu": "arm" }, "sha512-dnxczajOqt0gesZlN5pGQ1s1imQVrsmCw5G2Ci4oM+0WvNz3pyRnlWrT7McoZIb8VlFwCawdmbWRmxRn7HI+VQ=="], "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.61.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Bp3JpGP00Vu3f238ivRrjf7z3xSzVPXqCmaJYA9t2c+c8vKYvOzmXF7LkkeUalTEGd6cZcSWe+PFIP3Vy48fRg=="], diff --git a/docs/releases/UNRELEASED.md b/docs/releases/UNRELEASED.md index 8f95aea..f9c7210 100644 --- a/docs/releases/UNRELEASED.md +++ b/docs/releases/UNRELEASED.md @@ -52,6 +52,17 @@ reset this file. ## Internal/release changes +- Added the shared `@pickforge/tauri-updater` dialog behind the `studioUpdateDialog` + flag (default off; `@pickforge/flags`), part of + pickforge/pickforge-platform#36. While off, the legacy `window.confirm` + updater in `src/lib/updater.ts` is untouched. When on, `src/lib/updateDialog.ts` + mounts the shared controller only on the visible main window: a Tauri + window-label check excludes the floating capsule outright, and a hidden + main window (tray/login-start) defers the check until its first focus + event, mirroring the pre-existing `checkForUpdatesWhenVisible` deferral. + One controller per process enforces a single check. A dev-only fixture + (`?updateDialogFixture=available|downloading`, tree-shaken from production + builds) stands in for a visual baseline since PickGauge has no VRT harness. - Headless `usage --json` refreshes independent providers concurrently (join-all, emit in fixed service order) so an offline credentialed install pays ~max per-provider timeout instead of the sequential sum. @@ -152,8 +163,18 @@ reset this file. candidate by several days. The validated candidate remains installed with a checksum-verified rollback backup. +- pickforge/pickforge-platform#36 (PR 5, PickGauge integration): `bun run + lint`, `bun run check`, `bun run test` (85 vitest tests including + `flags.test.ts` and `updateDialog.test.ts`, covering flag-off default, + eligibility for an already-visible main window, capsule exclusion by + window label, and hidden-main-window deferral until focus), and `bun run + test:coverage` (ratchet holds). No Rust touched. + ### Not yet tested +- pickforge/pickforge-platform#36 (PR 5): owner-gated packaged-update smoke + (old build to staged newer build) and design-lead visual acceptance from + the dev-only fixture; both deferred to a later PR per the issue's PR plan. - Issue #49: real KDE Wayland/XWayland Alt+Tab, taskbar, and pager behavior for the float capsule — deferred to Elberte-PC, a live KDE session with `qdbus`/`kwriteconfig6` available. diff --git a/package.json b/package.json index 17520e5..35f7aa7 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,8 @@ }, "dependencies": { "@pickforge/brand": "0.2.1", + "@pickforge/flags": "^0.4.0", + "@pickforge/tauri-updater": "^0.12.0", "@tauri-apps/api": "^2.9.0", "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-updater": "^2.10.1", diff --git a/src/App.svelte b/src/App.svelte index 5c46482..0016da3 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -18,6 +18,8 @@ EVENT_SNAPSHOTS, } from "./lib/api"; import { serviceLabels, settingsSaveDisplayState } from "./lib/display"; + import { flagEnabled } from "./lib/flags"; + import { mountUpdateDialog, type UpdateDialogHost } from "./lib/updateDialog"; import { browserPreviewSnapshots, browserPreviewStateFromSearch, @@ -47,6 +49,8 @@ let statusMessage = $state(null); let statusIsError = $state(false); let statusTimer: ReturnType | null = null; + let updateDialogEl: HTMLElement | undefined = $state(); + const showUpdateDialog = flagEnabled("studioUpdateDialog"); const navItems: { id: View; label: string; icon: typeof Gauge }[] = [ { id: "dashboard", label: "Dashboard", icon: Gauge }, @@ -102,6 +106,10 @@ let cancelled = false; const cleanups: (() => void)[] = []; + if (showUpdateDialog && updateDialogEl) { + mountUpdateDialog(updateDialogEl as unknown as UpdateDialogHost); + } + if (!desktopApiAvailable()) { snapshots = browserPreviewSnapshots(browserPreviewStateFromSearch(window.location.search)); loading = false; @@ -288,6 +296,10 @@ {/if} +{#if showUpdateDialog} + +{/if} +