fix(ui): сохранить данные дашборда при сбоях и гонках запросов
This commit is contained in:
1 parent
0d418e2e39
commit
6a726b13b4
6 files changed
+316
-94
No files matched your search
@@ -0,0 +1,39 @@
|
||||
"use client"
|
||||
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/reui/alert"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { DASHBOARD_SOURCES, type DashboardSource, type DashboardSources } from "@/lib/dashboard-source-state"
|
||||
|
||||
export function DashboardDataStatus({ sources, refreshing, onRefresh }: {
|
||||
sources: DashboardSources
|
||||
refreshing: boolean
|
||||
onRefresh: () => void
|
||||
}) {
|
||||
const failed = Object.values(sources).filter(source => source.error)
|
||||
const summary = failed.length ? `Не обновлены источники: ${failed.length}` : "Состояние источников"
|
||||
return <div className="flex flex-col gap-2">
|
||||
{failed.length > 0 && <Alert variant="destructive">
|
||||
<AlertTitle>{summary}</AlertTitle>
|
||||
<AlertDescription>Последние полученные данные сохранены. Если источник ещё не загрузился, его показатели неизвестны.</AlertDescription>
|
||||
</Alert>}
|
||||
<div className="flex flex-wrap items-start justify-between gap-2">
|
||||
<details className="min-w-0 text-sm" open={failed.length > 0 || undefined}>
|
||||
<summary className="cursor-pointer">Источники и время получения</summary>
|
||||
<ul className="mt-2 flex flex-col gap-1 text-xs">
|
||||
{(Object.keys(DASHBOARD_SOURCES) as DashboardSource[]).map(key => {
|
||||
const source = sources[key]
|
||||
return <li key={key} data-source={key} className={`break-words ${source?.error ? "text-destructive" : "text-muted-foreground"}`}>
|
||||
{DASHBOARD_SOURCES[key]}: {source?.error ? `ошибка обновления — ${source.error}. ` : ""}
|
||||
{source?.receivedAt != null ? <>Получено <time dateTime={new Date(source.receivedAt).toISOString()}>{new Date(source.receivedAt).toLocaleString("ru-RU")}</time>{source.error ? " · данные могут быть устаревшими" : ""}</> : "Успешных загрузок ещё нет"}
|
||||
{source?.sampledAt && Number.isFinite(Date.parse(source.sampledAt)) && <> · замер <time dateTime={source.sampledAt}>{new Date(source.sampledAt).toLocaleString("ru-RU")}</time></>}
|
||||
</li>
|
||||
})}
|
||||
</ul>
|
||||
</details>
|
||||
<div className="flex items-center gap-2">
|
||||
<span role="status" className="text-xs text-muted-foreground">{refreshing ? "Обновление данных…" : "Обновление завершено"}</span>
|
||||
<Button type="button" size="sm" variant="outline" onClick={onRefresh} disabled={refreshing}>Обновить данные</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
Reference in new issue
Block a user