Compare commits

...

8 Commits

Author SHA1 Message Date
henrygd
75b372437c add small end buffer to chart x axis 2025-10-05 21:18:16 -04:00
henrygd
b661d00159 release 0.13.1 2025-10-05 20:09:49 -04:00
henrygd
898dbf73c8 update agent dockerfile volume 2025-10-05 20:06:17 -04:00
Marrrrrrrrry
e099304948 Add VOLUME to preserve config across container recreations (#1235) 2025-10-05 20:05:00 -04:00
Maximilian Krause
b61b7a12dc New translations en.po (German) 2025-10-05 19:40:44 -04:00
henrygd
37769050e5 fix loading system with direct id url 2025-10-05 19:38:37 -04:00
henrygd
d81e137291 update system permalinks to use id instead of name (#1231)
maintains backward compatibility with old permalinks
2025-10-05 14:18:00 -04:00
henrygd
ae820d348e fix one minute chart on systems without docker (#1237) 2025-10-05 13:19:35 -04:00
16 changed files with 56 additions and 29 deletions

View File

@@ -6,7 +6,7 @@ import "github.com/blang/semver"
const (
// Version is the current version of the application.
Version = "0.13.0"
Version = "0.13.1"
// AppName is the name of the application.
AppName = "beszel"
)

View File

@@ -23,4 +23,7 @@ COPY --from=builder /agent /agent
# this is so we don't need to create the /tmp directory in the scratch container
COPY --from=builder /tmp /tmp
# Ensure data persistence across container recreations
VOLUME ["/var/lib/beszel-agent"]
ENTRYPOINT ["/agent"]

View File

@@ -22,4 +22,7 @@ COPY --from=builder /agent /agent
RUN apk add --no-cache -X https://dl-cdn.alpinelinux.org/alpine/edge/testing igt-gpu-tools
# Ensure data persistence across container recreations
VOLUME ["/var/lib/beszel-agent"]
ENTRYPOINT ["/agent"]

View File

@@ -24,4 +24,7 @@ COPY --from=builder /agent /agent
# this is so we don't need to create the /tmp directory in the scratch container
COPY --from=builder /tmp /tmp
# Ensure data persistence across container recreations
VOLUME ["/var/lib/beszel-agent"]
ENTRYPOINT ["/agent"]

View File

@@ -25,6 +25,9 @@ FROM scratch
COPY --from=builder /beszel /
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Ensure data persistence across container recreations
VOLUME ["/beszel_data"]
EXPOSE 8090
ENTRYPOINT [ "/beszel" ]

View File

@@ -1,12 +1,12 @@
{
"name": "beszel",
"version": "0.13.0",
"version": "0.13.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "beszel",
"version": "0.13.0",
"version": "0.13.1",
"dependencies": {
"@henrygd/queue": "^1.0.7",
"@henrygd/semaphore": "^0.0.2",

View File

@@ -1,7 +1,7 @@
{
"name": "beszel",
"private": true,
"version": "0.13.0",
"version": "0.13.1",
"type": "module",
"scripts": {
"dev": "vite --host",

View File

@@ -65,7 +65,7 @@ export default memo(function CommandPalette({ open, setOpen }: { open: boolean;
<CommandItem
key={system.id}
onSelect={() => {
navigate(getPagePath($router, "system", { name: system.name }))
navigate(getPagePath($router, "system", { id: system.id }))
setOpen(false)
}}
>

View File

@@ -2,7 +2,7 @@ import { createRouter } from "@nanostores/router"
const routes = {
home: "/",
system: `/system/:name`,
system: `/system/:id`,
settings: `/settings/:name?`,
forgot_password: `/forgot-password`,
request_otp: `/request-otp`,

View File

@@ -112,7 +112,7 @@ const ActiveAlerts = () => {
)}
</AlertDescription>
<Link
href={getPagePath($router, "system", { name: systems[alert.system]?.name })}
href={getPagePath($router, "system", { id: systems[alert.system]?.id })}
className="absolute inset-0 w-full h-full"
aria-label="View system"
></Link>

View File

@@ -27,6 +27,7 @@ import { getPbTimestamp, pb } from "@/lib/api"
import { ChartType, ConnectionType, connectionTypeLabels, Os, SystemStatus, Unit } from "@/lib/enums"
import { batteryStateTranslations } from "@/lib/i18n"
import {
$allSystemsById,
$allSystemsByName,
$chartTime,
$containerFilter,
@@ -92,7 +93,8 @@ function getTimeData(chartTime: ChartTimes, lastCreated: number) {
}
}
const now = new Date()
const buffer = chartTime === "1m" ? 400 : 20_000
const now = new Date(Date.now() + buffer)
const startTime = chartTimeData[chartTime].getOffset(now)
const ticks = timeTicks(startTime, now, chartTimeData[chartTime].ticks ?? 12).map((date) => date.getTime())
const data = {
@@ -156,7 +158,7 @@ function dockerOrPodman(str: string, system: SystemRecord): string {
return str
}
export default memo(function SystemDetail({ name }: { name: string }) {
export default memo(function SystemDetail({ id }: { id: string }) {
const direction = useStore($direction)
const { t } = useLingui()
const systems = useStore($systems)
@@ -175,7 +177,6 @@ export default memo(function SystemDetail({ name }: { name: string }) {
const chartWrapRef = useRef<HTMLDivElement>(null)
useEffect(() => {
document.title = `${name} / Beszel`
return () => {
if (!persistChartTime.current) {
$chartTime.set($userSettings.get().chartTime)
@@ -185,15 +186,23 @@ export default memo(function SystemDetail({ name }: { name: string }) {
setContainerData([])
$containerFilter.set("")
}
}, [name])
}, [id])
// find matching system and update when it changes
useEffect(() => {
return subscribeKeys($allSystemsByName, [name], (newSystems) => {
const sys = newSystems[name]
sys?.id && setSystem(sys)
if (!systems.length) {
return
}
// allow old system-name slug to work
const store = $allSystemsById.get()[id] ? $allSystemsById : $allSystemsByName
return subscribeKeys(store, [id], (newSystems) => {
const sys = newSystems[id]
if (sys) {
setSystem(sys)
document.title = `${sys?.name} / Beszel`
}
})
}, [name])
}, [id, systems.length])
// hide 1m chart time if system agent version is less than 0.13.0
useEffect(() => {
@@ -217,8 +226,7 @@ export default memo(function SystemDetail({ name }: { name: string }) {
.subscribe(
`rt_metrics`,
(data: { container: ContainerStatsRecord[]; info: SystemInfo; stats: SystemStats }) => {
// console.log("received realtime metrics", data)
if (data.container.length > 0) {
if (data.container?.length > 0) {
const newContainerData = makeContainerData([
{ created: Date.now(), stats: data.container } as unknown as ContainerStatsRecord,
])
@@ -416,7 +424,7 @@ export default memo(function SystemDetail({ name }: { name: string }) {
) {
return
}
const currentIndex = systems.findIndex((s) => s.name === name)
const currentIndex = systems.findIndex((s) => s.id === id)
if (currentIndex === -1 || systems.length <= 1) {
return
}
@@ -425,18 +433,18 @@ export default memo(function SystemDetail({ name }: { name: string }) {
case "h": {
const prevIndex = (currentIndex - 1 + systems.length) % systems.length
persistChartTime.current = true
return navigate(getPagePath($router, "system", { name: systems[prevIndex].name }))
return navigate(getPagePath($router, "system", { id: systems[prevIndex].id }))
}
case "ArrowRight":
case "l": {
const nextIndex = (currentIndex + 1) % systems.length
persistChartTime.current = true
return navigate(getPagePath($router, "system", { name: systems[nextIndex].name }))
return navigate(getPagePath($router, "system", { id: systems[nextIndex].id }))
}
}
}
return listen(document, "keyup", handleKeyUp)
}, [name, systems])
}, [id, systems])
if (!system.id) {
return null

View File

@@ -77,6 +77,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
accessorKey: "name",
id: "system",
name: () => t`System`,
sortingFn: (a, b) => a.original.name.localeCompare(b.original.name),
filterFn: (() => {
let filterInput = ""
let filterInputLower = ""
@@ -110,7 +111,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
invertSorting: false,
Icon: ServerIcon,
cell: (info) => {
const { name } = info.row.original
const { name, id } = info.row.original
const longestName = useStore($longestSystemNameLen)
return (
<>
@@ -122,7 +123,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
</span>
</span>
<Link
href={getPagePath($router, "system", { name })}
href={getPagePath($router, "system", { id })}
className="inset-0 absolute size-full"
aria-label={name}
></Link>
@@ -279,7 +280,7 @@ export default function SystemsTableColumns(viewMode: "table" | "grid"): ColumnD
}
return (
<Link
href={getPagePath($router, "system", { name: system.name })}
href={getPagePath($router, "system", { id: system.id })}
className={cn(
"flex gap-1.5 items-center md:pe-5 tabular-nums relative z-10",
viewMode === "table" && "ps-0.5"

View File

@@ -486,7 +486,7 @@ const SystemCard = memo(
</div>
</CardContent>
<Link
href={getPagePath($router, "system", { name: row.original.name })}
href={getPagePath($router, "system", { id: row.original.id })}
className="inset-0 absolute w-full h-full"
>
<span className="sr-only">{row.original.name}</span>

View File

@@ -8,7 +8,7 @@ msgstr ""
"Language: de\n"
"Project-Id-Version: beszel\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-08-28 23:21\n"
"PO-Revision-Date: 2025-10-05 16:13\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -459,7 +459,7 @@ msgstr "Offline ({downSystemsLength})"
#: src/components/routes/system/network-sheet.tsx
msgid "Download"
msgstr "Download"
msgstr "Herunterladen"
#: src/components/alerts-history-columns.tsx
msgid "Duration"
@@ -1156,7 +1156,7 @@ msgstr "aktiv ({upSystemsLength})"
#: src/components/routes/system/network-sheet.tsx
msgid "Upload"
msgstr "Upload"
msgstr "Hochladen"
#: src/components/routes/system.tsx
msgid "Uptime"

View File

@@ -59,7 +59,7 @@ const App = memo(() => {
} else if (page.route === "home") {
return <Home />
} else if (page.route === "system") {
return <SystemDetail name={page.params.name} />
return <SystemDetail id={page.params.id} />
} else if (page.route === "settings") {
return <Settings />
}

View File

@@ -1,3 +1,9 @@
## 0.13.1
- Fix one minute charts on systems without Docker. (#1237)
- Change system permalinks to use ID instead of name. (#1231)
## 0.13.0
- Add one minute chart with one second interval.