feat(desktop): show the installed app's own version in the UI
Nothing displayed which desktop build was actually installed — debugging a stuck update meant inferring the current version backwards from the update prompt's target version. Added DesktopVersionBadge (next to the existing server-side VersionBadge) using @tauri-apps/api's getVersion(), the real running app version baked in from tauri.conf.json. No-ops in a browser. Exported inTauri() from origin.ts instead of redefining it again.
This commit is contained in:
@@ -39,7 +39,7 @@ export function wsUrl(path: string): string {
|
||||
}
|
||||
|
||||
/** True when running inside the Tauri webview (not a normal browser). */
|
||||
function inTauri(): boolean {
|
||||
export function inTauri(): boolean {
|
||||
return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
||||
}
|
||||
|
||||
|
||||
+26
-1
@@ -6,7 +6,7 @@ import {
|
||||
Outlet,
|
||||
redirect,
|
||||
} from "@tanstack/react-router";
|
||||
import { lazy, Suspense, useState } from "react";
|
||||
import { lazy, Suspense, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Lang, Permission, SessionUser, Theme } from "./api.js";
|
||||
@@ -30,6 +30,7 @@ import { Spinner } from "./ui/Spinner.js";
|
||||
import { setLanguage } from "./lib/i18n/index.js";
|
||||
import { applyTheme, applyFontScale } from "./lib/theme.js";
|
||||
import { useLiveFeed } from "./lib/use-live-feed.js";
|
||||
import { inTauri } from "./lib/origin.js";
|
||||
import { useShift } from "./lib/use-shift.js";
|
||||
import { DeviceFooter } from "./ui/DeviceFooter.js";
|
||||
import { StatusDot } from "./ui/StatusDot.js";
|
||||
@@ -106,6 +107,29 @@ function VersionBadge() {
|
||||
return <span className="ml-auto shrink-0 pl-3 text-[0.7rem] text-term-muted">{version}</span>;
|
||||
}
|
||||
|
||||
/** The installed Tauri app's own "vX.Y.Z" (from tauri.conf.json, synced to the git tag by
|
||||
* release.yml — see wiki/decisions/desktop-shell-tauri.md) — the client's version, distinct
|
||||
* from VersionBadge's SERVER build. No-op / renders nothing in a browser (there's no Tauri
|
||||
* API to call). Was invisible before this: an operator had no way to tell which desktop
|
||||
* build was actually installed short of reading the update-available prompt. */
|
||||
function DesktopVersionBadge() {
|
||||
const [version, setVersion] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!inTauri()) return;
|
||||
let cancelled = false;
|
||||
void import("@tauri-apps/api/app").then(({ getVersion }) =>
|
||||
getVersion().then((v) => {
|
||||
if (!cancelled) setVersion(v);
|
||||
}),
|
||||
);
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
if (!version) return null;
|
||||
return <span className="ml-auto shrink-0 pl-3 text-[0.7rem] text-term-muted">app v{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. */
|
||||
@@ -125,6 +149,7 @@ function SetupLayout() {
|
||||
{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 />}
|
||||
<DesktopVersionBadge />
|
||||
</nav>
|
||||
<Outlet />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user