visitor@nextdash: ~/posts — nextDash 1.0.3 update – nextDash 80×24

nextDash

MIT

Your bookmarks. Your terminal. Your rules.

visitor@nextdash:~/posts$ cat nextdash-1-0-3.md

nextdash-1-0-3.md 19.4K

-rw-r--r-- jordi

nextDash 1.0.3 update

18 min

nextDash 1.0.3 is out, and it closes a gap that had been sitting in the app for a long time: nextDash has always recorded when you added a bookmark, when you last opened it, how often you open it and what you tagged it — and almost none of that ever reached the parts of the app you actually drive. This release hands it over. It arrives on the back of two smaller releases, 1.0.1 and 1.0.2, which went out quietly over the two days before it; all three are covered below.

If you have been running nextDash since the 1.0.0 milestone, this is the first release that will reopen the What’s new modal for you. Both 1.0.1 and 1.0.2 were deliberately muted so they would not push a second dialog in front of anyone who had just read the 1.0 notes. That mute has now been lifted on both, so every version is visible in the modal again — which is part of why this post exists: two releases’ worth of work went past most people without a word.


nextDash 1.0.3 — 14 August 2026

One theme runs through most of this release. Five pieces of data — when a bookmark was created, when it was last changed, when it was last opened, how many times it has been opened, and its tags — were written on every path through the app, fed the built-in features, and reached almost none of the features you control yourself. Alongside that: Config → Bookmarks, which had no settings at all, now has ten.

Using what nextDash already knew

  • Search can ask when you added or last opened something. added: and opened: join the search parser, both taking today, week, month or year — plus opened:never. “Added this month and never opened since” is now a question you can ask straight from the search bar, instead of only from Config. A word the parser does not recognise filters nothing rather than everything, which is the safer way round for a typo.
  • Your own collections can ask the questions the built-in ones do. Custom collection rules gained pinned, untagged, days since last opened and days since last changed. So “my dev links I have not touched in ninety days” is something you can now build yourself, rather than something only the built-in collections could do. Pinned and untagged are allowed to stand on their own without a value, so the server no longer discards them as half-filled rows. Days-since-changed is, incidentally, the first thing on the dashboard that has ever read the “last modified” timestamp.
  • A Recently added smart collection. The other four all key on what you open, so “what did I just save?” had no answer anywhere. It is off by default and comes with its own limit and choice of pages.
  • Search now looks at the page’s own description. nextDash fetches it for every bookmark and nothing ever searched it — even though it is often the only place holding what you remember about a page whose title is “Untitled” or “Login”. It is scored below your own note: the site’s words matter, but yours matter more.
  • Drift shows on the dashboard. A link that quietly turned into a different page now reaches the header badge in the warning tier. It still answers with a perfectly healthy 200, which is exactly why it needed a human to look at it — and why leaving it buried in Health, where you had to go on purpose, was the wrong place for it.

Config → Bookmarks: ten settings that used to be constants

Every one of these was previously hardcoded. If the built-in value happened to suit you, you never noticed; if it did not, there was nothing to be done about it.

  • The list remembers how you sorted it. Health and the Inbox both keep their sort. This list snapped back to page order every time — including on the way back from editing a single bookmark.
  • Rows per load step is yours to pick. It was fixed at fifty: too many on a phone, too few when you are working through a large library.
  • A quick-added bookmark can land somewhere sensible. New links always arrived unchecked, unpinned and uncategorised — and everything landing uncategorised is precisely what creates the tidying-up that the cleanup filters exist to find. You can now choose the availability, the pin state and the category a quick-added bookmark starts with.
  • Switching bookmarks to Monitor no longer means correcting each one. Every row got fifteen minutes regardless of what you were watching, so thirty rows meant thirty corrections. The starting interval is now a setting, and it applies in bulk too.
  • Deleting can stop asking. Undo and the thirty-day trash already cover a misclick, so a tidy-up was costing an extra keypress per row for nothing. You choose how many rows a delete has to touch before it asks for confirmation — and the same for a bulk icon refresh.
  • “Not opened in a while” is a number you choose. It was ninety days, everywhere, and it also decides which bookmarks the overview is willing to call neglected.
  • Archive links can point at your own archive. They always went to the Wayback Machine. If you run something of your own, or simply prefer another service, the template is yours to set.

Every range is enforced on the server as well as in the controls, since the API is reachable without going through the browser. The archive template has to contain {url} and start with http, so it can never be turned into a javascript: URL that the app then opens for you.

Config picks up where you left off

Stepping out of Config to check something and coming back used to land you on Overview, leaving you to navigate your way back to the tab you were just on. It now returns you there for fifteen minutes, however you left — the old rule only saved your place when you left by one of two specific shortcuts, and cleared it on every other exit, so the most common route of all (Escape out, Shift + S back in) always dumped you on Overview. After fifteen minutes it starts on Overview again, on the reasonable assumption that by then you are doing something else.

One small related fix: opening a bookmark from Config now respects your “open in new tab” preference. The setting existed and the grid honoured it; this one path forced a new tab regardless.

The grid

  • Tags can show on the rows. Every row already carried its tags and displayed none of them — so the one place you could not act on a bookmark’s tag was the row showing it. Off by default; the first two show and the rest collapse into a +N count, with the cap configurable. They render inside the link rather than as an extra column, because the grid’s columns align across every category and a new column would have shifted every row on the page. That alignment was measured before and after down to the pixel, and pinned as a test.
  • Category headers take back their width. Four sort buttons sat on every header, and headers repeat down the page — together they were taking more room than the bookmark names beside them. The sort in use now stays in front and the rest move behind a menu, taking the strip from around 90px to 19px, or 58px once something is sorted.
  • Two more ways to sort a category: by when you added a bookmark, and by how often you open it.
  • “Recently added” meant two different things. Config sorted by when you added a bookmark; the grid used the same words for when you last opened one. The grid’s mode is now called what it actually is. Stored categories keep working — the old value is still accepted and translated.

Keyboard and mouse

  • Pinning has a key. Shift + P on the row you are on. It was a daily one-key decision that could only be made from the command palette or by opening the editor — and it now has a right-click entry too, which it never had at all, despite every other one-bit row action having one.
  • Sharing has a key. Shift + S shares the row, or copies its name and address where there is no share sheet.
  • Jump straight from a row into Health. Shift + R opens Health on that bookmark. Before this, opening Health and then finding the row again was the only way there.
  • Filter to a tag you can see. t filters to the tag on the row you are on, instead of opening the tag cloud and hunting for it among all the others.
  • Ctrl/Cmd + Enter opens in a new tab for that press alone. The keyboard path fired a bare click that carried no modifier at all, so it only ever honoured your standing preference — meaning opening one link differently meant reaching for the mouse.

Each of the new shortcuts delegates to the implementation that already existed behind the menu entry, rather than adding a second code path that could drift away from it.

Inbox

  • Triage ignored the keyboard. It is a keyboard-only way of working and it took no key but Escape: j, k, the arrows, promote, snooze, note and delete all did nothing, and it sat on the first link whatever you pressed. The cause was a guard asking “is a modal open?” — which counted the triage overlay itself, so the overlay was blocking its own keyboard. It now asks whether something sits over triage. This was reported once before and could not be reproduced at the time; the repro turned out to be a seeded queue of three and two presses of j.
  • A short tour the first time you open the Inbox. Seven steps through the whole loop: where links come from, what “read” really means, snoozing, notes, promoting, triage, and working on several at once. It appears once, and Config → Help → Inbox now covers the same ground whenever you want it. It is fetched on demand rather than loaded with the app, because the Inbox loads during startup for the unread badge — riding along would have cost every session that never opens the view.
  • “Show quick-start card again” now replays the tours and tips it promised. Its own dialog offered to bring back the welcome tour and the tips; it only ever brought back the quick-start card, so no tour or tip had ever actually come back for anyone.

nextDash 1.0.2 — 14 August 2026

Mostly a repair release, from a full audit of the config view. A handful of things in Config claimed to have worked when they had not, and a few doors only opened one way — you could take a theme or your bookmarks out, but not put them back.

The recurring fault was a single shape repeated in several places: a read that failed degraded to an empty list, and the next write posted that emptiness back as the complete state. Failure and emptiness were the same value, so a server blip in the middle of an edit could destroy real data behind a cheerful “Saved” badge.

Things that said they worked and did not

  • A hiccup while saving could wipe a page’s categories. If the app could not read the current list first, it treated that as “there are none” and saved the one category you were adding over all of them. Proven end to end: five categories in, one out, no error shown. It now stops and says so.
  • Refresh all favicons never worked. The button always ended on “Could not refresh the favicons”, whatever the state of your bookmarks — it was sending a request the endpoint could not accept. It now does what it says.
  • Deleting a category could report success while it was refused. The server keeps a category that bookmarks still point at; the screen said it was deleted anyway, offered to undo it, and filed it in the trash. The row now comes back with an explanation.
  • A new collection could vanish without a word. A collection with no name, or with no rule that had a value in it, was quietly discarded while the screen said “Saved” — and it was gone after a reload. The server now reports what it did not keep, surfaced when you leave the Collections tab rather than on every save, since a half-filled row is the normal state while you are typing.
  • Finders, categories and tags could be replaced by an empty list after a failed load. The list looked empty, and the next edit wrote that emptiness back over the real one. Both loaders now mark the failure, and both savers refuse to write while it is marked.
  • Changing a setting in a second tab left the first one stale. The listener, the queue and four tests all existed; nothing ever actually broadcast the change, so the other tab stayed stale until reloaded by hand. (The tests wrote the message themselves, which is why they passed either way.)
  • The icon-fetching overlay stopped swallowing clicks once it had finished. It covers the whole viewport and stayed up through the completion pause and the reloads after it, so the page read “Icons updated” while every click you made landed on the overlay instead of the button underneath.

Getting things in and out

  • Themes can be imported. Export has been there all along. A palette built on one machine can now be carried to another, or shared, without restoring a whole backup over everything. It lands as a new theme and cannot overwrite the palette you have on screen, and a JSON file with no colour values in it is refused.
  • Bookmarks can be imported from CSV. Export the list, tidy hundreds of rows in a spreadsheet — fixing categories, adding tags — and put the result back. Unlike the browser import, this route carries tags and notes. The parser is hand-written rather than a naive comma split, because the export quotes every field so that a note can contain a comma, a doubled quote or a newline. Columns are matched by their header, so reordering them in your spreadsheet still imports cleanly, and de-duplication by URL stays on the server.
  • The trash has a search box and can restore several at once. Undoing a bulk delete of twenty was twenty clicks in a list of up to five hundred, with no way to find anything in it. You can search by name, URL, tag, category or origin page, tick what you want and restore the lot — each one is restored on its own, so one that cannot come back does not take the batch with it.
  • Saved searches survive a new browser. They lived only in your browser’s storage, which meant they were in no ZIP backup at all and a cleared cache took them for good. They are now kept with the rest of your settings, and anything still sitting in browser storage is migrated on first read.
  • A failed load no longer reads as an empty trash — which is the one message most likely to stop you recovering something you have just lost.

Keyboard and screen readers

  • Settings controls now say what they are. A screen reader announced “combo box, 30” with nothing naming the setting, across all of Behavior and much of Appearance — the labels render as styled text rather than as real form labels. Every schema-rendered control is now named in a single pass after the panel is drawn, rather than at the thirty-odd render sites that would have drifted apart. Sliders also announce a readable value, since 0.85 is not what the interface shows you.
  • The arrow keys stopped working on the Appearance tabs after the first press: focus was lost the moment the panel redrew itself, and one press of ArrowRight killed every press after it.
  • Changing a setting no longer throws you back to the top of the page. Controls commit while they still have focus and the repaint replaced the whole panel body, so the next Tab started again from the top. Focus and caret position are now carried across the repaint.
  • Confirmation dialogs keep the keyboard inside them. Both hand-rolled dialogs declared themselves modal and only handled Escape, so Tab wandered off into the page behind — including on Reset all data.

Elsewhere in 1.0.2

  • Names cannot be emptied or pasted to any length. Clearing a category’s name saved it as nothing — a heading with no title, a blank row in the theme picker — and two emptied names stopped colliding with each other, because an empty name is never “taken”. Very long names pushed buttons off the screen. Both ends are now clamped, in the browser and on the server.
  • Check for updates says when it last checked. The answer is cached for a day, so the button used to look broken when it repeated itself.
  • The backup tile says when the next backup runs, rather than only that backups are switched on. The server had been sending that figure — along with the total kept — and nothing rendered either.
  • The Inbox conversion figure counts links you kept. They were left out of the sum while the panel above showed them as their own tile, so the arithmetic never added up.
  • Page archiving is gone from the manual. It was described as a working feature, with a note on where to find it. It had never been built — the setting had defaults and a migration, and not a single line of the app ever read it.

nextDash 1.0.1 — 13 August 2026

A small follow-up to the 1.0.0 milestone: the trend line in Health is now big enough to read and says what it is showing, and nextDash notices a new version again whatever order releases were published in.

Health

  • The trend line is readable at last. It sat squeezed into the toolbar between the buttons, competing with them for space and far too narrow to see anything in. It has moved down beside the text explaining the filter — where there was empty space all along — and now takes about half that width. (Reserving a column beside the buttons was tried first and reverted: it stranded whichever button ran out of room on a line of its own.)
  • Point at a day to see it. Hovering the chart names the day and the share of your bookmarks that were healthy on it. A day with no reading says so, rather than showing 0% as though everything had broken at once.
  • The chart says what it is measuring. A 100% mark on the left, a line through the middle for reference, and a dot on the most recent reading so the eye lands on where things stand now. The beside it explains why the scale never moves and why the line has gaps — kept as its own explainer rather than buried in the view-wide one.

Update checking

A new version could go unannounced. nextDash asked GitHub which release was published most recently, rather than which one is newest. Publishing a fix on an older line after a newer release therefore hid that newer release completely — the older tag came back as “latest”, was correctly rejected as not newer than what you were running, and that was the end of it. nextDash now reads the whole release listing and compares the version numbers itself, falling back to the old endpoint only if the listing cannot be read.

Documentation

Three Inbox shortcuts shipped in 1.0.0 without ever reaching the keyboard legend: Shift + ↑/↓ to extend the selection, Ctrl/Cmd + A to select all, and R to refresh. They now appear in both the inline legend and the cheat sheet, which went from 55 to 58 rows — the printable HTML and both PDFs have been regenerated.


Upgrading

If you are running the Docker image, the usual two lines will do it:

docker compose pull
docker compose up -d

Building from a git checkout instead:

git pull
docker compose -f docker-compose.prod.yml up -d --build

Or straight from source, without Docker:

git pull
go build -o nextDash && ./nextDash

There is nothing to migrate by hand. Saved searches move from browser storage into your settings on first read, and grid categories stored with the old sort name keep working. The What’s new modal will open once after the upgrade with 1.0.1, 1.0.2 and 1.0.3 all visible in it.

The full picture

Every entry above, plus the tests, locale keys and documentation work that came with them, is in the changelog. The manual has been updated for all of it — the Inbox tour in §4.4 and §7.9, the config location memory in §4.5 and the config chapter, and the shortcut table for the four new keys.

nextDash is a keyboard-first, self-hosted bookmark dashboard. No accounts, no cloud, no noise — and it tells you which of your links are already dead. Find it on GitHub.

online uptime 26d 11 posts utf-8 wp 7.1