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
+1 -1
View File
@@ -8,7 +8,7 @@ build: build-web build-server
# Build the Go server
build-server:
CGO_ENABLED=0 go build -o dumpster-server ./cmd/server
CGO_ENABLED=0 go build -ldflags "-X main.GitSHA=$(GIT_SHA)" -o dumpster-server ./cmd/server
# Build the TUI client
build-tui:
+10 -3
View File
@@ -47,9 +47,8 @@ import (
// @host localhost:8080
// @BasePath /api/v1
// @schemes http https
// @securityDefinitions.apikey SessionAuth
// @in cookie
// @name dumpster_session
var GitSHA = "dev"
func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
@@ -153,6 +152,14 @@ func main() {
// API routes
r.Route("/api/v1", func(r chi.Router) {
r.Get("/version", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
json.NewEncoder(w).Encode(map[string]string{
"version": GitSHA,
})
})
// Auth (public: register, login, logout) with strict rate limiting
r.Route("/auth", func(r chi.Router) {
r.Use(middleware.RateLimit(5, 10)) // 5 req/s, burst 10
+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>
);
}