ExportButton.tsx 3,89 ko
Newer Older
/**
 * Export button component - export results to CSV/JSON.
 */
import { useSimulationStore } from '../../store/simulationStore';

export default function ExportButton() {
  const { config, simulationResults, analyticalResults, comparisonResults } =
    useSimulationStore();

  const exportToJSON = () => {
    const data = {
      config,
      simulationResults,
      analyticalResults,
      comparisonResults,
      timestamp: new Date().toISOString(),
    };

    const blob = new Blob([JSON.stringify(data, null, 2)], {
      type: 'application/json',
    });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `simulation-results-${Date.now()}.json`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  const exportToCSV = () => {
    if (!simulationResults && !analyticalResults) return;

    let csv = 'Queue,Metric,Simulation,Analytical,Difference %\n';

    // System totals
    if (simulationResults && analyticalResults) {
      csv += `System,Total L,${simulationResults.total_requests_completed},${analyticalResults.total_average_customers},-\n`;
      csv += `System,Total W,${simulationResults.average_system_time},${analyticalResults.total_average_time},-\n`;
    }

    // Coordinator
    if (simulationResults) {
      csv += `Coordinator,Utilization,${simulationResults.coordinator_stats.utilization}`;
      if (analyticalResults) {
        csv += `,${analyticalResults.coordinator.utilization},-`;
      }
      csv += '\n';
      csv += `Coordinator,Wait Time,${simulationResults.coordinator_stats.average_wait_time},-,-\n`;
      csv += `Coordinator,System Time,${simulationResults.coordinator_stats.average_system_time}`;
      if (analyticalResults) {
        csv += `,-,${analyticalResults.coordinator.average_time ?? 0},-`;
      }
      csv += '\n';
    }

    // Servers
    if (simulationResults) {
      Object.entries(simulationResults.server_stats).forEach(([serverId, stats]) => {
        csv += `${serverId},Utilization,${stats.utilization}`;
        if (analyticalResults && analyticalResults.servers[serverId]) {
          csv += `,${analyticalResults.servers[serverId].utilization},-`;
        }
        csv += '\n';
        csv += `${serverId},Wait Time,${stats.average_wait_time},-,-\n`;
        csv += `${serverId},System Time,${stats.average_system_time}`;
        if (analyticalResults && analyticalResults.servers[serverId]) {
          csv += `,${analyticalResults.servers[serverId].average_time ?? 0},-`;
        }
        csv += '\n';
      });
    }

    const blob = new Blob([csv], { type: 'text/csv' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `simulation-results-${Date.now()}.csv`;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  const hasResults = simulationResults || analyticalResults;

  return (
    <div className="flex items-center space-x-2">
      <button
        onClick={exportToJSON}
        disabled={!hasResults}
        className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
          hasResults
            ? 'bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2'
            : 'bg-gray-300 text-gray-500 cursor-not-allowed'
        }`}
      >
        Exporter JSON
      </button>
      <button
        onClick={exportToCSV}
        disabled={!hasResults}
        className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
          hasResults
            ? 'bg-green-600 text-white hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2'
            : 'bg-gray-300 text-gray-500 cursor-not-allowed'
        }`}
      >
        Exporter CSV
      </button>
    </div>
  );
}