Files
Aegis/frontend/src/api/evidence.ts
T
kitos 1a974265de feat(evidence): inline preview for images and text/JSON files
Adds a View button (eye icon) on each evidence card for previewable file
types. Opens a full-screen modal:
- Images (png/jpg/gif/webp/svg/…): rendered directly via <img> tag
- JSON: fetched authenticated, pretty-printed in green mono
- Text/log/md/csv/xml/yaml/…: fetched authenticated, shown in <pre>

Non-previewable files only show the Download button as before.
Modal closes on Escape or backdrop click.
2026-05-28 13:49:35 +02:00

92 lines
3.2 KiB
TypeScript

import client from "./client";
import type { Evidence, TeamSide } from "../types/models";
// ── Response type (with download URL) ──────────────────────────────
export interface EvidenceOut extends Evidence {
download_url: string;
}
// ── Upload ─────────────────────────────────────────────────────────
/** Upload an evidence file for the given test.
*
* The ``team`` field is sent as form data alongside the file so the
* backend can enforce Red/Blue access control.
*/
export async function uploadEvidence(
testId: string,
file: File,
team: TeamSide,
notes?: string,
): Promise<EvidenceOut> {
const formData = new FormData();
formData.append("file", file);
formData.append("team", team);
if (notes) {
formData.append("notes", notes);
}
const { data } = await client.post<EvidenceOut>(
`/tests/${testId}/evidence`,
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
},
);
return data;
}
// ── List ───────────────────────────────────────────────────────────
/** List evidences for a test, optionally filtered by team. */
export async function getTestEvidences(
testId: string,
team?: TeamSide,
): Promise<EvidenceOut[]> {
const params = new URLSearchParams();
if (team) params.append("team", team);
const { data } = await client.get<EvidenceOut[]>(
`/tests/${testId}/evidence${params.toString() ? `?${params}` : ""}`,
);
return data;
}
// ── Detail ─────────────────────────────────────────────────────────
/** Get evidence metadata with presigned download URL. */
export async function getEvidence(evidenceId: string): Promise<EvidenceOut> {
const { data } = await client.get<EvidenceOut>(`/evidence/${evidenceId}`);
return data;
}
// ── Content fetch (for inline preview) ────────────────────────────
/** Fetch raw file content for inline preview (text / JSON). */
export async function getEvidenceRawContent(
evidenceId: string,
): Promise<{ text: string; contentType: string }> {
const response = await client.get(`/evidence/${evidenceId}/file`, {
responseType: "blob",
});
const blob = response.data as Blob;
const text = await blob.text();
const contentType = (response.headers["content-type"] as string) || "";
return { text, contentType };
}
// ── Delete ─────────────────────────────────────────────────────────
/** Delete an evidence record (only in editable states). */
export async function deleteEvidence(
evidenceId: string,
): Promise<{ detail: string }> {
const { data } = await client.delete<{ detail: string }>(
`/evidence/${evidenceId}`,
);
return data;
}