ParameterPanel.tsx 6,34 ko
Newer Older
 * Parameter panel with Material-UI - input fields for simulation configuration
import {
  Box,
  TextField,
  Typography,
  Divider,
  Button,
  IconButton,
  Paper,
  Alert,
  Stack,
} from '@mui/material';
import {
  Add as AddIcon,
  Delete as DeleteIcon,
  CheckCircle as CheckCircleIcon,
  Error as ErrorIcon,
} from '@mui/icons-material';
import { useSimulationStore } from '../../store/simulationStore';

export default function ParameterPanel() {
  const {
    config,
    updateConfig,
    addServer,
    removeServer,
    updateServer,
    isRunning,
  } = useSimulationStore();

  if (!config) {
    return (
      <Typography variant="body2" color="text.secondary" textAlign="center" py={3}>
        Aucune configuration chargée
    );
  }

  const handleArrivalRateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    updateConfig({ arrival_rate: parseFloat(e.target.value) || 0 });
  };

  const handleCoordinatorServiceRateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    updateConfig({ coordinator_service_rate: parseFloat(e.target.value) || 0 });
  };

  const handleExitProbabilityChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    updateConfig({ coordinator_exit_probability: parseFloat(e.target.value) || 0 });
  };

  const handleServerServiceRateChange = (serverId: string, value: string) => {
    updateServer(serverId, { service_rate: parseFloat(value) || 0 });
  };

  const handleServerRoutingProbChange = (serverId: string, value: string) => {
    updateServer(serverId, { routing_probability: parseFloat(value) || 0 });
  };

  // Calculate total routing probability
  const totalRoutingProb =
    config.coordinator_exit_probability +
    config.servers.reduce((sum, s) => sum + s.routing_probability, 0);

  const isProbabilityValid = Math.abs(totalRoutingProb - 1.0) < 0.001;

  return (
    <Box>
      <Divider sx={{ my: 2 }} />
      <Typography variant="subtitle2" fontWeight={600} gutterBottom>
        Paramètres du réseau
      </Typography>

      <Stack spacing={2} sx={{ mt: 2 }}>
        {/* External arrival rate */}
        <TextField
          label="Taux d'arrivée externe (λ)"
          type="number"
          inputProps={{ step: 0.001, min: 0 }}
          value={config.arrival_rate}
          onChange={handleArrivalRateChange}
          disabled={isRunning}
          fullWidth
          size="small"
          helperText="Requêtes par unité de temps"
        />

        {/* Coordinator parameters */}
        <Box>
          <Typography variant="caption" fontWeight={600} color="text.secondary" sx={{ textTransform: 'uppercase' }}>
          </Typography>
          <Stack spacing={1.5} sx={{ mt: 1 }}>
            <TextField
              label="Taux de service (μc)"
              type="number"
              inputProps={{ step: 0.01, min: 0 }}
              value={config.coordinator_service_rate}
              onChange={handleCoordinatorServiceRateChange}
              disabled={isRunning}
              fullWidth
              size="small"
            />
            <TextField
              label="Probabilité de sortie (p)"
              type="number"
              inputProps={{ step: 0.01, min: 0, max: 1 }}
              value={config.coordinator_exit_probability}
              onChange={handleExitProbabilityChange}
              disabled={isRunning}
              fullWidth
              size="small"
            />
          </Stack>
        </Box>
        <Box>
          <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
            <Typography variant="caption" fontWeight={600} color="text.secondary" sx={{ textTransform: 'uppercase' }}>
            </Typography>
            <Button
              size="small"
              startIcon={<AddIcon />}
              onClick={addServer}
              disabled={isRunning}
            >
            {config.servers.map((server, index) => (
              <Paper key={server.id} variant="outlined" sx={{ p: 1.5 }}>
                <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
                  <Typography variant="caption" fontWeight={600}>
                  {config.servers.length > 1 && (
                      onClick={() => removeServer(server.id)}
                      disabled={isRunning}
                      <DeleteIcon fontSize="small" />
                    </IconButton>
                </Box>

                <Stack spacing={1}>
                  <TextField
                    label={`Taux de service (μ${index + 1})`}
                    type="number"
                    inputProps={{ step: 0.001, min: 0 }}
                    value={server.service_rate}
                    onChange={(e) => handleServerServiceRateChange(server.id, e.target.value)}
                    disabled={isRunning}
                    fullWidth
                    size="small"
                  />
                  <TextField
                    label={`Probabilité de routage (q${index + 1})`}
                    type="number"
                    inputProps={{ step: 0.01, min: 0, max: 1 }}
                    value={server.routing_probability}
                    onChange={(e) => handleServerRoutingProbChange(server.id, e.target.value)}
                    disabled={isRunning}
                    fullWidth
                    size="small"
                  />
                </Stack>
              </Paper>
        <Alert
          severity={isProbabilityValid ? 'success' : 'error'}
          icon={isProbabilityValid ? <CheckCircleIcon /> : <ErrorIcon />}
          <Typography variant="caption" fontWeight={600}>
            Conservation des probabilités
          </Typography>
          <Typography variant="caption" component="div">
            p + Σq = {totalRoutingProb.toFixed(3)}
            {isProbabilityValid ? ' = 1.0 ✓' : ' ≠ 1.0 ✗'}
          </Typography>
        </Alert>
      </Stack>
    </Box>