225 lines
8.2 KiB
React
225 lines
8.2 KiB
React
// [TSM.ID].[11031972] -- All Rights Reserved. Proprietary & Confidential.
|
|
import { useEffect, useRef, useState } from 'react';
|
|
import { useAuth } from '../context/AuthContext';
|
|
import { useIam } from '../context/IamContext';
|
|
import { useWasm } from '../context/WasmContext';
|
|
import { useI18n } from '../context/I18nContext';
|
|
|
|
function useNeuralTelemetry() {
|
|
const [data, setData] = useState({
|
|
cpu_usage: 0,
|
|
ram_usage: 0,
|
|
active_connections: 0,
|
|
threats_blocked: 0,
|
|
status: 'SECURE'
|
|
});
|
|
|
|
useEffect(() => {
|
|
let sse;
|
|
const connect = () => {
|
|
// Menghubungkan ke Rust Backend yang sebenarnya
|
|
sse = new EventSource('/api/v1/telemetry/stream');
|
|
|
|
sse.onmessage = (event) => {
|
|
try {
|
|
const payload = JSON.parse(event.data);
|
|
setData(payload);
|
|
} catch (err) {
|
|
console.error("Neural Link Parse Error:", err);
|
|
}
|
|
};
|
|
|
|
sse.onerror = () => {
|
|
sse.close();
|
|
setTimeout(connect, 5000);
|
|
};
|
|
};
|
|
|
|
connect();
|
|
|
|
return () => {
|
|
if (sse) sse.close();
|
|
};
|
|
}, []);
|
|
|
|
return data;
|
|
}
|
|
|
|
export default function DashboardOverview() {
|
|
const canvasRef = useRef(null);
|
|
const { cryptographicKey } = useAuth();
|
|
const { identity } = useIam();
|
|
const { isWasmReady, wasmLogs, triggerPostQuantumShield, triggerAegisMatrix } = useWasm();
|
|
const { t } = useI18n();
|
|
const telemetry = useNeuralTelemetry();
|
|
|
|
// Quantum Particle Engine (Zero React Overhead Canvas)
|
|
useEffect(() => {
|
|
const canvas = canvasRef.current;
|
|
if (!canvas) return;
|
|
const ctx = canvas.getContext('2d');
|
|
|
|
let animationFrameId;
|
|
let particles = [];
|
|
const numParticles = 150;
|
|
|
|
for(let i=0; i < numParticles; i++) {
|
|
particles.push({
|
|
x: Math.random() * canvas.width,
|
|
y: Math.random() * canvas.height,
|
|
vx: (Math.random() - 0.5) * 3,
|
|
vy: (Math.random() - 0.5) * 3,
|
|
baseSize: Math.random() * 2 + 1
|
|
});
|
|
}
|
|
|
|
const render = () => {
|
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
const speedMultiplier = 1.0 + (telemetry.cpu_usage / 5.0);
|
|
|
|
particles.forEach(p => {
|
|
p.x += p.vx * speedMultiplier;
|
|
p.y += p.vy * speedMultiplier;
|
|
|
|
if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
|
|
if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
|
|
|
|
ctx.beginPath();
|
|
ctx.arc(p.x, p.y, p.baseSize, 0, Math.PI * 2);
|
|
|
|
ctx.fillStyle = identity.role === 'supreme_admin' ? '#00f3ff' : '#a855f7';
|
|
ctx.fill();
|
|
|
|
particles.forEach(p2 => {
|
|
const dx = p.x - p2.x;
|
|
const dy = p.y - p2.y;
|
|
const dist = Math.sqrt(dx*dx + dy*dy);
|
|
|
|
if(dist < 60) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(p.x, p.y);
|
|
ctx.lineTo(p2.x, p2.y);
|
|
if (identity.role === 'supreme_admin') {
|
|
ctx.strokeStyle = `rgba(0, 243, 255, ${1 - dist/60})`;
|
|
} else {
|
|
ctx.strokeStyle = `rgba(168, 85, 247, ${1 - dist/60})`;
|
|
}
|
|
ctx.lineWidth = 1;
|
|
ctx.stroke();
|
|
}
|
|
});
|
|
});
|
|
|
|
animationFrameId = requestAnimationFrame(render);
|
|
};
|
|
|
|
render();
|
|
|
|
return () => cancelAnimationFrame(animationFrameId);
|
|
}, [telemetry.cpu_usage, identity.role]);
|
|
|
|
return (
|
|
<div>
|
|
<div className="grid-cards">
|
|
<div className="glass-panel stat-card">
|
|
<div className="stat-title">{t('active_vvip')}</div>
|
|
<div className="stat-value cyan">{telemetry.active_connections.toLocaleString()}</div>
|
|
<div style={{marginTop: '15px', fontSize: '0.85rem', color: 'var(--accent-cyan)', fontFamily: 'monospace'}}>
|
|
{t('cpu_load').replace('{val}', telemetry.cpu_usage.toFixed(1))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="glass-panel stat-card">
|
|
<div className="stat-title">{t('threats_annihilated')}</div>
|
|
<div className="stat-value red">{telemetry.threats_blocked.toLocaleString()}</div>
|
|
<div style={{marginTop: '15px', fontSize: '0.85rem', color: 'var(--accent-red)', fontFamily: 'monospace'}}>
|
|
{t('ram_active').replace('{val}', telemetry.ram_usage.toFixed(1))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="glass-panel stat-card" style={{borderColor: 'var(--accent-green)'}}>
|
|
<div className="stat-title">{t('session_auth')}</div>
|
|
<div className="stat-value green" style={{fontSize: '1.5rem', wordBreak: 'break-all'}}>
|
|
{cryptographicKey ? cryptographicKey.substring(0, 16) + '...' : t('unauthorized')}
|
|
</div>
|
|
<div style={{marginTop: '15px', fontSize: '0.85rem', color: 'var(--accent-green)', fontFamily: 'monospace'}}>
|
|
{t('access_level')} {identity.role === 'supreme_admin' ? 'SUPREME ADMIN' : 'TENANT GATEWAY'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* QUANTUM ARSENAL PANEL (Only for Supreme Admin) */}
|
|
{identity.role === 'supreme_admin' && (
|
|
<div className="glass-panel" style={{padding: '30px', marginTop: '30px', borderColor: 'var(--accent-cyan)'}}>
|
|
<div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px'}}>
|
|
<h3 style={{color: 'var(--text-main)', fontFamily: 'monospace', letterSpacing: '2px'}}>{t('quantum_arsenal')}</h3>
|
|
<span className={`badge ${isWasmReady ? 'active' : 'revoked'}`}>
|
|
{isWasmReady ? t('wasm_online') : t('wasm_compiling')}
|
|
</span>
|
|
</div>
|
|
|
|
<div style={{display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px', marginBottom: '20px'}}>
|
|
<button
|
|
onClick={triggerPostQuantumShield}
|
|
disabled={!isWasmReady}
|
|
className="btn-primary"
|
|
style={{padding: '20px', fontSize: '1.1rem'}}
|
|
>
|
|
{t('engage_shield')}
|
|
<div style={{fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '10px', textTransform: 'none'}}>
|
|
Kyber-1024 Lattice Cryptography
|
|
</div>
|
|
</button>
|
|
<button
|
|
onClick={triggerAegisMatrix}
|
|
disabled={!isWasmReady}
|
|
className="btn-primary"
|
|
style={{padding: '20px', fontSize: '1.1rem', borderColor: 'var(--accent-blue)', color: 'var(--accent-blue)'}}
|
|
>
|
|
{t('engage_watermark')}
|
|
<div style={{fontSize: '0.7rem', color: 'var(--text-muted)', marginTop: '10px', textTransform: 'none'}}>
|
|
1% Opacity Microscopic Morse Flash
|
|
</div>
|
|
</button>
|
|
</div>
|
|
|
|
<div style={{background: 'var(--panel-bg)', padding: '15px', borderRadius: '8px', minHeight: '150px', maxHeight: '200px', overflowY: 'auto', border: '1px solid var(--table-border)', fontFamily: 'monospace', fontSize: '0.85rem', color: 'var(--accent-cyan)'}}>
|
|
<div style={{color: 'var(--text-muted)', marginBottom: '10px'}}>{t('wasm_logs')}</div>
|
|
{wasmLogs.length === 0 && <div style={{color: 'var(--text-main)'}}>{t('awaiting_command')}</div>}
|
|
{wasmLogs.map((log, i) => (
|
|
<div key={i} style={{marginBottom: '5px'}}>{log}</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="glass-panel" style={{padding: '30px', minHeight: '350px', marginTop: '30px', position: 'relative'}}>
|
|
<h3 style={{marginBottom: '25px', color: 'var(--text-main)', fontFamily: 'monospace', letterSpacing: '2px', borderBottom: '1px solid var(--glass-border)', paddingBottom: '15px'}}>
|
|
{t('global_routing')}
|
|
</h3>
|
|
<div style={{
|
|
width: '100%',
|
|
height: '300px',
|
|
background: 'var(--panel-bg)',
|
|
borderRadius: '12px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
overflow: 'hidden',
|
|
border: '1px solid var(--glass-border)',
|
|
boxShadow: 'inset 0 0 30px var(--glass-glow)'
|
|
}}>
|
|
<canvas
|
|
ref={canvasRef}
|
|
width={1000}
|
|
height={300}
|
|
style={{ width: '100%', height: '100%' }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|