mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-25 07:51:12 -05:00
- Implement maintenance hooks (useMaintenanceTables, useVacuumTable, useAnalyzeTable, useReindexTable) - Add DatabaseMaintenance page and UI for vacuum/analyze/reindex - Wire new route / admin/database-maintenance and sidebar entry - Remove DatabaseMaintenance icon usage on page and align with AdminLayout props
136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
import { supabase } from '@/integrations/supabase/client';
|
|
import { queryKeys } from '@/lib/queryKeys';
|
|
import { toast } from 'sonner';
|
|
|
|
export interface MaintenanceTable {
|
|
table_name: string;
|
|
row_count: number;
|
|
table_size: string;
|
|
indexes_size: string;
|
|
total_size: string;
|
|
}
|
|
|
|
export interface MaintenanceResult {
|
|
table_name: string;
|
|
operation: string;
|
|
started_at: string;
|
|
completed_at: string;
|
|
duration_ms: number;
|
|
success: boolean;
|
|
error?: string;
|
|
}
|
|
|
|
export function useMaintenanceTables() {
|
|
return useQuery({
|
|
queryKey: queryKeys.admin.maintenanceTables(),
|
|
queryFn: async () => {
|
|
const { data, error } = await supabase.rpc('get_maintenance_tables');
|
|
|
|
if (error) throw error;
|
|
|
|
return data as unknown as MaintenanceTable[];
|
|
},
|
|
staleTime: 2 * 60 * 1000, // 2 minutes
|
|
});
|
|
}
|
|
|
|
export function useVacuumTable() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async (tableName: string) => {
|
|
const { data, error } = await supabase.rpc('run_vacuum_table', {
|
|
table_name: tableName,
|
|
});
|
|
|
|
if (error) throw error;
|
|
|
|
return data as unknown as MaintenanceResult;
|
|
},
|
|
onSuccess: (result) => {
|
|
if (result.success) {
|
|
toast.success(`Vacuum completed on ${result.table_name}`, {
|
|
description: `Duration: ${Math.round(result.duration_ms)}ms`,
|
|
});
|
|
} else {
|
|
toast.error(`Vacuum failed on ${result.table_name}`, {
|
|
description: result.error,
|
|
});
|
|
}
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.admin.maintenanceTables() });
|
|
},
|
|
onError: (error: Error) => {
|
|
toast.error('Vacuum operation failed', {
|
|
description: error.message,
|
|
});
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useAnalyzeTable() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async (tableName: string) => {
|
|
const { data, error } = await supabase.rpc('run_analyze_table', {
|
|
table_name: tableName,
|
|
});
|
|
|
|
if (error) throw error;
|
|
|
|
return data as unknown as MaintenanceResult;
|
|
},
|
|
onSuccess: (result) => {
|
|
if (result.success) {
|
|
toast.success(`Analyze completed on ${result.table_name}`, {
|
|
description: `Duration: ${Math.round(result.duration_ms)}ms`,
|
|
});
|
|
} else {
|
|
toast.error(`Analyze failed on ${result.table_name}`, {
|
|
description: result.error,
|
|
});
|
|
}
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.admin.maintenanceTables() });
|
|
},
|
|
onError: (error: Error) => {
|
|
toast.error('Analyze operation failed', {
|
|
description: error.message,
|
|
});
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useReindexTable() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: async (tableName: string) => {
|
|
const { data, error } = await supabase.rpc('run_reindex_table', {
|
|
table_name: tableName,
|
|
});
|
|
|
|
if (error) throw error;
|
|
|
|
return data as unknown as MaintenanceResult;
|
|
},
|
|
onSuccess: (result) => {
|
|
if (result.success) {
|
|
toast.success(`Reindex completed on ${result.table_name}`, {
|
|
description: `Duration: ${Math.round(result.duration_ms)}ms`,
|
|
});
|
|
} else {
|
|
toast.error(`Reindex failed on ${result.table_name}`, {
|
|
description: result.error,
|
|
});
|
|
}
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.admin.maintenanceTables() });
|
|
},
|
|
onError: (error: Error) => {
|
|
toast.error('Reindex operation failed', {
|
|
description: error.message,
|
|
});
|
|
},
|
|
});
|
|
}
|