Let an update be silenced, and say it is still there - #100
Merged
Merged
Conversation
"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
force-pushed
the
feat/silence-an-update
branch
from
September 13, 2026 19:09
c07b86f to
2160a24
Compare
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #68.
dismiss()— the "Later" button — only cleared_updateand_statusin 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.skippedUpdateholds 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 keepsSettingsStore.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.updateNotificationssits 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.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 toUpdateStatusandCheckState, for the same reason those two were kept apart.It cannot read⚠️ , and the one thing here that is easy to get backwards. So
status().dismiss()returns that toidle, which is what closes the prompt, so a dot driven by it would disappear with the dialog it exists to outlive — the ticket's owndismiss()now leaves_updatestanding and moves only the status, and the prompt reads a newofferedcomputed instead.offeredisnullexactly when the status isidle— not "when it is notavailable", 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-hiddentwin: 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:
preferences.jsonholds"devbox.skippedUpdate": "0.1.3"""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.docs/architecture.mdandCLAUDE.mdrecord 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-wrapperalready 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-hiddentwin is carried by the button itself.The entry inside the menu keeps its inline placement, which is the conventional one there.