quality / commitlint (push) Skipped
quality / changes (push) Successful in 8s
quality / go (push) Skipped
quality / bird2 (push) Skipped
quality / docker-check (push) Skipped
quality / openapi (push) Successful in 22s
quality / web (push) Successful in 1m0s
CD / quality (push) Successful in 1m35s
CD / publish (push) Successful in 2m59s
Секции страниц переведены на segmented Tabs (c-tabs-9), статус грида — ToggleGroup в toolbar. Убраны календарь задач, пустые вкладки мониторинга и demo-деревья ReUI. KPI overflow как в CFDM, DetailPanel на карточке модуля, один FrameSection. Co-authored-by: Cursor <[email protected]>
118 lines
2.8 KiB
TypeScript
118 lines
2.8 KiB
TypeScript
import type { ComponentProps, ReactNode } from 'react'
|
|
|
|
import { cn } from '@evobgp/ui/lib/utils'
|
|
|
|
import { Badge } from '@/components/reui/badge'
|
|
import { jobStatusRu } from '@/lib/ui-labels'
|
|
|
|
type BadgeVariant = NonNullable<ComponentProps<typeof Badge>['variant']>
|
|
|
|
const STATUS_VARIANT: Record<string, BadgeVariant> = {
|
|
active: 'success-light',
|
|
ok: 'success-light',
|
|
paid: 'success-light',
|
|
established: 'success-light',
|
|
succeeded: 'success-light',
|
|
healthy: 'success-light',
|
|
approved: 'success-light',
|
|
accept: 'success-light',
|
|
paused: 'invert-light',
|
|
disabled: 'invert-light',
|
|
archived: 'outline',
|
|
error: 'destructive-light',
|
|
failed: 'destructive-light',
|
|
revoked: 'destructive-light',
|
|
block: 'destructive-light',
|
|
cancelled: 'destructive-light',
|
|
running: 'info-light',
|
|
queued: 'info-light',
|
|
overdue: 'warning-light',
|
|
stale: 'warning-light',
|
|
warning: 'warning-light',
|
|
mismatch: 'warning-light',
|
|
pending: 'warning-light',
|
|
}
|
|
|
|
const DOT_COLOR: Record<string, string> = {
|
|
'success-light': 'bg-success',
|
|
'info-light': 'bg-info',
|
|
'warning-light': 'bg-warning',
|
|
'destructive-light': 'bg-destructive',
|
|
'invert-light': 'bg-muted-foreground',
|
|
outline: 'bg-muted-foreground',
|
|
}
|
|
|
|
const TONE_VARIANT: Record<string, BadgeVariant> = {
|
|
neutral: 'outline',
|
|
info: 'info-light',
|
|
warning: 'warning-light',
|
|
success: 'success-light',
|
|
}
|
|
|
|
export function jobStatusVariant(status: string): BadgeVariant {
|
|
return STATUS_VARIANT[status.toLowerCase()] ?? 'outline'
|
|
}
|
|
|
|
export function StatusBadge({
|
|
status,
|
|
label,
|
|
hint,
|
|
className,
|
|
}: {
|
|
status: string
|
|
label?: string
|
|
hint?: string
|
|
className?: string
|
|
}) {
|
|
const variant = jobStatusVariant(status)
|
|
const dotColor = DOT_COLOR[variant] ?? 'bg-muted-foreground'
|
|
|
|
return (
|
|
<div className={cn('flex flex-col gap-0.5', className)}>
|
|
<Badge variant={variant} size="sm" radius="full" className="gap-1.5">
|
|
<span className={cn('size-1.5 shrink-0 rounded-full', dotColor)} aria-hidden />
|
|
{label ?? jobStatusRu(status)}
|
|
</Badge>
|
|
{hint ? <span className="text-xs text-muted-foreground">{hint}</span> : null}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function ModeBadge({
|
|
enabled,
|
|
onLabel = 'включён',
|
|
offLabel = 'выключен',
|
|
className,
|
|
}: {
|
|
enabled: boolean
|
|
onLabel?: string
|
|
offLabel?: string
|
|
className?: string
|
|
}) {
|
|
return enabled ? (
|
|
<Badge variant="success-light" size="sm" radius="full" className={className}>
|
|
{onLabel}
|
|
</Badge>
|
|
) : (
|
|
<Badge variant="secondary" size="sm" radius="full" className={className}>
|
|
{offLabel}
|
|
</Badge>
|
|
)
|
|
}
|
|
|
|
export function CategoryBadge({
|
|
children,
|
|
tone = 'neutral',
|
|
className,
|
|
}: {
|
|
children: ReactNode
|
|
tone?: keyof typeof TONE_VARIANT
|
|
className?: string
|
|
}) {
|
|
return (
|
|
<Badge variant={TONE_VARIANT[tone]} size="sm" radius="full" className={className}>
|
|
{children}
|
|
</Badge>
|
|
)
|
|
}
|