99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
import { Ban } from 'lucide-react';
|
|
import { Badge, Button, DataTable, Tooltip } from '../../../components/ui';
|
|
import { SCOPE_LABELS, type ApiKey } from '../../../modules/api-keys';
|
|
|
|
interface ApiKeyTableProps {
|
|
data: ApiKey[];
|
|
isLoading: boolean;
|
|
onRevoke: (key: ApiKey) => void;
|
|
}
|
|
|
|
function formatDate(value: string | null): string {
|
|
if (!value) return '—';
|
|
const date = new Date(value);
|
|
return date.toLocaleString('pt-BR', { dateStyle: 'short', timeStyle: 'short' });
|
|
}
|
|
|
|
export function ApiKeyTable({ data, isLoading, onRevoke }: ApiKeyTableProps) {
|
|
return (
|
|
<DataTable<ApiKey>
|
|
data={data}
|
|
isLoading={isLoading}
|
|
emptyMessage="Nenhuma API Key emitida."
|
|
rowKey="id"
|
|
columns={[
|
|
{
|
|
key: 'name',
|
|
header: 'Nome',
|
|
render: (k) => (
|
|
<span className={k.isActive ? 'text-primary' : 'text-text-muted line-through'}>
|
|
{k.name}
|
|
</span>
|
|
),
|
|
},
|
|
{
|
|
key: 'scopes',
|
|
header: 'Escopos',
|
|
render: (k) => (
|
|
<div className="flex flex-wrap gap-1">
|
|
{k.scopes.map((scope) => (
|
|
<Badge key={scope} variant="info">
|
|
{SCOPE_LABELS[scope] ?? scope}
|
|
</Badge>
|
|
))}
|
|
</div>
|
|
),
|
|
},
|
|
{
|
|
key: 'lastFourChars',
|
|
header: 'Chave',
|
|
render: (k) => (
|
|
<code className="font-mono text-small text-text-secondary">
|
|
••••••{k.lastFourChars}
|
|
</code>
|
|
),
|
|
},
|
|
{
|
|
key: 'isActive',
|
|
header: 'Status',
|
|
render: (k) => (
|
|
<Badge variant={k.isActive ? 'success' : 'danger'}>
|
|
{k.isActive ? 'Ativa' : 'Revogada'}
|
|
</Badge>
|
|
),
|
|
},
|
|
{
|
|
key: 'expiresAt',
|
|
header: 'Expiração',
|
|
render: (k) => <span className="text-text-secondary">{formatDate(k.expiresAt)}</span>,
|
|
},
|
|
{
|
|
key: 'lastUsedAt',
|
|
header: 'Último uso',
|
|
render: (k) => <span className="text-text-secondary">{formatDate(k.lastUsedAt)}</span>,
|
|
},
|
|
{
|
|
key: 'actions',
|
|
header: 'Ações',
|
|
render: (k) =>
|
|
k.isActive ? (
|
|
<Tooltip content="Revogar">
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={() => onRevoke(k)}
|
|
className="text-danger hover:text-danger/80"
|
|
aria-label="Revogar"
|
|
>
|
|
<Ban size={14} />
|
|
</Button>
|
|
</Tooltip>
|
|
) : (
|
|
<span className="text-text-muted text-small">—</span>
|
|
),
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
}
|