fix(version): cache-bust refresh + clear stale state on manual check, bump to v0.4.5

The refresh/retry button called fetchVersion() without clearing
versionInfo first, so the old value stayed displayed with no feedback.
On manual refresh it now immediately sets versionInfo to null (shows
spinner) then fetches with ?_t=Date.now() to bypass any browser cache
of the API response.

Bump version to 0.4.5 to include all fixes since 0.4.4 (day/night
toggle, uptime/kill allowlist, auto-retry on version error).
This commit is contained in:
NixReaper
2026-04-11 14:27:19 -05:00
parent ddb51a8b4d
commit 5af2762634
4 changed files with 24 additions and 6 deletions
+12
View File
@@ -6,6 +6,18 @@ Pre-1.0 versions treat MINOR as feature releases and PATCH as bug fixes.
---
## [0.4.5] — 2026-04-11
### Bug Fixes
- **Sidebar version refresh not updating** — clicking the refresh icon now clears the stale version immediately (shows spinner) and adds a `?_t=` cache-bust parameter so the browser never serves a cached response. Same fix applied to the "Retry" button in the error state.
- **`uptime` and `kill` missing from exec allowlist** — caused `GET /api/nixserver/system/info` to throw "Command not allowed", returning 500 and leaving Hostname/OS as `…` on the dashboard.
- **Version fetch auto-retry** — when the version API fails (e.g. during service restart after upgrade), the sidebar now automatically retries every 5 s until it succeeds instead of permanently showing "Version unavailable".
### New Features
- **Day/Night mode toggle** — sun/moon flip switch at the right end of the dashboard info bar. Light palette: page `#f0f4f8`, cards `#ffffff`. Preference persisted to `localStorage`. All pages switch via seven `[data-theme="light"]` CSS overrides in `index.css` without touching individual page files.
---
## [0.4.4] — 2026-04-11
### New Features
+10 -4
View File
@@ -465,10 +465,16 @@ export default function Layout() {
const [versionError, setVersionError] = useState(false)
const [upgradeState, setUpgradeState] = useState<'idle' | 'confirm' | 'running' | 'done' | 'error'>('idle')
const fetchVersion = useCallback(async () => {
const fetchVersion = useCallback(async (manual = false) => {
setVersionError(false)
// On a manual refresh, clear the stale value so the spinner shows
if (manual) setVersionInfo(null)
try {
const { data } = await api.get('/nixserver/system/version', { timeout: 10_000 })
const { data } = await api.get('/nixserver/system/version', {
timeout: 10_000,
// Cache-bust so the browser never serves a stale version response
params: { _t: Date.now() },
})
setVersionInfo(data.data)
} catch {
setVersionError(true)
@@ -685,7 +691,7 @@ export default function Layout() {
)}
</div>
<button
onClick={fetchVersion}
onClick={() => fetchVersion(true)}
title="Check for updates"
className="text-[#4a5568] hover:text-[#94a3b8] transition-colors"
>
@@ -741,7 +747,7 @@ export default function Layout() {
) : versionError ? (
<div className="flex items-center justify-between px-1 py-1">
<span className="text-[#4a5568] text-[10px]">Version unavailable</span>
<button onClick={fetchVersion} title="Retry" className="text-[#4a5568] hover:text-[#94a3b8] transition-colors">
<button onClick={() => fetchVersion(true)} title="Retry" className="text-[#4a5568] hover:text-[#94a3b8] transition-colors">
<RefreshCcw size={10} />
</button>
</div>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "nixpanel-server",
"version": "0.4.4",
"version": "0.4.5",
"private": true,
"workspaces": [
"server",
+1 -1
View File
@@ -73,7 +73,7 @@ export async function buildApp() {
fastify.get('/api/health', async () => ({
status: 'ok',
version: '0.4.4',
version: '0.4.5',
timestamp: new Date().toISOString(),
}))