krona-front/src/features/control-center/components/StatusBadge.tsx

227 lines
7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from 'react';
import {
CheckCircle2,
AlertTriangle,
XCircle,
Clock,
Radio,
ShieldAlert,
Smartphone,
Server,
Zap,
} from 'lucide-react';
export type StatusBadgeVariant =
| 'active'
| 'trial'
| 'grace'
| 'suspended'
| 'closed'
| 'normal'
| 'overdue'
| 'expiring_7d'
| 'expiring_30d'
| 'healthy'
| 'degraded'
| 'warning'
| 'critical'
| 'offline'
| 'unknown'
| 'supported'
| 'outdated'
| 'blocked'
| 'revoked'
| 'pilot'
| 'draft'
| 'percentage'
| 'general_availability'
| 'paused'
| 'rolled_back'
| 'open'
| 'mitigating'
| 'resolved';
interface StatusBadgeProps {
status: StatusBadgeVariant;
customLabel?: string;
size?: 'sm' | 'md';
}
interface BadgeConfig {
label: string;
className: string;
icon: React.ReactNode;
}
export const StatusBadge: React.FC<StatusBadgeProps> = ({ status, customLabel, size = 'md' }) => {
const isSmall = size === 'sm';
const iconSize = isSmall ? 'w-3 h-3' : 'w-3.5 h-3.5';
const configs: Record<StatusBadgeVariant, BadgeConfig> = {
// Platform & tenant
active: {
label: 'Активна',
className: 'bg-emerald-950/80 text-emerald-400 border-emerald-700/50',
icon: <CheckCircle2 className={iconSize} aria-hidden="true" />,
},
trial: {
label: 'Trial (Пробный)',
className: 'bg-amber-950/80 text-amber-300 border-amber-700/50',
icon: <Clock className={iconSize} aria-hidden="true" />,
},
grace: {
label: 'Grace Period',
className: 'bg-orange-950/80 text-orange-400 border-orange-700/50',
icon: <AlertTriangle className={iconSize} aria-hidden="true" />,
},
suspended: {
label: 'Приостановлена',
className: 'bg-rose-950/80 text-rose-400 border-rose-700/50',
icon: <XCircle className={iconSize} aria-hidden="true" />,
},
closed: {
label: 'Закрыта',
className: 'bg-zinc-900 text-zinc-400 border-zinc-700/50',
icon: <XCircle className={iconSize} aria-hidden="true" />,
},
normal: {
label: 'Оплачена',
className: 'bg-emerald-950/80 text-emerald-400 border-emerald-700/50',
icon: <CheckCircle2 className={iconSize} aria-hidden="true" />,
},
overdue: {
label: 'Просрочена',
className: 'bg-rose-950/80 text-rose-400 border-rose-700/50',
icon: <XCircle className={iconSize} aria-hidden="true" />,
},
expiring_7d: {
label: 'Истекает (< 7 дн.)',
className: 'bg-amber-950/80 text-amber-300 border-amber-700/50 font-semibold',
icon: <Clock className={iconSize} aria-hidden="true" />,
},
expiring_30d: {
label: 'Истекает (< 30 дн.)',
className: 'bg-sky-950/80 text-sky-300 border-sky-700/50',
icon: <Clock className={iconSize} aria-hidden="true" />,
},
// Health
healthy: {
label: 'В норме',
className: 'bg-emerald-950/80 text-emerald-400 border-emerald-700/50',
icon: <CheckCircle2 className={iconSize} aria-hidden="true" />,
},
degraded: {
label: 'Деградация',
className: 'bg-amber-950/80 text-amber-400 border-amber-700/50',
icon: <AlertTriangle className={iconSize} aria-hidden="true" />,
},
warning: {
label: 'Предупреждение',
className: 'bg-amber-950/80 text-amber-400 border-amber-700/50',
icon: <AlertTriangle className={iconSize} aria-hidden="true" />,
},
critical: {
label: 'Критический',
className: 'bg-red-950/80 text-red-400 border-red-700/50 font-semibold animate-pulse',
icon: <ShieldAlert className={iconSize} aria-hidden="true" />,
},
offline: {
label: 'Offline / Сбой',
className: 'bg-zinc-900 text-zinc-400 border-zinc-700/60',
icon: <Radio className={iconSize} aria-hidden="true" />,
},
unknown: {
label: 'Неизвестно',
className: 'bg-zinc-900 text-zinc-500 border-zinc-800',
icon: <Radio className={iconSize} aria-hidden="true" />,
},
// Installations
supported: {
label: 'Поддерживается',
className: 'bg-emerald-950/80 text-emerald-400 border-emerald-700/50',
icon: <CheckCircle2 className={iconSize} aria-hidden="true" />,
},
outdated: {
label: 'Устарела',
className: 'bg-amber-950/80 text-amber-300 border-amber-700/50',
icon: <Smartphone className={iconSize} aria-hidden="true" />,
},
blocked: {
label: 'Заблокирована',
className: 'bg-rose-950/80 text-rose-400 border-rose-700/50',
icon: <XCircle className={iconSize} aria-hidden="true" />,
},
revoked: {
label: 'Отозвана',
className: 'bg-zinc-900 text-zinc-400 border-zinc-700',
icon: <XCircle className={iconSize} aria-hidden="true" />,
},
// Rollout
draft: {
label: 'Черновик',
className: 'bg-zinc-900 text-zinc-400 border-zinc-700',
icon: <Clock className={iconSize} aria-hidden="true" />,
},
pilot: {
label: 'Пилот (Pilot)',
className: 'bg-indigo-950/80 text-indigo-300 border-indigo-700/50',
icon: <Zap className={iconSize} aria-hidden="true" />,
},
percentage: {
label: 'Поэтапная',
className: 'bg-sky-950/80 text-sky-300 border-sky-700/50',
icon: <Server className={iconSize} aria-hidden="true" />,
},
general_availability: {
label: 'Релиз (GA)',
className: 'bg-emerald-950/80 text-emerald-400 border-emerald-700/50',
icon: <CheckCircle2 className={iconSize} aria-hidden="true" />,
},
paused: {
label: 'На паузе',
className: 'bg-amber-950/80 text-amber-300 border-amber-700/50',
icon: <AlertTriangle className={iconSize} aria-hidden="true" />,
},
rolled_back: {
label: 'Откатан (Rollback)',
className: 'bg-rose-950/80 text-rose-400 border-rose-700/50',
icon: <XCircle className={iconSize} aria-hidden="true" />,
},
// Incidents
open: {
label: 'Открыт',
className: 'bg-rose-950/80 text-rose-400 border-rose-700/50 font-semibold',
icon: <AlertTriangle className={iconSize} aria-hidden="true" />,
},
mitigating: {
label: 'Митигация',
className: 'bg-amber-950/80 text-amber-300 border-amber-700/50',
icon: <Clock className={iconSize} aria-hidden="true" />,
},
resolved: {
label: 'Разрешен',
className: 'bg-emerald-950/80 text-emerald-400 border-emerald-700/50',
icon: <CheckCircle2 className={iconSize} aria-hidden="true" />,
},
};
const config = configs[status] || configs.unknown;
const label = customLabel || config.label;
return (
<span
className={`inline-flex items-center gap-1.5 rounded-md border font-medium tabular-nums tracking-wide transition-colors ${
isSmall ? 'px-2 py-0.5 text-xs' : 'px-2.5 py-1 text-xs'
} ${config.className}`}
data-status={status}
data-testid="status-badge"
>
{config.icon}
<span>{label}</span>
</span>
);
};