fix(ui): раскрывать предупреждения ресурсов порциями
This commit is contained in:
1 parent
2762f073a0
commit
ab334764cf
6 files changed
+77
-28
No files matched your search
+29
-26
@@ -870,6 +870,34 @@ function SortIcon({ k, sortKey, sortAsc }: { k: ResSortKey; sortKey: ResSortKey;
|
||||
|
||||
type ResTypeFilter = "all" | "jump-host" | "exit-node" | "home-router"
|
||||
|
||||
function ResourceWarnings({ rows }: { rows: UptimeResourceRow[] }) {
|
||||
const [expanded, setExpanded] = useState(false)
|
||||
const [visible, setVisible] = useState(55)
|
||||
if (!rows.length) return null
|
||||
function renderRow(row: UptimeResourceRow) {
|
||||
const issues: string[] = []
|
||||
if (row.cpu >= 85) issues.push(`CPU ${row.cpu}%`)
|
||||
if (row.ramPct >= 85) issues.push(`RAM ${row.ramPct}%`)
|
||||
if (row.hddPct >= 85) issues.push(`HDD ${row.hddPct}%`)
|
||||
if ((row.temp ?? 0) >= 70) issues.push(`${row.temp}°C`)
|
||||
return <span key={row.serverId} data-resource-warning={row.serverId} className="inline-flex items-center gap-1 text-[11px] font-mono rounded border border-destructive/30 bg-destructive/10 px-2 py-0.5">
|
||||
<Flag code={row.server.country} size={10} />{row.server.name} — {issues.join(", ")}
|
||||
</span>
|
||||
}
|
||||
return <Alert variant="destructive">
|
||||
<ServerCrashIcon />
|
||||
<AlertTitle className="text-xs mb-1">Серверов с предупреждениями: {rows.length}</AlertTitle>
|
||||
<AlertDescription>
|
||||
<div className="flex flex-wrap gap-1.5">{rows.slice(0, 5).map(renderRow)}</div>
|
||||
{rows.length > 5 && <details onToggle={event => { setExpanded(event.currentTarget.open); if (!event.currentTarget.open) setVisible(55) }}>
|
||||
<summary className="cursor-pointer rounded-md py-2 text-xs focus-visible:ring-2 focus-visible:ring-ring">Ещё {rows.length - 5}</summary>
|
||||
{expanded && <div className="flex flex-wrap gap-1.5">{rows.slice(5, visible).map(renderRow)}</div>}
|
||||
{expanded && rows.length > visible && <Button type="button" variant="ghost" size="sm" onClick={() => setVisible(count => Math.min(count + 50, rows.length))}>Показать ещё {Math.min(50, rows.length - visible)}</Button>}
|
||||
</details>}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
function ResourcesTab({ resources, serversList, liveApi }: { resources: ServerResource[]; serversList: Server[]; liveApi?: boolean }) {
|
||||
const { resource, setResourceSearch: setResSearch, setResourceType: setTypeFilter, resetResources } = useUptimeUrlState()
|
||||
const { search: resSearch, type: typeFilter, error: resourceError } = resource
|
||||
@@ -944,32 +972,7 @@ function ResourcesTab({ resources, serversList, liveApi }: { resources: ServerRe
|
||||
<div className="p-6 flex flex-col gap-4">
|
||||
|
||||
{/* ── Alert banner ──────────────────────────────────────────────────── */}
|
||||
{alerts.length > 0 && (
|
||||
<Alert variant="destructive">
|
||||
<ServerCrashIcon />
|
||||
<AlertTitle className="text-xs mb-1">
|
||||
{alerts.length} {alerts.length === 1 ? "сервер требует внимания" : "сервера требуют внимания"}
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
{alerts.map(r => {
|
||||
const s = r.server
|
||||
const issues: string[] = []
|
||||
if (r.cpu >= 85) issues.push(`CPU ${r.cpu}%`)
|
||||
if (r.ramPct >= 85) issues.push(`RAM ${r.ramPct}%`)
|
||||
if (r.hddPct >= 85) issues.push(`HDD ${r.hddPct}%`)
|
||||
if ((r.temp ?? 0) >= 70) issues.push(`${r.temp}°C`)
|
||||
return (
|
||||
<span key={r.serverId} className="inline-flex items-center gap-1 text-[11px] font-mono rounded border border-destructive/30 bg-destructive/10 px-2 py-0.5">
|
||||
<Flag code={s.country} size={10} />
|
||||
{s.name} — {issues.join(", ")}
|
||||
</span>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<ResourceWarnings rows={alerts} />
|
||||
|
||||
<KpiStatGrid
|
||||
aria-label="Сводка ресурсов"
|
||||
|
||||
Reference in new issue
Block a user