diff --git a/frontend/src/components/AlgorithmComparisonCenter.tsx b/frontend/src/components/AlgorithmComparisonCenter.tsx index 7233473..32f68ae 100644 --- a/frontend/src/components/AlgorithmComparisonCenter.tsx +++ b/frontend/src/components/AlgorithmComparisonCenter.tsx @@ -1,14 +1,11 @@ import { useState } from 'react'; import type { CatalogResponse, SimulationFrame } from '../models/types'; -import type { RaceResponse } from '../models/types'; import { getSortingMeta, getSearchingMeta, getPathfindingMeta, } from '../data/algorithmMetadata'; import { PseudocodeViewer } from './PseudocodeViewer'; -import { Download } from 'lucide-react'; -import { exportRaceToCSV, exportRaceToJSON } from '../utils/exportTelemetry'; interface AlgorithmComparisonCenterProps { algorithms: string[]; @@ -17,7 +14,6 @@ interface AlgorithmComparisonCenterProps { activeFrames?: Record | null; prevFrames?: Record | null; maxFrames?: number; - raceResponse?: RaceResponse | null; } export function AlgorithmComparisonCenter({ @@ -27,7 +23,6 @@ export function AlgorithmComparisonCenter({ activeFrames, prevFrames, maxFrames, - raceResponse, }: AlgorithmComparisonCenterProps) { const [active, setActive] = useState(0); const alg = algorithms[active] ?? algorithms[0] ?? ''; @@ -73,29 +68,9 @@ export function AlgorithmComparisonCenter({ return (
{/* Header */} -
-
-
Algorithm Comparison Center
-
Multi-Language Code & Algorithm Deep-Dive
-
- {raceResponse && ( -
- - -
- )} +
+
Algorithm Comparison Center
+
Multi-Language Code & Algorithm Deep-Dive
diff --git a/frontend/src/pages/PathfindingPage.tsx b/frontend/src/pages/PathfindingPage.tsx index 11c1130..96cc2e5 100644 --- a/frontend/src/pages/PathfindingPage.tsx +++ b/frontend/src/pages/PathfindingPage.tsx @@ -583,7 +583,6 @@ export function PathfindingPage({ catalog }: { catalog: CatalogResponse }) { activeFrames={activeFramesMap} prevFrames={prevFramesMap} maxFrames={playback.maxFrames} - raceResponse={response} />
diff --git a/frontend/src/pages/SearchingPage.tsx b/frontend/src/pages/SearchingPage.tsx index 4d10fd8..e31b34f 100644 --- a/frontend/src/pages/SearchingPage.tsx +++ b/frontend/src/pages/SearchingPage.tsx @@ -644,7 +644,6 @@ export function SearchingPage({ catalog }: { catalog: CatalogResponse }) { activeFrames={activeFramesMap} prevFrames={prevFramesMap} maxFrames={playback.maxFrames} - raceResponse={activeResponse} />
diff --git a/frontend/src/pages/SortingPage.tsx b/frontend/src/pages/SortingPage.tsx index 4157f8b..9cf3764 100644 --- a/frontend/src/pages/SortingPage.tsx +++ b/frontend/src/pages/SortingPage.tsx @@ -609,7 +609,6 @@ export function SortingPage({ catalog }: { catalog: CatalogResponse }) { activeFrames={activeFramesMap} prevFrames={prevFramesMap} maxFrames={playback.maxFrames} - raceResponse={activeResponse} /> diff --git a/frontend/src/utils/exportTelemetry.ts b/frontend/src/utils/exportTelemetry.ts deleted file mode 100644 index e0f49f7..0000000 --- a/frontend/src/utils/exportTelemetry.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type { RaceResponse } from '../models/types'; - -function triggerDownload(blob: Blob, filename: string) { - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); -} - -// Security: RFC 4180 CSV field sanitizer -function sanitizeCsvField(field: string | number | undefined | null | boolean): string { - if (field === undefined || field === null) return '""'; - let str = String(field); - if (/^[=+\-@\t\r]/.test(str)) { - str = `'${str}`; - } - const escaped = str.replace(/"/g, '""'); - return `"${escaped}"`; -} - -export function exportRaceToCSV(raceData: RaceResponse) { - const headers = ['Algorithm', 'Operations', 'Execution Time (ms)', 'Swaps / Path Steps', 'Winner', 'Dataset Config']; - const rows: string[][] = []; - - const datasetConfig = raceData.type === 'sorting' - ? (raceData.dataset ? `Array[${raceData.dataset.length}]` : 'N/A') - : raceData.type === 'searching' - ? (raceData.dataset ? `Array[${raceData.dataset.length}] Target: ${raceData.target}` : 'N/A') - : (raceData.walls ? `Grid[${raceData.walls.length}x${raceData.walls[0].length}]` : 'N/A'); - - raceData.lanes.forEach(lane => { - const isWinner = raceData.winner === lane.name ? 'Yes' : 'No'; - let operations = 0; - let secValue = 0; - - if (raceData.type === 'sorting') { - operations = lane.stats.comparisons; - secValue = lane.stats.swaps; - } else if (raceData.type === 'searching') { - operations = lane.stats.comparisons; - } else { - operations = lane.stats.comparisons; - secValue = lane.stats.steps; - } - - const row = [ - lane.name, - operations.toString(), - lane.stats.timeMs.toString(), - secValue.toString(), - isWinner, - datasetConfig - ]; - rows.push(row.map(sanitizeCsvField)); - }); - - const csvContent = [ - headers.map(sanitizeCsvField).join(','), - ...rows.map(row => row.join(',')) - ].join('\n'); - - const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); - triggerDownload(blob, `race_telemetry_${Date.now()}.csv`); -} - -export function exportRaceToJSON(raceData: RaceResponse) { - const telemetry = { - type: raceData.type, - winner: raceData.winner, - datasetConfig: raceData.type === 'sorting' - ? { size: raceData.dataset?.length } - : raceData.type === 'searching' - ? { size: raceData.dataset?.length, target: raceData.target } - : { gridRows: raceData.walls?.length, gridCols: raceData.walls?.[0]?.length }, - results: raceData.lanes.map(lane => ({ - algorithm: lane.name, - operations: raceData.type !== 'pathfinding' ? lane.stats.comparisons : lane.stats.steps, - comparisons: lane.stats.comparisons, - swaps: lane.stats.swaps, - steps: lane.stats.steps, - timeMs: lane.stats.timeMs, - isWinner: raceData.winner === lane.name - })) - }; - - const jsonContent = JSON.stringify(telemetry, null, 2); - const blob = new Blob([jsonContent], { type: 'application/json' }); - triggerDownload(blob, `race_telemetry_${Date.now()}.json`); -}