Skip to content

Release 1.5.2 — an empty dashboard explains itself - #32

Merged
cvaghela merged 3 commits into
mainfrom
empty-state
Aug 30, 2026
Merged

Release 1.5.2 — an empty dashboard explains itself#32
cvaghela merged 3 commits into
mainfrom
empty-state

Conversation

@cvaghela

@cvaghela cvaghela commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Answers IceWhaleTech/CasaOS-AppStore#1024. The maintainer installed Service Dash on ZimaOS, got a blank grid, checked that every container was healthy, and reasonably concluded the app was broken. It wasn't — Uptime Kuma wasn't there to read.

The only things the page said were OFFLINE in small type in the top bar and a toast that cleared itself after 5.2 seconds.

Three causes, three answers

Cause Top bar The panel says
Uptime Kuma unreachable OFFLINE Waiting for Uptime Kuma
Status page has no monitors CONNECTED Connected, but that status page is empty
Filters hide everything CONNECTED Nothing matches + Clear

The middle one is easy to miss. publicGroupList: [] is a valid empty array, so an empty status page is a successful fetch — CONNECTED, and still blank. Treating it as an unreachable Kuma sends people to check a port that was never the problem.

Both states carry setup steps, not just a diagnosis

The offline state leads with the misconception itself: Uptime Kuma is a separate application, and Service Dash does not bundle, install or start it. Then four steps — install on the host, create the admin account, publish a status page, match KUMA_PORT/STATUS_SLUG — with a copyable install command pinning louislam/uptime-kuma:2 (verified on Docker Hub; most guides still quote :1, two majors behind).

The empty-status-page state walks Uptime Kuma's editor, and its second step is the real gotcha: add a group first. Monitors are nested inside groups in Kuma's API, so a page with no group has nowhere to put them and stays blank. Confirmed against a live Kuma, along with published: true mattering.

The diagnostic command sits behind a fold — someone who never installed Kuma doesn't need to prove nothing is answering. Its three outputs pin the cause exactly, and it names this install's port and slug, which is why entrypoint.sh now writes kumaPort into config.js.

Deliberately absent: any mention of a dashboard "base URL" or of CORS. Neither exists here — the dashboard reaches Kuma at host.docker.internal:KUMA_PORT, and nginx proxies /kuma/ same-origin. Both would send readers to check something that cannot be the cause.

Two bugs found by building the sandbox, not by review

  • The panel explained an emptiness that wasn't there. With cards on screen, losing Kuma put "Waiting for Uptime Kuma" underneath a full grid. A dashboard up for a week that briefly loses Kuma keeps its cards and lets the top bar say why. Every branch is now guarded on the grid actually being empty. This only surfaced because the sandbox can move between states; the smoke host only ever tested a cold start.
  • Contrast. The offline title measured 1.36:1 on the light panel and looked perfectly fine in a screenshot. The override reaches 9.34:1 (dark: 13.84:1).

Release

Three image tags across all three Compose files, x-casaos.version, update_at, the ?v= cache-busters and the README line. The cache-buster matters more than usual — app.js, styles.css and entrypoint.sh all changed.

Release notes rewritten in all fifteen locales. No Compose change beyond tags and no new services, so no "Upgrading from" section is required.

Verified

Smoke-tested on the ZimaOS host, since this touches entrypoint.sh: all three states driven against a stand-in Kuma, both themes, desktop and phone, no sideways scroll, Clear restoring the grid, and the panel staying hidden while six cards are visible. Idempotent — a tagged child survives three re-renders, so the 15s poll doesn't rebuild it under the reader.

docker compose config on all four files against real Docker. check-compose-networks, check-release (fifteen locales), check-service-additions, check-empty-state, test-reporters (12 passed), and the upstream store render — all green.

scripts/check-empty-state.py runs as a step in the existing Checks job, so no required status check changes. Mutation-tested seven ways; its entrypoint.sh check passed vacuously on first writing, satisfied by the comment explaining the emission while the emission itself was deleted.

IceWhale's maintainer installed Service Dash on ZimaOS while reviewing it
for their store, got a blank grid, checked that every container was healthy,
and reasonably concluded the app was broken. It was not -- Uptime Kuma was
simply not there to read.

The only things the page said were the word OFFLINE in small type in the
topbar and a toast that cleared itself after 5.2 seconds. He was the most
motivated reader this app will ever have and it still could not tell him
"Kuma is not set up" apart from "this is broken". Everyone who installs
without reading the tips lands in the same place, and most of them will not
write to us.

A blank grid has three quite different causes, so the panel names which:

  * Kuma unreachable -- the fetch failed. Names the URL it tried, the port
    and the slug, and offers a copyable command that prints a different,
    unmistakable line for each cause: 200 OK, 404 Not Found, or connection
    refused.
  * Connected but the status page is empty -- publicGroupList: [] is a valid
    array, so this shows CONNECTED with no cards. Conflating it with the
    case above sends people to check entirely the wrong thing.
  * Nothing matches -- cards exist, the filters hide them all.

entrypoint.sh now puts kumaPort into config.js, for the diagnostic command
alone. A command naming the wrong port sends the reader to prove something
irrelevant.

Verified on a real ZimaOS host rather than by reading, since this touches
entrypoint.sh: all three states driven against a stand-in Kuma, both themes,
desktop and phone widths, no sideways scroll, the Clear button restoring the
grid, and the panel staying hidden while six cards are visible. The panel is
idempotent -- a tagged child survives three re-renders, so the fifteen-second
poll does not rebuild it under the reader.

Two things measurement caught that reading did not. --pending is a
dark-ground token: on the light panel it measures 1.36:1, which is not a
heading so much as a rumour of one. The override reaches 9.34:1. And the
stored error can be nginx's own 502 page, five hundred characters of markup
around four useful words, so it is stripped and capped.

scripts/check-empty-state.py guards all of it, and runs as a step in the
existing Checks job rather than a new one, so no required status check
changes. Mutation-tested six ways. The entrypoint check passed vacuously on
first writing -- it looked for "kumaPort" anywhere in the file, and the
comment explaining the emission satisfied it while the emission itself was
deleted. It now checks the printf format and its argument separately.
Two changes, both found by driving the states in the sandbox rather than
from a cold start on the smoke host.

The panel was explaining an emptiness that was not there. With cards on
screen, losing Kuma put "Waiting for Uptime Kuma" underneath a full grid,
which reads as though the app had lost them. A dashboard that has been up a
week and briefly loses Kuma should keep its cards and let the topbar's
OFFLINE say why they stopped moving. Every branch of emptyStateModel() is
now guarded on there being nothing on screen.

And the panel said what was wrong without saying what to do. Both states
now carry numbered steps.

Kuma offline leads with the misconception that cost IceWhale's maintainer
an afternoon -- Uptime Kuma is a separate application and this does not
bundle, install or start it -- then walks through installing it on the
host, creating the admin account, publishing a status page, and matching
KUMA_PORT and STATUS_SLUG. The diagnostic command moved behind a fold:
somebody who never installed Kuma does not need to prove nothing answers.

Empty status page walks through the editor, and its second step is the
gotcha: add a group FIRST. Monitors are nested inside groups in Kuma's API
response, so a page with no group has nowhere to put them and stays blank.
Verified against a real Kuma, along with the published flag mattering.

The install command pins louislam/uptime-kuma:2, checked against Docker Hub
rather than copied from a guide -- most still quote :1, which would start a
new install two majors behind.

Deliberately absent: any mention of a dashboard "base URL" or of CORS.
Neither exists here. The dashboard reaches Kuma at
host.docker.internal:KUMA_PORT, and nginx proxies /kuma/ on the dashboard's
own origin so nothing is ever cross-origin. Both would have sent readers to
check something that cannot be the cause.

check-empty-state.py gains a check that each branch stays guarded on an
empty grid, mutation-tested like the rest.
Bumps the three image tags in all three Compose files, x-casaos.version and
update_at, the ?v= cache-busters in index.html, and the README's
current-release line. The cache-buster matters more than usual this time:
app.js, styles.css and entrypoint.sh all changed, and a stale ?v= would
leave browsers on the old bundle.

Release notes rewritten in all fifteen locales, not just en_US --
check-release.py verifies each one separately.

No Compose change beyond the tags and no new services, so no "Upgrading
from" section is needed: a store update or a pull carries this on its own.

Validated before tagging, on a real Docker rather than by reading:
docker compose config on all four files, check-compose-networks,
check-release, check-service-additions, check-empty-state,
test-reporters (12 passed) and the upstream store render.
@cvaghela cvaghela changed the title Explain the blank grid instead of leaving people to guess Release 1.5.2 — an empty dashboard explains itself Aug 30, 2026
@cvaghela
cvaghela merged commit 36652db into main Aug 30, 2026
12 checks passed
@cvaghela
cvaghela deleted the empty-state branch August 30, 2026 19:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant