Files
EvoFirewall/apps/web/src/components/query-state.tsx
T
DenozordecandCursor ecaa22ed97
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 2m18s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped
fix(ui): выровнять IconTile chrome и доступность
Перевести KPI и агентские тайлы на IconTile, skip-link и live regions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-17 15:36:56 +07:00

64 lines
1.5 KiB
TypeScript

import { CircleAlertIcon } from 'lucide-react'
import {
Alert,
AlertDescription,
AlertTitle,
} from '@/components/reui/alert'
import { Button } from '@evofw/ui/components/button'
import { Skeleton } from '@evofw/ui/components/skeleton'
interface QueryStateProps {
isLoading?: boolean
isError?: boolean
error?: Error | null
onRetry?: () => void
skeleton?: React.ReactNode
children: React.ReactNode
}
function DefaultSkeleton() {
return (
<div className="flex flex-col gap-4">
<Skeleton className="h-8 w-1/3" />
<Skeleton className="h-40 w-full" />
<Skeleton className="h-40 w-full" />
</div>
)
}
export function QueryState({
isLoading,
isError,
error,
onRetry,
skeleton,
children,
}: QueryStateProps) {
if (isLoading) {
return (
<div role="status" aria-live="polite" aria-busy="true">
{skeleton ?? <DefaultSkeleton />}
</div>
)
}
if (isError) {
return (
<Alert variant="destructive">
<CircleAlertIcon />
<AlertTitle>Не удалось загрузить данные</AlertTitle>
<AlertDescription className="flex flex-col gap-2">
<span>{error?.message ?? 'Произошла ошибка при загрузке.'}</span>
{onRetry ? (
<Button variant="outline" size="sm" onClick={onRetry}>
Повторить
</Button>
) : null}
</AlertDescription>
</Alert>
)
}
return children
}