A round of fixes on v1.4.0, and three of them were things that had been quietly
not working rather than newly broken.
What's new
- fix — an upgrade shows its release notes again. Two settings record that onboarding is over —
quickStart.dismissedfor the card,onboardingCompletedfor everything allowed to appear afterwards — and an install can hold one without the other. That install goes quiet in both directions: quick start does not run because it is dismissed, and no unprompted card appears either becausecanShowUnpromptedUirefuses whileonboardingCompletedis false. The release check said there is something new here on every load and the prompt was even scheduled —shouldtrue, timer set,canShowPostOnboardingPromptsfalse — and then nothing asked, for the lifetime of the install, with nothing in the interface able to fix it: the one thing that sets the flag is dismissing a card that no longer appears. Dismissing the card is finishing onboarding, so the two are reconciled when the disagreement is met. - fix — Replay onboarding brings the card back, not just the flag. It cleared
onboardingCompletedand leftdismissedtrue, which is the same disagreement: the reader was promised the welcome tour and got nothing, and the install was left in the state that silences every unprompted card. Both are cleared now;setupDoneis left alone, since replaying the tour is no reason to ask again for a language and a theme already chosen. - fix — the unseen-release fast path was unreachable.
schedulePostOnboardingPromptstakes a 120ms delay and prefetches the modal when there is a release the reader has not seen, but the branch sits behindelse if (Number.isFinite(options.delay))and the only caller passeddelay: 900— which is the default the branch exists to shorten. Measured at 900ms with no prefetch before, 120ms with the modal already fetched after. The caller no longer names the default, and the trap is written down where it is set.
Overview
- fix — all ten posts from nextdash.cc reach the overview. Three caps disagreed about how many there were. The parse stopped at exactly ten, which matches a feed of ten only until an eleventh is published and the oldest silently stops arriving; the byte ceiling was 512KB against a feed measured at 172KB whose tenth item starts at 97% of the file; and the window held six rows shared with releases and features. The parse cap is twenty and the ceiling 2MB, so ten is a floor rather than a ceiling, and the window is fourteen rows with ten reserved for posts. The reservation itself was wrong at that size — it asked whether the window held a post at all, which was fair while two were reserved and let one post stand in for the other nine at ten. Measured at nine before, ten after.
Appearance
- fix — nineteen settings strings were never translated. The Depth and Backdrop controls, every option in both (Flat/Soft/Rich, Follow the theme/Dots/Grid/Lines/Hatch/None), Browse… beside the theme, the widget title label, the message a source shows when it needs a token, and the On/Off pair — all present only as English fallbacks in
t(key, fallback), in all four locale files. Two of them,themeDepthandbackgroundPattern, are prefixes for keys built by concatenation, so the option names were missing too. 19 keys × 4 languages. - fix — a category spanning two columns says so with its rule. The line under a category title fades out at 85% of its width, which is right for one column and lands well short of the edge across two, so a wide category looked like a narrow one whose line happened to be long. A wide category now gets a gradient that carries further and holds its colour longer — 70% accent against 55%, a full hairline where the old one had been transparent since 85%, reaching the end rather than stopping short of it. On a 752px title that is the last ~113px, which is exactly where the second column begins.
The dashboard
- fix — only a scroll the reader asked for closes the category menu. The menu closed on any
scrollevent. A re-render of the grid empties a column for an instant, the document gets shorter, and the browser clampsscrollTopback into range — which firesscrollexactly like a real one and took the open menu down with it. Wheel, touch, pointer and key are the marks a reader leaves; the clamp leaves none. Watched in the capture phase so a scroller that stops propagation still counts, and registered after the menu's own key handler so moving through the menu never reads as scroll intent.
Under the hood
- new — the Go sources moved to
internal/app/. 259 files sat in the repository root, which put the entire server in the same listing as the README, the Dockerfile and the compose files. They are one package still — a move, not a split, which would mean exporting every identifier crossing a new boundary and breaking whatever import cyclemodels.goandhandlers.goshare.main.gostays in the root because it has to://go:embedpatterns resolve relative to the file that declares them and cannot climb out with.., so the directive has to sit besidestatic/,templates/andlocales/. Three things broke quietly on the way: the embed reached the package as a parameter, so undergo test— where nothing callsRun— it sat at nil and every read through it failed; seven tests readstatic/…relative to the working directory, whichgo testsets to the package directory; and the Docker build stamped the version with-X main.buildVersion=, naming a package those variables had just left, which the linker does not object to.TestBuildVersionLdflagPathMatchesPackagereads the Dockerfile and fails on that mismatch now. - fix — the monitor interval fallback named 60 where everything else says 15.
dashboard-inline-edit.jsfell back to 60 minutes whenwindow.CheckModewas absent, againstDEFAULT_INTERVAL_MINUTES = 15in check-mode.js,defaultMonitorIntervalMinutes = 15on the server, and 15 at the two other fallback sites. Latent rather than active — check-mode.js loads withdeferand a bookmark is created on a click, so the fallback never fired — but it would have quartered the check frequency of that bookmark, silently, from the moment monitoring was switched on. - fix —
formatByteswas defined twice inDashboardConfig. The second definition silently overrode the first; measured over 0–1MB the two produced identical output, so nothing displayed differently, but the first was unreachable and editing it would have had no effect. The dead one is gone. - fix — the unused-locale-key check could not see a key built with
+. It recognises`config.${x}`but not'config.backgroundPattern' + option…, so every key in such a family was reported unreachable while being used on screen. It reads both forms now, and still reports a genuine orphan — verified by planting one.
Docs
- Release notes
static/data/whats-new/v1.4.1.1.json, theindex.jsonentry carryinghideFromModal, the constants spec, this changelog,README.md, and the Config → Help version paragraph in all four locales. NEXTDASH_WHATS_NEW_DATA_VERSIONis bumped andDASHBOARD_RELEASEis not. The release counts toward the version number and leads Config → Overview, but the modal keeps leading with v1.4.0: a round of fixes should not reopen the notes in front of readers who have just been shown a large release. Without the data token, though, a browser holding the old index would never learn this release exists at all.- No spotlight entry in
static/data/overview-features.json: this release introduces no setting worth switching on, and the feature window counts the two most recent releases that actually brought one, so a fixes-only release does not empty it. go generate ./...for the changed CSS, JS and locales.