import React, { useState } from 'react'; import { Plus, HardDrive, Copy, Check, ShieldAlert, Trash2, Laptop, Server as ServerIcon, X, Edit2, RefreshCw } from 'lucide-react'; import { ClientItem, api } from '../services/api'; interface ClientsViewProps { clients: ClientItem[]; onRefresh: () => void; } export const ClientsView: React.FC = ({ clients, onRefresh }) => { const [showModal, setShowModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [editingClient, setEditingClient] = useState(null); const [editAlias, setEditAlias] = useState(''); const [editQuotaGb, setEditQuotaGb] = useState(100); const [clientHint, setClientHint] = useState(''); const [generatedCode, setGeneratedCode] = useState<{ code: string; expires_at: string } | null>(null); const [isCopied, setIsCopied] = useState(false); const [loading, setLoading] = useState(false); const formatBytes = (bytes: number) => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; const handleGenerateCode = async (e: React.FormEvent) => { e.preventDefault(); setLoading(true); try { const res = await api.createRegistrationCode(clientHint); setGeneratedCode(res); } catch (err: any) { alert(`Error generating registration code: ${err.message}`); } finally { setLoading(false); } }; const handleRevoke = async (client: ClientItem) => { if (confirm(`¿Estás seguro de revocar las credenciales para el cliente ${client.name} (${client.client_code})?`)) { try { await api.revokeClient(client.id); onRefresh(); } catch (err: any) { alert(`Error: ${err.message}`); } } }; const handleDelete = async (client: ClientItem) => { if (confirm(`¿Eliminar definitivamente el cliente ${client.name} y todos sus registros?`)) { try { await api.deleteClient(client.id); onRefresh(); } catch (err: any) { alert(`Error: ${err.message}`); } } }; const handleReRegister = async (client: ClientItem) => { if (confirm(`¿Estás seguro de que deseas volver a generar el código de vinculación para el cliente "${client.name}"?\n\nEsto revocará de inmediato los tokens de acceso actuales del equipo.`)) { setLoading(true); try { const codeData = await api.generateReRegisterCode(client.id); setGeneratedCode(codeData); setShowModal(true); } catch (err: any) { alert(`Error al generar código de re-vinculación: ${err.message}`); } finally { setLoading(false); } } }; const handleOpenEditModal = (client: ClientItem) => { setEditingClient(client); setEditAlias(client.alias || ''); setEditQuotaGb(Math.round(client.storage_quota_bytes / (1024 * 1024 * 1024))); setShowEditModal(true); }; const handleSaveEdit = async (e: React.FormEvent) => { e.preventDefault(); if (!editingClient) return; setLoading(true); try { const quotaBytes = editQuotaGb * 1024 * 1024 * 1024; await api.updateClient(editingClient.id, { alias: editAlias.trim(), storage_quota_bytes: quotaBytes }); setShowEditModal(false); onRefresh(); } catch (err: any) { alert(`Error al actualizar cliente: ${err.message}`); } finally { setLoading(false); } }; const serverUrl = window.location.origin; const psCommand = generatedCode ? `python agent_cli.py register --server "${serverUrl}" --code "${generatedCode.code}"` : ''; const copyToClipboard = (text: string) => { navigator.clipboard.writeText(text); setIsCopied(true); setTimeout(() => setIsCopied(false), 2000); }; return (

Clientes Windows Registrados

Administración centralizada de agentes Windows 10, 11 y Windows Server

{clients.map((client) => { const isOnline = client.status === 'ONLINE'; return ( ); })} {clients.length === 0 && ( )}
Cliente ID Nombre / Hostname Ubicación / Alias Sistema Operativo Dirección IP Estado Espacio Utilizado Última Conexión Acciones
{client.client_code}
{client.os_info?.includes('Server') ? ( ) : ( )}
{client.name}
{client.hostname || 'Desconocido'} • v{client.agent_version}
{client.alias || '—'} {client.os_info || 'Windows'} {client.ip_address || '—'} {client.status}
{formatBytes(client.storage_used_bytes)}
de {formatBytes(client.storage_quota_bytes)}
{client.last_seen_at ? new Date(client.last_seen_at).toLocaleString() : 'Nunca'}
No hay clientes Windows registrados. Haz clic en "Registrar Nuevo Cliente" para comenzar.
{/* Registration Modal */} {showModal && (

Registrar Agente Windows

{!generatedCode ? (
setClientHint(e.target.value)} />

Se generará un código de un solo uso válido por 48 horas.

) : (
Código de Registro Único
{generatedCode.code}
Expira: {new Date(generatedCode.expires_at).toLocaleString()}
{psCommand}
)}
)} {/* Edit Client Modal */} {showEditModal && editingClient && (

Editar Cliente — {editingClient.client_code}

setEditAlias(e.target.value)} />
setEditQuotaGb(Number(e.target.value))} />
)}
); };