main
ts 153 lines 5.66 KB
Raw
1 import type { FlaskBaseResponse } from "@/types/flask.d"
2 import type {
3 CaseEvent,
4 CaseTask,
5 CaseTaskCreatePayload,
6 CaseTaskUpdatePayload,
7 CaseTemplate,
8 CaseTemplateCreatePayload,
9 CaseTemplateLibraryListResponse,
10 CaseTemplateLibraryRefreshResponse,
11 CaseTemplateTask,
12 CaseTemplateTaskCreatePayload,
13 CaseTemplateTaskUpdatePayload,
14 CaseTemplateUpdatePayload
15 } from "@/types/incidentManagement/caseTemplates.d"
16 import { HttpClient } from "../../httpClient"
17
18 // ---------------------------------------------------------------------------
19 // Case template management (admin/analyst only — backend gates by scope)
20 // ---------------------------------------------------------------------------
21
22 export interface CaseTemplateListFilters {
23 customerCode?: string
24 source?: string
25 includeGlobal?: boolean
26 }
27
28 export default {
29 listTemplates(filters: CaseTemplateListFilters = {}) {
30 const params: Record<string, string | boolean> = {}
31 if (filters.customerCode !== undefined) params.customer_code = filters.customerCode
32 if (filters.source !== undefined) params.source = filters.source
33 if (filters.includeGlobal !== undefined) params.include_global = filters.includeGlobal
34
35 return HttpClient.get<FlaskBaseResponse & { templates: CaseTemplate[] }>(`/incidents/case_templates`, {
36 params
37 })
38 },
39 getTemplate(templateId: number) {
40 return HttpClient.get<FlaskBaseResponse & { template: CaseTemplate | null }>(
41 `/incidents/case_templates/${templateId}`
42 )
43 },
44 createTemplate(payload: CaseTemplateCreatePayload) {
45 return HttpClient.post<FlaskBaseResponse & { template: CaseTemplate | null }>(
46 `/incidents/case_templates`,
47 payload
48 )
49 },
50 updateTemplate(templateId: number, payload: CaseTemplateUpdatePayload) {
51 return HttpClient.patch<FlaskBaseResponse & { template: CaseTemplate | null }>(
52 `/incidents/case_templates/${templateId}`,
53 payload
54 )
55 },
56 deleteTemplate(templateId: number) {
57 return HttpClient.delete<FlaskBaseResponse & { template: CaseTemplate | null }>(
58 `/incidents/case_templates/${templateId}`
59 )
60 },
61
62 // Template tasks
63 addTemplateTask(templateId: number, payload: CaseTemplateTaskCreatePayload) {
64 return HttpClient.post<FlaskBaseResponse & { task: CaseTemplateTask | null }>(
65 `/incidents/case_templates/${templateId}/tasks`,
66 payload
67 )
68 },
69 updateTemplateTask(taskId: number, payload: CaseTemplateTaskUpdatePayload) {
70 return HttpClient.patch<FlaskBaseResponse & { task: CaseTemplateTask | null }>(
71 `/incidents/case_templates/tasks/${taskId}`,
72 payload
73 )
74 },
75 deleteTemplateTask(taskId: number) {
76 return HttpClient.delete<FlaskBaseResponse & { task: CaseTemplateTask | null }>(
77 `/incidents/case_templates/tasks/${taskId}`
78 )
79 },
80 reorderTemplateTasks(templateId: number, orderedTaskIds: number[]) {
81 return HttpClient.post<FlaskBaseResponse & { template: CaseTemplate | null }>(
82 `/incidents/case_templates/${templateId}/tasks/reorder`,
83 orderedTaskIds
84 )
85 },
86
87 // ---------------------------------------------------------------------------
88 // Per-case tasks (visible to admin/analyst/customer_user; writes admin/analyst only)
89 // ---------------------------------------------------------------------------
90 listCaseTasks(caseId: number) {
91 return HttpClient.get<FlaskBaseResponse & { tasks: CaseTask[] }>(
92 `/incidents/db_operations/case/${caseId}/tasks`
93 )
94 },
95 addCaseTask(caseId: number, payload: CaseTaskCreatePayload) {
96 return HttpClient.post<FlaskBaseResponse & { task: CaseTask | null }>(
97 `/incidents/db_operations/case/${caseId}/tasks`,
98 payload
99 )
100 },
101 updateCaseTask(taskId: number, payload: CaseTaskUpdatePayload, signal?: AbortSignal) {
102 return HttpClient.patch<FlaskBaseResponse & { task: CaseTask | null }>(
103 `/incidents/db_operations/case/tasks/${taskId}`,
104 payload,
105 { signal }
106 )
107 },
108 deleteCaseTask(taskId: number) {
109 return HttpClient.delete<FlaskBaseResponse & { task: CaseTask | null }>(
110 `/incidents/db_operations/case/tasks/${taskId}`
111 )
112 },
113 applyTemplateToCase(caseId: number, templateId: number, alertId?: number | null) {
114 const params: Record<string, number> = {}
115 if (alertId !== undefined && alertId !== null) params.alert_id = alertId
116 return HttpClient.post<FlaskBaseResponse & { tasks_added: number }>(
117 `/incidents/db_operations/case/${caseId}/apply-template/${templateId}`,
118 undefined,
119 { params }
120 )
121 },
122
123 // ---------------------------------------------------------------------------
124 // Timeline (read-only for everyone with case access)
125 // ---------------------------------------------------------------------------
126 getCaseTimeline(caseId: number, limit = 500, offset = 0) {
127 return HttpClient.get<FlaskBaseResponse & { case_id: number; events: CaseEvent[] }>(
128 `/incidents/db_operations/case/${caseId}/timeline`,
129 { params: { limit, offset } }
130 )
131 },
132
133 // ---------------------------------------------------------------------------
134 // Case Template Library (admin/analyst only — backend gates by scope)
135 // Read-only catalog of YAML playbooks from
136 // https://github.com/socfortress/CoPilot-Case-Templates.
137 // ---------------------------------------------------------------------------
138 getLibrary() {
139 return HttpClient.get<FlaskBaseResponse & CaseTemplateLibraryListResponse>(`/incidents/case_templates/library`)
140 },
141 refreshLibrary() {
142 return HttpClient.post<FlaskBaseResponse & CaseTemplateLibraryRefreshResponse>(
143 `/incidents/case_templates/library/refresh`
144 )
145 },
146 importLibraryEntry(key: string) {
147 // Backend returns the standard CaseTemplateOperationResponse on success,
148 // or HTTP 409 if a CaseTemplate with the same name already exists.
149 return HttpClient.post<FlaskBaseResponse & { template: CaseTemplate | null }>(
150 `/incidents/case_templates/library/${encodeURIComponent(key)}/import`
151 )
152 }
153 }