diff --git a/web/src/App.jsx b/web/src/App.jsx index bc999ea..b37b605 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next"; import { useAuth } from "./auth"; import Icon from "./components/Icon"; import ErrorBoundary from "./components/ErrorBoundary"; +import StandHinweis from "./components/StandHinweis"; import BrandMark from "./components/BrandMark"; import Login from "./pages/Login"; import ChangePassword from "./pages/ChangePassword"; @@ -114,6 +115,9 @@ function Protected({ children, adminOnly = false, wide = false }) {
+ {/* Halbes Update: gebaut, aber nicht neu gestartet. Ohne den Hinweis + sieht das aus wie ein Fehler in der Funktion. */} + {children} diff --git a/web/src/components/StandHinweis.jsx b/web/src/components/StandHinweis.jsx new file mode 100644 index 0000000..f8feb87 --- /dev/null +++ b/web/src/components/StandHinweis.jsx @@ -0,0 +1,39 @@ +import { useEffect, useState } from "react"; +import { api } from "../api"; +import Icon from "./Icon"; + +// Wird von Vite beim Bauen eingesetzt (siehe vite.config.js). +const GEBAUT = typeof __APP_SHA__ === "string" ? __APP_SHA__ : ""; + +/** + * Weist darauf hin, wenn Oberfläche und Server aus verschiedenen Ständen + * stammen. + * + * Das passiert genau dann, wenn `npm run build` lief, der Dienst aber nicht neu + * gestartet wurde: Die Oberfläche ruft dann Endpunkte auf, die es serverseitig + * noch gar nicht gibt, und alles sieht nach einem Fehler in der Funktion aus + * statt nach einem halben Update. + * + * Verglichen wird nur, wenn BEIDE Seiten ihren Stand kennen – sonst schwiege + * der Hinweis besser, als falschen Alarm zu schlagen. + */ +export default function StandHinweis() { + const [server, setServer] = useState(null); + useEffect(() => { + let ok = true; + api.version().then((v) => ok && setServer(v?.git_sha || "")).catch(() => {}); + return () => { ok = false; }; + }, []); + + if (!GEBAUT || !server || server === GEBAUT) return null; + return ( +
+ + + Oberfläche ({GEBAUT}) und Server ({server}) laufen auf verschiedenen + Ständen. Bitte sudo ./deploy/update.sh ausführen – sonst + fehlen dem Server Funktionen, die die Oberfläche schon aufruft. + +
+ ); +} diff --git a/web/src/finance.css b/web/src/finance.css index b11ed6a..744504e 100644 --- a/web/src/finance.css +++ b/web/src/finance.css @@ -1587,3 +1587,31 @@ tr.row-dup { flex: 0 1 auto; max-width: 9em; } + +/* ---------- Halbes Update ---------- + Gebaut, aber der Dienst nicht neu gestartet: Die Oberfläche ruft dann + Endpunkte auf, die es serverseitig noch gar nicht gibt. Ohne diesen Hinweis + sieht das aus wie ein Fehler in der Funktion. */ +.stand-hinweis { + display: flex; + align-items: flex-start; + gap: var(--sp-2); + margin-bottom: var(--sp-4); + padding: var(--sp-3) var(--sp-4); + border: 1px solid var(--warn); + border-radius: var(--radius-sm); + background: var(--warn-soft); + color: var(--text); + font-size: 0.85rem; + line-height: 1.45; +} +.stand-hinweis svg { + flex: 0 0 auto; + margin-top: 2px; +} +.stand-hinweis code { + padding: 1px 5px; + border-radius: 4px; + background: var(--surface-2); + font-size: 0.95em; +} diff --git a/web/vite.config.js b/web/vite.config.js index 82299c9..fdf620f 100644 --- a/web/vite.config.js +++ b/web/vite.config.js @@ -1,12 +1,27 @@ +import { execSync } from "node:child_process"; + import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; +// Der Commit, aus dem dieses Bundle stammt. Die Oberflaeche vergleicht ihn mit +// dem, den der Server meldet – laufen beide auseinander, wurde gebaut, aber der +// Dienst nicht neu gestartet. Das kostete schon mehrfach eine halbe Stunde +// Fehlersuche an einer Funktion, die es serverseitig noch gar nicht gab. +function commit() { + try { + return execSync("git rev-parse --short HEAD", { encoding: "utf8" }).trim(); + } catch { + return ""; // Kein Git zur Hand – dann wird nichts verglichen. + } +} + // Im Dev-Modus wird /api an das lokale Backend weitergeleitet. Anders als in der // Vorlage wird der /api-Präfix NICHT entfernt – das Backend bedient die Routen // bewusst unter /api/... (ein Prozess liefert API und SPA gemeinsam aus). // In Produktion liefert derselbe FastAPI-Prozess das gebaute Frontend mit aus. export default defineConfig({ plugins: [react()], + define: { __APP_SHA__: JSON.stringify(commit()) }, server: { port: 5173, proxy: {