Skip to content

Let an update be silenced, and say it is still there - #100

Merged
vmillet-dev merged 3 commits into
mainfrom
feat/silence-an-update
Sep 13, 2026
Merged

vmillet-dev merged 3 commits into
mainfrom
feat/silence-an-update

Conversation

@vmillet-dev

@vmillet-dev vmillet-dev commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Closes #68.

dismiss() — the "Later" button — only cleared _update and _status in memory, so the next launch offered the same version again. Someone who means to update at the weekend got the same modal in the way five mornings running, and it is a modal: it takes the focus and the Escape key from whatever the app was opened to do.

The three pieces, in the order the user meets them.

The checkbox, and what it stores

In the prompt itself, because the decision belongs where the interruption happens.

What is written down is the version, never a boolean: storing "the user said no" would silence 0.1.6 along with 0.1.5. AppSettings.skippedUpdate holds it, '' meaning nothing is silenced — so a newer release is a new offer and needs no gesture to become one again.

Of the two shapes the ticket offers, this is the first: a setting on AppSettings, which keeps SettingsStore.setting(key, codec)'s one-line property. It needed one new codec, asText — the existing string codec rejects the empty string, which here is a real value.

updateNotifications sits beside it as the blunter switch, so the panel entry means something with no update pending, as the ticket asks. Turning it back on also forgets the skipped version: "tell me about updates" is exactly what taking a skip back means, and a user who has just asked for it should not have to find a second control.

⚠️ Only the silent startup check is silenced. checkNow() — the About menu's "Check for updates" — is a question asked out loud and always answers. Without that line the feature would be a trap: a user who silenced a version and later went looking for it would find the menu lying to them.

The dot

UpdateStore.hasPendingUpdate — "an update exists and is not installed" — a third thing next to UpdateStatus and CheckState, for the same reason those two were kept apart.

It cannot read status(). dismiss() returns that to idle, which is what closes the prompt, so a dot driven by it would disappear with the dialog it exists to outlive — the ticket's own ⚠️, and the one thing here that is easy to get backwards. So dismiss() now leaves _update standing and moves only the status, and the prompt reads a new offered computed instead.

offered is null exactly when the status is idlenot "when it is not available", which was my first cut and which made the dialog vanish the moment installing began. Five existing specs caught it.

The dot is on the About menu's trigger, which already carries "Check for updates", with a .visually-hidden twin: information shown only graphically needs one.

Verified against the real release

Locally downgraded to 0.1.2 (not committed) so the updater would find the published 0.1.3, then driven through the harness against the real GitHub endpoint:

step result
launch prompt: "DevBox 0.1.3 est disponible. Vous utilisez actuellement la version 0.1.2.", dot present
tick the box, "Later" prompt closed, dot still there, preferences.json holds "devbox.skippedUpdate": "0.1.3"
next start no prompt, dot still there
preferences panel "La version 0.1.3 ne sera plus proposée. [Rétablir]"
click "Rétablir" key back to ""
next start prompt is back

A version, on disk, and the whole round trip. Nothing was installed at any point.

Checked

  • npm test — 953 passing, 16 of them new: the store's silencing rules, the checkbox (including that Escape and the backdrop honour it, since neither produces a click on "Later"), the dot outliving the prompt, and the panel entry.
  • npm run lint — clean.
  • Full e2e — 15/15.

docs/architecture.md and CLAUDE.md record the version-not-boolean rule and why the dot cannot read the status.

🤖 Generated with Claude Code

The dot, after looking at it on screen

Two things were wrong with the first cut, and a screenshot settled both.

It was amber, and amber already means something else here. The accent colour is what this interface uses for "active" and "selected" — the space rail wears an amber dot of its own two rows below the menu, so the screen showed two identical dots meaning unrelated things. A badge in the accent colour reads as one more state rather than as news. It is now --green, which is free in the chrome: the only other use is the syntax theme.

On the trigger it was wedged between the label and the chevron. "À propos ● ▾" reads as punctuation inside the control rather than as a badge on it — the label and the chevron are one thing. It is now superimposed on the corner (position: absolute, 1px from the top and the right of the trigger, which .about-wrapper already gave a positioning context).

Measured on the assembled application rather than eyeballed: rgb(111, 191, 139), position: absolute, 1px from each edge, and the trigger's accessible name reads "À propos Une mise à jour est disponible" — the .visually-hidden twin is carried by the button itself.

The entry inside the menu keeps its inline placement, which is the conventional one there.

"Later" only cleared the store, so the same version was offered again at
every launch. The prompt now carries a checkbox, and what is written down
is the **version** — remembering "no" would silence the release after it
too, and a newer one is a new offer that needs no gesture.

The preferences panel names the silenced version with a way to take it
back, and a dot on the About menu says an update is still waiting. The
dot reads `hasPendingUpdate`, not the status: `dismiss()` returns that to
`idle`, so a dot driven by it would vanish with the dialog it outlives.

Only the silent startup check is silenced. `checkNow()` always answers.
The trigger's dot says something is waiting; opening the menu said
nothing about what for. "Check for updates" now carries the same dot.
@vmillet-dev
vmillet-dev force-pushed the feat/silence-an-update branch from c07b86f to 2160a24 Compare September 13, 2026 19:09
Amber is what this interface already means "active" and "selected" with —
the space rail wears an amber dot two rows below the menu — so a badge in
the accent colour reads as one more state rather than as news. Green is
free in the chrome; it is only used by the syntax theme.

On the trigger it is now superimposed on the corner rather than wedged
between the label and the chevron, which are one control and read as one.
@vmillet-dev
vmillet-dev merged commit 9f3a9c9 into main Sep 13, 2026
9 checks passed
@vmillet-dev
vmillet-dev deleted the feat/silence-an-update branch September 13, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The update prompt comes back at every launch, with no way to silence it

1 participant