Files
beszel-ipv6/beszel/site/src/main.tsx
henrygd 96f441de40 Virtualize All Systems table to improve performance with hundreds of systems (#1100)
- Also truncate long system names in tables and alerts sheet. (#1104)
2025-08-29 16:16:45 -04:00

141 lines
3.7 KiB
Go

import "./index.css"
// import { Suspense, lazy, useEffect, StrictMode } from "react"
import { Suspense, lazy, memo, useEffect } from "react"
import ReactDOM from "react-dom/client"
import { ThemeProvider } from "./components/theme-provider.tsx"
import { DirectionProvider } from "@radix-ui/react-direction"
import { $authenticated, $systems, $publicKey, $copyContent, $direction } from "./lib/stores.ts"
import { pb, updateSystemList, updateUserSettings } from "./lib/api.ts"
import { useStore } from "@nanostores/react"
import { Toaster } from "./components/ui/toaster.tsx"
import { $router } from "./components/router.tsx"
import { updateFavicon } from "@/lib/utils"
import Navbar from "./components/navbar.tsx"
import { I18nProvider } from "@lingui/react"
import { i18n } from "@lingui/core"
import { getLocale, dynamicActivate } from "./lib/i18n"
import { SystemStatus } from "./lib/enums"
import { alertManager } from "./lib/alerts"
import Settings from "./components/routes/settings/layout.tsx"
const LoginPage = lazy(() => import("@/components/login/login.tsx"))
const Home = lazy(() => import("@/components/routes/home.tsx"))
const SystemDetail = lazy(() => import("@/components/routes/system.tsx"))
const CopyToClipboardDialog = lazy(() => import("@/components/copy-to-clipboard.tsx"))
const App = memo(() => {
const page = useStore($router)
const authenticated = useStore($authenticated)
const systems = useStore($systems)
useEffect(() => {
// change auth store on auth change
pb.authStore.onChange(() => {
$authenticated.set(pb.authStore.isValid)
})
// get version / public key
pb.send("/api/beszel/getkey", {}).then((data) => {
$publicKey.set(data.key)
})
// get servers / alerts / settings
updateUserSettings()
// need to get system list before alerts
updateSystemList()
// get alerts
.then(alertManager.refresh)
// subscribe to new alert updates
.then(alertManager.subscribe)
return () => {
updateFavicon("favicon.svg")
alertManager.unsubscribe()
}
}, [])
// update favicon
useEffect(() => {
if (!systems.length || !authenticated) {
updateFavicon("favicon.svg")
} else {
let up = false
for (const system of systems) {
if (system.status === SystemStatus.Down) {
updateFavicon("favicon-red.svg")
return
}
if (system.status === SystemStatus.Up) {
up = true
}
}
updateFavicon(up ? "favicon-green.svg" : "favicon.svg")
}
}, [systems])
if (!page) {
return <h1 className="text-3xl text-center my-14">404</h1>
} else if (page.route === "home") {
return <Home />
} else if (page.route === "system") {
return <SystemDetail name={page.params.name} />
} else if (page.route === "settings") {
return <Settings />
}
})
const Layout = () => {
const authenticated = useStore($authenticated)
const copyContent = useStore($copyContent)
const direction = useStore($direction)
useEffect(() => {
document.documentElement.dir = direction
}, [direction])
return (
<DirectionProvider dir={direction}>
{!authenticated ? (
<Suspense>
<LoginPage />
</Suspense>
) : (
<>
<div className="container">
<Navbar />
</div>
<div className="container relative">
<App />
{copyContent && (
<Suspense>
<CopyToClipboardDialog content={copyContent} />
</Suspense>
)}
</div>
</>
)}
</DirectionProvider>
)
}
const I18nApp = () => {
useEffect(() => {
dynamicActivate(getLocale())
}, [])
return (
<I18nProvider i18n={i18n}>
<ThemeProvider>
<Layout />
<Toaster />
</ThemeProvider>
</I18nProvider>
)
}
ReactDOM.createRoot(document.getElementById("app")!).render(
// strict mode in dev mounts / unmounts components twice
// and breaks the clipboard dialog
//<StrictMode>
<I18nApp />
//</StrictMode>
)