feat(web): add automated build version tracking and update notification banner

This commit is contained in:
2026-07-27 09:51:15 -04:00
parent 83c6badc20
commit 13e3aec2d5
4 changed files with 71 additions and 4 deletions
+2
View File
@@ -15,6 +15,7 @@ import { MemberList } from './MemberList.tsx';
import { VoicePanel } from './VoicePanel.tsx';
import { ServerSettingsModal } from './ServerSettingsModal.tsx';
import { ThemeToggle } from './ThemeToggle.tsx';
import { VersionNotifier } from './VersionNotifier.tsx';
const STATUS_CYCLE: UserStatus[] = ['online', 'idle', 'dnd', 'offline'];
function statusColor(status: UserStatus): string {
@@ -99,6 +100,7 @@ export function Layout() {
return (
<div className="h-full w-full bg-gb-bg text-gb-fg font-mono flex flex-col">
<VersionNotifier />
{/* Outer terminal frame with safe area */}
<div className="flex-1 terminal-border bg-gb-bg-h flex flex-col min-h-0"
style={{ padding: 'var(--safe-top, 0.25rem) var(--safe-right, 0) var(--safe-bottom, 0) var(--safe-left, 0)' }}>
+58
View File
@@ -0,0 +1,58 @@
import { useEffect, useState } from "react";
import { api } from "../lib/api.ts";
import { useWebSocketStore } from "../stores/ws.ts";
export function VersionNotifier() {
const [serverVersion, setServerVersion] = useState<string | null>(null);
const [updateAvailable, setUpdateAvailable] = useState(false);
const connected = useWebSocketStore((s) => s.connected);
const checkVersion = async () => {
try {
const data = await api.get<{ version: string }>("/version");
if (data && data.version && data.version !== "dev") {
setServerVersion((prev) => {
if (!prev) {
return data.version;
}
if (prev !== data.version) {
setUpdateAvailable(true);
}
return data.version;
});
}
} catch {
// ignore check errors
}
};
useEffect(() => {
checkVersion();
const interval = setInterval(checkVersion, 2 * 60 * 1000); // Check every 2 mins
return () => clearInterval(interval);
}, []);
useEffect(() => {
if (connected) {
checkVersion();
}
}, [connected]);
const handleReload = () => {
window.location.reload();
};
if (!updateAvailable) return null;
return (
<div className="bg-gb-accent text-gb-bg-h px-4 py-2 text-xs font-semibold flex items-center justify-between shadow-lg z-50 animate-pulse">
<span>🚀 A new update is available! ({serverVersion})</span>
<button
onClick={handleReload}
className="bg-gb-bg-h text-gb-accent px-3 py-1 rounded hover:opacity-90 font-bold transition-all"
>
Update Now
</button>
</div>
);
}