Skip to content

feat(desktop): download updates in background - #110

Merged
incognitojam merged 1 commit into
mainfrom
t3code/download-updates-in-background
Aug 12, 2026
Merged

feat(desktop): download updates in background#110
incognitojam merged 1 commit into
mainfrom
t3code/download-updates-in-background

Conversation

@incognitojam

@incognitojam incognitojam commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Desktop updates currently wait for a user click before downloading, which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available release, without restarting the app automatically. While the download is active, the sidebar update control uses its existing refresh icon as a quiet spinner and keeps the changelog tooltip available. Once the download completes, the existing restart action and confirmation flow remain unchanged. Failed downloads can still be retried manually.

Screenshots:

Downloading Downloaded — ready to restart
Downloading update state Downloaded update state

Tests:

  • vp test run apps/desktop/src/updates/DesktopUpdates.test.ts apps/web/src/components/desktopUpdate.logic.test.ts apps/web/src/state/desktopUpdate.test.ts apps/web/src/components/desktopUpdate.toast.test.tsx
  • Targeted lint for the changed TypeScript files
  • vp run --filter @t3tools/web typecheck
  • vp run --filter @t3tools/desktop typecheck

Written by an agent (T3 Code, gpt-5.6-sol).

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S labels Aug 12, 2026
@incognitojam
incognitojam force-pushed the t3code/download-updates-in-background branch from 770862f to d08964c Compare August 12, 2026 15:42
@github-actions github-actions Bot added size:XS and removed size:S labels Aug 12, 2026
@incognitojam incognitojam reopened this Aug 12, 2026
@github-actions github-actions Bot added size:S and removed size:XS labels Aug 12, 2026
@incognitojam
incognitojam merged commit 58b06fc into main Aug 12, 2026
14 of 16 checks passed
@incognitojam
incognitojam deleted the t3code/download-updates-in-background branch August 12, 2026 16:07
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 12, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 13, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 13, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 13, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 13, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 14, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
incognitojam added a commit that referenced this pull request Aug 14, 2026
Background update downloads landed in #110, but the sidebar control still
treated downloading as a call to action: it shared the `isUpdateState`
branch with the states that want a click, so an automatic download lit the
button and its tooltip in update blue while needing no input at all. The
downloaded state then offered a circular-arrow icon, the same metaphor this
app uses for refresh and retry everywhere else.

Split the tone decision out into `resolveDesktopUpdateButtonTone`, so call-to-
action colour is reserved for states that actually want a click — install, or
retry a failed download. Downloading now renders a muted progress ring around
a download glyph, driven by `downloadPercent`, and the downloaded state uses
an upward arrow, matching the update glyph the provider settings already use.

The main process only broadcasts progress every 10%, so the ring transitions
its stroke to glide between steps, and treats the initial 0 as indeterminate
rather than drawing a zero-length arc for the first tenth of the download. A
manual retry keeps the button natively disabled for the whole download, so
the quiet branch omits the disabled dimming to stop the same state rendering
two different ways.

Tests:

- `vp test run apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx
apps/desktop/src/updates/DesktopUpdates.test.ts`
- `vp run --filter @t3tools/web typecheck`
- Targeted lint for the changed TypeScript files
incognitojam added a commit that referenced this pull request Aug 14, 2026
Background update downloads landed in #110, but the sidebar control still
treated downloading as a call to action: it shared the `isUpdateState`
branch with the states that want a click, so an automatic download lit the
button and its tooltip in update blue while needing no input at all. The
downloaded state then offered a circular-arrow icon, the same metaphor this
app uses for refresh and retry everywhere else.

Split the tone decision out into `resolveDesktopUpdateButtonTone`, so call-to-
action colour is reserved for states that actually want a click — install, or
retry a failed download. Downloading now renders a muted progress ring around
a download glyph, driven by `downloadPercent`, and the downloaded state uses
an upward arrow, matching the update glyph the provider settings already use.

The main process only broadcasts progress every 10%, so the ring transitions
its stroke to glide between steps, and treats the initial 0 as indeterminate
rather than drawing a zero-length arc for the first tenth of the download. A
manual retry keeps the button natively disabled for the whole download, so
the quiet branch omits the disabled dimming to stop the same state rendering
two different ways.

Tests:

- `vp test run apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx
apps/desktop/src/updates/DesktopUpdates.test.ts`
- `vp run --filter @t3tools/web typecheck`
- Targeted lint for the changed TypeScript files
incognitojam added a commit that referenced this pull request Aug 14, 2026
Background update downloads landed in #110, but the sidebar control still
treated downloading as a call to action: it shared the `isUpdateState`
branch with the states that want a click, so an automatic download lit the
button and its tooltip in update blue while needing no input at all. The
downloaded state then offered a circular-arrow icon, the same metaphor this
app uses for refresh and retry everywhere else.

Split the tone decision out into `resolveDesktopUpdateButtonTone`, so call-to-
action colour is reserved for states that actually want a click — install, or
retry a failed download. Downloading now renders a muted progress ring around
a download glyph, driven by `downloadPercent`, and the downloaded state uses
an upward arrow, matching the update glyph the provider settings already use.

The main process only broadcasts progress every 10%, so the ring transitions
its stroke to glide between steps, and treats the initial 0 as indeterminate
rather than drawing a zero-length arc for the first tenth of the download. A
manual retry keeps the button natively disabled for the whole download, so
the quiet branch omits the disabled dimming to stop the same state rendering
two different ways.

Tests:

- `vp test run apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx
apps/desktop/src/updates/DesktopUpdates.test.ts`
- `vp run --filter @t3tools/web typecheck`
- Targeted lint for the changed TypeScript files
incognitojam added a commit that referenced this pull request Aug 14, 2026
Background update downloads landed in #110, but the sidebar control still
treated downloading as a call to action: it shared the `isUpdateState`
branch with the states that want a click, so an automatic download lit the
button and its tooltip in update blue while needing no input at all. The
downloaded state then offered a circular-arrow icon, the same metaphor this
app uses for refresh and retry everywhere else.

Split the tone decision out into `resolveDesktopUpdateButtonTone`, so call-to-
action colour is reserved for states that actually want a click — install, or
retry a failed download. Downloading now renders a muted progress ring around
a download glyph, driven by `downloadPercent`, and the downloaded state uses
an upward arrow, matching the update glyph the provider settings already use.

The main process only broadcasts progress every 10%, so the ring transitions
its stroke to glide between steps, and treats the initial 0 as indeterminate
rather than drawing a zero-length arc for the first tenth of the download. A
manual retry keeps the button natively disabled for the whole download, so
the quiet branch omits the disabled dimming to stop the same state rendering
two different ways.

Tests:

- `vp test run apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx
apps/desktop/src/updates/DesktopUpdates.test.ts`
- `vp run --filter @t3tools/web typecheck`
- Targeted lint for the changed TypeScript files
incognitojam added a commit that referenced this pull request Aug 14, 2026
Background update downloads landed in #110, but the sidebar control
still treated downloading as a call to action: it shared the
`isUpdateState` styling branch with the states that want a click, so an
automatic download lit the button and its changelog tooltip in update
blue while needing no input at all. The downloaded state then offered a
circular-arrow icon — the same metaphor this app uses for refresh and
retry everywhere else, including the check-for-updates state of this
very button.

This splits the tone decision into `resolveDesktopUpdateButtonTone`
(`"cta" | "quiet" | "idle"`), so call-to-action colour is reserved for
states that actually want a click: install, or retry a failed download.
The intended flow is now visually staged:

1. Check for updates in the background (existing pollers, unchanged)
2. Update available → download starts automatically (#110, unchanged)
3. **Downloading → muted progress ring around a download glyph, no CTA
colour**
4. **Downloaded → CTA colour with an upward arrow, matching the update
glyph in provider settings**

| | Downloading | Downloaded — ready to restart |
| --- | --- | --- |
| Before | ![Before: downloading rendered as a blue CTA with a spinning
refresh
icon](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/before-downloading.png)
| ![Before: downloaded rendered as a blue CTA with a circular rotate
arrow](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/before-downloaded.png)
|
| After | ![After: downloading rendered as a muted progress ring around
a download
glyph](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/after-downloading.png)
| ![After: downloaded rendered as a blue CTA with an upward circle
arrow](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/after-downloaded.png)
|

Full motion — indeterminate spin before the first progress event,
gliding through the 10% progress broadcasts, then flipping to the CTA on
completion:


https://github.com/user-attachments/assets/80d64f3c-06d3-4f9e-aace-bfa2e29f1be8

Implementation notes:

- The ring follows the `ContextWindowMeter` construct (track +
dash-offset arc, `-rotate-90 transform-gpu`,
`motion-reduce:transition-none`), with its stroke transitioned over
500ms so the 10%-step broadcasts from the main process glide instead of
jumping.
- `reduceDesktopUpdateStateOnDownloadStart` reports `downloadPercent: 0`
until the first progress event, which would draw a zero-length arc, so
`0` renders as an indeterminate spinning arc instead.
- A manual retry keeps the button natively disabled for the whole
download; the quiet branch omits the `disabled:` dimming so background
and manual downloads render identically.
- The changelog tooltip stays available while downloading, just without
the update-tinted glass treatment.
- Tone is decided in `desktopUpdate.logic.ts` and covered by tests, so a
regression to the always-CTA behaviour would now fail the suite.

Tests:

- `vp test run apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx
apps/desktop/src/updates/DesktopUpdates.test.ts`
- `vp run --filter @t3tools/web typecheck`
- Targeted lint for the changed TypeScript files

---
Written by an agent (T3 Code, claude-fable-5).
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 14, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
yngatech-nightly Bot pushed a commit that referenced this pull request Aug 14, 2026
Background update downloads landed in #110, but the sidebar control
still treated downloading as a call to action: it shared the
`isUpdateState` styling branch with the states that want a click, so an
automatic download lit the button and its changelog tooltip in update
blue while needing no input at all. The downloaded state then offered a
circular-arrow icon — the same metaphor this app uses for refresh and
retry everywhere else, including the check-for-updates state of this
very button.

This splits the tone decision into `resolveDesktopUpdateButtonTone`
(`"cta" | "quiet" | "idle"`), so call-to-action colour is reserved for
states that actually want a click: install, or retry a failed download.
The intended flow is now visually staged:

1. Check for updates in the background (existing pollers, unchanged)
2. Update available → download starts automatically (#110, unchanged)
3. **Downloading → muted progress ring around a download glyph, no CTA
colour**
4. **Downloaded → CTA colour with an upward arrow, matching the update
glyph in provider settings**

| | Downloading | Downloaded — ready to restart |
| --- | --- | --- |
| Before | ![Before: downloading rendered as a blue CTA with a spinning
refresh
icon](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/before-downloading.png)
| ![Before: downloaded rendered as a blue CTA with a circular rotate
arrow](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/before-downloaded.png)
|
| After | ![After: downloading rendered as a muted progress ring around
a download
glyph](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/after-downloading.png)
| ![After: downloaded rendered as a blue CTA with an upward circle
arrow](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/after-downloaded.png)
|

Full motion — indeterminate spin before the first progress event,
gliding through the 10% progress broadcasts, then flipping to the CTA on
completion:

https://github.com/user-attachments/assets/80d64f3c-06d3-4f9e-aace-bfa2e29f1be8

Implementation notes:

- The ring follows the `ContextWindowMeter` construct (track +
dash-offset arc, `-rotate-90 transform-gpu`,
`motion-reduce:transition-none`), with its stroke transitioned over
500ms so the 10%-step broadcasts from the main process glide instead of
jumping.
- `reduceDesktopUpdateStateOnDownloadStart` reports `downloadPercent: 0`
until the first progress event, which would draw a zero-length arc, so
`0` renders as an indeterminate spinning arc instead.
- A manual retry keeps the button natively disabled for the whole
download; the quiet branch omits the `disabled:` dimming so background
and manual downloads render identically.
- The changelog tooltip stays available while downloading, just without
the update-tinted glass treatment.
- Tone is decided in `desktopUpdate.logic.ts` and covered by tests, so a
regression to the always-CTA behaviour would now fail the suite.

Tests:

- `vp test run apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx
apps/desktop/src/updates/DesktopUpdates.test.ts`
- `vp run --filter @t3tools/web typecheck`
- Targeted lint for the changed TypeScript files

---
Written by an agent (T3 Code, claude-fable-5).
incognitojam added a commit that referenced this pull request Aug 15, 2026
Desktop updates currently wait for a user click before downloading,
which makes the later restart action slower than it needs to be.

This starts the download as soon as the updater reports an available
release, without restarting the app automatically. While the download is
active, the sidebar update control uses its existing refresh icon as a
quiet spinner and keeps the changelog tooltip available. Once the
download completes, the existing restart action and confirmation flow
remain unchanged. Failed downloads can still be retried manually.

Screenshots:

| Downloading | Downloaded — ready to restart |
| --- | --- |
| ![Downloading update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloading.webp)
| ![Downloaded update
state](https://raw.githubusercontent.com/yngatech/t3code/979137ffeb1aad3add55a51ffe91e1a4a0de52a6/downloaded.webp)
|

Tests:

- `vp test run apps/desktop/src/updates/DesktopUpdates.test.ts
apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx`
- Targeted lint for the changed TypeScript files
- `vp run --filter @t3tools/web typecheck`
- `vp run --filter @t3tools/desktop typecheck`

---
Written by an agent (T3 Code, gpt-5.6-sol).
incognitojam added a commit that referenced this pull request Aug 15, 2026
Background update downloads landed in #110, but the sidebar control
still treated downloading as a call to action: it shared the
`isUpdateState` styling branch with the states that want a click, so an
automatic download lit the button and its changelog tooltip in update
blue while needing no input at all. The downloaded state then offered a
circular-arrow icon — the same metaphor this app uses for refresh and
retry everywhere else, including the check-for-updates state of this
very button.

This splits the tone decision into `resolveDesktopUpdateButtonTone`
(`"cta" | "quiet" | "idle"`), so call-to-action colour is reserved for
states that actually want a click: install, or retry a failed download.
The intended flow is now visually staged:

1. Check for updates in the background (existing pollers, unchanged)
2. Update available → download starts automatically (#110, unchanged)
3. **Downloading → muted progress ring around a download glyph, no CTA
colour**
4. **Downloaded → CTA colour with an upward arrow, matching the update
glyph in provider settings**

| | Downloading | Downloaded — ready to restart |
| --- | --- | --- |
| Before | ![Before: downloading rendered as a blue CTA with a spinning
refresh
icon](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/before-downloading.png)
| ![Before: downloaded rendered as a blue CTA with a circular rotate
arrow](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/before-downloaded.png)
|
| After | ![After: downloading rendered as a muted progress ring around
a download
glyph](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/after-downloading.png)
| ![After: downloaded rendered as a blue CTA with an upward circle
arrow](https://raw.githubusercontent.com/yngatech/t3code/assets/pr-update-pill-quiet-download/after-downloaded.png)
|

Full motion — indeterminate spin before the first progress event,
gliding through the 10% progress broadcasts, then flipping to the CTA on
completion:

https://github.com/user-attachments/assets/80d64f3c-06d3-4f9e-aace-bfa2e29f1be8

Implementation notes:

- The ring follows the `ContextWindowMeter` construct (track +
dash-offset arc, `-rotate-90 transform-gpu`,
`motion-reduce:transition-none`), with its stroke transitioned over
500ms so the 10%-step broadcasts from the main process glide instead of
jumping.
- `reduceDesktopUpdateStateOnDownloadStart` reports `downloadPercent: 0`
until the first progress event, which would draw a zero-length arc, so
`0` renders as an indeterminate spinning arc instead.
- A manual retry keeps the button natively disabled for the whole
download; the quiet branch omits the `disabled:` dimming so background
and manual downloads render identically.
- The changelog tooltip stays available while downloading, just without
the update-tinted glass treatment.
- Tone is decided in `desktopUpdate.logic.ts` and covered by tests, so a
regression to the always-CTA behaviour would now fail the suite.

Tests:

- `vp test run apps/web/src/components/desktopUpdate.logic.test.ts
apps/web/src/state/desktopUpdate.test.ts
apps/web/src/components/desktopUpdate.toast.test.tsx
apps/desktop/src/updates/DesktopUpdates.test.ts`
- `vp run --filter @t3tools/web typecheck`
- Targeted lint for the changed TypeScript files

---
Written by an agent (T3 Code, claude-fable-5).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant