UI: add version status pill before Health in web header (#24648)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: f240589d33
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
Gustavo Madeira Santana
2026-02-23 12:27:17 -05:00
committed by GitHub
parent fdd185cfaa
commit 28377e1b7a
7 changed files with 32 additions and 3 deletions

View File

@@ -2,6 +2,7 @@ import type { TranslationMap } from "../lib/types.ts";
export const en: TranslationMap = {
common: {
version: "Version",
health: "Health",
ok: "OK",
offline: "Offline",

View File

@@ -2,6 +2,7 @@ import type { TranslationMap } from "../lib/types.ts";
export const pt_BR: TranslationMap = {
common: {
version: "Versão",
health: "Saúde",
ok: "OK",
offline: "Offline",

View File

@@ -2,6 +2,7 @@ import type { TranslationMap } from "../lib/types.ts";
export const zh_CN: TranslationMap = {
common: {
version: "版本",
health: "健康状况",
ok: "正常",
offline: "离线",

View File

@@ -2,6 +2,7 @@ import type { TranslationMap } from "../lib/types.ts";
export const zh_TW: TranslationMap = {
common: {
version: "版本",
health: "健康狀況",
ok: "正常",
offline: "離線",

View File

@@ -328,6 +328,12 @@
animation: none;
}
.statusDot.warn {
background: var(--warn);
box-shadow: 0 0 8px rgba(245, 158, 11, 0.5);
animation: none;
}
/* ===========================================
Buttons - Tactile with personality
=========================================== */

View File

@@ -136,6 +136,16 @@ function resolveAssistantAvatarUrl(state: AppViewState): string | undefined {
}
export function renderApp(state: AppViewState) {
const openClawVersion =
(typeof state.hello?.server?.version === "string" && state.hello.server.version.trim()) ||
state.updateAvailable?.currentVersion ||
t("common.na");
const availableUpdate =
state.updateAvailable &&
state.updateAvailable.latestVersion !== state.updateAvailable.currentVersion
? state.updateAvailable
: null;
const versionStatusClass = availableUpdate ? "warn" : "ok";
const presenceCount = state.presenceEntries.length;
const sessionsCount = state.sessionsResult?.count ?? null;
const cronNext = state.cronStatus?.nextWakeAtMs ?? null;
@@ -231,6 +241,11 @@ export function renderApp(state: AppViewState) {
</div>
</div>
<div class="topbar-status">
<div class="pill">
<span class="statusDot ${versionStatusClass}"></span>
<span>${t("common.version")}</span>
<span class="mono">${openClawVersion}</span>
</div>
<div class="pill">
<span class="statusDot ${state.connected ? "ok" : ""}"></span>
<span>${t("common.health")}</span>
@@ -286,10 +301,10 @@ export function renderApp(state: AppViewState) {
</aside>
<main class="content ${isChat ? "content--chat" : ""}">
${
state.updateAvailable
availableUpdate
? html`<div class="update-banner callout danger" role="alert">
<strong>Update available:</strong> v${state.updateAvailable.latestVersion}
(running v${state.updateAvailable.currentVersion}).
<strong>Update available:</strong> v${availableUpdate.latestVersion}
(running v${availableUpdate.currentVersion}).
<button
class="btn btn--sm update-banner__btn"
?disabled=${state.updateRunning || !state.connected}

View File

@@ -53,6 +53,10 @@ export function resolveGatewayErrorDetailCode(
export type GatewayHelloOk = {
type: "hello-ok";
protocol: number;
server?: {
version?: string;
connId?: string;
};
features?: { methods?: string[]; events?: string[] };
snapshot?: unknown;
auth?: {