Commit inicial - upload de todos os arquivos da pasta
This commit is contained in:
98
src/pages/admin/api-keys/ApiKeyTable.tsx
Normal file
98
src/pages/admin/api-keys/ApiKeyTable.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
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>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user