refactor: integrate PanelCard and enhance dashboard components for improved layout
CI / changes (push) Successful in 10s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Successful in 52s
CI / go (push) Has been skipped
CI / bird2 (push) Has been skipped
CI / release (push) Successful in 4m7s

Refactored multiple dashboard components to utilize the new PanelCard for better organization and presentation. Updated the DashboardFramePanel, DashboardQuickLinks, and DashboardOperationsBreakdown components to streamline layouts and enhance user experience. Removed deprecated components and improved loading states in various sections, ensuring a cohesive interface throughout the application.
This commit is contained in:
Denozordec
2026-07-09 21:39:20 +07:00
parent 1a142e68a9
commit a3f3ffd672
161 changed files with 17496 additions and 605 deletions
+53 -73
View File
@@ -1,10 +1,9 @@
import { createFileRoute, useSearch } from '@tanstack/react-router'
import { useQuery } from '@tanstack/react-query'
import { Activity, AlertTriangle, Bird, RefreshCw } from 'lucide-react'
import { AlertTriangle, Bird, Database, FileText, RefreshCw } from 'lucide-react'
import { Button } from '@evobgp/ui/components/button'
import { PanelCard } from '@/components/panel-card'
import { Separator } from '@evobgp/ui/components/separator'
import { BadgeTabs, TabsContent } from '@/components/badge-tabs'
import { DataGridCard } from '@/components/data-grid-shell'
import { StatusBadge } from '@/components/status-badge'
@@ -16,6 +15,8 @@ import {
import { MonitoringReadyGrid } from '@/components/monitoring/monitoring-ready-grid'
import { PageHeader } from '@/components/page-header'
import { QueryState } from '@/components/query-state'
import { IllustratedEmptyState } from '@/components/patterns/illustrated-empty-state'
import { SegmentedProgressCard } from '@/components/patterns/segmented-progress-card'
import { AnalyticsDashboardSkeleton } from '@/components/skeletons'
import {
@@ -164,52 +165,50 @@ function MonitoringComponent() {
</div>
<div className="grid gap-4 lg:grid-cols-2">
<PanelCard
title={
<span className="flex items-center gap-2">
<Activity className="size-4" />
Задачи
</span>
}
description="Последние 100 задач · GET /v1/jobs"
contentClassName="space-y-4 py-4"
>
<div className="flex flex-wrap gap-4 text-sm">
<Metric label="Активных" value={jobs.filter((j) => j.status === 'running' || j.status === 'queued').length} />
<Metric
label="С ошибками"
value={failed}
valueClass={failed > 0 ? 'text-warning' : 'text-success'}
/>
<Metric label="В выборке" value={jobs.length} />
</div>
<Separator />
{failedJobs.length > 0 ? (
<div className="space-y-3">
<p className="text-sm font-medium">Последние ошибки</p>
<ul className="space-y-2">
{failedJobs.map((job) => (
<li key={job.job_id} className="rounded-lg border px-3 py-2 text-sm">
<div className="flex items-start justify-between gap-2">
<p className="font-medium">{jobKindRu(job.kind)}</p>
<StatusBadge status={job.status} />
</div>
{job.error ? (
<p className="mt-1 text-xs text-muted-foreground">
{job.error.slice(0, 120)}
{job.error.length > 120 ? '…' : ''}
</p>
) : null}
</li>
))}
</ul>
</div>
) : (
<p className="text-sm text-muted-foreground">
Критичных сбоев в последних 100 задачах нет.
</p>
)}
</PanelCard>
<div className="flex flex-col gap-4">
<SegmentedProgressCard
title="Задачи"
description="Последние 100 задач · GET /v1/jobs"
primary={{
value: jobs.filter((j) => j.status === 'running' || j.status === 'queued').length,
label: 'Активных',
percent:
jobs.length > 0
? Math.round(
(jobs.filter((j) => j.status === 'running' || j.status === 'queued').length /
jobs.length) *
100,
)
: 0,
}}
secondary={{
value: failed,
label: 'С ошибками',
percent: jobs.length > 0 ? Math.round((failed / jobs.length) * 100) : 0,
}}
footer={`В выборке: ${jobs.length} задач`}
/>
{failedJobs.length > 0 ? (
<PanelCard title="Последние ошибки" contentClassName="space-y-2 py-4">
<ul className="space-y-2">
{failedJobs.map((job) => (
<li key={job.job_id} className="rounded-lg border px-3 py-2 text-sm">
<div className="flex items-start justify-between gap-2">
<p className="font-medium">{jobKindRu(job.kind)}</p>
<StatusBadge status={job.status} />
</div>
{job.error ? (
<p className="mt-1 text-xs text-muted-foreground">
{job.error.slice(0, 120)}
{job.error.length > 120 ? '…' : ''}
</p>
) : null}
</li>
))}
</ul>
</PanelCard>
) : null}
</div>
<PanelCard
title={
@@ -246,28 +245,18 @@ function MonitoringComponent() {
</TabsContent>
<TabsContent value="postgres" className="mt-0">
<PanelCard
<IllustratedEmptyState
icon={Database}
title="PostgreSQL"
description={
<>
Статус соединения и пул. PostgreSQL отображается в readiness-проверке на вкладке «Система»
(check <code className="text-xs">postgres</code>).
</>
}
contentClassName="py-4"
description="Статус соединения и пул отображаются в readiness-проверке на вкладке «Система» (check postgres)."
/>
</TabsContent>
<TabsContent value="runtime-logs" className="mt-0">
<PanelCard
<IllustratedEmptyState
icon={FileText}
title="Файловые логи"
description={
<>
Логи API и pipeline настраиваются переменной <code className="text-xs">EVOBGP_LOG_*</code> и
управляются в tenant-settings.
</>
}
contentClassName="py-4"
description="Логи API и pipeline настраиваются переменной EVOBGP_LOG_* и управляются в tenant-settings."
/>
</TabsContent>
</BadgeTabs>
@@ -275,15 +264,6 @@ function MonitoringComponent() {
)
}
function Metric({ label, value, valueClass }: { label: string; value: number | string; valueClass?: string }) {
return (
<div>
<p className="text-muted-foreground">{label}</p>
<p className={`text-2xl font-bold tabular-nums ${valueClass ?? ''}`}>{value}</p>
</div>
)
}
function formatVersion(version?: VersionInfo | null): string {
if (!version) return '—'
return version.version ?? version.app ?? '—'