Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 54 additions & 15 deletions frontend/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,15 @@ export function getPluginSchema(id: string) {
return request<PluginSchemaResponse>(`/plugin/${id}/schema`)
}

export function getSettings() {
return request<any>(`/settings`)
export interface SettingsResponse {
execution_context?: {
default?: ExecutionContext
}
[key: string]: unknown
}

export function getSettings(): Promise<SettingsResponse | null> {
return request<SettingsResponse | null>('/settings')
}

export function getDashboardSummary() {
Expand Down Expand Up @@ -453,7 +460,7 @@ export interface NotificationRuleUpdatePayload {
}

export async function listNotificationRules(): Promise<NotificationRule[]> {
const data: any = await request('/notifications/rules')
const data = await request<NotificationRule[] | { rules: NotificationRule[] }>('/notifications/rules')
const rules = Array.isArray(data) ? data : data?.rules
return Array.isArray(rules) ? (rules as NotificationRule[]) : []
}
Expand Down Expand Up @@ -490,7 +497,12 @@ export async function listNotificationHistory(params?: {
if (typeof params?.limit === 'number') sp.set('limit', String(params.limit))
if (typeof params?.offset === 'number') sp.set('offset', String(params.offset))
const suffix = sp.toString() ? `?${sp.toString()}` : ''
const data: any = await request(`/notifications/history${suffix}`)
const data = await request<{
history?: NotificationHistoryRow[]
total?: number
limit?: number
offset?: number
}>(`/notifications/history${suffix}`)
return {
history: Array.isArray(data?.history) ? (data.history as NotificationHistoryRow[]) : [],
total: Number(data?.total ?? 0),
Expand Down Expand Up @@ -532,12 +544,21 @@ export function getTasks(params?: URLSearchParams) {

export type ScanPhase = 'queued' | 'running_command' | 'parsing' | 'reporting' | 'finished'

export function getTaskStatus(taskId: string): Promise<any> {
return request<any>(`/task/${taskId}/status`)
export interface TaskStatusResponse {
task_id?: string
status: string
phase?: ScanPhase
progress?: number
message?: string
error_message?: string | null
}

export function getTaskStatus(taskId: string): Promise<TaskStatusResponse> {
return request<TaskStatusResponse>(`/task/${taskId}/status`)
}

export function getTaskResult(taskId: string): Promise<any> {
return request<TaskResultResponse>(`/task/${taskId}/result`)
export function getTaskResult(taskId: string): Promise<TaskResultResponse | null> {
return request<TaskResultResponse | null>(`/task/${taskId}/result`)
}

export function getTaskDiff(taskId: string): Promise<ScanDiff> {
Expand Down Expand Up @@ -636,10 +657,28 @@ export interface WorkflowUpdatePayload {
}

interface WorkflowListResponse {
workflows: unknown[]
workflows: RawWorkflow[]
total: number
}

interface RawWorkflow {
id: unknown
name?: unknown
schedule_seconds?: unknown
enabled?: unknown
steps?: unknown
steps_json?: unknown
last_run_at?: string | null
queued_task_ids?: unknown
queued_tasks?: unknown
created_at?: string
}

interface WorkflowRunResponse {
queued_task_ids?: string[]
queued_tasks?: string[]
}

function parseWorkflowSteps(value: unknown): WorkflowStep[] {
if (Array.isArray(value)) return value as WorkflowStep[]
if (typeof value !== 'string' || value.trim() === '') return []
Expand All @@ -658,7 +697,7 @@ function parseScheduleSeconds(value: unknown): number | null {
return Number.isFinite(parsed) ? parsed : null
}

function normalizeWorkflow(raw: any): Workflow {
function normalizeWorkflow(raw: RawWorkflow): Workflow {
return {
id: String(raw.id),
name: String(raw.name ?? ''),
Expand All @@ -676,13 +715,13 @@ function normalizeWorkflow(raw: any): Workflow {
}

export async function getWorkflows(): Promise<Workflow[]> {
const data = await request<WorkflowListResponse | unknown[]>('/workflows')
const data = await request<WorkflowListResponse | RawWorkflow[]>('/workflows')
const workflows = Array.isArray(data) ? data : data.workflows
return Array.isArray(workflows) ? workflows.map(normalizeWorkflow) : []
}

export async function createWorkflow(data: WorkflowCreatePayload): Promise<Workflow> {
const workflow = await request<unknown>('/workflows', {
const workflow = await request<RawWorkflow>('/workflows', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
Expand All @@ -691,7 +730,7 @@ export async function createWorkflow(data: WorkflowCreatePayload): Promise<Workf
}

export async function runWorkflow(workflowId: string): Promise<{ queued_task_ids: string[] }> {
const result: any = await request(`/workflows/${workflowId}/run`, {
const result = await request<WorkflowRunResponse>(`/workflows/${workflowId}/run`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
})
Expand All @@ -705,7 +744,7 @@ export async function runWorkflow(workflowId: string): Promise<{ queued_task_ids
}

export async function updateWorkflow(workflowId: string, data: WorkflowUpdatePayload): Promise<Workflow> {
const workflow = await request<unknown>(`/workflows/${workflowId}`, {
const workflow = await request<RawWorkflow>(`/workflows/${workflowId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
Expand Down Expand Up @@ -764,7 +803,7 @@ export async function rollbackWorkflow(workflowId: string, versionNumber: number
workflow_id: string
rolled_back_to_version: number
new_version_number: number
workflow: any
workflow: RawWorkflow
}>(`/workflows/${workflowId}/rollback/${versionNumber}`, {
method: 'POST',
})
Expand Down
2 changes: 1 addition & 1 deletion frontend/testing/unit/hooks/useTaskSubscription.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ describe('useTaskSubscription', () => {
})

it('stops polling on terminal status', async () => {
let resolveGetTaskStatus: (value: unknown) => void
let resolveGetTaskStatus: (value: Awaited<ReturnType<typeof getTaskStatus>>) => void
vi.mocked(getTaskStatus).mockImplementation(() => new Promise(resolve => {
resolveGetTaskStatus = resolve
}))
Expand Down
Loading