site static directory + other site updates

This commit is contained in:
Henry Dollman
2024-07-20 16:17:48 -04:00
parent af1afa8076
commit b18433f428
41 changed files with 81 additions and 70 deletions

13
main.go
View File

@@ -49,7 +49,7 @@ func main() {
// // enable auto creation of migration files when making collection changes in the Admin UI
migratecmd.MustRegister(app, app.RootCmd, migratecmd.Config{
// (the isGoRun check is to enable it only during development)
// Automigrate: isGoRun,
Automigrate: isGoRun,
})
// set auth settings
@@ -81,11 +81,11 @@ func main() {
Scheme: "http",
Host: "localhost:5173",
})
e.Router.GET("/icons/*", apis.StaticDirectoryHandler(os.DirFS("./site/public/icons"), false))
e.Router.GET("/static/*", apis.StaticDirectoryHandler(os.DirFS("./site/public/static"), false))
e.Router.Any("/*", echo.WrapHandler(proxy))
// e.Router.Any("/", echo.WrapHandler(proxy))
default:
e.Router.GET("/icons/*", apis.StaticDirectoryHandler(site.Icons, false))
e.Router.GET("/static/*", apis.StaticDirectoryHandler(site.Static, false))
e.Router.Any("/*", apis.StaticDirectoryHandler(site.Dist, true))
}
return nil
@@ -95,7 +95,7 @@ func main() {
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
scheduler := cron.New()
// delete records that are older than the display period
scheduler.MustAdd("delete old records", "0 */2 * * *", func() {
scheduler.MustAdd("delete old records", "8 */2 * * *", func() {
deleteOldRecords("system_stats", "1m", time.Hour)
deleteOldRecords("container_stats", "1m", time.Hour)
deleteOldRecords("system_stats", "10m", 12*time.Hour)
@@ -188,6 +188,11 @@ func main() {
return nil
})
app.OnModelAfterCreate("container_stats").Add(func(e *core.ModelEvent) error {
createLongerRecords("container_stats", e.Model.(*models.Record))
return nil
})
if err := app.Start(); err != nil {
log.Fatal(err)
}

View File

@@ -12,4 +12,4 @@ var assets embed.FS
var Dist = echo.MustSubFS(assets, "dist")
var Icons = echo.MustSubFS(assets, "dist/icons")
var Static = echo.MustSubFS(assets, "dist/static")

View File

@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Beszel</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70 70"><path fill="#22c55e" d="M70 52.2v2.4a15.6 15.6 0 0 1-.3 2.8 20.5 20.5 0 0 1-.5 2.3q-.8 2.7-2.7 5a14 14 0 0 1-3.2 2.9 17.2 17.2 0 0 1-1.5.9q-3 1.5-7.2 1.5H6.4a6.7 6.7 0 0 1-2-.2 6.1 6.1 0 0 1-.5-.3 6.2 6.2 0 0 1-2-1.3 6.2 6.2 0 0 1-1.4-2A6.4 6.4 0 0 1 0 64a7.5 7.5 0 0 1 0-.4V6.4a6.4 6.4 0 0 1 .5-2.5Q1 2.7 1.8 2a6 6 0 0 1 2-1.4A6.4 6.4 0 0 1 6.2 0a7.5 7.5 0 0 1 .3 0h42.5a15.2 15.2 0 0 1 2.7.3 20 20 0 0 1 2.3.5q2.7.9 5 2.7a14 14 0 0 1 3 3.4 17 17 0 0 1 .9 1.4q1.5 2.9 1.5 7.1v2.4a23.2 23.2 0 0 1-.3 4 30.7 30.7 0 0 1-.8 3.3 23.9 23.9 0 0 1-3.5 7.1 26.8 26.8 0 0 1-.1.2 22.4 22.4 0 0 1 4 3.2 20.1 20.1 0 0 1 3 3.8 22.6 22.6 0 0 1 .3.5 21.5 21.5 0 0 1 1.7 3.6 26 26 0 0 1 .5 2 23.8 23.8 0 0 1 .7 3.9 30 30 0 0 1 .2 2.8Zm-12.7 2.3v-2.3a13.6 13.6 0 0 0-.2-2.5 10.7 10.7 0 0 0-.6-2 10 10 0 0 0-1.8-2.9 9.4 9.4 0 0 0-.4-.5 9.4 9.4 0 0 0-3.1-2 11 11 0 0 0-.3-.1 11.6 11.6 0 0 0-2.7-.7 14.7 14.7 0 0 0-1.8 0H17.8V28.5h22.9a14.1 14.1 0 0 0 2.5-.2 11.2 11.2 0 0 0 2-.5 9.7 9.7 0 0 0 2.7-1.6 9 9 0 0 0 .7-.6 9.5 9.5 0 0 0 2.1-3.3 11 11 0 0 0 0-.1 11.3 11.3 0 0 0 .7-2.6 14.6 14.6 0 0 0 .1-1.9v-2.4q0-2.7-2.6-2.7H12.7v44.6h41.9a6 6 0 0 0 .3 0h.5a2 2 0 0 0 .7-.2 2 2 0 0 0 .2-.1 1.5 1.5 0 0 0 .3-.3l.4-.5.3-1a6 6 0 0 0 0-.7Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70 70"><path fill="#dc2626" d="M70 52.2v2.4a15.6 15.6 0 0 1-.3 2.8 20.5 20.5 0 0 1-.5 2.3q-.8 2.7-2.7 5a14 14 0 0 1-3.2 2.9 17.2 17.2 0 0 1-1.5.9q-3 1.5-7.2 1.5H6.4a6.7 6.7 0 0 1-2-.2 6.1 6.1 0 0 1-.5-.3 6.2 6.2 0 0 1-2-1.3 6.2 6.2 0 0 1-1.4-2A6.4 6.4 0 0 1 0 64a7.5 7.5 0 0 1 0-.4V6.4a6.4 6.4 0 0 1 .5-2.5Q1 2.7 1.8 2a6 6 0 0 1 2-1.4A6.4 6.4 0 0 1 6.2 0a7.5 7.5 0 0 1 .3 0h42.5a15.2 15.2 0 0 1 2.7.3 20 20 0 0 1 2.3.5q2.7.9 5 2.7a14 14 0 0 1 3 3.4 17 17 0 0 1 .9 1.4q1.5 2.9 1.5 7.1v2.4a23.2 23.2 0 0 1-.3 4 30.7 30.7 0 0 1-.8 3.3 23.9 23.9 0 0 1-3.5 7.1 26.8 26.8 0 0 1-.1.2 22.4 22.4 0 0 1 4 3.2 20.1 20.1 0 0 1 3 3.8 22.6 22.6 0 0 1 .3.5 21.5 21.5 0 0 1 1.7 3.6 26 26 0 0 1 .5 2 23.8 23.8 0 0 1 .7 3.9 30 30 0 0 1 .2 2.8Zm-12.7 2.3v-2.3a13.6 13.6 0 0 0-.2-2.5 10.7 10.7 0 0 0-.6-2 10 10 0 0 0-1.8-2.9 9.4 9.4 0 0 0-.4-.5 9.4 9.4 0 0 0-3.1-2 11 11 0 0 0-.3-.1 11.6 11.6 0 0 0-2.7-.7 14.7 14.7 0 0 0-1.8 0H17.8V28.5h22.9a14.1 14.1 0 0 0 2.5-.2 11.2 11.2 0 0 0 2-.5 9.7 9.7 0 0 0 2.7-1.6 9 9 0 0 0 .7-.6 9.5 9.5 0 0 0 2.1-3.3 11 11 0 0 0 0-.1 11.3 11.3 0 0 0 .7-2.6 14.6 14.6 0 0 0 .1-1.9v-2.4q0-2.7-2.6-2.7H12.7v44.6h41.9a6 6 0 0 0 .3 0h.5a2 2 0 0 0 .7-.2 2 2 0 0 0 .2-.1 1.5 1.5 0 0 0 .3-.3l.4-.5.3-1a6 6 0 0 0 0-.7Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70 70"><path fill="#888" d="M70 52.2v2.4a15.6 15.6 0 0 1-.3 2.8 20.5 20.5 0 0 1-.5 2.3q-.8 2.7-2.7 5a14 14 0 0 1-3.2 2.9 17.2 17.2 0 0 1-1.5.9q-3 1.5-7.2 1.5H6.4a6.7 6.7 0 0 1-2-.2 6.1 6.1 0 0 1-.5-.3 6.2 6.2 0 0 1-2-1.3 6.2 6.2 0 0 1-1.4-2A6.4 6.4 0 0 1 0 64a7.5 7.5 0 0 1 0-.4V6.4a6.4 6.4 0 0 1 .5-2.5Q1 2.7 1.8 2a6 6 0 0 1 2-1.4A6.4 6.4 0 0 1 6.2 0a7.5 7.5 0 0 1 .3 0h42.5a15.2 15.2 0 0 1 2.7.3 20 20 0 0 1 2.3.5q2.7.9 5 2.7a14 14 0 0 1 3 3.4 17 17 0 0 1 .9 1.4q1.5 2.9 1.5 7.1v2.4a23.2 23.2 0 0 1-.3 4 30.7 30.7 0 0 1-.8 3.3 23.9 23.9 0 0 1-3.5 7.1 26.8 26.8 0 0 1-.1.2 22.4 22.4 0 0 1 4 3.2 20.1 20.1 0 0 1 3 3.8 22.6 22.6 0 0 1 .3.5 21.5 21.5 0 0 1 1.7 3.6 26 26 0 0 1 .5 2 23.8 23.8 0 0 1 .7 3.9 30 30 0 0 1 .2 2.8Zm-12.7 2.3v-2.3a13.6 13.6 0 0 0-.2-2.5 10.7 10.7 0 0 0-.6-2 10 10 0 0 0-1.8-2.9 9.4 9.4 0 0 0-.4-.5 9.4 9.4 0 0 0-3.1-2 11 11 0 0 0-.3-.1 11.6 11.6 0 0 0-2.7-.7 14.7 14.7 0 0 0-1.8 0H17.8V28.5h22.9a14.1 14.1 0 0 0 2.5-.2 11.2 11.2 0 0 0 2-.5 9.7 9.7 0 0 0 2.7-1.6 9 9 0 0 0 .7-.6 9.5 9.5 0 0 0 2.1-3.3 11 11 0 0 0 0-.1 11.3 11.3 0 0 0 .7-2.6 14.6 14.6 0 0 0 .1-1.9v-2.4q0-2.7-2.6-2.7H12.7v44.6h41.9a6 6 0 0 0 .3 0h.5a2 2 0 0 0 .7-.2 2 2 0 0 0 .2-.1 1.5 1.5 0 0 0 .3-.3l.4-.5.3-1a6 6 0 0 0 0-.7Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 378 B

After

Width:  |  Height:  |  Size: 378 B

View File

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 196 B

View File

Before

Width:  |  Height:  |  Size: 506 B

After

Width:  |  Height:  |  Size: 506 B

View File

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 295 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 70" fill="#22c55e"><path d="M35 70H0V0h35q4.4 0 8.2 1.7a21.4 21.4 0 0 1 6.6 4.5q2.9 2.8 4.5 6.6Q56 16.7 56 21a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5Q53 39.1 54 41a18.3 18.3 0 0 1 1.5 4 17.4 17.4 0 0 1 .5 3 15.3 15.3 0 0 1 0 1q0 4.4-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.6Q39.4 70 35 70ZM14 14v14h21a7 7 0 0 0 2.3-.3 6.6 6.6 0 0 0 .4-.2Q39 27 40 26a6.9 6.9 0 0 0 1.5-2.2q.5-1.3.5-2.8a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 17 40 16a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm0 28v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 54.9 40 54a7 7 0 0 0 1.5-2.2 6.9 6.9 0 0 0 .5-2.6 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 45 40 44a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Z"/></svg>

After

Width:  |  Height:  |  Size: 906 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 70" fill="#dc2626"><path d="M35 70H0V0h35q4.4 0 8.2 1.7a21.4 21.4 0 0 1 6.6 4.5q2.9 2.8 4.5 6.6Q56 16.7 56 21a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5Q53 39.1 54 41a18.3 18.3 0 0 1 1.5 4 17.4 17.4 0 0 1 .5 3 15.3 15.3 0 0 1 0 1q0 4.4-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.6Q39.4 70 35 70ZM14 14v14h21a7 7 0 0 0 2.3-.3 6.6 6.6 0 0 0 .4-.2Q39 27 40 26a6.9 6.9 0 0 0 1.5-2.2q.5-1.3.5-2.8a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 17 40 16a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm0 28v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 54.9 40 54a7 7 0 0 0 1.5-2.2 6.9 6.9 0 0 0 .5-2.6 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 45 40 44a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Z"/></svg>

After

Width:  |  Height:  |  Size: 906 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56 70" fill="#888"><path d="M35 70H0V0h35q4.4 0 8.2 1.7a21.4 21.4 0 0 1 6.6 4.5q2.9 2.8 4.5 6.6Q56 16.7 56 21a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5Q53 39.1 54 41a18.3 18.3 0 0 1 1.5 4 17.4 17.4 0 0 1 .5 3 15.3 15.3 0 0 1 0 1q0 4.4-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.6Q39.4 70 35 70ZM14 14v14h21a7 7 0 0 0 2.3-.3 6.6 6.6 0 0 0 .4-.2Q39 27 40 26a6.9 6.9 0 0 0 1.5-2.2q.5-1.3.5-2.8a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 17 40 16a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm0 28v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 54.9 40 54a7 7 0 0 0 1.5-2.2 6.9 6.9 0 0 0 .5-2.6 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 45 40 44a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Z"/></svg>

After

Width:  |  Height:  |  Size: 903 B

View File

Before

Width:  |  Height:  |  Size: 907 B

After

Width:  |  Height:  |  Size: 907 B

View File

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 406 B

View File

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 470 B

View File

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 302 B

View File

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 299 B

View File

Before

Width:  |  Height:  |  Size: 856 B

After

Width:  |  Height:  |  Size: 856 B

View File

Before

Width:  |  Height:  |  Size: 257 B

After

Width:  |  Height:  |  Size: 257 B

View File

Before

Width:  |  Height:  |  Size: 276 B

After

Width:  |  Height:  |  Size: 276 B

View File

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

View File

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 495 B

View File

Before

Width:  |  Height:  |  Size: 154 B

After

Width:  |  Height:  |  Size: 154 B

View File

Before

Width:  |  Height:  |  Size: 206 B

After

Width:  |  Height:  |  Size: 206 B

View File

Before

Width:  |  Height:  |  Size: 371 B

After

Width:  |  Height:  |  Size: 371 B

View File

@@ -84,6 +84,7 @@ export default function BandwidthChart({
fill="var(--color-sent)"
fillOpacity={0.4}
stroke="var(--color-sent)"
animationDuration={1200}
/>
<Area
dataKey="recv"
@@ -91,6 +92,7 @@ export default function BandwidthChart({
fill="var(--color-recv)"
fillOpacity={0.4}
stroke="var(--color-recv)"
animationDuration={1200}
/>
</AreaChart>
</ChartContainer>

View File

@@ -9,16 +9,10 @@ import { $chartTime } from '@/lib/stores'
import { chartTimeData, cn } from '@/lib/utils'
import { ChartTimes } from '@/types'
import { useStore } from '@nanostores/react'
import { useEffect } from 'react'
export default function ChartTimeSelect({ className }: { className?: string }) {
const chartTime = useStore($chartTime)
useEffect(() => {
// todo make sure this doesn't cause multiple fetches on load
return () => $chartTime.set('1h')
}, [])
return (
<Select
defaultValue="1h"

View File

@@ -18,10 +18,6 @@ export default function ContainerCpuChart({
chartData: Record<string, number | string>[]
ticks: number[]
}) {
if (!chartData.length || !ticks.length) {
return <Spinner />
}
const chartConfig = useMemo(() => {
let config = {} as Record<
string,
@@ -57,6 +53,10 @@ export default function ContainerCpuChart({
return config satisfies ChartConfig
}, [chartData])
if (!chartData.length || !ticks.length) {
return <Spinner />
}
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
<AreaChart
@@ -102,6 +102,7 @@ export default function ContainerCpuChart({
key={key}
// isAnimationActive={chartData.length < 20}
animateNewValues={false}
animationDuration={1200}
dataKey={key}
type="monotoneX"
fill={chartConfig[key].color}

View File

@@ -18,10 +18,6 @@ export default function ({
chartData: Record<string, number | string>[]
ticks: number[]
}) {
if (!chartData.length || !ticks.length) {
return <Spinner />
}
const chartConfig = useMemo(() => {
let config = {} as Record<
string,
@@ -57,6 +53,10 @@ export default function ({
return config satisfies ChartConfig
}, [chartData])
if (!chartData.length || !ticks.length) {
return <Spinner />
}
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
<AreaChart
@@ -108,6 +108,7 @@ export default function ({
key={key}
isAnimationActive={chartData.length < 20}
animateNewValues={false}
animationDuration={1200}
dataKey={key}
type="monotoneX"
fill={chartConfig[key].color}

View File

@@ -25,10 +25,11 @@ export default function CpuChart({
chartData: { time: number; cpu: number }[]
ticks: number[]
}) {
const chartTime = useStore($chartTime)
if (!chartData.length || !ticks.length) {
return <Spinner />
}
const chartTime = useStore($chartTime)
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
@@ -70,7 +71,9 @@ export default function CpuChart({
fill="var(--color-cpu)"
fillOpacity={0.4}
stroke="var(--color-cpu)"
animateNewValues={false}
animationDuration={1200}
// animationEasing="ease-out"
// animateNewValues={false}
/>
</AreaChart>
</ChartContainer>

View File

@@ -24,10 +24,6 @@ export default function DiskChart({
chartData: { time: number; disk: number; diskUsed: number }[]
ticks: number[]
}) {
if (!chartData.length || !ticks.length) {
return <Spinner />
}
const diskSize = useMemo(() => {
return Math.round(chartData[0]?.disk)
}, [chartData])
@@ -41,6 +37,10 @@ export default function DiskChart({
// return ticks
// }, [diskSize])
if (!chartData.length || !ticks.length) {
return <Spinner />
}
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
<AreaChart
@@ -94,6 +94,7 @@ export default function DiskChart({
fill="var(--color-diskUsed)"
fillOpacity={0.4}
stroke="var(--color-diskUsed)"
animationDuration={1200}
/>
</AreaChart>
</ChartContainer>

View File

@@ -84,6 +84,7 @@ export default function DiskIoChart({
fill="var(--color-write)"
fillOpacity={0.4}
stroke="var(--color-write)"
animationDuration={1200}
/>
<Area
dataKey="read"
@@ -91,6 +92,7 @@ export default function DiskIoChart({
fill="var(--color-read)"
fillOpacity={0.4}
stroke="var(--color-read)"
animationDuration={1200}
/>
</AreaChart>
</ChartContainer>

View File

@@ -17,10 +17,6 @@ export default function MemChart({
chartData: { time: number; mem: number; memUsed: number; memCache: number }[]
ticks: number[]
}) {
if (!chartData.length || !ticks.length) {
return <Spinner />
}
const totalMem = useMemo(() => {
return Math.ceil(chartData[0]?.mem)
}, [chartData])
@@ -39,6 +35,10 @@ export default function MemChart({
[]
) satisfies ChartConfig
if (!chartData.length || !ticks.length) {
return <Spinner />
}
return (
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
<AreaChart
@@ -92,6 +92,7 @@ export default function MemChart({
fillOpacity={0.4}
stroke="var(--color-memUsed)"
stackId="a"
animationDuration={1200}
/>
<Area
dataKey="memCache"
@@ -101,6 +102,7 @@ export default function MemChart({
strokeOpacity={0.3}
stroke="var(--color-memCache)"
stackId="a"
animationDuration={1200}
/>
</AreaChart>
</ChartContainer>

View File

@@ -264,10 +264,10 @@ export function UserAuthForm({
) : (
<img
className="mr-2 h-4 w-4 dark:invert"
src={`/icons/${provider.name}.svg`}
src={`/static/${provider.name}.svg`}
alt=""
onError={(e) => {
e.currentTarget.src = '/icons/lock.svg'
e.currentTarget.src = '/static/lock.svg'
}}
/>
)}

View File

@@ -1,19 +1,8 @@
export function Logo({ className }: { className?: string }) {
return (
// audiowide
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 353.3 75.1" className={className}>
<path d="M118.9 57.3H96v-12h22.9a6.8 6.8 0 0 0 1.6-.3 4.6 4.6 0 0 0 2.4-1.4 5.5 5.5 0 0 0 1.4-3.3 7.3 7.3 0 0 0 0-.6 6.3 6.3 0 0 0-.2-1.7 4.5 4.5 0 0 0-1.4-2.2 5.5 5.5 0 0 0-3.7-1.4 7 7 0 0 0-.1 0H96a6.8 6.8 0 0 0-1.6.2A4.6 4.6 0 0 0 92 36a5.5 5.5 0 0 0-1.4 3.3 7.3 7.3 0 0 0 0 .6v17.7a6.5 6.5 0 0 0 .2 1.7 4.6 4.6 0 0 0 1.4 2.3 5.5 5.5 0 0 0 3.3 1.4 7.3 7.3 0 0 0 .6 0h22.8V75H96a17.3 17.3 0 0 1-3-.3 23.1 23.1 0 0 1-2.7-.6 17 17 0 0 1-5.7-3 15.9 15.9 0 0 1-3.3-3.7 19.6 19.6 0 0 1-1-1.8q-1.7-3.1-1.8-7.5a25.4 25.4 0 0 1 0-.6V39.8a17.3 17.3 0 0 1 .3-3 23.1 23.1 0 0 1 .6-2.7 17 17 0 0 1 3-5.7 15.9 15.9 0 0 1 3.7-3.3 19.6 19.6 0 0 1 1.8-1q3.1-1.7 7.5-1.8a25.4 25.4 0 0 1 .6 0h22.9a17.3 17.3 0 0 1 3 .3 23.1 23.1 0 0 1 2.7.6 17 17 0 0 1 5.6 3 15.9 15.9 0 0 1 3.4 3.7 19.6 19.6 0 0 1 1 1.8q1.7 3.1 1.8 7.5a25.4 25.4 0 0 1 0 .6 17.3 17.3 0 0 1-.3 3 23.1 23.1 0 0 1-.7 2.7 17 17 0 0 1-3 5.6 15.9 15.9 0 0 1-3.6 3.4 19.6 19.6 0 0 1-1.8 1q-3.1 1.7-7.5 1.8a25.4 25.4 0 0 1-.6 0Zm185.2 0h-23v-12h23a6.8 6.8 0 0 0 1.6-.3 4.6 4.6 0 0 0 2.4-1.4 5.5 5.5 0 0 0 1.3-3.3 7.3 7.3 0 0 0 0-.6 6.3 6.3 0 0 0-.1-1.7 4.5 4.5 0 0 0-1.4-2.2 5.5 5.5 0 0 0-3.7-1.4 7 7 0 0 0-.1 0h-23a6.8 6.8 0 0 0-1.6.2 4.6 4.6 0 0 0-2.4 1.4 5.5 5.5 0 0 0-1.3 3.3 7.3 7.3 0 0 0 0 .6v17.7a6.5 6.5 0 0 0 .1 1.7 4.6 4.6 0 0 0 1.4 2.3 5.5 5.5 0 0 0 3.3 1.4 7.3 7.3 0 0 0 .6 0h22.9V75h-23a17.3 17.3 0 0 1-3-.3 23.1 23.1 0 0 1-2.6-.6 17 17 0 0 1-5.7-3 15.9 15.9 0 0 1-3.3-3.7 19.6 19.6 0 0 1-1-1.8q-1.7-3.1-1.8-7.5a25.4 25.4 0 0 1 0-.6V39.8a17.3 17.3 0 0 1 .3-3 23.1 23.1 0 0 1 .6-2.7 17 17 0 0 1 3-5.7 15.9 15.9 0 0 1 3.6-3.3 19.6 19.6 0 0 1 1.8-1q3.2-1.7 7.6-1.8a25.4 25.4 0 0 1 .6 0H304a17.3 17.3 0 0 1 3 .3 23.1 23.1 0 0 1 2.6.6 17 17 0 0 1 5.7 3 15.9 15.9 0 0 1 3.3 3.7 19.6 19.6 0 0 1 1 1.8q1.7 3.1 1.8 7.5a25.4 25.4 0 0 1 0 .6 17.3 17.3 0 0 1-.3 3 23.1 23.1 0 0 1-.6 2.7 17 17 0 0 1-3 5.6 15.9 15.9 0 0 1-3.6 3.4 19.6 19.6 0 0 1-1.8 1q-3.2 1.7-7.6 1.8a25.4 25.4 0 0 1-.5 0ZM178 75h-34.3V62.4H178a8 8 0 0 0 1.5-.1l1.5-.5a4 4 0 0 0 1-.7 4.2 4.2 0 0 0 1-1.8q.2-.7.2-1.5a8.7 8.7 0 0 0 0-.5 7.7 7.7 0 0 0-.3-2q-.8-2.4-3.1-3a7.2 7.2 0 0 0-1.7-.1h-19.7a20 20 0 0 1-3.2-.2q-1.7-.3-3.2-1a11.7 11.7 0 0 1-.7-.3 16 16 0 0 1-2.9-1.8 13.1 13.1 0 0 1-1.8-1.8 14.3 14.3 0 0 1-2.2-3.5 13.2 13.2 0 0 1-.5-1.3q-.8-2.5-.8-4.7a19.8 19.8 0 0 1 .3-3.2q.2-1.7.9-3.2a11.3 11.3 0 0 1 .3-.8 15.4 15.4 0 0 1 2-3 13 13 0 0 1 1.8-1.7 15 15 0 0 1 5-2.6 20.2 20.2 0 0 1 2.6-.6 15.4 15.4 0 0 1 2.4-.2h31.2V35h-31q-1 0-1.6.2a2 2 0 0 0 0 0 2.5 2.5 0 0 0-.4.2l-.3.3a1.3 1.3 0 0 0-.1.1 1.7 1.7 0 0 0-.3.5 1.5 1.5 0 0 0 0 .3v.8a4.6 4.6 0 0 0 0 .5v.4a1.9 1.9 0 0 0 .2.3 1.9 1.9 0 0 0 .2.4 1.4 1.4 0 0 0 .4.3 1.9 1.9 0 0 0 .6.2 2.3 2.3 0 0 0 .2 0 17.2 17.2 0 0 0 1 0 16 16 0 0 0 0 0H178a22.7 22.7 0 0 1 3.8.3q2.1.4 3.9 1.1a13.5 13.5 0 0 1 .6.4 18 18 0 0 1 3.4 2.2 15 15 0 0 1 2.1 2.2q2.1 2.6 3 5.8a23.3 23.3 0 0 1 .8 3 17.3 17.3 0 0 1 .2 2.8 22.2 22.2 0 0 1-.2 3 17 17 0 0 1-.6 2.9A18.6 18.6 0 0 1 194 66a15.3 15.3 0 0 1-1 1.7 15 15 0 0 1-3.1 3.4 14.2 14.2 0 0 1 0 0 18.5 18.5 0 0 1-3.8 2.3 19.5 19.5 0 0 1-4 1.3 20.8 20.8 0 0 1-2.4.3 17 17 0 0 1-1.5.1Zm75.5-42-29.4 29.3h30.5v12.7H209q-2 0-3.5-1.1a6.8 6.8 0 0 1-2.4-2.8 6.4 6.4 0 0 1-.5-2.5 6.5 6.5 0 0 1 .2-1.2 6.3 6.3 0 0 1 1.7-3.3L233.6 35h-30.5V22.3h46a6.3 6.3 0 0 1 3.4 1q1.6 1 2.3 3 .6 1.2.6 2.4a6 6 0 0 1-.2 1.2q-.3 1.8-1.6 3.2ZM70 57.3v2.4a15.6 15.6 0 0 1-.3 2.8 20.5 20.5 0 0 1-.5 2.2q-.8 2.7-2.7 5a14 14 0 0 1-3.2 3 17.2 17.2 0 0 1-1.5.9q-3 1.5-7.2 1.5H6.4a6.7 6.7 0 0 1-2-.3 6.1 6.1 0 0 1-.5-.2 6.2 6.2 0 0 1-2-1.3 6.2 6.2 0 0 1-1.4-2A6.4 6.4 0 0 1 0 69a7.5 7.5 0 0 1 0-.3V11.5A6.4 6.4 0 0 1 .5 9Q1 7.8 1.8 7a6 6 0 0 1 2-1.4A6.4 6.4 0 0 1 6.2 5a7.5 7.5 0 0 1 .3 0h42.5a15.2 15.2 0 0 1 2.7.2A20 20 0 0 1 54 6q2.7.8 5 2.7a14 14 0 0 1 3 3.3 17 17 0 0 1 .9 1.4q1.5 3 1.5 7.2V23a23.2 23.2 0 0 1-.3 4 30.7 30.7 0 0 1-.8 3.3 23.9 23.9 0 0 1-3.5 7 26.8 26.8 0 0 1-.1.3 22.4 22.4 0 0 1 4 3.2 20.1 20.1 0 0 1 3 3.8 22.6 22.6 0 0 1 .3.5 21.5 21.5 0 0 1 1.7 3.6 26 26 0 0 1 .5 1.9 23.8 23.8 0 0 1 .7 4 30 30 0 0 1 .2 2.8Zm-12.7 2.3v-2.3a13.6 13.6 0 0 0-.2-2.5 10.7 10.7 0 0 0-.6-2 10 10 0 0 0-1.8-3 9.4 9.4 0 0 0-.4-.4 9.4 9.4 0 0 0-3.1-2 11 11 0 0 0-.3-.2 11.6 11.6 0 0 0-2.7-.6 14.7 14.7 0 0 0-1.8-.1H17.8V33.7h22.9a14.1 14.1 0 0 0 2.5-.2 11.2 11.2 0 0 0 2-.6 9.7 9.7 0 0 0 2.7-1.5 9 9 0 0 0 .7-.6 9.5 9.5 0 0 0 2.1-3.3 11 11 0 0 0 0-.1 11.3 11.3 0 0 0 .7-2.7 14.6 14.6 0 0 0 .1-1.8v-2.4q0-2.7-2.6-2.7H12.7v44.6h41.9a6 6 0 0 0 .3 0h.5a2 2 0 0 0 .7-.2 2 2 0 0 0 .2-.1 1.5 1.5 0 0 0 .3-.3l.4-.6.3-1a6 6 0 0 0 0-.6Zm296 2.8v12.7h-5.7a18.4 18.4 0 0 1-3.3-.3 23.8 23.8 0 0 1-2.5-.6 17.2 17.2 0 0 1-5.6-3 19.5 19.5 0 0 1-.2 0 16 16 0 0 1-3.5-4 19.4 19.4 0 0 1-1-1.6q-1.6-3-1.7-7.4a26.5 26.5 0 0 1 0-1V0h12.7v57.3a6 6 0 0 0 .2 1.6 4.5 4.5 0 0 0 1.2 2.1 5 5 0 0 0 3.3 1.4 6.6 6.6 0 0 0 .4 0h5.7Z" />
</svg>
)
}
export function Can({ className }: { className?: string }) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" className={className}>
<path
fill="currentColor"
d="M9.5 4a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1M11 2.5a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m0 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m2-3a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m0 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m0 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0m-3.02.87v.07l.01.02.01.04v6.75A1.75 1.75 0 0 1 8.25 15h-3.5A1.75 1.75 0 0 1 3 13.25V6.46l.01-.02a.5.5 0 0 1 .14-.3L5 4.3V2.5a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 .5.5v1.8l1.85 1.85a.5.5 0 0 1 .12.22M7 3H6v1h1zm.3 2H5.7l-1 1h3.6zm.95 9a.75.75 0 0 0 .75-.75V7H4v6.25c0 .41.34.75.75.75z"
/>
// Righteous
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 283.4 74.1" className={className}>
<path d="M146.4 73.1h-30.5V59.8h30.5a3.2 3.2 0 0 0 2.3-1 3.2 3.2 0 0 0 1-2.3q0-.8-.3-1.3a1.5 1.5 0 0 0-.7-.6 4.7 4.7 0 0 0-1-.3l-1.3-.1h-13.9q-3.4 0-6.5-1.3-3-1.3-5.2-3.6a16.9 16.9 0 0 1-3.6-5.3 16.3 16.3 0 0 1-1.3-6.5 16.4 16.4 0 0 1 1.3-6.4q1.3-3.1 3.6-5.4 2.2-2.2 5.2-3.5a16.3 16.3 0 0 1 6.5-1.3h27v13.3h-27a3.2 3.2 0 0 0-2.3 1 3.2 3.2 0 0 0-1 2.3 3.3 3.3 0 0 0 1 2.4 3.3 3.3 0 0 0 1.2.8 3.2 3.2 0 0 0 1.1.2h13.9a18.1 18.1 0 0 1 6 1 17.3 17.3 0 0 1 .4.2q3 1.1 5.3 3.2a15.1 15.1 0 0 1 3.6 4.9 14.7 14.7 0 0 1 1.3 5.4 17.2 17.2 0 0 1 0 .9 16 16 0 0 1-1 5.8 15.4 15.4 0 0 1-.3.7 17.3 17.3 0 0 1-3.6 5.2 16.4 16.4 0 0 1-5.3 3.6 16.2 16.2 0 0 1-6.4 1.3Zm64.5-13.3v13.3h-43.6l22-39h-22V21h43.6l-22 39h22ZM35 73.1H0v-70h35q4.4 0 8.2 1.6a21.4 21.4 0 0 1 6.6 4.6q2.9 2.8 4.5 6.6 1.7 3.8 1.7 8.2a15.4 15.4 0 0 1-.3 3.2 17.6 17.6 0 0 1-.2.8 19.4 19.4 0 0 1-1.5 4 17 17 0 0 1-2.4 3.4 13.5 13.5 0 0 1-2.6 2.3 12.5 12.5 0 0 1-.4.3q1.7 1 3 2.5 1.4 1.6 2.4 3.5a18.3 18.3 0 0 1 1.5 4A17.4 17.4 0 0 1 56 51a15.3 15.3 0 0 1 0 1.1q0 4.3-1.7 8.2a21.4 21.4 0 0 1-4.5 6.6q-2.8 2.9-6.6 4.5-3.8 1.7-8.2 1.7Zm76-43L86 60.4l1.5.3a16.7 16.7 0 0 0 1.6 0q2 0 3.8-.4 1.8-.6 3.4-1.6 1.6-1 2.8-2.4a12.8 12.8 0 0 0 2-3.2l9.8 9.8q-1.9 2.6-4.3 4.7a27 27 0 0 1-5.2 3.6 26.1 26.1 0 0 1-6 2.2 26.8 26.8 0 0 1-6.3.8 26.4 26.4 0 0 1-10.4-2 26.2 26.2 0 0 1-8.5-5.8 26.7 26.7 0 0 1-5.5-8.3 30.4 30.4 0 0 1-.2-.4q-2.1-5-2.1-11.1a31.9 31.9 0 0 1 .7-7 27 27 0 0 1 1.4-4.3 27 27 0 0 1 3.8-6.6 24.5 24.5 0 0 1 2-2.2 26 26 0 0 1 8.4-5.6 27 27 0 0 1 10.4-2 26.3 26.3 0 0 1 6.4.8 26.9 26.9 0 0 1 6 2.2q2.7 1.5 5.2 3.6 2.4 2.1 4.3 4.8Zm152.3 0-25 30.2 1.5.3a16.7 16.7 0 0 0 1.6 0q2 0 3.8-.4 1.8-.6 3.4-1.6 1.5-1 2.8-2.4a12.8 12.8 0 0 0 2-3.2l9.8 9.8q-1.9 2.6-4.3 4.7a27 27 0 0 1-5.2 3.6 26.1 26.1 0 0 1-6 2.2 26.8 26.8 0 0 1-6.3.8 26.4 26.4 0 0 1-10.4-2 26.2 26.2 0 0 1-8.5-5.8A26.7 26.7 0 0 1 217 58a30.4 30.4 0 0 1-.2-.4q-2.1-5-2.1-11.1a31.9 31.9 0 0 1 .7-7 27 27 0 0 1 1.4-4.3 27 27 0 0 1 3.8-6.6 24.5 24.5 0 0 1 2-2.2 26 26 0 0 1 8.4-5.6 27 27 0 0 1 10.4-2 26.3 26.3 0 0 1 6.4.8 26.9 26.9 0 0 1 6 2.2q2.7 1.5 5.2 3.6 2.4 2.1 4.3 4.8ZM283.4 0v73.1H270V0h13.4ZM14 17v14.1h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.1Q39 30 40 29a6.9 6.9 0 0 0 1.5-2.3q.5-1.3.5-2.7a7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.5q-.6-1.2-1.5-2.2a7 7 0 0 0-2.3-1.5 6.9 6.9 0 0 0-2.5-.5 7.9 7.9 0 0 0-.2 0H14Zm0 28.1v14h21a7 7 0 0 0 2.3-.4 6.6 6.6 0 0 0 .4-.2Q39 58 40 57.1a7 7 0 0 0 1.5-2.3 6.9 6.9 0 0 0 .5-2.5 7.9 7.9 0 0 0 0-.2 7 7 0 0 0-.4-2.3 6.6 6.6 0 0 0-.1-.4Q40.9 48 40 47a7 7 0 0 0-2.3-1.4 6.9 6.9 0 0 0-2.5-.6 7.9 7.9 0 0 0-.2 0H14Zm63.3 8.3 15.5-20.6a8 8 0 0 0-1.4-.4 7 7 0 0 0-.4 0 17.2 17.2 0 0 0-1.6-.1 19.2 19.2 0 0 0-.3 0 13.3 13.3 0 0 0-5.1 1q-2.5 1-4.2 2.8a13.1 13.1 0 0 0-2.5 3.6 15.5 15.5 0 0 0-.3.9 14.7 14.7 0 0 0-1 3.5 18.7 18.7 0 0 0 0 2.4 17.6 17.6 0 0 0 0 .7v.8a29.4 29.4 0 0 0 0 .1 19.2 19.2 0 0 0 .2 2 20.2 20.2 0 0 0 .4 1.6 18.6 18.6 0 0 0 0 .2 7.5 7.5 0 0 0 .4.9 6 6 0 0 0 .3.6Zm152.3 0L245 32.8a8 8 0 0 0-1.4-.4 7 7 0 0 0-.4 0 17.2 17.2 0 0 0-1.6-.1 19.2 19.2 0 0 0-.3 0 13.3 13.3 0 0 0-5.1 1q-2.5 1-4.2 2.8a13.1 13.1 0 0 0-2.5 3.6 15.5 15.5 0 0 0-.4.9 14.7 14.7 0 0 0-.8 3.5 18.7 18.7 0 0 0-.2 2.4 17.6 17.6 0 0 0 0 .7v.8a29.4 29.4 0 0 0 .1.1 19.2 19.2 0 0 0 .2 2 20.2 20.2 0 0 0 .4 1.6 18.6 18.6 0 0 0 0 .2 7.5 7.5 0 0 0 .4.9 6 6 0 0 0 .3.6Z" />
</svg>
)
}

View File

@@ -1,6 +1,6 @@
import { $updatedSystem, $systems, pb, $chartTime } from '@/lib/stores'
import { ContainerStatsRecord, SystemRecord, SystemStatsRecord } from '@/types'
import { Suspense, lazy, useEffect, useMemo, useState } from 'react'
import { Suspense, lazy, useCallback, useEffect, useMemo, useState } from 'react'
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '../ui/card'
import { useStore } from '@nanostores/react'
import Spinner from '../spinner'
@@ -51,16 +51,23 @@ export default function ServerDetail({ name }: { name: string }) {
useEffect(() => {
document.title = `${name} / Beszel`
return () => {
setServer({} as SystemRecord)
setCpuChartData([])
setMemChartData([])
setDiskChartData([])
setBandwidthChartData([])
setDockerCpuChartData([])
setDockerMemChartData([])
resetCharts()
$chartTime.set('1h')
}
}, [name])
const resetCharts = useCallback(() => {
setServerStats([])
setCpuChartData([])
setMemChartData([])
setDiskChartData([])
setBandwidthChartData([])
setDockerCpuChartData([])
setDockerMemChartData([])
}, [])
useEffect(resetCharts, [chartTime])
useEffect(() => {
if (server.id && server.name === name) {
return
@@ -138,20 +145,25 @@ export default function ServerDetail({ name }: { name: string }) {
setTicks(scale.ticks().map((d) => d.getTime()))
}, [chartTime, serverStats])
// get container stats
useEffect(() => {
if (!server.id) {
if (!server.id || !chartTime) {
return
}
pb.collection<ContainerStatsRecord>('container_stats')
.getFullList({
filter: `system="${server.id}" && created > "${getPbTimestamp('1h')}"`,
filter: pb.filter('system={:id} && created > {:created} && type={:type}', {
id: server.id,
created: getPbTimestamp(chartTime),
type: chartTimeData[chartTime].type,
}),
fields: 'created,stats',
sort: 'created',
})
.then((records) => {
setContainers(records)
})
}, [server])
}, [server, chartTime])
// container stats for charts
useEffect(() => {

View File

@@ -68,7 +68,7 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
const val = info.getValue() as number
return (
<div className="flex gap-1 items-center tabular-nums tracking-tight">
<span className="w-16">{val.toFixed(2)}%</span>
<span className="min-w-[3.5em]">{val.toFixed(1)}%</span>
<span className="grow min-w-10 block bg-muted h-[1em] relative rounded-sm overflow-hidden">
<span
className={cn(

View File

@@ -72,8 +72,8 @@ export const formatDay = (timestamp: string) => {
return dayFormatter.format(new Date(timestamp))
}
export const updateFavicon = (newIconUrl: string) =>
((document.querySelector("link[rel='icon']") as HTMLLinkElement).href = newIconUrl)
export const updateFavicon = (newIcon: string) =>
((document.querySelector("link[rel='icon']") as HTMLLinkElement).href = `/static/${newIcon}`)
export const isAdmin = () => pb.authStore.model?.role === 'admin'
export const isReadOnlyUser = () => pb.authStore.model?.role === 'readonly'

View File

@@ -80,22 +80,22 @@ const App = () => {
// update favicon
useEffect(() => {
if (!authenticated || !servers.length) {
updateFavicon('/favicon.svg')
updateFavicon('favicon.svg')
} else {
let up = false
for (const server of servers) {
if (server.status === 'down') {
updateFavicon('/favicon-red.svg')
return () => updateFavicon('/favicon.svg')
updateFavicon('favicon-red.svg')
return () => updateFavicon('favicon.svg')
} else if (server.status === 'up') {
up = true
}
}
updateFavicon(up ? '/favicon-green.svg' : '/favicon.svg')
return () => updateFavicon('/favicon.svg')
updateFavicon(up ? 'favicon-green.svg' : 'favicon.svg')
return () => updateFavicon('favicon.svg')
}
return () => {
updateFavicon('/favicon.svg')
updateFavicon('favicon.svg')
}
}, [authenticated, servers])

View File

@@ -47,7 +47,6 @@ type ContainerStats struct {
Name string `json:"n"`
Cpu float64 `json:"c"`
Mem float64 `json:"m"`
// MemPct float64 `json:"mp"`
}
type EmailData struct {