feat(ui): integrate KpiStatGrid for enhanced statistics display
Docker images / prepare-release (push) Successful in 9s
Docker images / backend-image (push) Successful in 1m43s
Docker images / frontend-image (push) Successful in 2m58s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 39s
Docker images / publish-release (push) Successful in 8s

Replaced existing KPI display implementations across multiple pages with the new KpiStatGrid component for a more consistent and visually appealing presentation of statistics. Updated the Backups, BGP, Certificates, Communities, Containers, Dashboard, and Data Collection pages to utilize the KpiStatGrid, improving the overall user experience and maintainability of the codebase. Additionally, added new dependencies in package.json for required libraries.
This commit is contained in:
Denozordec
2026-09-06 17:58:05 +07:00
parent 6123660346
commit fe32c9313a
47 changed files with 5371 additions and 1531 deletions
+41 -90
View File
@@ -16,18 +16,12 @@ import {
FrameTitle,
} from "@/components/reui/frame"
import { ScrollArea } from "@/components/ui/scroll-area"
import { ServerRailLayout, ServerRailMobileButton } from "@/components/server-rail-layout"
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet"
import {
ServerTileRail,
type ServerTileItem,
} from "@/components/server-tile-rail"
import {
TrashIcon, RefreshCwIcon, CircleIcon, Loader2Icon, ServerIcon,
TrashIcon, RefreshCwIcon, CircleIcon, Loader2Icon,
} from "lucide-react"
import { cn } from "@/lib/utils"
@@ -456,7 +450,6 @@ export default function TerminalPage() {
const [liveServers, setLiveServers] = useState<TermServer[]>([])
const [serversLoading, setServersLoading] = useState(false)
const [refreshKey, setRefreshKey] = useState(0) // force terminal remount on reconnect
const [railOpen, setRailOpen] = useState(false)
// Load servers from backend when in live mode
useEffect(() => {
@@ -516,6 +509,7 @@ export default function TerminalPage() {
return termServers.map((s) => ({
id: s.uid,
name: s.name,
host: s.host,
country: s.country || undefined,
status: (s.status ?? undefined) as ServerStatus | undefined,
enabled: s.enabled,
@@ -524,31 +518,15 @@ export default function TerminalPage() {
}))
}, [termServers])
function handleSelectServer(id: string) {
const handleSelectServer = useCallback((id: string) => {
setSelectedUid(id)
setRefreshKey((k) => k + 1)
setRailOpen(false)
}
}, [])
const railHeaderRight = isLive
? serversLoading
? <Loader2Icon className="size-3.5 animate-spin text-muted-foreground" />
: <Badge variant="success-light" size="xs">LIVE</Badge>
const railHeaderRight = isLive && !serversLoading
? <Badge variant="success-light" size="xs">LIVE</Badge>
: undefined
const rail = (
<ServerTileRail
items={railItems}
selectedId={selected?.uid ?? selectedUid}
onSelect={handleSelectServer}
showAll={false}
showCount={false}
showType={false}
headerRight={railHeaderRight}
className="min-h-0 flex-1"
/>
)
function QuickCmds() {
return (
<Frame dense spacing="sm" className="min-h-0 shrink-0">
@@ -595,42 +573,39 @@ export default function TerminalPage() {
}
return (
<div className="flex h-full flex-col">
<PageHeader
crumbs={[{ label: "Инструменты" }, { label: "Терминал" }]}
actions={
<>
<Button
size="sm"
variant="outline"
className="md:hidden"
onClick={() => setRailOpen(true)}
>
<ServerIcon className="size-4" />
{selected?.name ?? "Сервер"}
</Button>
<Button
variant="outline"
size="sm"
onClick={() => {
setRefreshKey((k) => k + 1)
if (isLive) setSelectedUid("")
}}
>
<RefreshCwIcon className="size-4" />
Переподключить
</Button>
</>
}
/>
<div className="flex min-h-0 flex-1">
<aside className="hidden min-h-0 w-60 shrink-0 flex-col gap-3 p-3 pr-0 md:flex">
{rail}
<QuickCmds />
</aside>
<div className="min-w-0 flex-1 overflow-hidden p-3 md:p-4">
<ServerRailLayout
items={railItems}
selectedId={selected?.uid ?? selectedUid}
onSelect={handleSelectServer}
showAll={false}
showCount={false}
showType={false}
headerRight={railHeaderRight}
loading={serversLoading}
extra={<QuickCmds />}
contentClassName="overflow-hidden p-3 md:p-4"
header={
<PageHeader
crumbs={[{ label: "Инструменты" }, { label: "Терминал" }]}
actions={
<>
<ServerRailMobileButton />
<Button
variant="outline"
size="sm"
onClick={() => {
setRefreshKey((k) => k + 1)
if (isLive) setSelectedUid("")
}}
>
<RefreshCwIcon className="size-4" />
Переподключить
</Button>
</>
}
/>
}
>
{selected ? (
<Terminal
key={termKey}
@@ -643,30 +618,6 @@ export default function TerminalPage() {
{serversLoading ? "Загрузка серверов…" : "Выберите сервер"}
</div>
)}
</div>
</div>
<Sheet open={railOpen} onOpenChange={setRailOpen}>
<SheetContent side="left" className="flex w-72 flex-col gap-3 p-3" showCloseButton>
<SheetHeader className="px-1 pt-1">
<SheetTitle>Серверы</SheetTitle>
</SheetHeader>
<div className="flex min-h-0 flex-1 flex-col gap-3">
<ServerTileRail
items={railItems}
selectedId={selected?.uid ?? selectedUid}
onSelect={handleSelectServer}
showAll={false}
showCount={false}
showType={false}
showHeader={false}
headerRight={railHeaderRight}
className="min-h-0 flex-1"
/>
<QuickCmds />
</div>
</SheetContent>
</Sheet>
</div>
</ServerRailLayout>
)
}