fix: EmptyState по центру и импорт SQLite без 413
Docker / build (push) Failing after 19s

Центрирование заглушек в графиках/Frame; лимит тела backup 100 MiB;
WAL checkpoint при экспорте и очистка -wal/-shm при импорте.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
DenozordecandCursor committed 2026-07-19 04:41:42 +07:00
1 parent 2931d6ee0f
commit e079a61811
12 files changed
+284 -62

No files matched your search

+1 -1
View File
@@ -370,7 +370,7 @@ export function DataGridCard<TData extends object>({
{hasHeader ? (
<DataGridSectionHeader title={title} description={description} actions={headerActions} />
) : null}
<FramePanel>
<FramePanel className="flex min-h-72 w-full flex-col items-center justify-center">
<EmptyState title={emptyTitle} description={emptyDescription} action={emptyAction} />
</FramePanel>
</Frame>
+18 -8
View File
@@ -51,7 +51,13 @@ import { aggregateBurnByProject } from '@/lib/project-analytics'
import { EmptyState } from '@/components/empty-state'
function ChartEmpty({ message }: { message: string }) {
return <EmptyState title={message} className="h-72 border-none" />
return (
<EmptyState
title={message}
className="min-h-72 w-full flex-1 py-0"
stackedIcon
/>
)
}
const EXPENSE_CONFIG: ChartConfig = {
@@ -103,7 +109,7 @@ export function MonthlyExpenseChart({
<CardTitle>{title}</CardTitle>
<CardDescription>{description ?? `Топ-10 по monthly rate, в ${baseCurrency}`}</CardDescription>
</CardHeader>
<CardContent>
<CardContent className="flex min-h-72 flex-1 flex-col items-center justify-center">
{data.length === 0 ? (
<ChartEmpty message="Нет данных для графика" />
) : (
@@ -167,7 +173,7 @@ export function PaymentsPieChart({
<CardTitle>Платежи по типам</CardTitle>
<CardDescription>Структура в {baseCurrency}</CardDescription>
</CardHeader>
<CardContent>
<CardContent className="flex min-h-72 flex-1 flex-col items-center justify-center">
{data.length === 0 ? (
<ChartEmpty message="Нет данных о платежах" />
) : (
@@ -264,7 +270,7 @@ function DashboardMonthlyBarChart({
</div>
</CardAction>
</CardHeader>
<CardContent>
<CardContent className="flex min-h-72 flex-1 flex-col items-center justify-center">
{!hasData ? (
<ChartEmpty message="Нет данных за выбранный период" />
) : (
@@ -384,7 +390,7 @@ export function DashboardExpensesChart({
</div>
</CardAction>
</CardHeader>
<CardContent>
<CardContent className="flex min-h-72 flex-1 flex-col items-center justify-center">
{!hasData ? (
<ChartEmpty message="Нет данных за выбранный период" />
) : (
@@ -440,7 +446,7 @@ export function MonthlyTrendChart({
<CardTitle>Динамика платежей</CardTitle>
<CardDescription>Последние 12 месяцев, {baseCurrency}</CardDescription>
</CardHeader>
<CardContent>
<CardContent className="flex min-h-72 flex-1 flex-col items-center justify-center">
{data.length === 0 ? (
<ChartEmpty message="Нет данных за выбранный период" />
) : (
@@ -460,7 +466,11 @@ export function MonthlyTrendChart({
}
export function ChartsGrid({ children }: { children: ReactNode }) {
return <div className="grid w-full gap-4 lg:grid-cols-2">{children}</div>
return (
<div className="grid w-full gap-4 lg:grid-cols-2 lg:items-stretch [&>*]:min-h-0 [&>*]:h-full">
{children}
</div>
)
}
export function ProjectExpenseChart({
@@ -506,7 +516,7 @@ export function ProjectExpenseChart({
<CardTitle>Расходы по проектам (мес)</CardTitle>
<CardDescription>Активные VPS, в {baseCurrency}</CardDescription>
</CardHeader>
<CardContent>
<CardContent className="flex min-h-72 flex-1 flex-col items-center justify-center">
{data.length === 0 ? (
<ChartEmpty message="Нет данных для графика" />
) : (
+38 -5
View File
@@ -1,3 +1,8 @@
/**
* ReUI Empty + IconStack — adapted from empty-state-12.
* Preview: https://reui.io/preview/base/empty-state-12
* Docs: https://reui.io/blocks
*/
import { InboxIcon, type LucideIcon } from 'lucide-react'
import { IconStack } from '@/components/reui/icon-stack'
import {
@@ -20,6 +25,11 @@ interface EmptyStateProps {
className?: string
/** Use IconStack media (empty-state-12). Default true. */
stackedIcon?: boolean
/**
* Center in available width/height (empty-state-12).
* Set false for tight panels/sheets where the parent already centers.
*/
centered?: boolean
}
function isLucideIcon(icon: LucideIcon | ReactNode): icon is LucideIcon {
@@ -33,7 +43,6 @@ function isLucideIcon(icon: LucideIcon | ReactNode): icon is LucideIcon {
return false
}
/** Empty state — ReUI empty-state-12. Preview: https://reui.io/preview/base/empty-state-12 */
export function EmptyState({
icon,
title,
@@ -41,18 +50,24 @@ export function EmptyState({
action,
className,
stackedIcon = true,
centered = true,
}: EmptyStateProps) {
const Icon = isLucideIcon(icon) ? icon : InboxIcon
const customIcon = icon && !isLucideIcon(icon) ? icon : null
return (
<Empty className={cn('max-w-md flex-none border-0 bg-transparent p-0', className)}>
const body = (
<Empty
className={cn(
'max-w-md flex-none border-0 bg-transparent p-0',
!centered && className,
)}
>
<EmptyHeader className="gap-5 text-center">
<EmptyMedia className="mb-0">
{customIcon ? (
<div className="text-muted-foreground">{customIcon}</div>
) : stackedIcon ? (
<IconStack aria-hidden="true" className="h-14 w-12">
<IconStack aria-hidden="true" className="h-14 w-12 shrink-0">
<Icon strokeWidth={1.9} aria-hidden="true" className="size-5" />
</IconStack>
) : (
@@ -72,7 +87,25 @@ export function EmptyState({
) : null}
</div>
</EmptyHeader>
{action ? <EmptyContent>{action}</EmptyContent> : null}
{action ? (
<EmptyContent className="mt-1 items-center justify-center">
{action}
</EmptyContent>
) : null}
</Empty>
)
if (!centered) return body
// empty-state-12: center in available height (parent must be flex column / stretch)
return (
<div
className={cn(
'flex w-full flex-1 items-center justify-center self-stretch py-14 sm:py-16',
className,
)}
>
{body}
</div>
)
}
@@ -242,11 +242,15 @@ export function ResourcePage<T extends object>({
if (data.length === 0 && emptyState) {
return (
<EmptyState
title={emptyState.title}
description={emptyState.description}
action={emptyState.action}
/>
<Frame dense spacing="sm" className="w-full">
<FramePanel className="flex min-h-[min(28rem,55svh)] w-full flex-col items-center justify-center p-0">
<EmptyState
title={emptyState.title}
description={emptyState.description}
action={emptyState.action}
/>
</FramePanel>
</Frame>
)
}