feat(webui): show Upgrade on rows with a newer release line

Three rows read "CRITICAL · V1.159.0 AVAILABLE" and offered no button, so the
Updates tab looked broken — reported twice as "I can't see an update button".
Nothing was broken: Update is gated on update_available, which is false for all
14 apps here. Those three have newer_version instead, whose action is `upgrade`,
and that button existed only inside the row detail.

Hiding it was justified as wanting more care than a row button. It does not buy
that. updater-page's upgrade() already opens a confirmation spelling out the
per-step recovery snapshot, the rollback-and-stop behaviour and the likely
duration, and nothing runs until it is accepted. So the care is in the dialog
either way; hiding the button only hid the action behind a Details click nobody
had a reason to make.

The row now shows whichever action applies — Update (primary) for a same-tag
image, Upgrade to <version> (secondary) for a new release line — keeping the two
visibly different. The handler was already wired for `upgrade`; only the button
was missing. Update all and the multi-select tickboxes stay gated on
update_available, since walking release lines in bulk is a different risk.

Verified against the live WebUI: Matrix, Rocket.Chat and Mattermost now carry
Upgrade to v1.159.0 / 8.7.1 / 11.10 beside Details.
This commit is contained in:
librelad 2026-08-20 22:15:20 +01:00
parent 45b54651b0
commit 597825e798

View File

@ -748,9 +748,25 @@ class OverviewManager {
const newer = a.newer_version
? `<span class="updater-badge updater-badge-unknown" title="You track ${esc(a.channel || '')}${esc(a.newer_version)} has been published. Change Version on the app's Advanced tab to move.">${esc(a.newer_version)} available</span>`
: '';
// Two different actions, and the row shows whichever applies.
//
// `update` pulls a new image for the tag you already track — one click, low
// risk, primary styling.
//
// `upgrade` moves to a newer release LINE, which needs the pinned version
// changed and walks the releases one at a time. It used to live only inside
// the row detail, on the reasoning that it wants more care than a row button.
// But the care is already there: updater-page's upgrade() opens a confirmation
// spelling out the snapshot-per-step, the rollback behaviour and the likely
// duration, and nothing runs until that is accepted. Hiding the button bought
// no safety — it just left rows reading "CRITICAL · V1.159.0 AVAILABLE" with
// no way to act on them, which is exactly how it was reported. Secondary
// styling keeps the two visibly different.
const updBtn = a.update_available
? `<button class="updater-btn updater-btn-primary" data-updater-action="update" data-app="${slug}">Update</button>`
: '';
: (a.newer_version
? `<button class="updater-btn ov-upgrade-btn" data-updater-action="upgrade" data-app="${slug}" data-version="${esc(a.newer_version)}" title="Move to the ${esc(a.newer_version)} release line — you will be asked to confirm first">Upgrade to ${esc(a.newer_version)}</button>`
: '');
// Only rows with something to apply are selectable. A checkbox on a row
// that is already current would offer a choice with no outcome, and
// "selected 6, updated 2" is a worse answer than not offering the 4.