ParameterPanel.tsx 7,64 ko
Newer Older
/**
 * Parameter panel - input fields for simulation configuration.
 */
import { useSimulationStore } from '../../store/simulationStore';

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

  if (!config) {
    return (
      <div className="text-sm text-gray-500 text-center py-4">
        Aucune configuration chargée
      </div>
    );
  }

  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 (
    <div className="space-y-4">
      <div className="border-t border-gray-200 pt-4">
        <h3 className="text-sm font-medium text-gray-700 mb-3">
          Paramètres du réseau
        </h3>

        {/* External arrival rate */}
        <div className="mb-4">
          <label className="block text-xs font-medium text-gray-600 mb-1">
            Taux d'arrivée externe (λ)
          </label>
          <input
            type="number"
            step="0.001"
            min="0"
            value={config.arrival_rate}
            onChange={handleArrivalRateChange}
            disabled={isRunning}
            className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 text-sm disabled:bg-gray-100"
          />
          <p className="text-xs text-gray-500 mt-1">
            Requêtes par unité de temps
          </p>
        </div>

        {/* Coordinator parameters */}
        <div className="mb-4">
          <h4 className="text-xs font-semibold text-gray-700 mb-2 uppercase">
            Coordinateur
          </h4>

          <div className="space-y-3">
            <div>
              <label className="block text-xs font-medium text-gray-600 mb-1">
                Taux de service (μc)
              </label>
              <input
                type="number"
                step="0.01"
                min="0"
                value={config.coordinator_service_rate}
                onChange={handleCoordinatorServiceRateChange}
                disabled={isRunning}
                className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 text-sm disabled:bg-gray-100"
              />
            </div>

            <div>
              <label className="block text-xs font-medium text-gray-600 mb-1">
                Probabilité de sortie (p)
              </label>
              <input
                type="number"
                step="0.01"
                min="0"
                max="1"
                value={config.coordinator_exit_probability}
                onChange={handleExitProbabilityChange}
                disabled={isRunning}
                className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 text-sm disabled:bg-gray-100"
              />
            </div>
          </div>
        </div>

        {/* Servers */}
        <div className="mb-4">
          <div className="flex items-center justify-between mb-2">
            <h4 className="text-xs font-semibold text-gray-700 uppercase">
              Serveurs
            </h4>
            <button
              onClick={addServer}
              disabled={isRunning}
              className="text-xs text-blue-600 hover:text-blue-700 disabled:text-gray-400 font-medium"
            >
              + Ajouter serveur
            </button>
          </div>

          <div className="space-y-3">
            {config.servers.map((server, index) => (
              <div
                key={server.id}
                className="border border-gray-200 rounded-md p-3 bg-gray-50"
              >
                <div className="flex items-center justify-between mb-2">
                  <span className="text-xs font-medium text-gray-700">
                    Serveur {index + 1}
                  </span>
                  {config.servers.length > 1 && (
                    <button
                      onClick={() => removeServer(server.id)}
                      disabled={isRunning}
                      className="text-xs text-red-600 hover:text-red-700 disabled:text-gray-400"
                    >
                      Supprimer
                    </button>
                  )}
                </div>

                <div className="space-y-2">
                  <div>
                    <label className="block text-xs text-gray-600 mb-1">
                      Taux de service (μ{index + 1})
                    </label>
                    <input
                      type="number"
                      step="0.001"
                      min="0"
                      value={server.service_rate}
                      onChange={(e) =>
                        handleServerServiceRateChange(server.id, e.target.value)
                      }
                      disabled={isRunning}
                      className="block w-full px-2 py-1 border border-gray-300 rounded text-sm disabled:bg-gray-100"
                    />
                  </div>

                  <div>
                    <label className="block text-xs text-gray-600 mb-1">
                      Probabilité de routage (q{index + 1})
                    </label>
                    <input
                      type="number"
                      step="0.01"
                      min="0"
                      max="1"
                      value={server.routing_probability}
                      onChange={(e) =>
                        handleServerRoutingProbChange(server.id, e.target.value)
                      }
                      disabled={isRunning}
                      className="block w-full px-2 py-1 border border-gray-300 rounded text-sm disabled:bg-gray-100"
                    />
                  </div>
                </div>
              </div>
            ))}
          </div>
        </div>

        {/* Probability validation */}
        <div
          className={`p-3 rounded-md text-xs ${
            isProbabilityValid
              ? 'bg-green-50 border border-green-200 text-green-800'
              : 'bg-red-50 border border-red-200 text-red-800'
          }`}
        >
          <div className="flex items-center justify-between">
            <span className="font-medium">
              Conservation des probabilités
            </span>
            <span className="font-mono">
              {isProbabilityValid ? '' : ''}
            </span>
          </div>
          <div className="mt-1 font-mono">
            p + Σq = {totalRoutingProb.toFixed(3)}
            {isProbabilityValid ? ' = 1.0' : ' ≠ 1.0'}
          </div>
        </div>
      </div>
    </div>
  );
}