Newer
Older
* Results display component with Material-UI - shows simulation results, analytical results, and comparison.
import { useState } from 'react';
import {
Box,
Tabs,
Tab,
Typography,
CircularProgress,
Alert,
AlertTitle,
Stack,
} from '@mui/material';
import {
Assessment as AssessmentIcon,
BarChart as BarChartIcon,
CompareArrows as CompareArrowsIcon,
} from '@mui/icons-material';
import { useSimulationStore } from '../../store/simulationStore';
import MetricsCard from './MetricsCard';
import ComparisonTable from './ComparisonTable';
import NetworkDiagram from '../visualization/NetworkDiagram';
import UtilizationChart from '../visualization/UtilizationChart';
import MetricsComparisonChart from '../visualization/MetricsComparisonChart';
import TimeSeriesChart from '../visualization/TimeSeriesChart';
import ProcessingTimeHistogram from '../visualization/ProcessingTimeHistogram';
import SteadyStateChart from '../visualization/SteadyStateChart';
export default function ResultsDisplay() {
const {
simulationResults,
analyticalResults,
comparisonResults,
isLoading,
} = useSimulationStore();
const [activeTab, setActiveTab] = useState<number>(0);
if (isLoading) {
return (
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', py: 8 }}>
<CircularProgress size={50} sx={{ mb: 2 }} />
<Typography variant="body1" color="text.secondary">
Calcul en cours...
</Typography>
</Box>
);
}
if (!simulationResults && !analyticalResults) {
return (
<Box sx={{ textAlign: 'center', py: 8 }}>
<AssessmentIcon sx={{ fontSize: 64, color: 'text.disabled', mb: 2 }} />
<Typography variant="h6" gutterBottom>
Aucun résultat disponible
</Typography>
<Typography variant="body2" color="text.secondary">
Lancez une simulation pour voir les résultats
</Typography>
</Box>
);
}
return (
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
<Tabs value={activeTab} onChange={(_, newValue) => setActiveTab(newValue)}>
<Tab icon={<AssessmentIcon />} iconPosition="start" label="Métriques" />
<Tab icon={<BarChartIcon />} iconPosition="start" label="Visualisations" />
<Tab icon={<CompareArrowsIcon />} iconPosition="start" label="Comparaison" />
</Tabs>
</Box>
{/* Stability indicator */}
{(simulationResults || analyticalResults) && (
<Alert
severity={
(simulationResults?.is_stable ?? analyticalResults?.is_stable)
? 'success'
: 'error'
}
sx={{ mb: 3 }}
<AlertTitle>
{(simulationResults?.is_stable ?? analyticalResults?.is_stable)
? 'Système stable'
: 'Système instable'}
</AlertTitle>
{!simulationResults?.is_stable && simulationResults?.stability_notes && (
<Typography variant="body2">
{simulationResults.stability_notes}
</Typography>
)}
{!analyticalResults?.is_stable && analyticalResults?.instability_reason && (
<Typography variant="body2">
{analyticalResults.instability_reason}
</Typography>
)}
</Alert>
{activeTab === 0 && (
<Stack spacing={4}>
{/* Simulation results */}
{simulationResults && (
<Box>
<Typography variant="h6" gutterBottom sx={{ fontWeight: 600 }}>
Résultats de simulation
</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 2, mb: 3 }}>
<MetricsCard
title="Total requêtes"
value={simulationResults.total_requests_completed}
unit="requêtes"
/>
<MetricsCard
title="Temps moyen dans le système"
value={simulationResults.average_system_time}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
{/* Coordinator stats */}
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
Coordinateur
</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
<MetricsCard
title="Utilisation (ρ)"
value={simulationResults.coordinator_stats.utilization}
decimals={4}
compact
/>
<MetricsCard
title="Temps d'attente"
value={simulationResults.coordinator_stats.average_wait_time}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
<MetricsCard
title="Temps de service"
value={simulationResults.coordinator_stats.average_service_time}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
<MetricsCard
title="Temps système"
value={simulationResults.coordinator_stats.average_system_time}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
</Box>
</Box>
{/* Server stats */}
{Object.entries(simulationResults.server_stats).map(([serverId, stats]) => (
<Box key={serverId} sx={{ mb: 3 }}>
<Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
{serverId.replace('_', ' ').charAt(0).toUpperCase() +
serverId.replace('_', ' ').slice(1)}
</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
<MetricsCard
title="Utilisation (ρ)"
value={stats.utilization}
decimals={4}
compact
/>
<MetricsCard
title="Temps d'attente"
value={stats.average_wait_time}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
<MetricsCard
title="Temps de service"
value={stats.average_service_time}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
<MetricsCard
title="Temps système"
value={stats.average_system_time}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
</Box>
</Box>
))}
</Box>
)}
{/* Analytical results */}
{analyticalResults && (
<Box>
<Typography variant="h6" gutterBottom sx={{ fontWeight: 600 }}>
Résultats analytiques (Théorème de Jackson)
</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: '1fr 1fr' }, gap: 2, mb: 3 }}>
<MetricsCard
title="Nombre moyen de clients (L)"
value={analyticalResults.total_average_customers}
decimals={4}
/>
<MetricsCard
title="Temps moyen (W)"
value={analyticalResults.total_average_time}
decimals={timeUnit === 's' ? 3 : 2}
unit={timeUnit}
</Box>
{/* Coordinator analytics */}
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
Coordinateur
</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
<MetricsCard
title="Utilisation (ρ)"
value={analyticalResults.coordinator.utilization}
decimals={4}
compact
/>
<MetricsCard
title="L"
value={analyticalResults.coordinator.average_customers ?? 0}
decimals={4}
compact
/>
<MetricsCard
title="W"
value={analyticalResults.coordinator.average_time ?? 0}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
<MetricsCard
title="Wq"
value={analyticalResults.coordinator.average_wait_time ?? 0}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
compact
/>
</Box>
</Box>
{/* Server analytics */}
{Object.entries(analyticalResults.servers).map(([serverId, analytics]) => (
<Box key={serverId} sx={{ mb: 3 }}>
<Typography variant="subtitle2" color="text.secondary" gutterBottom sx={{ fontWeight: 600 }}>
{serverId.replace('_', ' ').charAt(0).toUpperCase() +
serverId.replace('_', ' ').slice(1)}
</Typography>
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr 1fr', md: 'repeat(4, 1fr)' }, gap: 1.5 }}>
<MetricsCard
title="Utilisation (ρ)"
value={analytics.utilization}
decimals={4}
compact
/>
<MetricsCard
title="L"
value={analytics.average_customers ?? 0}
decimals={4}
compact
/>
<MetricsCard
title="W"
value={analytics.average_time ?? 0}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
<MetricsCard
title="Wq"
value={analytics.average_wait_time ?? 0}
unit={timeUnit}
decimals={timeUnit === 's' ? 3 : 2}
compact
/>
</Box>
</Box>
))}
</Box>
)}
</Stack>
)}
{/* Visualizations Tab */}
{activeTab === 1 && (
<Stack spacing={4}>
{/* Steady state detection chart */}
{simulationResults?.time_series && config && (
<Box>
<SteadyStateChart warmupTime={config.warmup_time} />
</Box>
)}
{/* Time series chart */}
{simulationResults?.time_series && (
<Box>
<TimeSeriesChart timeSeriesData={simulationResults.time_series} />
</Box>
)}
{/* Processing time histogram */}
{simulationResults?.processing_time_histogram && (
<Box>
<ProcessingTimeHistogram histogramData={simulationResults.processing_time_histogram} />
</Box>
)}
{/* Network diagram */}
{config && (
<NetworkDiagram config={config} />
)}
{/* Utilization chart */}
{(simulationResults || analyticalResults) && (
<UtilizationChart
simulationResults={simulationResults}
analyticalResults={analyticalResults}
/>
)}
{/* Metrics charts */}
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', lg: '1fr 1fr' }, gap: 3 }}>
{analyticalResults && (
<MetricsComparisonChart
simulationResults={simulationResults}
analyticalResults={analyticalResults}
metric="L"
/>
)}
{(simulationResults || analyticalResults) && (
<MetricsComparisonChart
simulationResults={simulationResults}
analyticalResults={analyticalResults}
metric="W"
/>
)}
</Box>
</Stack>
)}
{/* Comparison Tab */}
{activeTab === 2 && (
<Stack spacing={4}>
{comparisonResults ? (
<>
<Box>
<Typography variant="h6" gutterBottom sx={{ fontWeight: 600 }}>
Comparaison Analytique vs Simulation
<ComparisonTable comparison={comparisonResults} />
{/* Visualization of comparison */}
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', lg: '1fr 1fr' }, gap: 3 }}>
<UtilizationChart
simulationResults={simulationResults}
analyticalResults={analyticalResults}
/>
<MetricsComparisonChart
simulationResults={simulationResults}
analyticalResults={analyticalResults}
metric="W"
/>
<Box sx={{ textAlign: 'center', py: 8 }}>
<Typography variant="body1" color="text.secondary">
Lancez une simulation pour voir la comparaison avec les résultats analytiques
</Typography>
</Box>