feat: Initial commit for OnEver Drive centralized backup system with Windows PyQt6 agent and Proxmox LXC deployment

This commit is contained in:
2026-08-13 19:33:44 -03:00
commit 1bfb808c79
77 changed files with 10675 additions and 0 deletions
@@ -0,0 +1,90 @@
import React from 'react';
import { UploadCloud, CheckCircle2, AlertTriangle } from 'lucide-react';
export interface ActiveUpload {
session_code: string;
filename: string;
client_id: number;
chunk_index: number;
received_chunks: number;
total_chunks: number;
progress_percent: number;
status?: string;
speed_mb?: number;
}
interface LiveTransferMeterProps {
uploads: ActiveUpload[];
}
export const LiveTransferMeter: React.FC<LiveTransferMeterProps> = ({ uploads }) => {
if (uploads.length === 0) {
return (
<div className="glass-card" style={{ marginBottom: '28px', textAlign: 'center', padding: '32px 20px' }}>
<UploadCloud size={32} color="var(--text-dim)" style={{ margin: '0 auto 10px auto' }} />
<h4 style={{ fontSize: '0.95rem', fontWeight: 600, color: 'var(--text-muted)' }}>Sin transferencias activas</h4>
<p style={{ fontSize: '0.8rem', color: 'var(--text-dim)', marginTop: '4px' }}>
Los agentes Windows transmitirán bloques de archivos automáticamente según sus trabajos programados.
</p>
</div>
);
}
return (
<div className="glass-card" style={{ marginBottom: '28px', border: '1px solid rgba(6, 182, 212, 0.3)' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '16px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<div className="pulse-dot" />
<h3 style={{ fontSize: '1rem', fontWeight: 700 }}>Transferencias en Vivo ({uploads.length})</h3>
</div>
<span className="badge badge-syncing">Motor de Chunks Activo</span>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
{uploads.map((upload) => {
const isComplete = upload.progress_percent >= 100;
return (
<div
key={upload.session_code}
style={{
background: 'rgba(0,0,0,0.3)',
padding: '16px',
borderRadius: 'var(--radius-md)',
border: '1px solid var(--border-color)',
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
<div>
<span style={{ fontWeight: 600, fontSize: '0.92rem', color: '#fff' }}>
{upload.filename}
</span>
<span style={{ fontSize: '0.78rem', color: 'var(--text-muted)', marginLeft: '12px' }}>
Cliente #{upload.client_id}
</span>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<span style={{ fontFamily: 'var(--font-mono)', fontSize: '0.85rem', color: 'var(--accent-cyan)', fontWeight: 600 }}>
{upload.received_chunks} / {upload.total_chunks} Chunks ({upload.progress_percent}%)
</span>
{isComplete && <CheckCircle2 size={16} color="var(--accent-emerald)" />}
</div>
</div>
<div className="progress-track" style={{ height: '10px' }}>
<div
className={`progress-fill ${isComplete ? '' : 'animated'}`}
style={{ width: `${Math.min(100, upload.progress_percent)}%` }}
/>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '0.74rem', color: 'var(--text-dim)', marginTop: '6px' }}>
<span>Sesión: {upload.session_code.substring(0, 18)}...</span>
<span>{isComplete ? 'Ensamblando & Verificando SHA-256...' : 'Transmitiendo bloques de 4 MB'}</span>
</div>
</div>
);
})}
</div>
</div>
);
};