You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(desktop): drive updates from a sidebar button and one overlay (#172)
## Related Issue
No issue — requested directly: an Update button at the top of the
sidebar that opens one centred overlay with download, progress, and
cancel, then installs.
## Problem
The desktop app could already find, download, and install an update, but
the surface around it was wrong in three ways:
1. **No entry point.** Nothing in the main window said an update was
waiting. Discovering one meant opening Settings.
2. **No way out of a download.** Once bytes were moving there was no
cancel — only quitting the app, which leaves a partial file behind.
3. **Two places showed progress.** A bottom-right toast and the Settings
panel both rendered the same feed, and the toast could surface over
other UI while the user was working.
## What changed
**Sidebar** — an Update button sits above New Chat. It renders only on
desktop, only when a version is waiting, and only when that version has
not been skipped.
**One overlay** carries the whole flow:
| state | shows |
| --- | --- |
| available | version, release date, **Download** / Skip / View notes |
| downloading | transferred against total, progress bar, **Cancel
download** |
| downloaded | **Restart to update** / Later |
| error | Retry / Dismiss |
While a download is running, overlay-click and Esc are disabled — Cancel
is the only exit, so the frame cannot be dismissed out from under an
in-flight transfer.
**Cancel** is the only genuinely new capability in the main process. Two
things made it more than a one-liner:
- `electron-updater` reports a cancelled download through the same
`error` path as a real failure, and `CancellationError` carries no
distinguishing `name`. The token itself is the discriminator, and the
guard reads **the token that owns the rejection** rather than the
current one — so a retry started after a cancel cannot inherit the
cancelled download's error.
- `builder-util-runtime` was a phantom dependency: used through
`electron-updater` but never declared. It is now declared at `9.7.0`.
The lockfile resolves exactly one copy, `electron-updater` pins the same
one, and the package contains no `instanceof CancellationToken`, so
class identity is not load-bearing.
**Removed** `UpdateToast.vue` and its test. Download and install remain
two deliberate actions — the main process refuses to combine them, and a
test holds that line.
The shared `useDesktopUpdate` composable keeps module-level state on
purpose: the sidebar button and the overlay read one feed, so two
components can never open two `onUpdateState` listeners, and the button
must know whether to render before the overlay is ever mounted.
## Checklist
- [x] I have read the
[CONTRIBUTING](https://github.com/PyModel/pythinker-code/blob/main/CONTRIBUTING.md)
document.
- [ ] I have linked a related issue (external PRs: the issue must have a
maintainer's `/approve`).
- [x] I have added tests that prove my feature works.
- [x] Ran `gen-changesets` skill, or this PR needs no changeset.
- [x] Ran `gen-docs` skill, or this PR needs no doc update.
## Verification
desktop 157/157 · web 939/939 · `pnpm run typecheck` 0 · `pnpm run lint`
0 errors · `check-nix-workspace.mjs` 0 · `nix build .#pythinker-code`
exit 0 (the lockfile change is importer-only, so the `pnpmDeps` hash is
unaffected) · `pnpm run build:web` 0 with the shipped bundle rebuilt.
All six new tests are mutation-proven. Dropping the cancellation token,
removing the cancelled-download guard, unguarding the dialog close,
pointing Cancel at download, rendering the sidebar button
unconditionally, and neutering its click each turn exactly their own
test red — no test passes for a reason other than the one it claims.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a desktop sidebar update button with the available version
displayed.
* Added an update dialog for reviewing release notes, downloading
updates, monitoring progress, cancelling downloads, retrying, skipping
versions, and restarting to apply updates.
* Added localized update messaging and responsive progress displays.
* **Bug Fixes**
* Cancelled downloads now safely return to the available state without
showing errors.
* Update retries are handled more reliably after interrupted downloads.
* **Tests**
* Added coverage for update actions, progress states, cancellation,
retries, restart flows, and sidebar behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Add an Update button to the top of the desktop sidebar that opens a single overlay for the whole update: download it, watch the progress, cancel it mid-transfer, then restart to apply it.
0 commit comments