The Containers view's big round: a live logs window, a Disk tab, notices when a container goes down, a timeline and health checks per container, skip, hold and rollback for updates, CPU and RAM columns, compose stacks and ticked containers acted on as one, and the analytics that go with them. The Bookmarks and Inbox views get sortable column headings, a string of settings, backup and listener fixes lands everywhere, and the docs and translations catch up. Announced in the What's new window.
Everywhere
-
new — the category sort menu says what each sort does. The ⋯ in a category header listed Rec and Top; it now reads Manual, A–Z, Last opened, Newest and Most opened, and only the chip in front of it keeps the short name. A new spec,
dashboard-category-sort-usage.spec.js, checks the order Last opened and Most opened give, never-opened bookmarks last. -
fix — the Inbox key legend named keys that did nothing. It always listed
Shift + K, which only keeps a link while Unsorted is on, and called a double click open even with the double-click setting on note. The legend now follows both. -
fix — suggested tags were read out as a bare name and "×". The chips under the tags field (bookmark form, inbox, Config → Bookmarks) now carry the same labels as their tooltips: Tag this bookmark #… and Stop proposing #… here.
-
fix — the tag cloud's close button had no name until the modal first opened. It now has a static
aria-label, translated on open. -
fix — the analytics notice could pass markup through. Its escape helper fell back to returning the text as it was; it and the stat tile now use the shared
escape-html.js. A new spec,shared-escape-callers.spec.js, checks that markup arrives as text. -
fix — Config's status tiles, danger panel and setting swatches ignored the theme. Hard-coded colours in
config-view.cssandsetting-art.cssare now the theme's success, warning and error tokens and a mix of its background; the six theme plates keep their own colours on purpose. -
fix — preview card images load lazily and decode off the main thread. The favicon, the video poster and the link-preview image in the bookmark form gained
loading="lazy"anddecoding="async", as the card's main image already had. -
fix — one
formatBytesinstead of three. Widgets, Config and the mount picker each had their own; they now shareshared/format-bytes.js, each keeping its wording through an option. -
i18n — the strings still in English are translated. About 190 per language in Dutch, German, French, Spanish and Chinese, most of them the Containers view's newer text (Disk, logs, updates, rollback, the tour), plus three in the Dutch extension. Terms follow each language's existing file; words that read the same in that language (Docker, CPU, Tags, Health) stay as they are.
-
fix — a Bookmarks view link kept the reader's last sort and group. Absent keys in
#bookmarks?…cleared the filters but not the sort or group, so following a link, or going Back to one, kept the order you had and then wrote it into the address. Absent now means the default, as the address is written; an unknown sort is ignored. -
fix — with the inbox rail folded, every visit left a document listener behind. Its outside-click handler was added on each mount and never removed, each holding the old view. It is now removed when the view closes and before a new one is added.
-
fix — every Appearance repaint left a document listener behind. The theme picker's outside-click handler was added on each bind and never removed, so old ones held their detached lists, and one bound while the list was open could revert the theme preview on every later click. The previous handler is now removed first.
-
fix — the inbox's bulk Promote menu could list one page's categories under another. Choosing page A, going back and choosing B let A's categories, arriving late, be added under B's heading, so a click promoted to A. A late answer for a step no longer showing is now dropped.
-
fix — duplicating a page could make an empty copy and call it a success. A failed read of the source's bookmarks or categories counted as none, and a failed category save let the copied bookmarks point at categories the new page did not have. Either now stops the copy with an error.
-
fix — an inbox tag filter stayed in the address after going back to a page. Leaving the inbox removed its keys from the address by name, and
ib_tagwas not on the list, so a reload brought the tag back and it outranked the stored filter and sort. Everyib_andhv_key now goes, by prefix. -
fix — the server log could show lines that did not match the filter, or the same lines twice. A poll that landed after the search changed was appended to the filtered list, and on a slow server two polls asked from the same position. Only the newest read's answer is used now, and a poll waits while one is on its way.
-
fix — clicking a category in Statistics → Collection opened an empty Bookmarks list. The row passed the category's name as the filter, but bookmarks carry the category's id; it now passes the page-and-id key, and no longer also types the name into the search.
-
fix — three things in the Containers side panel. After a refused or failed action the list was re-read but the side panel kept the old state; it now refreshes too. The CPU and memory figures polled the daemon every two seconds even with the tab hidden; they now wait until it is visible. And their labels, CPU and Memory, now go through the translations.
-
fix — the Container list widget opened
http://[IP]:…, and a non-web address from a label reached the browser. The widget used the raw web UI address; it now fills[IP]as the table does. AndwebuiHref(), which every web UI link goes through (table, side panel, row menu, search, widget), now returns nothing for an address that is nothttp(s)://, so ajavascript:label set by an image is never opened. -
fix — the update badge could come back right after an update. An update check reads the image states, asks the registries, then writes them all back; an update or rollback that finished in between was overwritten by the older reading, and the badge stayed until the next check. An entry newer than the check's start is now kept.
-
fix — a stop, restart or remove could slip into a running container update. Actions were locked by container id, but they resolve the container by name, and an update moves the name to a new id halfway; a second tab could then act on the half-made new container. The lock now holds the name as well.
-
fix — a failed container update could leave the old container stopped and renamed. The rollback ran on the update's ten-minute budget, so an update that spent it on the pull failed its rollback too; and a new container already removed (from another tab) made the rollback stop before it restored the old one. The rollback now has two minutes of its own and treats a 404 on removing the new container as done.
-
fix — two settings saves at once could drop one of them. A settings POST, a favicon or font upload and the archive-key save each read the settings, changed their field and wrote the whole struct back; two at once started from the same snapshot and the second erased the first's change. Each read-change-write now runs under one lock.
-
fix — restoring a backup could leave torn or mixed data. Each file was written straight over the live one, so a crash or a full disk mid-restore left half a JSON file, and a bookmark click during the restore could write its page back over the restored one. Files now go through the atomic writer (which also puts back 0600 on an existing secret file), all under the store lock.
-
fix — a maintenance window whose days were all invalid silenced alerts every day. Out-of-range days were dropped, and a window left with no days reads as every day; such a window is now dropped instead.
-
fix — posting a settings file from another instance reset depth, glow and effects to follow.
SaveSettingskept every one-time migration marker a save left out exceptsurfaceFollowMigrated, so the next read ran that pass again over the forced look. -
fix — the activity log kept one backup fewer than set. Rotation moved
.1onto.2before.2had moved on, so.3never existed and a rotation's worth of history was lost each time; the shift now runs oldest first. -
fix — Remember scroll position and soft 404 detection were off on installs from before 17 August. Both default on, but a settings file written before they existed read as off; an absent key now means on, as it does for the other default-on switches.
-
docs — Help and the manual describe the sortable column headings. Config → Help (Bookmarks view → the list, Inbox → working the list, in all six languages) and MANUAL §11.2, §11.13 and §13: which headings sort and in what order, the arrow, that Sort follows, and the
rev=andib_diraddress keys. -
fix — seven more places no longer report a failed settings save as done.
saveSettings()resolvesfalseon a failed save rather than rejecting, and resetting onboarding, bringing a tour back, a choice in the changes tour, the Shift+Q search mode, the ask-again for browser notifications, the date-and-weather card and the feeds switch in the fresh tutorial each ignored that answer: they said the change was made, or kept it on screen, beside the save error. Each now checks the answer. -
fix — restoring a bookmark from the trash keeps its page free of duplicates. A page holds each address once, as a save insists, but a restore put the bookmark back even when the address had been added again since: it is now refused and the item stays in the trash. A shortcut taken since is let go, and the bookmark comes back without it.
TestRestoreTrashItemKeepsThePageFreeOfDuplicatesfails on the old code. -
fix — the Go tests are race-clean again.
go test -race ./...failed four tests on races in shared state: the activity log's config and its test override were read without a lock while a save or a test replaced them, and every set of handlers rewired the Containers view's settings source. Both now sit behind atomic pointers. -
new — every column heading in the Bookmarks view sorts. Tags (A to Z by the first tag, untagged last), Shortcut (the keyed ones first), Usage (the most opens in the sparkline's window first) and Score (the worst first, now without a Health filter too) join Name, Pinned, Opens, Last opened and Added; the toolbar's Sort offers the same four. The labels reuse the column names, so no new strings.
-
new — analytics, when switched on, also reports how widgets, the Containers view, Health, Inbox and the Bookmarks view are used. Three more once-per-load events beside the settings and content snapshots:
widgets-snapshot(how many widgets of each type),containers-snapshot(which Containers options are on, whether a socket and control are configured, and counts of hidden containers, custom addresses and waiting updates) andviews-snapshot(Health's checked, down and certificate counts and the age of the last check; Inbox's unread, snoozed and noted counts and which of the known sources were ever used; the layout options chosen for Inbox and the Bookmarks view). The server counts them (analytics_snapshots.go), only when analytics is on and cached for ten minutes like the content counts, dropped on a settings save; the browser buckets every count before it leaves. Nothing names anything: no container, image or widget names, no addresses, and Docker itself is never asked. The privacy text and the manual's table say so; the new sentence is English in the other five languages until the next docs round. -
new — the column headings in the Bookmarks and Inbox views sort the list. A click sorts by that column in the order it reads naturally (names A to Z, counts and dates the highest first, the worst score first), a second click turns it round, and the toolbar's Sort follows; picking from the toolbar starts afresh in the natural order. An arrow on the heading says which way the list runs (
data-lvs-sort, drawn by the shared.lvs-colhead-sortinlist-view-shell.css). Bookmarks sorts on Name, Pinned, Opens, Last opened, Added, and Score while a Health filter is on; a turned-round sort rides in the address asrev=1. Inbox sorts on Title and Site, a second click reversing them (ib_dir=desc, kept like the sort), and Added switches between newest and oldest first; under Snoozed, which keeps its wake order, the headings stay text. -
fix — the header hid its Bookmarks, Inbox, Containers and Config buttons at some window widths with room to spare.
fitHeaderZones()measured the clock by the box it is drawn in, and that box is the row's1frtrack, stretched over whatever the other zones leave, so the sum always came to exactly the row's width and a fraction of a pixel decided: 1440px hid the buttons, 1452px kept them. Each zone is now measured at its content width (max-content, for the measurement only), with a pixel of slack for fractional widths. A new spec walks the window from 1100px to 1700px and fails on the old code at a dozen widths. The same comment block, pasted three times in that function, is down to one. -
new — the Bookmarks and Inbox views name their columns, as the Containers view does. One shared style,
.lvs-colheadinlist-view-shell.css: the group heads' uppercase caption in the theme's own text, surface and rule colours, pinned under the view's header while the list scrolls, and gone at phone width. Bookmarks lays its headings on the rows' own grid from the same column choices (View → Columns shown) and the same cell classes, so a heading stands over its column at every width; it sits outside#config-bm-list, so the virtual window and the row queries never see it. Inbox shows Title, Site (Address when the whole address is shown, none when hidden) and Added. No new strings: every label already existed.
Containers
- new — tick containers and act on the lot. A box in front of each name,
xorSpaceticks a row,Shift-click,Shift + XorShift + ↑/↓a run, andCtrl/Cmd + Aeverything the filter shows. The bar above the list starts, stops, restarts, updates or mutes the ticked containers one at a time, with a count, and ends with one notice such as 3 restarted, 1 failed; nextDash's own container is left out, and without actions switched on only muting is offered.Escclears the ticks first. New spec:docker-bulk-select.spec.js. - new — container actions in analytics. With analytics on, each action sends one
docker-actionevent: which action, whether it worked, and where it came from (row, side panel, menu, key, command, selection bar), with a bucketed count for a selection. No names, images or addresses. An update the server had to roll back now counts as failed. - new — a custom web UI address shows where you look. The side panel's head shows the web UI address under the name, tagged Custom when it is one you set (the tag opens the Custom section), and the table's Web UI column puts a dot in front of it.
- fix — the Containers column headings use the shared
.lvs-colhead-sort, as Bookmarks and Inbox do; sort keys and the stored sort are unchanged. - fix — an update keeps the container's anonymous volumes. A volume the image declares (
VOLUME) and nothing mounts by name is created per container, so the swap gave the new container a fresh, empty one and left the data in a volume nothing used -- which the Disk tab then offered to remove.dockerKeepAnonymousVolumes()mounts the old container's into the new one; binds and named volumes stay as HostConfig has them. A rollback does the same.TestDockerRecreateKeepsAnonymousVolumesfails on the old code. - fix — an update or rollback refuses what it cannot swap safely, before anything is pulled or stopped. A container others run inside (
network_mode: container:X, a VPN container and its clients) would have left them pointing at a container that no longer exists: refused asnetwork-shared, naming them. One started with--rmwould have been removed by its own stop, with nothing to go back to:auto-remove. One made from an image id has no reference to update:pinned-by-id, and the update check no longer asks Docker Hub forlibrary/sha256. Each has its own message.TestDockerRecreateRefusesWhatItCannotSwapSafelyfails on the old code. - fix — nextDash speaks the daemon's minimum API version when its own is too old. Docker Engine 29.0 to 29.2 refused anything older than 1.44, and nextDash asked for 1.41: every Docker call failed, and the list said the socket was missing. The version is now read once per socket from
/versionand raised to the daemon's minimum when needed; a daemon that refuses is reported as such, not as a missing socket.TestDockerSpeaksTheDaemonsMinimumVersionWhenOursIsTooOldfails on the old code. - fix — the Disk tab counts shared layers once. What an unused image frees is its size less the layers other images keep, the images together take
LayersSize, and a shared or in-use build-cache record does not go with a prune -- asdocker system dfcounts. Measured on a real host, the old figure said 396 MB reclaimable where Docker said 168 MB. The Containers tile's reclaimable figure follows.TestDockerDiskCountsSharedLayersOncefails on the old code. - fix — a container left behind by its tag offers no skip. Its newer image is already on the host, so there is no version on offer to skip; the drawer said Skip this version and the server answered
nothing-to-skip. The row now carriesrecreate, the Updates part says the image is here and an update recreates, and Skip is left out. A new spec indocker-updates.spec.jsfails on the old code. - fix — the Containers tile counts updates per container and restarts by uptime. Updates is counted as the view's badge counts, so a container left behind by its tag counts too; just restarted reads when a container last started (its uptime) rather than when it was created, which a restart does not move and a recreate does.
TestDockerMetricsExtrasandTestCountContainersReadsRestartsFromUptimeNotCreationfail on the old code. - fix — Resume in the logs window brings every line since the last one. The resume asked for the ordinary tail as well, so more lines than that written meanwhile left a silent gap; with
since, the tail is what the window keeps, 5,000 lines.TestDockerLogStreamRoutefails on the old code. - fix — an update refused because a prune is running says so, as
prune-running(A clean-up on the Disk tab is still running), rather than Another action is still running on this container. - fix — an env value or log the drawer cannot read says so. A refused or failed read showed an empty value, dropping its button, and an empty log; the value's button stays with a message, and the log reads The log could not be reached. A new spec in
docker-view.spec.jsfails on the old code. - fix — a web UI address the server refuses to save is not kept. The drawer waited for
saveSettings()to throw, but a failed save resolvesfalse; it said Web UI address saved beside the save error. A new spec indocker-custom-webui.spec.jsfails on the old code. - new — the Containers and Container list widgets report more. The Containers tile's figures can add updates waiting, reclaimable disk space and incidents (24 h), and a new Name the three busiest by CPU lists the top three under them. Updates count as the Containers view counts them:
DockerMetrics.Updatesread the raw check results, so a skipped or held version was still counted, and now reads them with the reader's choices applied. Reclaimable is the last Disk measurement, whoever asked for it; once it is six hours old the tile's next read starts a new one in the background (dockerReclaimable(), one at a time) and shows the old figure meanwhile, or a dash before the first. Incidents are the timeline's crashes and turns unhealthy of the last day; the busiest come from the stats sampler. Nothing ticked still means every figure, so the three new ones appear for anyone who never chose, and nine figures lay out three abreast. The Container list sorts by CPU or memory, busiest first, and can show CPU and memory beside the name — with three rows, a top three.widgetFieldsaccepts the new choices; MANUAL §15 and Help say so; locale keys in English outsideenuntil the next docs round. - new — a compose project updates as one stack. Grouped by project, the project's row gains Update (n) beside Start, Stop and Restart: n is how many containers in the stack have an update waiting, and only those are updated — a skipped or held version, an image no check has looked at and nextDash's own container stay as they are. The selection bar's
runBulk()asks once, naming them, and updates them one at a time; a filter or search narrows the stack as it does for the other stack buttons. Disabled when nothing waits, absent read-only. MANUAL §14.2 and Help say so; one new locale key, in English outsideenuntil the next docs round. - fix — an update no longer carries the old image's defaults into the new container. Docker folds an image's Env, Cmd, Entrypoint, working directory, user, healthcheck, labels, exposed ports and volumes into a container's Config when it is made, and inspect hands them back merged; recreate sent them back as they were, so a new version with a new
PATH, entrypoint or healthcheck started with the old one's.dropImageDefaults()indocker_recreate.gonow leaves out what equals the old image's value, so the new image fills it in; what was set for the container stays, and an entrypoint of its own keeps its command. A rollback benefits the same way.TestDockerRecreateLeavesImageDefaultsToTheNewImagefails on the old code. - fix — a container left behind by its tag shows its update. After one of two containers on the same image was updated, or after
docker compose pullwithoutup, or after a failed update that had already pulled, the daemon lists the container by image id: the table showedsha256:…, the check answered unknown, and the badge was gone although the container ran an older image. The list now takes the reference from the container's own Config for those rows, and a container that runs an older image than its tag points at shows an update (held stays held), which a click installs with a recreate alone. One/images/jsonper list read.TestDockerContainerLeftBehindByItsTagShowsAnUpdatefails on the old code. - fix — a failed list read keeps the containers table. A poll or the refresh after an action that could not read the list (a timeout, a restart, the daemon answering not available) emptied the table, set the header badge to 0 and closed the side panel of a container that was still there; the last list now stays. Only the newest read is applied, and a poll waits for the one still on its way. A new spec in
docker-view.spec.jsfails on the old code. - fix — a port bound to 127.0.0.1 or ::1 is no web UI. The Web UI column's fallback and the row menu's Web UI linked the first published TCP port even when it answers on the Docker host only; they now skip loopback bindings, through one helper,
DockerSearchIndex.firstWebPort(). A new spec indocker-table-webui.spec.jsfails on the old code. - fix — the release notes follow the container and the last check. The changelog cache was one list per repository, filtered by the first container that asked: a container on a prerelease and one on a stable version of the same project saw each other's list for a day. The key now carries the prerelease choice, and a list fetched before the last update check is fetched again, so a release the check just found is not missing.
TestChangelogCacheKeepsPrereleasesApartAndFollowsTheCheckfails on the old code. - fix — a GitHub token that is turned down says so. A 403 was always rate-limited; with requests left it is now
auth-failed, and the drawer says to check the token under Config → Containers (dockerChangesAuthFailed, English fallback until the next docs round).TestChangelogRouteNamesARefusedTokenfails on the old code. - fix — docker error responses are JSON again.
writeDockerError,dockerTargetand the update-failure answer set the status before the content type, so every 404, 502 and 503 went out astext/plain.TestDockerErrorsAreJSONfails on the old code. - new — a timeline per container. The side panel's Overview gains Timeline: what happened to the container, newest first — started, stopped (by you, by someone, or by nextDash), exited on its own, crashed with its exit code or out of memory, turned unhealthy and healthy again, paused and resumed, updated and rolled back — with a run of crash-and-restart cycles folded into one Kept restarting line. The notifier, which reads Docker's event stream anyway, writes these to
data/docker-events.jsonwhatever the notices are set to (Docker keeps only a few hundred events itself, and healthcheck execs use them up): a hundred per container, for thirty days, kept by name so a container an update recreated keeps its history, saved in batches on the notifier's tick.GET /api/docker/containers/{id}/timelinemerges them with the update history; the part asks for it only when opened. The first healthy of a container that was never unhealthy is its healthcheck starting, and is not written down.docker_timeline.go. - new — keys for the logs window, mute and Disk, and Shift+Y into the view. In the Containers view,
lopens the selected container's logs window,mmutes or unmutes its notices anddswitches between the list and Disk — none of them taken elsewhere; from the dashboard or Config,Shift+Yopens Containers (C, D, K, N and O were taken). The legend now names every key of the view — move, details, search as well — and shows without actions switched on too, leaving out the keys that act on Docker; the cheat sheet and its PDF list the new keys. - new — the Containers key legend goes above the list, below it, or away. Config → Containers → View → The key legend, with the choices Bookmarks and Inbox offer; above, where it always stood, is the default (
dockerViewKeyLegend). - new — the Containers tour covers what was added. Two steps more, ten in all: Logs, live and What the disk holds; the others now name the sortable headings, CPU and RAM, the stack buttons, Health, Updates and Timeline, skip, hold and rollback, notices and mute, and Shift+Y. The tip id stays
containersTutorialV1, so nobody gets the tour again unasked. - fix — a failed webhook post for a container names the container in the log. The warning used the notice's URL, which a container notice does not have, so it read " could not be reached"; it now falls back to the name.
- fix — a rollback that had to be undone says it was a rollback. When the new container failed and the old one was put back, the message spoke of a failed update; it now reads The rollback of {name} failed at "{step}"; the container runs as before. (
dockerRollbackRolledBack, English fallback only until the next docs round). A new spec indocker-updates.spec.jsfails on the old code. - fix — muting a container whose save fails is no longer kept or reported as done.
toggleMute()waited forsaveSettings()to throw, but a failed save resolvesfalse: the muted list stayed changed in the browser, the menu said Unmute, and "No more notices about …" showed beside the save error. It now puts the list back and says nothing of success. A new spec indocker-notify.spec.jsfails on the old code. - fix — a burst of container notices reaches the webhook as one message. One crash taking its dependants along sent a message per container, the pattern Slack and Telegram rate-limit. Four or more notices of one event at once now go as one — 6 containers need attention (or recovered), naming the first three and a count — as Health's own downtime alerts already did; fewer, or a mix of downs and ups, go one by one. Browser notifications stay one per container.
TestDockerNotifierDigestsABurstfails on the old code. - fix — a corrupt update history is no longer overwritten. A
docker-update-history.jsonthat does not parse is left alone, with a warning, instead of being replaced by the next update's single entry, which lost every rollback in it.TestDockerUpdateHistoryKeepsAnUnreadableFilefails on the old code. - fix — the logs stream's heartbeat stops before its handler returns. A beat due just as the stream ended could write to a response the server had already taken back.
TestDockerLogStreamHeartbeatEndsWithTheHandlerfails under-raceon the old code. - fix — container notices no longer call a slow stop a crash, or a finished job one. A stop whose grace period ran past ten seconds was told as "stopped unexpectedly": a stop's SIGTERM or SIGKILL now covers five minutes, a reload signal such as HUP covers nothing, and a start ends it. nextDash's own action counts as expected for its whole length rather than ten seconds from its start, so a long pull before the stop no longer matters. A container that exits 0 and stays down finished its work and raises no notice; a loop of them still does.
TestContainerNotifierLongStopsAndFinishedJobsfails on the old code. - fix — an image prune no longer takes the image an update is about to use. Between an update's pull (or a rollback's tag) and its create, the new image is unused, and a prune of unused images removed it. An image prune now answers
busywhile any container action runs, and an update or rollback answersbusywhile a prune runs; the build cache is not held back.TestDockerPruneAndUpdateExcludeEachOtherfails on the old code. - fix — sort by uptime follows when a container last started, not when it was created. An old container that restarted five minutes ago used to sort as the longest running.
compareFn()indashboard-docker.jsnow orders onstartedAt, longest up first; a stopped container has no uptime and goes to the end, by name. - fix — the logs window and the volume confirmation dim the page behind them. Their
::backdropreadvar(--modal-scrim), but a backdrop inherits no custom properties in every browser (Safari among them), so the page stayed as bright as before; the scrim is now written out, a shade darker than the app modal's, with its 3 px blur. - fix — an empty Disk tile reads 0 B, not 0 KiB.
formatBytes()indashboard-docker-disk.jscounts in bytes below one KiB. - new — a Disk tab in the Containers view: what images, volumes and build cache take up, and clearing what nothing uses. Containers | Disk sit in the toolbar row; Disk has its own address,
#docker/~disk(no container name can start with~, so a container calleddiskkeeps#docker/disk). Four tiles — unused images, dangling images, build cache, unused volumes — each with its size and its clean-up, then the images and volumes themselves, biggest first, with what uses them; an untagged image that is still a container's way back (the update history of the Updates part) says "rollback for sonarr", and the dangling and unused tiles warn which rollbacks a prune ends, as does the question before it runs. Every prune asks first with the size it frees; volumes, which hold data, are never pruned in bulk but removed one at a time from their row, only after typing delete (a fixed word: an anonymous volume's name is 64 random characters), and never while a container — a stopped one included — holds them. The rail gains Disk used and Reclaimable once the tab has measured; measuring (/system/df) is slow on a big host, so it happens when the tab is opened and on Refresh. Read-only shows the sizes and no buttons. New routes:GET /api/docker/disk,POST /api/docker/prune/{images-dangling|images-unused|build-cache}andDELETE /api/docker/volumes/{name}?confirm={name}, the last two behind control and the write token like the actions, one prune at a time, each in the activity log.dashboard-docker-disk.js, loaded with the view. Any open native<dialog>now counts as a modal for the view's keys. New strings have English fallbacks only, until the next docs round. - new — the Web UI column falls back to the first published TCP port. A container with no web UI address (no Unraid template label, none set in the drawer's Custom) showed an empty cell, which on a plain Docker or compose host was every row. It now links the first public TCP port, as
:port, as the row menu's Web UI already did; UDP alone still leaves it empty, and a template or custom address still wins.DashboardDocker.portLink(); the link carriesdata-docker-webui-port. - new — the containers side panel closes on a press beside it. As in Bookmarks and Inbox, through the shared side panel's
closeOnOutside: a click or touch anywhere else closes it, one on another container row moves it there instead, and Config → Containers → Close on a click beside it (dockerViewCloseOutside, on by default, and on for a settings file that predates it) keeps it open. fix — the shared side panel now also ignores presses inside a native<dialog>, which carries its role without the attribute: a click in the logs window no longer closed the drawer behind it. - fix — the containers table fits between the phone layout and a wide screen. With CPU and RAM beside it, the table ran out of room around 800 pixels: the image broke mid-word and the status wrapped over three lines. Below 1100 pixels the Image column now goes (the drawer names it), and below 900 pixels CPU and RAM go as well; from 768 pixels down the phone layout takes over as before.
- new — notices when a container stops unexpectedly, keeps restarting or turns unhealthy. And a second notice when it recovers: running again, stable again after ten quiet minutes, or healthy again. nextDash follows the daemon's event stream (
GET /events, one connection, reconnected with a growing pause) rather than polling, so a crash the restart policy fixes within seconds is still seen, and a crash is told apart from a deliberate stop: Docker's own stop sends kill before die, and nextDash's own stop, restart, update and rollback are marked as expected. A die is only told when no start follows within 30 seconds; three crash-and-restart cycles in ten minutes are a loop, told once. Out-of-memory kills say so. One notice per incident. The notices go where Health's downtime alerts go — the alert webhook with its presets (the raw JSON carriessource: "container", and ntfy's button opens the container) — and to browser notifications under a new category, Notify when a container stops, keeps restarting or turns unhealthy. Config → Containers gains Notifications (dockerNotify, on by default, and on for a settings file that predates it) and Muted containers, which says where notices go or that nothing receives them yet; a container is muted from its row menu or its drawer's ⋯ menu, and the drawer's Details says Notifications: on, muted or off. Muted, hidden and nextDash's own container raise nothing. Every notice is also in the activity log. The decisions are a state machine fed events and a clock (docker_notify.go); the webhook sending that monitors used is nowpostMonitorTarget, shared by both. New strings have English fallbacks only, until the next docs round. - fix — the drawer's image chip names the tag once.
nginx:alpinereadnginx:alpine:alpine:_layout()indashboard-docker-drawer.jsadded the tag to a reference that already carries it. The chip now shows the reference as the container was made from it. - new — skip a version, hold updates, see what updates did, and roll the last one back. The drawer's Overview gains an Updates part: where the image stands, Skip this version (the digest on offer stops counting as an update — no badge, no count, left out of an update of a selection — until a newer one appears), Hold updates (the image never counts as having one until resumed; the row shows a quiet held label), Undo for either, and a history of what updates did, newest first, with versions from
org.opencontainers.image.versionor short image ids. While the image the last update replaced is still on the host, Roll back to that version asks first, then tags that image as the reference again and recreates the container on it — the update's own swap without a pull, so the container keeps its ordinary reference and later checks still work — writes it down, and skips the version it left so it is not offered straight back. Updating by hand still works on a skipped or held image. New:data/docker-update-history.json(twenty entries per container),heldandskippedbeside the check's results indocker-updates.json, which every route now serves with those choices applied (statusskippedorheld),POST /api/docker/updates/choicebehind the write token, and arollbackaction behind the same control and token as update, which refuses with a reason (no-rollback,old-image-gone,pinned-by-digest) and touches nothing when it cannot. A check keeps the choices, and lets go of a skip once the registry has moved past that digest.dockerRecreateis split so the swap (dockerRecreateOn) serves both. New strings have English fallbacks only, until the next docs round. - new — a logs window that follows a container's log live. Opened from the row menu's Show logs, from
:docker <name> logs, or from Open logs window in the drawer's Logs tab, which stays the quick look. It takes most of the page (the whole screen on a phone) and follows the log as it is written; scrolling up pauses the follow and counts what arrives meanwhile, with Jump to latest to catch up, and a stream that ends (the container stopped) offers Resume, which picks up after the last line without showing it twice. One toolbar: search that marks every match with Enter and Shift+Enter to step through them, Filter to show only matching lines, All/stdout/stderr, how many lines to start with, timestamps, wrapping, Copy for the lines shown and Download for the loaded lines as<name>-YYYYMMDD-HHMM.log; stderr lines are red. Keys:/search,ffollow, Enter next match, Escape close. The choices are kept per browser. It reads a new route,GET /api/docker/containers/{id}/logs/stream, which follows the daemon's log with timestamps and answers NDJSON, one{t, s, m}object per line with its stream (a TTY container's lines all count as stdout); it sits behind the write token like/logs, lifts the server's read and write timeouts for itself, sends a blank heartbeat line every 25 seconds so a reverse proxy keeps a quiet stream open, and ends when the container stops or the window closes. At most 5,000 lines stay on screen and 16 KiB per line. A native<dialog>, so the page behind is inert while it is open. New strings have English fallbacks only, until the next docs round. - new — CPU and RAM columns in the containers table. Each running container shows the stats sampler's latest reading (every 30 seconds) beside its status, right-aligned; a stopped one, or one not read twice yet, shows —. The list route carries the reading as
usagefrom the sampler's in-memory store and saysusageEnabled, so the columns cost no stats call per row; with Config → Containers' history switched off there are no columns and no CPU or memory sort. Both headings sort, highest first on the first click, and a container without a reading stays last either way; the toolbar's sort select offers CPU and memory too. Hidden at phone width, like Image. New strings have English fallbacks only, until the next docs round. - new — the container drawer shows the healthcheck's last checks. Overview gains a Health part, there only for a container that reports a health state: the status, how many checks have failed in a row, the healthcheck command as typed (
CMDarguments joined, aCMD-SHELLline as is), and the last five checks newest first, each with its time, a ✓ or ✗ with the exit code, and its output capped at 2,000 characters. The checks come from a new route,GET /api/docker/containers/{id}/health, read from inspect'sState.HealthandConfig.Healthcheck; it sits behind the write token like logs and env values, since a check's output is a command's output, and it is only asked for when the part is opened. New strings have English fallbacks only, until the next docs round. - new — a compose project starts, stops and restarts as one stack. Grouped by project, each project's group row carries Start, Stop and Restart; they run the selection bar's
runBulk()over the project's rows as shown, so Stop asks once with the names and the containers go one at a time, and a filter or search narrows the stack as it narrows a selection. A button is disabled when no container in the stack allows it, No project gets none, and a read-only daemon (NEXTDASH_DOCKER_CONTROLoff) shows none. Enter on a focused stack button runs it instead of opening the selected row's drawer. Update stays with the selection bar. No new strings. - new — the Name and Status headings sort the containers table. A click sorts by that column; a second click turns the order round, and the direction is kept with the rest of the view state (
sortDirinnextdash.docker.view). The toolbar's sort select follows the headings, and picking a sort there starts in its natural direction; uptime stays in the select only, as it has no column. The active heading carriesaria-sortand a drawn arrow; Enter on a focused heading sorts instead of opening the selected row's drawer, and focus stays on the heading. No new strings. - new — the containers table names its columns. Name, Image, Status, Web UI and Ports sit above the rows and stay pinned under the view's header while the list scrolls; at phone width, where rows fold into two lines, the headings are hidden. The Name, Status and Ports labels are new locale keys, still English outside
enuntil the next docs round. - new — web UI and port links reach the container, not just the page's host. A container on a macvlan or ipvlan network (Unraid's
br0) has its own LAN address, and[IP]in its web UI now means that address; the list and detail routes hand it over aslanIP, read from the daemon's network list, and a daemon that will not list its networks leaves the links as they were. Config → Containers → Links adds Docker host address for when the dashboard is opened through a reverse proxy or tunnel: ports and[IP]then point there instead of at the browser's host. One helper indocker-search-index.jsnow fills[IP]for the table, the drawer, the row menu and:docker <name> open, which each did it themselves before.
Docs
-
fix — the check-mode menu spec closes an open menu before the next right-click. On CI the bookmark menu still open from the previous step covered the first row and took the click, every retry;
dashboard-check-mode-menu.spec.jsnow presses Escape until it is gone. -
fix — the settings-jump spec looks for the uptime webhook by field. Searching "webhook" now also finds Containers' notices first, so the test landed in Config → Containers; it picks
monitorNotifyUrlitself. -
fix — a statistics CSV export could carry a bookmark's old name or count. The export read the figures memoised at the last paint, so a rename or an open since then went out stale;
exportStatsCSV()now drops the memo first.config-stats-export-truncation.spec.jsmemoises before renaming, and was the flaky failure on CI's third e2e shard. -
fix — the wide Containers tile spec counts nine figures. Updates, reclaimable space and incidents joined the tile's figures, and an unset list shows them all;
widget-wide-columns.spec.jsstill expected six and failed CI's last e2e shard. -
fix — CI's gofmt check passes again. Two Containers test files,
docker_fake_test.goanddocker_recreate_test.go, were committed unformatted, so thego-testjob stopped atmake fmt-checkbeforego vetand the tests ran. -
docs —
static/data/whats-new/v1.15.2.jsonand its index entry, and four Overview features.whats-new-stub.jsmovesNEXTDASH_WHATS_NEW_DATA_VERSIONtowhats-new-v306andDASHBOARD_RELEASEto v1.15.2, so the window opens once for this release. Config → Overview and About → News & features gain Several containers at once, A container's log, live, What the Docker disk holds and Told when a container goes down (since: v1.15.2, in all six languages); their buttons open the Containers view or Config → Containers, whichopenViewFromTile()now reaches.go generaterefreshedasset_hashes_gen.go. -
docs — README, manual, Help and translations caught up for v1.15.2. README's Containers list now names the logs window, Disk, notices, stack and ticked actions, skip, hold and rollback. MANUAL §9.3 describes the category ⋯ sort menu (it still spoke of A–Z and Recent chips), §14.2–§14.4 ticking containers, the custom address dot and head tag and their keys, §23.8 the
docker-actionevent, and §14.9 the full Behavior → Status & alerts → Downtime alerts path. Config → Help (Containers, Bookmarks, Self-hosting) says the same. In Dutch, German, French, Spanish and Chinese: the 15 new keys, and 13 texts whose English had grown since they were translated (the Containers tour, the analytics notice, three Help pages). -
fix — the Docker host address spec no longer fails one run in twenty or so. A load of
/#config/containersdraws config twice, fromloadData()and again frominit()'srenderDashboard()once the language is in; afill()that landed between the two was drawn over, so Tab committed nothing and the poll of/api/settingsnever sawtower.lan.docker-table-webui.spec.jsnow waits for_configRefreshReadybefore typing; 100 runs in a row pass. -
docs — Help, the manual and the cheat sheet describe the Containers additions. Config → Help → Containers (The Containers view and Setting it up) and MANUAL §14 (with new §14.7 Disk, §14.8 The logs window, §14.9 Notices), §7.1 and §17.7 cover Shift+Y, the keys, sorting, CPU and RAM, stacks, Health, Updates, Timeline, the logs window, Disk, notices and the new settings;
npm run generate:cheatsheetrebuilt the cheat sheet's HTML and PDF. The 176 locale keys the Containers work had left as code fallbacks are now in all six locale files, in English outsideenuntil the next docs round translates them; the English Help and tour texts that changed keep their earlier translations until then.