Files
leocrm/frontend/src/api/webhooks.ts
T
Agent Zero 79ece0fe2e Phase 4: Webhooks, Backup/Restore UI, Onboarding/Tutorial
- Webhooks Backend: model, schema, service (HMAC-SHA256, httpx), routes, event bus dispatcher, migration 0042
- Webhooks Frontend: SettingsWebhooksPage (CRUD, test button, event multi-select), API client
- Backup/Restore Backend: model, schema, service (pg_dump/pg_restore), routes (admin-only), migration 0043
- Backup/Restore Frontend: SettingsBackupPage (create, list, restore dialog with RESTORE confirmation, auto-refresh)
- Onboarding: OnboardingTour (8 steps, custom CSS overlay), WelcomeDialog, onboardingStore (zustand + localStorage)
- Onboarding integrated into AppShell
- Routes: /settings/webhooks, /settings/backup registered
- Settings nav: Webhooks, Backup & Restore entries added
- Migration conflict fixed: 0042_webhooks → 0043_backups chain
2026-07-26 03:17:40 +02:00

127 lines
3.4 KiB
TypeScript

/**
* Webhooks API client and React Query hooks.
*/
import { apiGet, apiPost, apiPatch, apiDelete } from '@/api/client';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
export interface Webhook {
id: string;
tenant_id: string;
url: string;
events: string[];
secret: string | null;
is_active: boolean;
retry_count: number;
timeout_seconds: number;
created_by: string | null;
updated_by: string | null;
created_at: string;
updated_at: string;
}
export interface CreateWebhookPayload {
url: string;
events: string[];
secret?: string | null;
is_active?: boolean;
retry_count?: number;
timeout_seconds?: number;
}
export interface UpdateWebhookPayload {
url?: string;
events?: string[];
secret?: string | null;
is_active?: boolean;
retry_count?: number;
timeout_seconds?: number;
}
export interface WebhookTestResult {
success: boolean;
status_code: number | null;
error: string | null;
}
// ─── API Functions ──────────────────────────────────────────────────────────
export async function fetchWebhooks(event?: string): Promise<Webhook[]> {
const params = event ? `?event=${encodeURIComponent(event)}` : '';
return apiGet<Webhook[]>(`/webhooks${params}`);
}
export async function fetchWebhook(id: string): Promise<Webhook> {
return apiGet<Webhook>(`/webhooks/${id}`);
}
export async function createWebhook(data: CreateWebhookPayload): Promise<Webhook> {
return apiPost<Webhook>('/webhooks', data);
}
export async function updateWebhook(id: string, data: UpdateWebhookPayload): Promise<Webhook> {
return apiPatch<Webhook>(`/webhooks/${id}`, data);
}
export async function deleteWebhook(id: string): Promise<void> {
return apiDelete<void>(`/webhooks/${id}`);
}
export async function testWebhook(id: string): Promise<WebhookTestResult> {
return apiPost<WebhookTestResult>(`/webhooks/${id}/test`);
}
// ─── React Query Hooks ───────────────────────────────────────────────────────
export function useWebhooks(event?: string) {
return useQuery({
queryKey: ['webhooks', event],
queryFn: () => fetchWebhooks(event),
});
}
export function useWebhook(id: string) {
return useQuery({
queryKey: ['webhooks', id],
queryFn: () => fetchWebhook(id),
enabled: !!id,
});
}
export function useCreateWebhook() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateWebhookPayload) => createWebhook(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['webhooks'] });
},
});
}
export function useUpdateWebhook() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UpdateWebhookPayload }) =>
updateWebhook(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['webhooks'] });
},
});
}
export function useDeleteWebhook() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => deleteWebhook(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['webhooks'] });
},
});
}
export function useTestWebhook() {
return useMutation({
mutationFn: (id: string) => testWebhook(id),
});
}