Fix coverage: add /api/coverage route, remove stray gather code from loadCoverage
This commit is contained in:
127
frontend_src/Sidebar.tsx
Normal file
127
frontend_src/Sidebar.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import Plot from 'react-plotly.js';
|
||||
import { Node, DataWindow } from '../types';
|
||||
|
||||
interface SidebarProps {
|
||||
selectedNode: Node | null;
|
||||
dataWindow: DataWindow | null;
|
||||
loading: boolean;
|
||||
sampleRate: number;
|
||||
}
|
||||
|
||||
type ViewMode = 'waveform' | 'rms';
|
||||
|
||||
function Sidebar({ selectedNode, dataWindow, loading, sampleRate }: SidebarProps) {
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('waveform');
|
||||
const [showRaw, setShowRaw] = useState(false);
|
||||
|
||||
const samples = dataWindow?.samples || [];
|
||||
const startTs = dataWindow?.startTimestamp || 0;
|
||||
|
||||
// Calcul RMS glissant
|
||||
const rmsData = useMemo(() => {
|
||||
if (samples.length === 0) return [];
|
||||
const windowSize = 20;
|
||||
const result = [];
|
||||
for (let i = 0; i < samples.length; i++) {
|
||||
const start = Math.max(0, i - windowSize);
|
||||
const window = samples.slice(start, i + 1);
|
||||
const rms = Math.sqrt(window.reduce((a, b) => a + b*b, 0) / window.length);
|
||||
result.push(rms);
|
||||
}
|
||||
return result;
|
||||
}, [samples]);
|
||||
|
||||
// Formatter pour le X (DD hh:mm:ss)
|
||||
const formatXAxis = (ts: number) => {
|
||||
const d = new Date(ts * 1000);
|
||||
const day = d.getDate().toString().padStart(2, '0');
|
||||
const h = d.getHours().toString().padStart(2, '0');
|
||||
const m = d.getMinutes().toString().padStart(2, '0');
|
||||
const s = d.getSeconds().toString().padStart(2, '0');
|
||||
return `${day} ${h}:${m}:${s}`;
|
||||
};
|
||||
|
||||
const xValues = useMemo(() => {
|
||||
return samples.map((_, i) => formatXAxis(startTs + i / sampleRate));
|
||||
}, [samples, startTs, sampleRate]);
|
||||
|
||||
const plotData: any[] = [];
|
||||
if (samples.length > 0) {
|
||||
if (viewMode === 'waveform') {
|
||||
plotData.push({
|
||||
x: xValues,
|
||||
y: samples,
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
name: 'ADC Brute',
|
||||
line: { color: '#4ade80', width: 1.5 }
|
||||
});
|
||||
} else {
|
||||
plotData.push({
|
||||
x: xValues,
|
||||
y: rmsData,
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
name: 'RMS',
|
||||
line: { color: '#fbbf24', width: 2 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="sidebar" style={{ width: '450px', background: '#1e293b', borderLeft: '1px solid #334155', display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<div style={{ padding: '20px', borderBottom: '1px solid #334155' }}>
|
||||
<h2 style={{ margin: 0, color: '#f8fafc' }}>Analyse Node</h2>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, overflowY: 'auto', padding: '20px' }}>
|
||||
{selectedNode ? (
|
||||
<>
|
||||
<div style={{ marginBottom: '20px', background: '#0f172a', padding: '15px', borderRadius: '8px' }}>
|
||||
<h3 style={{ margin: '0 0 10px 0', color: '#38bdf8' }}>Node b{selectedNode.id}</h3>
|
||||
<p style={{ margin: '5px 0', fontSize: '0.9rem' }}>E: {selectedNode.position?.easting.toFixed(0)} N: {selectedNode.position?.northing.toFixed(0)}</p>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: '5px', marginBottom: '15px' }}>
|
||||
<button onClick={() => setViewMode('waveform')} style={{ flex: 1, padding: '8px', background: viewMode === 'waveform' ? '#3b82f6' : '#334155', border: 'none', color: '#fff', borderRadius: '4px', cursor: 'pointer' }}>Waveform (Brute)</button>
|
||||
<button onClick={() => setViewMode('rms')} style={{ flex: 1, padding: '8px', background: viewMode === 'rms' ? '#3b82f6' : '#334155', border: 'none', color: '#fff', borderRadius: '4px', cursor: 'pointer' }}>RMS</button>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<div style={{ textAlign: 'center', padding: '40px', color: '#94a3b8' }}>Chargement…</div>
|
||||
) : samples.length > 0 ? (
|
||||
<>
|
||||
<div style={{ background: '#000', borderRadius: '8px', overflow: 'hidden', height: '300px' }}>
|
||||
<Plot
|
||||
data={plotData}
|
||||
layout={{
|
||||
autosize: true,
|
||||
height: 300,
|
||||
margin: { t: 10, b: 60, l: 50, r: 10 },
|
||||
paper_bgcolor: 'rgba(0,0,0,0)',
|
||||
plot_bgcolor: 'rgba(0,0,0,0)',
|
||||
font: { color: '#94a3b8', size: 10 },
|
||||
xaxis: {
|
||||
gridcolor: '#1e293b',
|
||||
zerolinecolor: '#334155',
|
||||
tickangle: -45,
|
||||
nticks: 5
|
||||
},
|
||||
yaxis: { gridcolor: '#1e293b', zerolinecolor: '#334155', title: 'Amplitude' }
|
||||
}}
|
||||
config={{ responsive: true, displayModeBar: true }}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
{/* Stats... */}
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
export default Sidebar;
|
||||
Reference in New Issue
Block a user