feat(frontend): sprint 2 — simulations UI + MITRE picker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
9
frontend/src/api/mitre.ts
Normal file
9
frontend/src/api/mitre.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { apiClient } from './client';
|
||||
import type { MitreTechnique } from './types';
|
||||
|
||||
export async function searchMitreTechniques(query: string): Promise<MitreTechnique[]> {
|
||||
const { data } = await apiClient.get<MitreTechnique[]>('/mitre/techniques', {
|
||||
params: { q: query },
|
||||
});
|
||||
return data;
|
||||
}
|
||||
37
frontend/src/api/simulations.ts
Normal file
37
frontend/src/api/simulations.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { apiClient } from './client';
|
||||
import type { Simulation, SimulationCreateInput, SimulationPatchInput, SimulationStatus } from './types';
|
||||
|
||||
export async function listSimulations(engagementId: number): Promise<Simulation[]> {
|
||||
const { data } = await apiClient.get<Simulation[]>(`/engagements/${engagementId}/simulations`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function createSimulation(
|
||||
engagementId: number,
|
||||
input: SimulationCreateInput,
|
||||
): Promise<Simulation> {
|
||||
const { data } = await apiClient.post<Simulation>(`/engagements/${engagementId}/simulations`, input);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getSimulation(id: number): Promise<Simulation> {
|
||||
const { data } = await apiClient.get<Simulation>(`/simulations/${id}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateSimulation(id: number, patch: SimulationPatchInput): Promise<Simulation> {
|
||||
const { data } = await apiClient.patch<Simulation>(`/simulations/${id}`, patch);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function deleteSimulation(id: number): Promise<void> {
|
||||
await apiClient.delete(`/simulations/${id}`);
|
||||
}
|
||||
|
||||
export async function transitionSimulation(
|
||||
id: number,
|
||||
to: Extract<SimulationStatus, 'review_required' | 'done'>,
|
||||
): Promise<Simulation> {
|
||||
const { data } = await apiClient.post<Simulation>(`/simulations/${id}/transition`, { to });
|
||||
return data;
|
||||
}
|
||||
@@ -52,3 +52,51 @@ export interface UserPatchInput {
|
||||
export interface ApiError {
|
||||
error: string;
|
||||
}
|
||||
|
||||
export type SimulationStatus = 'pending' | 'in_progress' | 'review_required' | 'done';
|
||||
|
||||
export interface MitreTechnique {
|
||||
id: string;
|
||||
name: string;
|
||||
tactics: string[];
|
||||
}
|
||||
|
||||
export interface Simulation {
|
||||
id: number;
|
||||
engagement_id: number;
|
||||
name: string;
|
||||
mitre_technique_id: string | null;
|
||||
mitre_technique_name: string | null;
|
||||
description: string | null;
|
||||
commands: string | null;
|
||||
prerequisites: string | null;
|
||||
executed_at: string | null;
|
||||
execution_result: string | null;
|
||||
log_source: string | null;
|
||||
logs: string | null;
|
||||
soc_comment: string | null;
|
||||
incident_number: string | null;
|
||||
status: SimulationStatus;
|
||||
created_at: string;
|
||||
updated_at: string | null;
|
||||
created_by: { id: number; username: string };
|
||||
}
|
||||
|
||||
export interface SimulationCreateInput {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface SimulationPatchInput {
|
||||
name?: string;
|
||||
mitre_technique_id?: string | null;
|
||||
mitre_technique_name?: string | null;
|
||||
description?: string | null;
|
||||
commands?: string | null;
|
||||
prerequisites?: string | null;
|
||||
executed_at?: string | null;
|
||||
execution_result?: string | null;
|
||||
log_source?: string | null;
|
||||
logs?: string | null;
|
||||
soc_comment?: string | null;
|
||||
incident_number?: string | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user