mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-25 20:25:51 +08:00
feat(version): warn when the server was updated but not restarted (#898)
When the package is updated on disk but the long-lived server process is not restarted, the new frontend bundle (served from disk) talks to the old running backend. New DB-backed features then fail silently — e.g. deleting/archiving a session appears to do nothing — because the new schema/routes only take effect on restart. Nothing currently detects this skew: useVersionCheck only compares the frontend's build-time version against the latest GitHub release. This exposes the running server's version (captured once at startup) via /health, compares it to the frontend's build-time version in useVersionCheck, and shows a "restart required" banner in the sidebar (and a small indicator in the collapsed sidebar) when they differ. - server: add `version` (RUNNING_VERSION, read once at startup) to /health - useVersionCheck: return `restartRequired` / `runningVersion` - SidebarFooter / SidebarCollapsed: surface a restart-required banner - i18n: add `version.restartRequired` to all 10 sidebar locales Verified with `tsc --noEmit` (client + server) and eslint. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Simos Mikelatos <simosmik@gmail.com>
This commit is contained in:
@@ -28,20 +28,31 @@ export const useVersionCheck = (owner: string, repo: string) => {
|
||||
const [latestVersion, setLatestVersion] = useState<string | null>(null);
|
||||
const [releaseInfo, setReleaseInfo] = useState<ReleaseInfo | null>(null);
|
||||
const [installMode, setInstallMode] = useState<InstallMode>('git');
|
||||
const [runningVersion, setRunningVersion] = useState<string | null>(null);
|
||||
const [restartRequired, setRestartRequired] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchInstallMode = async () => {
|
||||
const fetchHealth = async () => {
|
||||
try {
|
||||
const response = await fetch('/health');
|
||||
const data = await response.json();
|
||||
if (data.installMode === 'npm' || data.installMode === 'git') {
|
||||
setInstallMode(data.installMode);
|
||||
}
|
||||
// `data.version` is the version the server process is actually running.
|
||||
// This module's `version` is baked into the frontend bundle at build
|
||||
// time, so it reflects the installed (on-disk) package. If they differ,
|
||||
// the package was updated but the server process was not restarted, and
|
||||
// DB-backed actions may silently fail until it is.
|
||||
if (typeof data.version === 'string' && data.version.length > 0) {
|
||||
setRunningVersion(data.version);
|
||||
setRestartRequired(data.version !== version);
|
||||
}
|
||||
} catch {
|
||||
// Default to git on error
|
||||
// Default to git / no restart hint on error
|
||||
}
|
||||
};
|
||||
fetchInstallMode();
|
||||
fetchHealth();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -84,5 +95,5 @@ export const useVersionCheck = (owner: string, repo: string) => {
|
||||
return () => clearInterval(interval);
|
||||
}, [owner, repo]);
|
||||
|
||||
return { updateAvailable, latestVersion, currentVersion: version, releaseInfo, installMode };
|
||||
return { updateAvailable, latestVersion, currentVersion: version, releaseInfo, installMode, runningVersion, restartRequired };
|
||||
};
|
||||
Reference in New Issue
Block a user