diff --git a/cmd/panel/main.go b/cmd/panel/main.go index 7ef8a19..888df48 100644 --- a/cmd/panel/main.go +++ b/cmd/panel/main.go @@ -38,7 +38,7 @@ import ( // version is the panel build version. It defaults to the contents of the VERSION // file and is overridden at build time via -ldflags "-X main.version=...". -var version = "1.4.0" +var version = "1.4.1" func main() { logBuf := logbuf.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}), 2000) diff --git a/web/package-lock.json b/web/package-lock.json index dd36586..e36c518 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1,12 +1,12 @@ { "name": "vortexui-web", - "version": "1.4.0", + "version": "1.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "vortexui-web", - "version": "1.4.0", + "version": "1.4.1", "dependencies": { "@tanstack/react-query": "^5.59.0", "@types/leaflet": "^1.9.21", @@ -954,9 +954,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -971,9 +968,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -988,9 +982,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1005,9 +996,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1022,9 +1010,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1039,9 +1024,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1056,9 +1038,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1073,9 +1052,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1090,9 +1066,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1107,9 +1080,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1124,9 +1094,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1141,9 +1108,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1158,9 +1122,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2265,7 +2226,7 @@ "license": "MIT" }, "node_modules/expect-type": { - "version": "1.4.0", + "version": "1.4.1", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", "dev": true, @@ -2676,7 +2637,7 @@ "license": "MIT" }, "node_modules/loose-envify": { - "version": "1.4.0", + "version": "1.4.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", diff --git a/web/package.json b/web/package.json index ab9aa7d..cffd9ed 100644 --- a/web/package.json +++ b/web/package.json @@ -1,7 +1,7 @@ { "name": "vortexui-web", "private": true, - "version": "1.4.0", + "version": "1.4.1", "type": "module", "scripts": { "dev": "vite", diff --git a/web/src/api/hooks.ts b/web/src/api/hooks.ts index 5b6103b..efa20dd 100644 --- a/web/src/api/hooks.ts +++ b/web/src/api/hooks.ts @@ -5,9 +5,17 @@ import type { CoreType, CreateUserInput, EnrollmentBundle, ListUsersResponse, No // --- panel version --- +// PANEL_VERSION is the web bundle's own build version (injected by Vite at +// build time from ../VERSION). It doubles as the fallback whenever +// GET /api/version is unreachable or errors. +export const PANEL_VERSION = __PANEL_VERSION__; + // useVersion fetches the actually running panel build version from the backend // (GET /api/version). The value only changes when the binary changes, so it is -// cached for the whole session. +// cached for the whole session. initialData is the build-time bundle version +// and flows through `select`, so consumers always get a string from the very +// first render — even when the request fails (e.g. a reseller without +// system:read gets 403) or while it is still in flight. export function useVersion() { return useQuery({ queryKey: ["version"], @@ -17,6 +25,8 @@ export function useVersion() { refetchOnWindowFocus: false, refetchOnMount: false, refetchOnReconnect: false, + retry: false, + initialData: { version: __PANEL_VERSION__ }, select: (d) => d.version, }); } diff --git a/web/src/components/AppHeader.tsx b/web/src/components/AppHeader.tsx index 62f4cac..59a93a2 100644 --- a/web/src/components/AppHeader.tsx +++ b/web/src/components/AppHeader.tsx @@ -25,7 +25,7 @@ export function AppHeader() { const { resolved, toggle: toggleTheme } = useTheme(); const { t, lang, setLang } = useI18n(); const navigate = useNavigate(); - const panelVersion = useVersion().data; + const panelVersion = useVersion().data ?? __PANEL_VERSION__; const [searchFocused, setSearchFocused] = useState(false); const [langOpen, setLangOpen] = useState(false); diff --git a/web/src/pages/Overview.tsx b/web/src/pages/Overview.tsx index 2ac0679..a9cec54 100644 --- a/web/src/pages/Overview.tsx +++ b/web/src/pages/Overview.tsx @@ -105,7 +105,7 @@ export function Overview() { const { data, isLoading: overviewLoading } = useOverview(); const sys = useSystem(); const nodesQ = useNodes(); - const panelVersion = useVersion().data; + const panelVersion = useVersion().data ?? __PANEL_VERSION__; const { t } = useI18n(); const [trafficRange, setTrafficRange] = useState("24h"); const trafficSeries = useTrafficSeries(trafficRange);