mirror of
https://github.com/henrygd/beszel.git
synced 2025-12-17 10:46:16 +01:00
refactor: add api module and page preloading
This commit is contained in:
@@ -13,8 +13,9 @@ import {
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { $publicKey, pb } from "@/lib/stores"
|
||||
import { cn, generateToken, isReadOnlyUser, tokenMap, useLocalStorage } from "@/lib/utils"
|
||||
import { $publicKey } from "@/lib/stores"
|
||||
import { cn, generateToken, tokenMap, useLocalStorage } from "@/lib/utils"
|
||||
import { pb, isReadOnlyUser } from "@/lib/api"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { ChevronDownIcon, ExternalLinkIcon, PlusIcon } from "lucide-react"
|
||||
import { memo, useEffect, useRef, useState } from "react"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans, Plural } from "@lingui/react/macro"
|
||||
import { $alerts, $systems, pb } from "@/lib/stores"
|
||||
import { $alerts, $systems } from "@/lib/stores"
|
||||
import { cn, debounce } from "@/lib/utils"
|
||||
import { alertInfo } from "@/lib/alerts"
|
||||
import { Switch } from "@/components/ui/switch"
|
||||
@@ -15,6 +15,7 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"
|
||||
import { ServerIcon, GlobeIcon } from "lucide-react"
|
||||
import { $router, Link } from "@/components/router"
|
||||
import { DialogHeader } from "@/components/ui/dialog"
|
||||
import { pb } from "@/lib/api"
|
||||
|
||||
const Slider = lazy(() => import("@/components/ui/slider"))
|
||||
|
||||
|
||||
@@ -23,11 +23,13 @@ import {
|
||||
} from "@/components/ui/command"
|
||||
import { memo, useEffect, useMemo } from "react"
|
||||
import { $systems } from "@/lib/stores"
|
||||
import { getHostDisplayValue, isAdmin, listen } from "@/lib/utils"
|
||||
import { getHostDisplayValue, listen } from "@/lib/utils"
|
||||
import { $router, basePath, navigate, prependBasePath } from "./router"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { DialogDescription } from "@radix-ui/react-dialog"
|
||||
import { isAdmin } from "@/lib/api"
|
||||
|
||||
export default memo(function CommandPalette({ open, setOpen }: { open: boolean; setOpen: (open: boolean) => void }) {
|
||||
useEffect(() => {
|
||||
@@ -54,11 +56,9 @@ export default memo(function CommandPalette({ open, setOpen }: { open: boolean;
|
||||
)
|
||||
return (
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<DialogDescription className="sr-only">Command palette</DialogDescription>
|
||||
<CommandInput placeholder={t`Search for systems or settings...`} />
|
||||
<CommandList>
|
||||
<CommandEmpty>
|
||||
<Trans>No results found.</Trans>
|
||||
</CommandEmpty>
|
||||
{systems.length > 0 && (
|
||||
<>
|
||||
<CommandGroup>
|
||||
@@ -214,6 +214,9 @@ export default memo(function CommandPalette({ open, setOpen }: { open: boolean;
|
||||
</CommandGroup>
|
||||
</>
|
||||
)}
|
||||
<CommandEmpty>
|
||||
<Trans>No results found.</Trans>
|
||||
</CommandEmpty>
|
||||
</CommandList>
|
||||
</CommandDialog>
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { buttonVariants } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { LoaderCircle, LockIcon, LogInIcon, MailIcon } from "lucide-react"
|
||||
import { $authenticated, pb } from "@/lib/stores"
|
||||
import { $authenticated } from "@/lib/stores"
|
||||
import * as v from "valibot"
|
||||
import { toast } from "../ui/use-toast"
|
||||
import { Dialog, DialogContent, DialogTrigger, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||
@@ -13,6 +13,7 @@ import { useCallback, useEffect, useState } from "react"
|
||||
import { AuthMethodsList, AuthProviderInfo, OAuth2AuthConfig } from "pocketbase"
|
||||
import { $router, Link, prependBasePath } from "../router"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { pb } from "@/lib/api"
|
||||
|
||||
const honeypot = v.literal("")
|
||||
const emailSchema = v.pipe(v.string(), v.email(t`Invalid email address.`))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { LoaderCircle, MailIcon, SendHorizonalIcon } from "lucide-react"
|
||||
import { Input } from "../ui/input"
|
||||
import { Label } from "../ui/label"
|
||||
@@ -7,9 +7,9 @@ import { useCallback, useState } from "react"
|
||||
import { toast } from "../ui/use-toast"
|
||||
import { buttonVariants } from "../ui/button"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { Dialog, DialogHeader } from "../ui/dialog"
|
||||
import { DialogContent, DialogTrigger, DialogTitle } from "../ui/dialog"
|
||||
import { pb } from "@/lib/api"
|
||||
|
||||
const showLoginFaliedToast = () => {
|
||||
toast({
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { UserAuthForm } from "@/components/login/auth-form"
|
||||
import { Logo } from "../logo"
|
||||
import { useEffect, useMemo, useState } from "react"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import ForgotPassword from "./forgot-pass-form"
|
||||
import { $router } from "../router"
|
||||
import { AuthMethodsList } from "pocketbase"
|
||||
import { useTheme } from "../theme-provider"
|
||||
import { pb } from "@/lib/api"
|
||||
|
||||
export default function () {
|
||||
const page = useStore($router)
|
||||
|
||||
@@ -15,8 +15,8 @@ import { $router, basePath, Link, prependBasePath } from "./router"
|
||||
import { LangToggle } from "./lang-toggle"
|
||||
import { ModeToggle } from "./mode-toggle"
|
||||
import { Logo } from "./logo"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { cn, isReadOnlyUser, isAdmin, logOut } from "@/lib/utils"
|
||||
import { cn, runOnce } from "@/lib/utils"
|
||||
import { isReadOnlyUser, isAdmin, logOut, pb } from "@/lib/api"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
@@ -36,12 +36,17 @@ const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0
|
||||
export default function Navbar() {
|
||||
return (
|
||||
<div className="flex items-center h-14 md:h-16 bg-card px-4 pe-3 sm:px-6 border border-border/60 bt-0 rounded-md my-4">
|
||||
<Link href={basePath} aria-label="Home" className="p-2 ps-0 me-3">
|
||||
<Link
|
||||
href={basePath}
|
||||
aria-label="Home"
|
||||
className="p-2 ps-0 me-3"
|
||||
onMouseEnter={runOnce(() => import("@/components/routes/home"))}
|
||||
>
|
||||
<Logo className="h-[1.1rem] md:h-5 fill-foreground" />
|
||||
</Link>
|
||||
<SearchButton />
|
||||
|
||||
<div className="flex items-center ms-auto">
|
||||
<div className="flex items-center ms-auto" onMouseEnter={() => import("@/components/routes/settings/general")}>
|
||||
<LangToggle />
|
||||
<ModeToggle />
|
||||
<Link
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { Suspense, lazy, memo, useEffect, useMemo } from "react"
|
||||
import { Suspense, memo, useEffect, useMemo } from "react"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card"
|
||||
import { $alerts, $systems, pb } from "@/lib/stores"
|
||||
import { $alerts, $systems } from "@/lib/stores"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { GithubIcon } from "lucide-react"
|
||||
import { Separator } from "../ui/separator"
|
||||
import { getSystemNameFromId, updateRecordList, updateSystemList } from "@/lib/utils"
|
||||
import { getSystemNameFromId } from "@/lib/utils"
|
||||
import { pb, updateRecordList, updateSystemList } from "@/lib/api"
|
||||
import { AlertRecord, SystemRecord } from "@/types"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
import { $router, Link } from "../router"
|
||||
import { Plural, Trans, useLingui } from "@lingui/react/macro"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { alertInfo } from "@/lib/alerts"
|
||||
import SystemsTable from "@/components/systems-table/systems-table"
|
||||
|
||||
const SystemsTable = lazy(() => import("../systems-table/systems-table"))
|
||||
// const SystemsTable = lazy(() => import("../systems-table/systems-table"))
|
||||
|
||||
export default memo(function () {
|
||||
const { t } = useLingui()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { pb } from "@/lib/stores"
|
||||
import { pb } from "@/lib/api"
|
||||
import { cn, formatDuration, formatShortDate } from "@/lib/utils"
|
||||
import { alertInfo } from "@/lib/alerts"
|
||||
import { AlertsHistoryRecord } from "@/types"
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { isAdmin } from "@/lib/utils"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { redirectPage } from "@nanostores/router"
|
||||
import { $router } from "@/components/router"
|
||||
import { AlertCircleIcon, FileSlidersIcon, LoaderCircleIcon } from "lucide-react"
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { useState } from "react"
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
import { toast } from "@/components/ui/use-toast"
|
||||
import clsx from "clsx"
|
||||
import { isAdmin, pb } from "@/lib/api"
|
||||
|
||||
export default function ConfigYaml() {
|
||||
const [configContent, setConfigContent] = useState<string>("")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { useEffect } from "react"
|
||||
import { lazy, useEffect } from "react"
|
||||
import { Separator } from "../../ui/separator"
|
||||
import { SidebarNav } from "./sidebar-nav.tsx"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
||||
@@ -8,15 +8,23 @@ import { useStore } from "@nanostores/react"
|
||||
import { $router } from "@/components/router.tsx"
|
||||
import { getPagePath, redirectPage } from "@nanostores/router"
|
||||
import { BellIcon, FileSlidersIcon, FingerprintIcon, SettingsIcon, AlertOctagonIcon } from "lucide-react"
|
||||
import { $userSettings, pb } from "@/lib/stores.ts"
|
||||
import { $userSettings } from "@/lib/stores.ts"
|
||||
import { toast } from "@/components/ui/use-toast.ts"
|
||||
import { UserSettings } from "@/types"
|
||||
import General from "./general.tsx"
|
||||
import Notifications from "./notifications.tsx"
|
||||
import ConfigYaml from "./config-yaml.tsx"
|
||||
import { useLingui } from "@lingui/react/macro"
|
||||
import Fingerprints from "./tokens-fingerprints.tsx"
|
||||
import AlertsHistoryDataTable from "./alerts-history-data-table"
|
||||
import { pb } from "@/lib/api"
|
||||
|
||||
const generalSettingsImport = () => import("./general.tsx")
|
||||
const notificationsSettingsImport = () => import("./notifications.tsx")
|
||||
const configYamlSettingsImport = () => import("./config-yaml.tsx")
|
||||
const fingerprintsSettingsImport = () => import("./tokens-fingerprints.tsx")
|
||||
const alertsHistoryDataTableSettingsImport = () => import("./alerts-history-data-table.tsx")
|
||||
|
||||
const GeneralSettings = lazy(generalSettingsImport)
|
||||
const NotificationsSettings = lazy(notificationsSettingsImport)
|
||||
const ConfigYamlSettings = lazy(configYamlSettingsImport)
|
||||
const FingerprintsSettings = lazy(fingerprintsSettingsImport)
|
||||
const AlertsHistoryDataTableSettings = lazy(alertsHistoryDataTableSettingsImport)
|
||||
|
||||
export async function saveSettings(newSettings: Partial<UserSettings>) {
|
||||
try {
|
||||
@@ -59,23 +67,27 @@ export default function SettingsLayout() {
|
||||
title: t`Notifications`,
|
||||
href: getPagePath($router, "settings", { name: "notifications" }),
|
||||
icon: BellIcon,
|
||||
preload: notificationsSettingsImport,
|
||||
},
|
||||
{
|
||||
title: t`Tokens & Fingerprints`,
|
||||
href: getPagePath($router, "settings", { name: "tokens" }),
|
||||
icon: FingerprintIcon,
|
||||
noReadOnly: true,
|
||||
preload: fingerprintsSettingsImport,
|
||||
},
|
||||
{
|
||||
title: t`Alert History`,
|
||||
href: getPagePath($router, "settings", { name: "alert-history" }),
|
||||
icon: AlertOctagonIcon,
|
||||
preload: alertsHistoryDataTableSettingsImport,
|
||||
},
|
||||
{
|
||||
title: t`YAML Config`,
|
||||
href: getPagePath($router, "settings", { name: "config" }),
|
||||
icon: FileSlidersIcon,
|
||||
admin: true,
|
||||
preload: configYamlSettingsImport,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -120,14 +132,14 @@ function SettingsContent({ name }: { name: string }) {
|
||||
|
||||
switch (name) {
|
||||
case "general":
|
||||
return <General userSettings={userSettings} />
|
||||
return <GeneralSettings userSettings={userSettings} />
|
||||
case "notifications":
|
||||
return <Notifications userSettings={userSettings} />
|
||||
return <NotificationsSettings userSettings={userSettings} />
|
||||
case "config":
|
||||
return <ConfigYaml />
|
||||
return <ConfigYamlSettings />
|
||||
case "tokens":
|
||||
return <Fingerprints />
|
||||
return <FingerprintsSettings />
|
||||
case "alert-history":
|
||||
return <AlertsHistoryDataTable />
|
||||
return <AlertsHistoryDataTableSettings />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Trans } from "@lingui/react/macro"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { pb } from "@/lib/stores"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { Card } from "@/components/ui/card"
|
||||
import { BellIcon, LoaderCircleIcon, PlusIcon, SaveIcon, Trash2Icon } from "lucide-react"
|
||||
@@ -13,8 +12,8 @@ import { InputTags } from "@/components/ui/input-tags"
|
||||
import { UserSettings } from "@/types"
|
||||
import { saveSettings } from "./layout"
|
||||
import * as v from "valibot"
|
||||
import { isAdmin } from "@/lib/utils"
|
||||
import { prependBasePath } from "@/components/router"
|
||||
import { isAdmin, pb } from "@/lib/api"
|
||||
|
||||
interface ShoutrrrUrlCardProps {
|
||||
url: string
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react"
|
||||
import { cn, isAdmin, isReadOnlyUser } from "@/lib/utils"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { isAdmin, isReadOnlyUser } from "@/lib/api"
|
||||
import { buttonVariants } from "../../ui/button"
|
||||
import { $router, Link, navigate } from "../../router"
|
||||
import { useStore } from "@nanostores/react"
|
||||
@@ -13,6 +14,7 @@ interface SidebarNavProps extends React.HTMLAttributes<HTMLElement> {
|
||||
icon?: React.FC<React.SVGProps<SVGSVGElement>>
|
||||
admin?: boolean
|
||||
noReadOnly?: boolean
|
||||
preload?: () => Promise<{ default: React.ComponentType<any> }>
|
||||
}[]
|
||||
}
|
||||
|
||||
@@ -52,6 +54,7 @@ export function SidebarNav({ className, items, ...props }: SidebarNavProps) {
|
||||
}
|
||||
return (
|
||||
<Link
|
||||
onMouseEnter={() => item.preload?.()}
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Trans, useLingui } from "@lingui/react/macro"
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { $publicKey, pb } from "@/lib/stores"
|
||||
import { $publicKey } from "@/lib/stores"
|
||||
import { memo, useEffect, useMemo, useState } from "react"
|
||||
import { Table, TableCell, TableHead, TableBody, TableRow, TableHeader } from "@/components/ui/table"
|
||||
import { FingerprintRecord } from "@/types"
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
Trash2Icon,
|
||||
} from "lucide-react"
|
||||
import { toast } from "@/components/ui/use-toast"
|
||||
import { cn, copyToClipboard, generateToken, getHubURL, isReadOnlyUser, tokenMap } from "@/lib/utils"
|
||||
import { cn, copyToClipboard, generateToken, getHubURL, tokenMap } from "@/lib/utils"
|
||||
import { isReadOnlyUser, pb } from "@/lib/api"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { t } from "@lingui/core/macro"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { Plural, Trans } from "@lingui/react/macro"
|
||||
import {
|
||||
$systems,
|
||||
pb,
|
||||
$chartTime,
|
||||
$containerFilter,
|
||||
$userSettings,
|
||||
@@ -12,7 +11,7 @@ import {
|
||||
} from "@/lib/stores"
|
||||
import { ChartData, ChartTimes, ContainerStatsRecord, GPUData, SystemRecord, SystemStatsRecord } from "@/types"
|
||||
import { ChartType, Unit, Os, SystemStatus } from "@/lib/enums"
|
||||
import React, { lazy, memo, useCallback, useEffect, useMemo, useRef, useState, type JSX } from "react"
|
||||
import React, { memo, useCallback, useEffect, useMemo, useRef, useState, type JSX } from "react"
|
||||
import { Card, CardHeader, CardTitle, CardDescription } from "../ui/card"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import Spinner from "../spinner"
|
||||
@@ -24,13 +23,12 @@ import {
|
||||
decimalString,
|
||||
formatBytes,
|
||||
getHostDisplayValue,
|
||||
getPbTimestamp,
|
||||
listen,
|
||||
parseSemVer,
|
||||
toFixedFloat,
|
||||
useLocalStorage,
|
||||
formatUptimeString,
|
||||
} from "@/lib/utils"
|
||||
import { getPbTimestamp, pb } from "@/lib/api"
|
||||
import { Separator } from "../ui/separator"
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip"
|
||||
import { Button } from "../ui/button"
|
||||
@@ -43,15 +41,14 @@ import { useLingui } from "@lingui/react/macro"
|
||||
import { $router, navigate } from "../router"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { batteryStateTranslations } from "@/lib/i18n"
|
||||
|
||||
const AreaChartDefault = lazy(() => import("../charts/area-chart"))
|
||||
const ContainerChart = lazy(() => import("../charts/container-chart"))
|
||||
const MemChart = lazy(() => import("../charts/mem-chart"))
|
||||
const DiskChart = lazy(() => import("../charts/disk-chart"))
|
||||
const SwapChart = lazy(() => import("../charts/swap-chart"))
|
||||
const TemperatureChart = lazy(() => import("../charts/temperature-chart"))
|
||||
const GpuPowerChart = lazy(() => import("../charts/gpu-power-chart"))
|
||||
const LoadAverageChart = lazy(() => import("../charts/load-average-chart"))
|
||||
import AreaChartDefault from "@/components/charts/area-chart"
|
||||
import ContainerChart from "@/components/charts/container-chart"
|
||||
import MemChart from "@/components/charts/mem-chart"
|
||||
import DiskChart from "@/components/charts/disk-chart"
|
||||
import SwapChart from "@/components/charts/swap-chart"
|
||||
import TemperatureChart from "@/components/charts/temperature-chart"
|
||||
import GpuPowerChart from "@/components/charts/gpu-power-chart"
|
||||
import LoadAverageChart from "@/components/charts/load-average-chart"
|
||||
|
||||
const cache = new Map<string, any>()
|
||||
|
||||
@@ -288,8 +285,16 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
value: system.info.k,
|
||||
},
|
||||
}
|
||||
|
||||
let uptime: React.ReactNode = formatUptimeString(system.info.u)
|
||||
let uptime: React.ReactNode
|
||||
if (system.info.u < 3600) {
|
||||
const mins = Math.trunc(system.info.u / 60)
|
||||
uptime = <Plural value={mins} one="# minute" other="# minutes" />
|
||||
} else if (system.info.u < 172800) {
|
||||
const hours = Math.trunc(system.info.u / 3600)
|
||||
uptime = <Plural value={hours} one="# hour" other="# hours" />
|
||||
} else {
|
||||
uptime = <Plural value={Math.trunc(system.info?.u / 86400)} one="# day" other="# days" />
|
||||
}
|
||||
return [
|
||||
{ value: getHostDisplayValue(system), Icon: GlobeIcon },
|
||||
{
|
||||
@@ -312,7 +317,7 @@ export default function SystemDetail({ name }: { name: string }) {
|
||||
Icon: any
|
||||
hide?: boolean
|
||||
}[]
|
||||
}, [system.info])
|
||||
}, [system.info, t])
|
||||
|
||||
/** Space for tooltip if more than 12 containers */
|
||||
useEffect(() => {
|
||||
|
||||
@@ -23,12 +23,11 @@ import {
|
||||
formatBytes,
|
||||
formatTemperature,
|
||||
getMeterState,
|
||||
isReadOnlyUser,
|
||||
parseSemVer,
|
||||
} from "@/lib/utils"
|
||||
import { EthernetIcon, GpuIcon, HourglassIcon, ThermometerIcon } from "../ui/icons"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { $userSettings, pb } from "@/lib/stores"
|
||||
import { $userSettings } from "@/lib/stores"
|
||||
import { Trans, useLingui } from "@lingui/react/macro"
|
||||
import { useMemo, useRef, useState } from "react"
|
||||
import { memo } from "react"
|
||||
@@ -57,6 +56,7 @@ import { t } from "@lingui/core/macro"
|
||||
import { MeterState, SystemStatus } from "@/lib/enums"
|
||||
import { $router, Link } from "../router"
|
||||
import { getPagePath } from "@nanostores/router"
|
||||
import { isReadOnlyUser, pb } from "@/lib/api"
|
||||
|
||||
const STATUS_COLORS = {
|
||||
[SystemStatus.Up]: "bg-green-500",
|
||||
|
||||
@@ -11,11 +11,8 @@ import {
|
||||
Row,
|
||||
Table as TableType,
|
||||
} from "@tanstack/react-table"
|
||||
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuCheckboxItem,
|
||||
@@ -41,7 +38,7 @@ import {
|
||||
import { memo, useEffect, useMemo, useState } from "react"
|
||||
import { $systems } from "@/lib/stores"
|
||||
import { useStore } from "@nanostores/react"
|
||||
import { cn, useLocalStorage } from "@/lib/utils"
|
||||
import { cn, runOnce, useLocalStorage } from "@/lib/utils"
|
||||
import { $router, Link } from "../router"
|
||||
import { useLingui, Trans } from "@lingui/react/macro"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
|
||||
@@ -54,6 +51,8 @@ import { SystemStatus } from "@/lib/enums"
|
||||
type ViewMode = "table" | "grid"
|
||||
type StatusFilter = "all" | "up" | "down" | "paused"
|
||||
|
||||
const preloadSystemDetail = runOnce(() => import("@/components/routes/system.tsx"))
|
||||
|
||||
export default function SystemsTable() {
|
||||
const data = useStore($systems)
|
||||
const { i18n, t } = useLingui()
|
||||
@@ -283,7 +282,7 @@ const AllSystemsTable = memo(
|
||||
return (
|
||||
<Table>
|
||||
<SystemsTableHead table={table} colLength={colLength} />
|
||||
<TableBody>
|
||||
<TableBody onMouseEnter={preloadSystemDetail}>
|
||||
{rows.length ? (
|
||||
rows.map((row) => (
|
||||
<SystemTableRow key={row.original.id} row={row} length={rows.length} colLength={colLength} />
|
||||
@@ -359,6 +358,7 @@ const SystemCard = memo(
|
||||
return useMemo(() => {
|
||||
return (
|
||||
<Card
|
||||
onMouseEnter={preloadSystemDetail}
|
||||
key={system.id}
|
||||
className={cn(
|
||||
"cursor-pointer hover:shadow-md transition-all bg-transparent w-full dark:border-border duration-200 relative",
|
||||
|
||||
Reference in New Issue
Block a user