- types.ts: SimulationTemplate, SimulationTemplateCreateInput, SimulationTemplatePatchInput, extend SimulationCreateInput with template_id - api/templates.ts: listTemplates, getTemplate, createTemplate, updateTemplate, deleteTemplate - hooks/useTemplates.ts: useTemplates, useTemplate, useCreateTemplate, useUpdateTemplate, useDeleteTemplate (TanStack Query, invalidates ["templates"]) - TemplatesListPage: /admin/templates — table (name, MITRE count, created by, updated), New/Edit/Delete actions, loading/error/empty states - TemplateFormPage: /admin/templates/new + /admin/templates/:id/edit — controlled form with inline MITRE field (picker + matrix modal), ConfirmDialog for delete - TemplatePickerModal: reusable modal listing templates with empty state (AC-27.6) - SimulationList: replace "New simulation" link with split-button dropdown (Blank → /simulations/new | From template… → TemplatePickerModal + POST template_id) - Layout: "Templates" nav link (admin | redteam, before "Users") - App.tsx: /admin/templates routes gated roles=["admin","redteam"] - 26 new Vitest tests (118 total, 92 original preserved) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
import { apiClient } from './client';
|
|
import type {
|
|
SimulationTemplate,
|
|
SimulationTemplateCreateInput,
|
|
SimulationTemplatePatchInput,
|
|
} from './types';
|
|
|
|
export async function listTemplates(): Promise<SimulationTemplate[]> {
|
|
const { data } = await apiClient.get<SimulationTemplate[]>('/simulation-templates');
|
|
return data;
|
|
}
|
|
|
|
export async function getTemplate(id: number): Promise<SimulationTemplate> {
|
|
const { data } = await apiClient.get<SimulationTemplate>(`/simulation-templates/${id}`);
|
|
return data;
|
|
}
|
|
|
|
export async function createTemplate(
|
|
input: SimulationTemplateCreateInput,
|
|
): Promise<SimulationTemplate> {
|
|
const { data } = await apiClient.post<SimulationTemplate>('/simulation-templates', input);
|
|
return data;
|
|
}
|
|
|
|
export async function updateTemplate(
|
|
id: number,
|
|
patch: SimulationTemplatePatchInput,
|
|
): Promise<SimulationTemplate> {
|
|
const { data } = await apiClient.patch<SimulationTemplate>(`/simulation-templates/${id}`, patch);
|
|
return data;
|
|
}
|
|
|
|
export async function deleteTemplate(id: number): Promise<void> {
|
|
await apiClient.delete(`/simulation-templates/${id}`);
|
|
}
|