feat(setup): show running build version in the Setup tab bar
Build desktop / desktop (push) Successful in 4m21s
Build & push images / images (push) Successful in 3m6s
CI / check (push) Successful in 42s

CI already computes <branch>-<short-sha> for image tags but never
surfaced it anywhere reachable from the app, so there was no way to
tell what's actually deployed on a booth without cross-referencing
komodo/resources.toml's TAG by hand.

Thread it through: CI passes BUILD_VERSION as a Docker build-arg,
the Dockerfile captures it as a runtime env var, GET /api/version
(gated by the existing site:read permission) exposes it, and the
Setup page's tab bar shows it right-aligned, muted, absent entirely
on a local/dev build with no CI-supplied value.

Claude-Session: https://claude.ai/code/session_01FWncR69HgGPuei1dLrW3cU
This commit is contained in:
2026-08-30 19:01:15 +02:00
parent cb9f4d4979
commit 642c5f4f70
6 changed files with 69 additions and 0 deletions
+13
View File
@@ -14,6 +14,7 @@ import {
can,
closeShift,
fetchShiftReport,
fetchVersion,
logout,
openShift,
setLanguagePref,
@@ -94,6 +95,17 @@ function SetupTab({ to, label, exact = false }: { to: string; label: string; exa
);
}
/** The running deploy's "<branch>-<short-sha>" (matches the Komodo Stack's TAG in
* komodo/resources.toml), gated the same as the "Park" tab (site:read) since it's the
* same kind of read-only app metadata. Renders nothing if the value isn't known (e.g. a
* local/dev build with no CI-supplied BUILD_VERSION) rather than showing an empty badge. */
function VersionBadge() {
const q = useQuery({ queryKey: ["version"], queryFn: fetchVersion, staleTime: Infinity });
const version = q.data?.buildVersion;
if (!version) return null;
return <span className="ml-auto shrink-0 pl-3 text-[0.7rem] text-term-muted">{version}</span>;
}
/** Setup layout — the config hub. Renders a permission-gated tab bar and the active
* tab's screen via <Outlet>. Each tab is a child route (its own URL + guard), so
* deep links and the back button work and a denied tab redirects to the booth. */
@@ -112,6 +124,7 @@ function SetupLayout() {
{show("recyclebin:read") && <SetupTab to="/setup/recycle-bin" label={t("nav.recycleBin")} />}
{show("log:read") && <SetupTab to="/setup/logs" label={t("nav.logs")} />}
{show("backup:read") && <SetupTab to="/setup/backup" label={t("nav.backup")} />}
{show("site:read") && <VersionBadge />}
</nav>
<Outlet />
</div>