fix(ui): улучшить функциональность панели данных и заменить устаревшие компоненты
Docker images / prepare-release (push) Successful in 7s
Docker images / backend-image (push) Successful in 2m1s
Docker images / frontend-image (push) Successful in 2m7s
Docker images / updater-image (push) Successful in 41s
Docker images / notify-webhook (push) Has been skipped
Docker images / publish-release (push) Successful in 8s

This commit is contained in:
Denozordec
2026-06-30 22:36:00 +07:00
parent d3a2d38b37
commit d2de8d3188
16 changed files with 162 additions and 214 deletions
+22 -46
View File
@@ -11,6 +11,7 @@ import { Flag } from "@/components/flag"
import { StatusDot } from "@/components/status-dot"
import { Sparkline } from "@/components/sparkline"
import { DataPageCard } from "@/components/data-page-card"
import { DataPageToolbar } from "@/components/data-page-toolbar"
import {
UptimeResourcesDataGrid,
type UptimeResourceRow,
@@ -981,48 +982,25 @@ function ResourcesTab({ resources, serversList, liveApi }: { resources: ServerRe
))}
</div>
{/* ── Toolbar ───────────────────────────────────────────────────────── */}
<div className="flex items-center gap-3 flex-wrap">
{/* Type filter */}
<div className="flex items-center gap-0.5 rounded-md border border-border bg-muted/40 p-0.5 shrink-0">
{typeOpts.map(o => (
<button key={o.value} onClick={() => setTypeFilter(o.value)}
className={cn(
"px-2.5 py-1 text-xs rounded transition-colors whitespace-nowrap",
typeFilter === o.value
? "bg-background text-foreground shadow-sm"
: "text-muted-foreground hover:text-foreground",
)}>
{o.label}
</button>
))}
</div>
{/* Search */}
<div className="relative min-w-[180px] flex-1 max-w-xs">
<SearchIcon className="absolute left-2.5 top-1/2 -translate-y-1/2 size-3.5 text-muted-foreground pointer-events-none" />
<Input className="pl-8 h-8 text-sm" placeholder="Поиск по имени, площадке…"
value={resSearch} onChange={e => setResSearch(e.target.value)} />
{resSearch && (
<button onClick={() => setResSearch("")}
className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground">
<XIcon className="size-3.5" />
</button>
)}
</div>
<span className="text-xs text-muted-foreground ml-auto shrink-0">
{visible.length} из {rows.length} серверов
</span>
{/* Export CSV */}
<Button variant="outline" size="sm" className="h-8 gap-1.5 shrink-0" onClick={exportCsv}>
<DownloadIcon className="size-3.5" />CSV
</Button>
</div>
{/* ── Table ─────────────────────────────────────────────────────────── */}
<DataPageCard>
<DataPageToolbar
segmented={{
value: typeFilter,
onChange: setTypeFilter,
options: typeOpts,
}}
search={resSearch}
onSearchChange={setResSearch}
searchPlaceholder="Поиск по имени, площадке…"
countLabel={`${visible.length} из ${rows.length} серверов`}
actions={
<Button variant="outline" size="sm" className="h-8 gap-1.5 shrink-0" onClick={exportCsv}>
<DownloadIcon className="size-3.5" />
CSV
</Button>
}
/>
<UptimeResourcesDataGrid rows={visible} />
</DataPageCard>
@@ -2273,15 +2251,13 @@ export default function UptimePage() {
{/* ── history ── */}
{speedRuns.length > 0 && (
<Card className="overflow-hidden">
<div className="flex items-center justify-between px-4 py-3 border-b">
<DataPageCard>
<div className="flex items-center justify-between px-5 py-3 border-b">
<p className="text-sm font-medium">История тестов</p>
<span className="text-xs text-muted-foreground">{speedRuns.length} запусков</span>
</div>
<div className="overflow-x-auto">
<UptimeSpeedHistoryDataGrid runs={speedRuns} servers={allServers} />
</div>
</Card>
<UptimeSpeedHistoryDataGrid runs={speedRuns} servers={allServers} />
</DataPageCard>
)}
</div>