Files
leocrm/frontend/src/api/entityHistory.ts
T

120 lines
3.6 KiB
TypeScript
Raw Normal View History

2026-07-23 08:42:26 +02:00
/**
* Entity History hooks — undo/restore/trash functionality.
2026-07-23 08:42:26 +02:00
*/
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { apiGet, apiPost, apiClient } from './client';
export interface EntityHistoryEntry {
id: string;
entity_type: string;
entity_id: string;
action: 'create' | 'update' | 'delete';
snapshot_before: Record<string, unknown> | null;
snapshot_after: Record<string, unknown> | null;
changes: Record<string, { old: unknown; new: unknown }> | null;
2026-07-23 08:42:26 +02:00
user_id: string | null;
created_at: string;
}
export interface EntityHistoryList {
items: EntityHistoryEntry[];
total: number;
}
export interface TrashItem {
history_id: string;
entity_type: string;
entity_id: string;
snapshot_before: Record<string, unknown> | null;
deleted_at: string | null;
user_id: string | null;
}
export interface TrashListResponse {
items: TrashItem[];
total: number;
limit: number;
offset: number;
}
export interface BulkRestoreResultItem {
history_id: string;
success: boolean;
entity_type: string | null;
entity_id: string | null;
error: string | null;
}
export interface BulkRestoreResponse {
total: number;
succeeded: number;
failed: number;
results: BulkRestoreResultItem[];
partial_success: boolean;
}
export function useEntityHistory(entityType?: string, entityId?: string, limit = 50) {
2026-07-23 08:42:26 +02:00
return useQuery({
queryKey: ['entityHistory', entityType, entityId, limit],
2026-07-23 08:42:26 +02:00
queryFn: () =>
apiGet<EntityHistoryList>(`/entity-history/${entityType}/${entityId}?limit=${limit}`),
2026-07-23 08:42:26 +02:00
enabled: !!entityType && !!entityId,
});
}
export function useTrashList(entityType?: string, limit = 50, offset = 0) {
const params = new URLSearchParams();
params.set('limit', String(limit));
params.set('offset', String(offset));
if (entityType) {
params.set('entity_type', entityType);
}
return useQuery({
queryKey: ['trash', entityType ?? 'all', limit, offset],
queryFn: () => apiGet<TrashListResponse>(`/entity-history/trash?${params.toString()}`),
});
}
2026-07-23 08:42:26 +02:00
export function useRestoreFromHistory() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (historyId: string) =>
apiClient.post('/entity-history/restore', { history_id: historyId }).then(r => r.data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['entityHistory'] });
queryClient.invalidateQueries({ queryKey: ['trash'] });
queryClient.invalidateQueries({ queryKey: ['contacts'] });
queryClient.invalidateQueries({ queryKey: ['contact'] });
},
});
}
export function useBulkRestore() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (historyIds: string[]) =>
apiPost<BulkRestoreResponse>('/entity-history/bulk-restore', { history_ids: historyIds }),
onSuccess: () => {
2026-07-23 08:42:26 +02:00
queryClient.invalidateQueries({ queryKey: ['entityHistory'] });
queryClient.invalidateQueries({ queryKey: ['trash'] });
2026-07-23 08:42:26 +02:00
queryClient.invalidateQueries({ queryKey: ['contacts'] });
queryClient.invalidateQueries({ queryKey: ['contact'] });
},
});
}
export function useUndoLastAction() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ entityType, entityId }: { entityType: string; entityId: string }) =>
apiPost(`/entity-history/undo/${entityType}/${entityId}`, {}),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['entityHistory'] });
queryClient.invalidateQueries({ queryKey: ['trash'] });
2026-07-23 08:42:26 +02:00
queryClient.invalidateQueries({ queryKey: ['contacts'] });
queryClient.invalidateQueries({ queryKey: ['contact'] });
},
});
}