dashboard: dimmed default icon for unreachable containers

A stopped or mid-transient (restarting / rebuilding) container's
web server isn't answering, so its <url>/icon background-image
just failed to an empty box on the card.

When the container isn't reachable (not running, or a transient
is in flight) the icon now falls back to the dimmed hyperhive
mark — /favicon.svg, served by the dashboard itself so it's
always loadable — greyscaled + lowered opacity via the
.icon-unreachable class.

closes #195
This commit is contained in:
iris 2026-05-21 21:56:39 +02:00
parent f42ba9b561
commit 16f614f45d
3 changed files with 21 additions and 7 deletions

View file

@ -580,13 +580,18 @@
// Full-height square agent icon, left of the card body. A
// background-image on a div (not <img>) contributes no intrinsic
// size, so loading or failing it can't shift the row layout, and
// a failed load (stopped container, web server down) just shows
// the placeholder fill — no broken-image glyph, no collapse.
// (issue #177)
// size, so loading or failing it can't shift the row layout —
// no broken-image glyph, no collapse. (issue #177)
//
// When the container is stopped or mid-transient (restarting,
// rebuilding…) its web server isn't answering, so `<url>/icon`
// would just fail to an empty box. Fall back to the dimmed
// hyperhive mark (`/favicon.svg`, served by the dashboard
// itself, always reachable) instead. (issue #195)
const reachable = c.running && !pending;
const icon = el('div', {
class: 'container-icon',
style: `background-image:url("${url}icon")`,
class: 'container-icon' + (reachable ? '' : ' icon-unreachable'),
style: `background-image:url("${reachable ? `${url}icon` : '/favicon.svg'}")`,
});
// Card body: the three stacked content lines, right of the icon.
const body = el('div', { class: 'card-body' });

View file

@ -98,6 +98,12 @@ a:hover {
background-position: center;
background-repeat: no-repeat;
}
/* Stopped / mid-transient container: the dimmed hyperhive mark stands
in for the unreachable agent icon (issue #195). */
.container-row:not(.tombstone) > .container-icon.icon-unreachable {
filter: grayscale(1);
opacity: 0.4;
}
.container-row .card-body {
flex: 1;
min-width: 0;