feat(hub): show "update available" notification in hub web UI (#1830)

* refactor, make opt-in, and deprecate /api/beszel/getkey in favor of /api/beszel/info

---------

Co-authored-by: henrygd <hank@henrygd.me>
This commit is contained in:
Sven van Ginkel
2026-03-22 22:23:54 +01:00
committed by GitHub
parent c159eaacd1
commit b2fd50211e
7 changed files with 125 additions and 24 deletions

View File

@@ -1,7 +1,11 @@
import { useStore } from "@nanostores/react"
import { GithubIcon } from "lucide-react"
import { $newVersion } from "@/lib/stores"
import { Separator } from "./ui/separator"
import { Trans } from "@lingui/react/macro"
export function FooterRepoLink() {
const newVersion = useStore($newVersion)
return (
<div className="flex gap-1.5 justify-end items-center pe-3 sm:pe-6 mt-3.5 mb-4 text-xs opacity-80">
<a
@@ -21,6 +25,19 @@ export function FooterRepoLink() {
>
Beszel {globalThis.BESZEL.HUB_VERSION}
</a>
{newVersion?.v && (
<>
<Separator orientation="vertical" className="h-2.5 bg-muted-foreground opacity-70" />
<a
href={newVersion.url}
target="_blank"
className="text-yellow-500 hover:text-yellow-400 duration-75"
rel="noopener"
>
<Trans context="New version available">{newVersion.v} available</Trans>
</a>
</>
)}
</div>
)
}

View File

@@ -1,5 +1,5 @@
import { atom, computed, listenKeys, map, type ReadableAtom } from "nanostores"
import type { AlertMap, ChartTimes, SystemRecord, UserSettings } from "@/types"
import type { AlertMap, ChartTimes, SystemRecord, UpdateInfo, UserSettings } from "@/types"
import { pb } from "./api"
import { Unit } from "./enums"
@@ -28,6 +28,9 @@ export const $alerts = map<AlertMap>({})
/** SSH public key */
export const $publicKey = atom("")
/** New version info if an update is available, otherwise undefined */
export const $newVersion = atom<UpdateInfo | undefined>()
/** Chart time period */
export const $chartTime = atom<ChartTimes>("1h")

View File

@@ -12,17 +12,19 @@ import Settings from "@/components/routes/settings/layout.tsx"
import { ThemeProvider } from "@/components/theme-provider.tsx"
import { Toaster } from "@/components/ui/toaster.tsx"
import { alertManager } from "@/lib/alerts"
import { pb, updateUserSettings } from "@/lib/api.ts"
import { isAdmin, pb, updateUserSettings } from "@/lib/api.ts"
import { dynamicActivate, getLocale } from "@/lib/i18n"
import {
$authenticated,
$copyContent,
$direction,
$newVersion,
$publicKey,
$userSettings,
defaultLayoutWidth,
} from "@/lib/stores.ts"
import * as systemsManager from "@/lib/systemsManager.ts"
import type { BeszelInfo, UpdateInfo } from "./types"
const LoginPage = lazy(() => import("@/components/login/login.tsx"))
const Home = lazy(() => import("@/components/routes/home.tsx"))
@@ -39,9 +41,13 @@ const App = memo(() => {
pb.authStore.onChange(() => {
$authenticated.set(pb.authStore.isValid)
})
// get version / public key
pb.send("/api/beszel/getkey", {}).then((data) => {
// get general info for authenticated users, such as public key and version
pb.send<BeszelInfo>("/api/beszel/info", {}).then((data) => {
$publicKey.set(data.key)
// check for updates if enabled
if (data.cu && isAdmin()) {
pb.send<UpdateInfo>("/api/beszel/update", {}).then($newVersion.set)
}
})
// get user settings
updateUserSettings()

View File

@@ -525,4 +525,15 @@ export interface SystemdServiceDetails {
WantedBy: any[];
Wants: string[];
WantsMountsFor: any[];
}
}
export interface BeszelInfo {
key: string // public key
v: string // version
cu: boolean // check updates
}
export interface UpdateInfo {
v: string // new version
url: string // url to new version
}