mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 01:39:34 +08:00
site updates
This commit is contained in:
@@ -26,8 +26,8 @@ export function AddServerButton() {
|
||||
function copyDockerCompose(port: string) {
|
||||
copyToClipboard(`services:
|
||||
agent:
|
||||
image: 'henrygd/ubik-agent'
|
||||
container_name: 'ubik-agent'
|
||||
image: 'henrygd/quoma-agent'
|
||||
container_name: 'quoma-agent'
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '${port}:45876'
|
||||
|
110
site/src/components/charts/container-mem-chart.tsx
Normal file
110
site/src/components/charts/container-mem-chart.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
'use client'
|
||||
|
||||
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
||||
import {
|
||||
ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
} from '@/components/ui/chart'
|
||||
import { useMemo } from 'react'
|
||||
import { formatShortDate, formatShortTime } from '@/lib/utils'
|
||||
import Spinner from '../spinner'
|
||||
|
||||
export default function ({
|
||||
chartData,
|
||||
max,
|
||||
}: {
|
||||
chartData: Record<string, number | string>[]
|
||||
max: number
|
||||
}) {
|
||||
console.log('max', max)
|
||||
const chartConfig = useMemo(() => {
|
||||
let config = {} as Record<
|
||||
string,
|
||||
{
|
||||
label: string
|
||||
color: string
|
||||
}
|
||||
>
|
||||
const totalUsage = {} as Record<string, number>
|
||||
for (let stats of chartData) {
|
||||
for (let key in stats) {
|
||||
if (key === 'time') {
|
||||
continue
|
||||
}
|
||||
if (!(key in totalUsage)) {
|
||||
totalUsage[key] = 0
|
||||
}
|
||||
// @ts-ignore
|
||||
totalUsage[key] += stats[key]
|
||||
}
|
||||
}
|
||||
let keys = Object.keys(totalUsage)
|
||||
keys.sort((a, b) => (totalUsage[a] > totalUsage[b] ? -1 : 1))
|
||||
const length = keys.length
|
||||
for (let i = 0; i < length; i++) {
|
||||
const key = keys[i]
|
||||
const hue = ((i * 360) / length) % 360
|
||||
config[key] = {
|
||||
label: key,
|
||||
color: `hsl(${hue}, 60%, 60%)`,
|
||||
}
|
||||
}
|
||||
return config satisfies ChartConfig
|
||||
}, [chartData])
|
||||
|
||||
if (!chartData.length) {
|
||||
return <Spinner />
|
||||
}
|
||||
|
||||
return (
|
||||
<ChartContainer config={chartConfig} className="h-full w-full absolute aspect-auto">
|
||||
<AreaChart
|
||||
accessibilityLayer
|
||||
data={chartData}
|
||||
|
||||
// reverseStackOrder={true}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<YAxis
|
||||
domain={[0, max]}
|
||||
tickCount={9}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickFormatter={(v) => `${Math.ceil(v / 1024)} GiB`}
|
||||
/>
|
||||
<XAxis
|
||||
dataKey="time"
|
||||
tickLine={true}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
minTickGap={30}
|
||||
tickFormatter={formatShortTime}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
labelFormatter={formatShortDate}
|
||||
// itemSorter={(item) => {
|
||||
// console.log('itemSorter', item)
|
||||
// return -item.value
|
||||
// }}
|
||||
content={<ChartTooltipContent indicator="line" />}
|
||||
/>
|
||||
{Object.keys(chartConfig).map((key) => (
|
||||
<Area
|
||||
key={key}
|
||||
// isAnimationActive={false}
|
||||
animateNewValues={false}
|
||||
dataKey={key}
|
||||
type="natural"
|
||||
fill={chartConfig[key].color}
|
||||
fillOpacity={0.4}
|
||||
stroke={chartConfig[key].color}
|
||||
stackId="a"
|
||||
/>
|
||||
))}
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
)
|
||||
}
|
@@ -1,7 +1,8 @@
|
||||
export function Logo({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg viewBox="0 0 421.6 140.2" className={className}>
|
||||
<path d="M0 109.4V0h20.4v109.4a9.6 9.6 0 0 0 2.4 6.4 12.8 12.8 0 0 0 .7.7q3.1 3.1 7.1 3.1h58.6V0h20.2v119.6H89.2V140H30.6a33.4 33.4 0 0 1-9.6-1.3 30.7 30.7 0 0 1-2.7-1 30 30 0 0 1-7-4 26.8 26.8 0 0 1-2.7-2.3 28.1 28.1 0 0 1-5.5-8 33 33 0 0 1-.8-1.7 32.2 32.2 0 0 1-2.3-11 37.1 37.1 0 0 1 0-1.3ZM307 0h20.4v73.8l58.4-30.6q2 0 3-.8t1.5-2q.5-1.2.6-2.5l.1-2.3V17.8l20.4-10.2v28a29.5 29.5 0 0 1-3.8 14.4 34.6 34.6 0 0 1-.1.2 26 26 0 0 1-11 10.5 31.6 31.6 0 0 1-.5.3l-17.8 10.2 43.4 68.8h-23l-38.2-58.6-28 12.8q-2 2-3.5 3.8a7 7 0 0 0-1 1.5 5.3 5.3 0 0 0-.5 2.3V140H307V0ZM127.6 109.4v-89h20.2V0H214q5.8 0 11.3 2.3 5.5 2.3 9.8 6.3a30 30 0 0 1 6.5 9 34.4 34.4 0 0 1 .4.7 29.3 29.3 0 0 1 2.6 12.2 33.4 33.4 0 0 1 0 .1v12.6a23.3 23.3 0 0 1-1.2 7.4 26.1 26.1 0 0 1-.1.2q-1.3 3.8-3.4 7.1-2.1 3.3-4.9 6.1a48.8 48.8 0 0 1-3.3 3 39.5 39.5 0 0 1-2.3 1.8l2.4 2.4q7.6 4 12.7 11a28 28 0 0 1 3.7 6.7 22.5 22.5 0 0 1 1.4 7.9v12.6a29.4 29.4 0 0 1-2.4 11.8 28.6 28.6 0 0 1-.2.5 30.7 30.7 0 0 1-5.3 8 28.7 28.7 0 0 1-1.6 1.7q-4.3 4-9.7 6.3-5.4 2.3-11.2 2.3h-63.6q-5.8 0-10.9-2.3-5.1-2.3-8.9-6.3a28 28 0 0 1-5-7.3 33.7 33.7 0 0 1-1-2.4 33.3 33.3 0 0 1-2.2-10.6 38.6 38.6 0 0 1 0-1.7Zm20.2-89V112q0 6 5 7.3a11.8 11.8 0 0 0 2.8.3h63.6a9.2 9.2 0 0 0 5.3-1.7 13 13 0 0 0 1.7-1.4 11.2 11.2 0 0 0 2.1-2.7 9 9 0 0 0 1.1-4.4V96.8q0-2-1.6-3.9a11 11 0 0 0 0 0 57.9 57.9 0 0 0-2.2-2.4 70.3 70.3 0 0 0-1.4-1.5l-17.8-7.6-43.2 23v-23l56-30.4q1.6 0 3-2.3a12.4 12.4 0 0 0 .4-.6 18.3 18.3 0 0 0 .8-1.6q.7-1.8.8-3.1a5.2 5.2 0 0 0 0-.2V30.6a9.6 9.6 0 0 0-2.4-6.4 12.8 12.8 0 0 0-.7-.7q-3.1-3.1-7.1-3.1h-66.2ZM266.4 0H287v140.2h-20.6V0Z" />
|
||||
// audiowide
|
||||
<svg viewBox="0 0 370 82" className={className} fill="currentColor">
|
||||
<path d="M271.8 36v35H259V36a7.5 7.5 0 0 0-.1-1.5q-.2-.8-.6-1.4a3.9 3.9 0 0 0-.6-.9q-1.1-1-3.1-1.3a9.2 9.2 0 0 0-.8 0h-16.5V71h-12.7V24.5a6.3 6.3 0 0 1 .4-2.2 6 6 0 0 1 0-.3q.5-1.1 1.4-2 .9-.8 2-1.3a6.4 6.4 0 0 1 2.6-.5H254a17.2 17.2 0 0 1 3 .3 22.8 22.8 0 0 1 2.6.6q3 1 5.8 3v-3.9h17.2a17.7 17.7 0 0 1 2.5.2 21.3 21.3 0 0 1 1.3.2 19.5 19.5 0 0 1 3.8 1.3 21.5 21.5 0 0 1 .2 0q2 .9 3.7 2.3a15 15 0 0 1 3.2 3.3 16.3 16.3 0 0 1 1.6 3 19.7 19.7 0 0 1 .6 1.6q.8 2.6.8 5.9v35h-12.7V36a8 8 0 0 0 0-1.5q-.3-1.4-1.2-2.3-1.2-1.3-3.8-1.3H271q.7 2.4.7 5Zm94.7-.3v17.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.7 1Q354 71 349.6 71a25.4 25.4 0 0 1-.6 0h-22.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.3-3.7 19.6 19.6 0 0 1-1.1-1.8q-1.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.4 23.4 0 0 1 .7-2.7q.9-3 3-5.7a15.9 15.9 0 0 1 3.6-3.3 19.6 19.6 0 0 1 1.8-1q3.1-1.7 7.6-1.8a25.4 25.4 0 0 1 .5 0h23V48h-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.4 3.3 7.3 7.3 0 0 0 0 .6 6 6 0 0 0 .2 1.7 4.4 4.4 0 0 0 1.4 2.2 5.8 5.8 0 0 0 4 1.4H349a6.9 6.9 0 0 0 1.7-.2 4.6 4.6 0 0 0 2.3-1.4 5.4 5.4 0 0 0 1.4-3.2 7.2 7.2 0 0 0 0-.7V35.7a6.5 6.5 0 0 0-.2-1.7 4.8 4.8 0 0 0-1.3-2.3q-1.5-1.4-3.9-1.4h-27.9v-12h28a17.3 17.3 0 0 1 3 .2 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 .6Zm-222-17.5v46.4a6.7 6.7 0 0 1-.2 2 6.1 6.1 0 0 1-.3.5 6.2 6.2 0 0 1-1.3 2q-.9 1-2 1.4a6.2 6.2 0 0 1-2.4.5h-28.8a23.3 23.3 0 0 1-3-.2 29 29 0 0 1-2-.3 23.6 23.6 0 0 1-5.2-1.8 27 27 0 0 1-4.7-2.8 30 30 0 0 1-.3-.2q-2.5-1.8-4.3-4.4a21.5 21.5 0 0 1-2.1-4 26.1 26.1 0 0 1-.8-2 22.4 22.4 0 0 1-.9-4.2 29.5 29.5 0 0 1-.2-3.6V18.2h12.7v29.3A12.5 12.5 0 0 0 99 50a10 10 0 0 0 .6 2 10.5 10.5 0 0 0 2 3 10 10 0 0 0 .3.4q1.5 1.4 3.4 2.1 2 .8 4.3.8h22.2v-40h12.7ZM75.7 29.3v13.4a32.8 32.8 0 0 1-.8 7.1 29.5 29.5 0 0 1-.5 2 29 29 0 0 1-3.1 7 26.9 26.9 0 0 1-.6 1 27 27 0 0 1-5.7 6 27 27 0 0 1-7.4 4.2l14.8 11.8H54L41.8 72H29.3a32.1 32.1 0 0 1-8.2-1 28.7 28.7 0 0 1-3.5-1.2q-5.3-2.2-9.3-6a28.2 28.2 0 0 1-6-9.4A29.6 29.6 0 0 1 0 45.2a35.1 35.1 0 0 1-.1-2.5V29.3A31.8 31.8 0 0 1 1 21a28.5 28.5 0 0 1 1.2-3.4 28.1 28.1 0 0 1 5.2-8.3 26.7 26.7 0 0 1 1-1 28 28 0 0 1 9.1-6 31.8 31.8 0 0 1 .1-.1A29.9 29.9 0 0 1 27.4.1a35 35 0 0 1 1.9-.1h17.2a31.6 31.6 0 0 1 8.2 1 28.2 28.2 0 0 1 3.4 1.2 28.1 28.1 0 0 1 9.3 6 27.5 27.5 0 0 1 6 9 31.3 31.3 0 0 1 0 .4 30.1 30.1 0 0 1 2.2 9.6 35.4 35.4 0 0 1 0 2.1ZM213.9 36v17.2a22.2 22.2 0 0 1-.2 3 17 17 0 0 1-.7 2.9 18.6 18.6 0 0 1-1.1 2.8 15.3 15.3 0 0 1-1 1.7 15 15 0 0 1-3.2 3.4 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.3.3 17 17 0 0 1-1.6.1h-22.9q-2.6 0-5.7-1-3.1-.9-5.8-3a16.3 16.3 0 0 1-3.4-3.7 20 20 0 0 1-1-1.8 14.7 14.7 0 0 1-1.4-3.8q-.3-1.7-.4-3.6a26.1 26.1 0 0 1 0-1V36q0-4.4 1.4-7.6a13.2 13.2 0 0 1 .4-.7 18.6 18.6 0 0 1 2.3-3.5 15.6 15.6 0 0 1 2.1-2q2.7-2.1 5.8-3a24.2 24.2 0 0 1 2.8-.7q1.5-.3 3-.3H196a22.7 22.7 0 0 1 3.8.3q2.1.4 3.9 1.2a13.5 13.5 0 0 1 .6.3 18 18 0 0 1 3.5 2.2 15 15 0 0 1 2 2.2q2.2 2.7 3.1 5.8a23.3 23.3 0 0 1 .7 3 17.3 17.3 0 0 1 .3 2.8Zm-151 6.7V29.3a20.4 20.4 0 0 0-.3-4 16.6 16.6 0 0 0-.8-2.8 15.4 15.4 0 0 0-2.5-4.2 14.3 14.3 0 0 0-.9-1 15 15 0 0 0-4.8-3.2 17.2 17.2 0 0 0-.4-.2 17.5 17.5 0 0 0-4.9-1.1 21 21 0 0 0-1.8-.1H29.3a20 20 0 0 0-4 .4 16.6 16.6 0 0 0-2.8.8q-3 1.2-5.2 3.4a14.8 14.8 0 0 0-3.3 5 17 17 0 0 0-.1.2 17.3 17.3 0 0 0-1 4.4 21.6 21.6 0 0 0-.2 2.4v13.4a20.4 20.4 0 0 0 .4 4 16.6 16.6 0 0 0 .8 2.8 15 15 0 0 0 2.7 4.5 14.3 14.3 0 0 0 .7.7 15.2 15.2 0 0 0 5 3.3 17.5 17.5 0 0 0 .2 0 17.4 17.4 0 0 0 4.7 1.2 21.3 21.3 0 0 0 2.1 0h17a20 20 0 0 0 4.2-.3A16.6 16.6 0 0 0 53 58q3.1-1.2 5.3-3.4a14.8 14.8 0 0 0 3.3-5 17 17 0 0 0 0-.2A17.3 17.3 0 0 0 63 45a21.6 21.6 0 0 0 0-2.4Zm138.3 10.5V36a8.4 8.4 0 0 0-.1-1.5l-.5-1.4a3.7 3.7 0 0 0-.7-1 4.2 4.2 0 0 0-1.8-1l-1.4-.3a8.9 8.9 0 0 0-.7 0h-22.8q-1.7 0-3 .6a4 4 0 0 0-.8.7q-1.2 1.1-1.3 3.2a8.7 8.7 0 0 0 0 .6v17.2q0 1.8.7 3a4 4 0 0 0 .6.8 4.2 4.2 0 0 0 1.7 1l1.5.3a8.9 8.9 0 0 0 .6 0H196a8 8 0 0 0 1.5-.1l1.4-.5a3.7 3.7 0 0 0 1-.7 4.2 4.2 0 0 0 1-1.7l.3-1.5a8.9 8.9 0 0 0 0-.6Z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
@@ -8,7 +8,8 @@ import CpuChart from '../charts/cpu-chart'
|
||||
import MemChart from '../charts/mem-chart'
|
||||
import DiskChart from '../charts/disk-chart'
|
||||
import ContainerCpuChart from '../charts/container-cpu-chart'
|
||||
import { CpuIcon } from 'lucide-react'
|
||||
import { CpuIcon, MemoryStickIcon } from 'lucide-react'
|
||||
import ContainerMemChart from '../charts/container-mem-chart'
|
||||
|
||||
// const CpuChart = lazy(() => import('../cpu-chart'))
|
||||
|
||||
@@ -42,14 +43,17 @@ export default function ServerDetail({ name }: { name: string }) {
|
||||
const [containerCpuChartData, setContainerCpuChartData] = useState(
|
||||
[] as Record<string, number | string>[]
|
||||
)
|
||||
const [containerMemChartData, setContainerMemChartData] = useState(
|
||||
[] as Record<string, number | string>[]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
document.title = name
|
||||
return () => {
|
||||
setContainerCpuChartData([])
|
||||
setCpuChartData({} as { max: number; data: { time: string; cpu: number }[] })
|
||||
setMemChartData([] as { time: string; mem: number; memUsed: number }[])
|
||||
setDiskChartData([] as { time: string; disk: number; diskUsed: number }[])
|
||||
setMemChartData([])
|
||||
setDiskChartData([])
|
||||
}
|
||||
}, [name])
|
||||
|
||||
@@ -76,16 +80,18 @@ export default function ServerDetail({ name }: { name: string }) {
|
||||
if (!serverStats.length) {
|
||||
return
|
||||
}
|
||||
let maxCpu = 0
|
||||
const cpuData = [] as { time: string; cpu: number }[]
|
||||
const memData = [] as { time: string; mem: number; memUsed: number }[]
|
||||
const diskData = [] as { time: string; disk: number; diskUsed: number }[]
|
||||
for (let { created, stats } of serverStats) {
|
||||
cpuData.push({ time: created, cpu: stats.cpu })
|
||||
maxCpu = Math.max(maxCpu, stats.cpu)
|
||||
memData.push({ time: created, mem: stats.mem, memUsed: stats.memUsed })
|
||||
diskData.push({ time: created, disk: stats.disk, diskUsed: stats.diskUsed })
|
||||
}
|
||||
setCpuChartData({
|
||||
max: Math.ceil(Math.max(...cpuData.map((d) => d.cpu))),
|
||||
max: Math.ceil(maxCpu),
|
||||
data: cpuData.reverse(),
|
||||
})
|
||||
setMemChartData(memData.reverse())
|
||||
@@ -125,15 +131,20 @@ export default function ServerDetail({ name }: { name: string }) {
|
||||
useEffect(() => {
|
||||
console.log('containers', containers)
|
||||
const containerCpuData = [] as Record<string, number | string>[]
|
||||
const containerMemData = [] as Record<string, number | string>[]
|
||||
|
||||
for (let { created, stats } of containers) {
|
||||
let obj = { time: created } as Record<string, number | string>
|
||||
for (let { name, cpu } of stats) {
|
||||
obj[name] = cpu
|
||||
let cpuData = { time: created } as Record<string, number | string>
|
||||
let memData = { time: created } as Record<string, number | string>
|
||||
for (let container of stats) {
|
||||
cpuData[container.name] = container.cpu
|
||||
memData[container.name] = container.mem
|
||||
}
|
||||
containerCpuData.push(obj)
|
||||
containerCpuData.push(cpuData)
|
||||
containerMemData.push(memData)
|
||||
}
|
||||
setContainerCpuChartData(containerCpuData.reverse())
|
||||
setContainerMemChartData(containerMemData.reverse())
|
||||
}, [containers])
|
||||
|
||||
return (
|
||||
@@ -175,9 +186,28 @@ export default function ServerDetail({ name }: { name: string }) {
|
||||
<CardDescription>Precise usage at the recorded time</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className={'pl-1 w-[calc(100%-2em)] h-52 relative'}>
|
||||
{/* <Suspense fallback={<Spinner />}> */}
|
||||
<MemChart chartData={memChartData} />
|
||||
{/* </Suspense> */}
|
||||
<Suspense fallback={<Spinner />}>
|
||||
<MemChart chartData={memChartData} />
|
||||
</Suspense>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="pb-2">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex gap-2 justify-between">
|
||||
<span>Docker Memory Usage</span>
|
||||
<MemoryStickIcon className="opacity-70" />
|
||||
</CardTitle>{' '}
|
||||
<CardDescription>Memory usage of docker containers</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className={'pl-1 w-[calc(100%-2em)] h-52 relative'}>
|
||||
<Suspense fallback={<Spinner />}>
|
||||
{server?.stats?.mem && (
|
||||
<ContainerMemChart
|
||||
chartData={containerMemChartData}
|
||||
max={server.stats.mem * 1024}
|
||||
/>
|
||||
)}
|
||||
</Suspense>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card className="pb-2">
|
||||
|
@@ -69,7 +69,7 @@ function CellFormatter(info: CellContext<SystemRecord, unknown>) {
|
||||
}
|
||||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
<span className="grow block bg-muted h-4 relative rounded-sm overflow-hidden">
|
||||
<span className="grow min-w-10 block bg-muted h-4 relative rounded-sm overflow-hidden">
|
||||
<span
|
||||
className={cn('absolute inset-0 w-full h-full origin-left', `bg-${color}-500`)}
|
||||
style={{ transform: `scalex(${val}%)` }}
|
||||
@@ -109,7 +109,7 @@ export default function () {
|
||||
<span className="flex gap-0.5 items-center text-base">
|
||||
<span
|
||||
className={cn(
|
||||
'w-2.5 h-2.5 block left-0 rounded-full',
|
||||
'w-2.5 h-2.5 left-0 rounded-full',
|
||||
info.row.original.active ? 'bg-green-500' : 'bg-red-500'
|
||||
)}
|
||||
style={{ marginBottom: '-1px' }}
|
||||
@@ -159,12 +159,15 @@ export default function () {
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||
<DropdownMenuItem
|
||||
{/* <DropdownMenuItem
|
||||
onSelect={() => {
|
||||
navigate(`/server/${system.name}`)
|
||||
}}
|
||||
>
|
||||
View details
|
||||
</DropdownMenuItem> */}
|
||||
<DropdownMenuItem onClick={() => console.log('pause server')}>
|
||||
Pause
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => navigator.clipboard.writeText(system.ip)}>
|
||||
Copy IP address
|
||||
|
@@ -10,7 +10,7 @@ import { buttonVariants } from './components/ui/button.tsx'
|
||||
import { Github } from 'lucide-react'
|
||||
import { useStore } from '@nanostores/react'
|
||||
import { Toaster } from './components/ui/toaster.tsx'
|
||||
import { Can, Logo } from './components/logo.tsx'
|
||||
import { Logo } from './components/logo.tsx'
|
||||
import {
|
||||
TooltipProvider,
|
||||
Tooltip,
|
||||
@@ -51,19 +51,20 @@ const Layout = () => {
|
||||
return (
|
||||
<>
|
||||
<div className="container">
|
||||
<div className="flex items-center py-3.5 bg-card px-6 border bt-0 rounded-md my-5">
|
||||
<div className="flex items-center h-16 bg-card px-6 border bt-0 rounded-md my-5">
|
||||
<TooltipProvider delayDuration={300}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<a
|
||||
href="/"
|
||||
aria-label="Home"
|
||||
className={'p-2 pl-0 -mb-1'}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
navigate('/')
|
||||
}}
|
||||
>
|
||||
<Logo className="h-5 fill-foreground" />
|
||||
<Logo className="h-[1.1em] fill-foreground" />
|
||||
</a>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
|
2
site/src/types.d.ts
vendored
2
site/src/types.d.ts
vendored
@@ -27,7 +27,7 @@ interface ContainerStats {
|
||||
name: string
|
||||
cpu: number
|
||||
mem: number
|
||||
mempct: number
|
||||
memPct: number
|
||||
}
|
||||
|
||||
export interface SystemStatsRecord extends RecordModel {
|
||||
|
Reference in New Issue
Block a user