diff --git a/frontend/web/src/api.ts b/frontend/web/src/api.ts index 53f3d1a..34ea973 100644 --- a/frontend/web/src/api.ts +++ b/frontend/web/src/api.ts @@ -264,9 +264,16 @@ export interface RunLogsResponse { export const reportsApi = { get: (runId: string) => api.get(`/reports/${runId}`), - html: (runId: string) => api.get(`/reports/${runId}/html`), - json: (runId: string) => api.get(`/reports/${runId}/json`), - markdownUrl: (runId: string) => `/api/reports/${runId}/markdown`, + download: async (runId: string, format: 'html' | 'json' | 'markdown') => { + const ext = format === 'markdown' ? 'md' : format + const res = await api.get(`/reports/${runId}/${format}`, { responseType: 'blob' }) + const url = URL.createObjectURL(res.data as Blob) + const a = document.createElement('a') + a.href = url + a.download = `report-${runId.slice(0, 8)}.${ext}` + a.click() + URL.revokeObjectURL(url) + }, compare: (run1: string, run2: string) => api.get(`/reports/compare`, { params: { run1, run2 } }), } diff --git a/frontend/web/src/pages/Reports.tsx b/frontend/web/src/pages/Reports.tsx index d3335f2..b314f6a 100644 --- a/frontend/web/src/pages/Reports.tsx +++ b/frontend/web/src/pages/Reports.tsx @@ -325,10 +325,10 @@ export default function ReportsPage() { {viewMode === 'single' && report && ( - - diff --git a/frontend/web/src/pages/Runs.tsx b/frontend/web/src/pages/Runs.tsx index d818e5c..185db48 100644 --- a/frontend/web/src/pages/Runs.tsx +++ b/frontend/web/src/pages/Runs.tsx @@ -6,7 +6,7 @@ import { import { FileTextOutlined, PlayCircleOutlined, ReloadOutlined, StopOutlined, } from '@ant-design/icons' -import { runsApi, scenariosApi, targetsApi, type Run, type Scenario, type Target } from '../api' +import { reportsApi, runsApi, scenariosApi, targetsApi, type Run, type Scenario, type Target } from '../api' import RunList from '../components/RunList' import CaseBlock from '../components/CaseBlock' import RuleOverview from '../components/RuleOverview' @@ -226,7 +226,7 @@ export default function RunsPage() { } }} onOpenReport={handleOpenReport} - onExportJson={(runId) => window.open(`/api/reports/${runId}/json`, '_blank')} + onExportJson={(runId) => reportsApi.download(runId, 'json')} onRerun={async () => { if (!session.run) return await startRun(session.run.target_id, session.run.scenario_id)