fix(web): открытие detail-роутов и паритет ReUI DataGrid с EvoBGP/CFDM
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 1m52s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped

Sibling routes index+$id, ColumnHeader/PrimaryCell/StatusBadge/ConfirmDialog, tabs и таблица entries списков.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-07-20 22:40:48 +07:00
co-authored by Cursor
parent 0bed4367c7
commit 7f0c1009de
10 changed files with 1040 additions and 360 deletions
@@ -0,0 +1,46 @@
import type { ReactNode } from 'react'
import { cn } from '@evofw/ui/lib/utils'
const ACCENT_CLASS = {
primary: 'font-medium text-primary',
default: 'font-medium text-foreground',
mono: 'font-mono text-sm text-primary',
} as const
export function DataGridPrimaryCell({
title,
subtitle,
accent = 'default',
className,
}: {
title: ReactNode
subtitle?: ReactNode
accent?: keyof typeof ACCENT_CLASS
className?: string
}) {
return (
<div className={cn('flex min-w-0 flex-col gap-0.5', className)}>
<span className={cn('truncate', ACCENT_CLASS[accent])}>{title}</span>
{subtitle ? (
<span className="truncate text-xs text-muted-foreground">{subtitle}</span>
) : null}
</div>
)
}
export function DataGridMutedCell({
children,
className,
}: {
children: ReactNode
className?: string
}) {
return (
<span
className={cn('whitespace-nowrap text-xs text-muted-foreground', className)}
>
{children}
</span>
)
}
+32 -2
View File
@@ -11,13 +11,24 @@ const STATUS_VARIANT: Record<string, BadgeVariant> = {
synced: 'success-light',
ok: 'success-light',
up: 'success-light',
enabled: 'success-light',
approved: 'success-light',
allow: 'success-light',
pending_push: 'secondary',
pending: 'warning-light',
warning: 'warning-light',
degraded: 'warning-light',
conflict: 'destructive-light',
error: 'destructive-light',
expired: 'destructive-light',
down: 'destructive-light',
deny: 'destructive-light',
revoked: 'secondary',
disabled: 'secondary',
static: 'secondary',
domains: 'info-light',
json_url: 'info-light',
evobgp_community: 'info-light',
unknown: 'outline',
}
@@ -37,6 +48,13 @@ const STATUS_LABELS: Record<string, string> = {
active: 'Активен',
synced: 'Синхронизировано',
pending_push: 'Ожидает отправки',
pending: 'Pending',
approved: 'Approved',
revoked: 'Revoked',
enabled: 'Включён',
disabled: 'Выключен',
allow: 'allow',
deny: 'deny',
conflict: 'Конфликт',
error: 'Ошибка',
ok: 'OK',
@@ -45,6 +63,10 @@ const STATUS_LABELS: Record<string, string> = {
degraded: 'Slow',
down: 'Down',
expired: 'Истёк',
static: 'static',
domains: 'domains',
json_url: 'json_url',
evobgp_community: 'evobgp_community',
unknown: 'Неизвестно',
}
@@ -60,8 +82,16 @@ export function StatusBadge({
const variant = STATUS_VARIANT[status] ?? 'outline'
const dotColor = DOT_COLOR[variant] ?? 'bg-muted-foreground'
return (
<Badge variant={variant} size="sm" radius="full" className={cn('gap-1.5', className)}>
<span className={cn('size-1.5 shrink-0 rounded-full', dotColor)} aria-hidden />
<Badge
variant={variant}
size="sm"
radius="full"
className={cn('gap-1.5', className)}
>
<span
className={cn('size-1.5 shrink-0 rounded-full', dotColor)}
aria-hidden
/>
{label ?? STATUS_LABELS[status] ?? status}
</Badge>
)