170 lines
5.0 KiB
TypeScript
170 lines
5.0 KiB
TypeScript
/**
|
|
* Backup API client — database backup management.
|
|
*
|
|
* Features:
|
|
* - List backups
|
|
* - Create backup
|
|
* - Restore backup
|
|
* - Delete backup
|
|
*/
|
|
|
|
import { apiGet, apiPost, apiPut, apiDelete } from './client';
|
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
|
|
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
|
|
export interface Backup {
|
|
id: string;
|
|
tenant_id: string;
|
|
filename: string;
|
|
size_bytes: number | null;
|
|
status: 'pending' | 'completed' | 'failed';
|
|
error_message: string | null;
|
|
created_by: string | null;
|
|
created_at: string;
|
|
completed_at: string | null;
|
|
}
|
|
|
|
export interface BackupListResponse {
|
|
backups: Backup[];
|
|
total: number;
|
|
}
|
|
|
|
// ─── API Functions ──────────────────────────────────────────────────────────
|
|
|
|
export async function fetchBackups(): Promise<BackupListResponse> {
|
|
return apiGet<BackupListResponse>('/backups');
|
|
}
|
|
|
|
export async function createBackup(): Promise<Backup> {
|
|
return apiPost<Backup>('/backups');
|
|
}
|
|
|
|
export async function restoreBackup(backupId: string): Promise<Backup> {
|
|
return apiPost<Backup>(`/backups/${backupId}/restore`);
|
|
}
|
|
|
|
export async function deleteBackup(backupId: string): Promise<void> {
|
|
return apiDelete<void>(`/backups/${backupId}`);
|
|
}
|
|
|
|
// ─── React Query Hooks ─────────────────────────────────────────────────────
|
|
|
|
export function useBackups() {
|
|
return useQuery<BackupListResponse>({
|
|
queryKey: ['backups'],
|
|
queryFn: fetchBackups,
|
|
refetchInterval: (query) => {
|
|
// Auto-refresh while any backup is pending
|
|
const data = query.state.data;
|
|
if (data && data.backups.some((b) => b.status === 'pending')) {
|
|
return 3000; // Poll every 3 seconds
|
|
}
|
|
return false;
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useCreateBackup() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation<Backup, Error>({
|
|
mutationFn: createBackup,
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['backups'] });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useRestoreBackup() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation<Backup, Error, string>({
|
|
mutationFn: restoreBackup,
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['backups'] });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useDeleteBackup() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation<void, Error, string>({
|
|
mutationFn: deleteBackup,
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['backups'] });
|
|
},
|
|
});
|
|
}
|
|
|
|
// ─── Backup Configuration ────────────────────────────────────────────────────
|
|
|
|
export interface BackupConfig {
|
|
backup_enabled: boolean;
|
|
backup_interval: string;
|
|
backup_retention_days: number;
|
|
backup_destination: string;
|
|
}
|
|
|
|
export interface BackupHistoryEntry {
|
|
id: string;
|
|
timestamp: string | null;
|
|
action: string;
|
|
success: boolean;
|
|
destination: string;
|
|
error: string;
|
|
}
|
|
|
|
export interface BackupHistoryResponse {
|
|
history: BackupHistoryEntry[];
|
|
}
|
|
|
|
export async function fetchBackupConfig(): Promise<BackupConfig> {
|
|
return apiGet<BackupConfig>('/system-settings/backup-config');
|
|
}
|
|
|
|
export async function updateBackupConfig(config: Partial<BackupConfig>): Promise<BackupConfig> {
|
|
return apiPut<BackupConfig>('/system-settings/backup-config', config);
|
|
}
|
|
|
|
export async function triggerBackupNow(): Promise<{ message: string; job_id: string }> {
|
|
return apiPost<{ message: string; job_id: string }>('/system-settings/backup-now');
|
|
}
|
|
|
|
export async function fetchBackupHistory(): Promise<BackupHistoryResponse> {
|
|
return apiGet<BackupHistoryResponse>('/system-settings/backup-history');
|
|
}
|
|
|
|
export function useBackupConfig() {
|
|
return useQuery<BackupConfig>({
|
|
queryKey: ['backup-config'],
|
|
queryFn: fetchBackupConfig,
|
|
});
|
|
}
|
|
|
|
export function useUpdateBackupConfig() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation<BackupConfig, Error, Partial<BackupConfig>>({
|
|
mutationFn: updateBackupConfig,
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['backup-config'] });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useTriggerBackupNow() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation<{ message: string; job_id: string }, Error>({
|
|
mutationFn: triggerBackupNow,
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ['backups'] });
|
|
queryClient.invalidateQueries({ queryKey: ['backup-history'] });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useBackupHistory() {
|
|
return useQuery<BackupHistoryResponse>({
|
|
queryKey: ['backup-history'],
|
|
queryFn: fetchBackupHistory,
|
|
});
|
|
}
|