implement tasks fetching and cancelling on useQuery
This commit is contained in:
parent
7dfe90c8a6
commit
41e4ecefdb
3 changed files with 206 additions and 0 deletions
47
frontend/src/app/api/mutations/useCancelTaskMutation.ts
Normal file
47
frontend/src/app/api/mutations/useCancelTaskMutation.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import {
|
||||
type UseMutationOptions,
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
export interface CancelTaskRequest {
|
||||
taskId: string;
|
||||
}
|
||||
|
||||
export interface CancelTaskResponse {
|
||||
status: string;
|
||||
task_id: string;
|
||||
}
|
||||
|
||||
export const useCancelTaskMutation = (
|
||||
options?: Omit<
|
||||
UseMutationOptions<CancelTaskResponse, Error, CancelTaskRequest>,
|
||||
"mutationFn"
|
||||
>
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
async function cancelTask(
|
||||
variables: CancelTaskRequest,
|
||||
): Promise<CancelTaskResponse> {
|
||||
const response = await fetch(`/api/tasks/${variables.taskId}/cancel`, {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.error || "Failed to cancel task");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
return useMutation({
|
||||
mutationFn: cancelTask,
|
||||
onSuccess: () => {
|
||||
// Invalidate tasks query to refresh the list
|
||||
queryClient.invalidateQueries({ queryKey: ["tasks"] });
|
||||
},
|
||||
...options,
|
||||
});
|
||||
};
|
||||
80
frontend/src/app/api/queries/useGetTaskStatusQuery.ts
Normal file
80
frontend/src/app/api/queries/useGetTaskStatusQuery.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import {
|
||||
type UseQueryOptions,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
export interface TaskStatus {
|
||||
task_id: string;
|
||||
status:
|
||||
| "pending"
|
||||
| "running"
|
||||
| "processing"
|
||||
| "completed"
|
||||
| "failed"
|
||||
| "error";
|
||||
total_files?: number;
|
||||
processed_files?: number;
|
||||
successful_files?: number;
|
||||
failed_files?: number;
|
||||
running_files?: number;
|
||||
pending_files?: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
duration_seconds?: number;
|
||||
result?: Record<string, unknown>;
|
||||
error?: string;
|
||||
files?: Record<string, Record<string, unknown>>;
|
||||
}
|
||||
|
||||
export const useGetTaskStatusQuery = (
|
||||
taskId: string,
|
||||
options?: Omit<UseQueryOptions<TaskStatus | null>, "queryKey" | "queryFn">
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
async function getTaskStatus(): Promise<TaskStatus | null> {
|
||||
if (!taskId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const response = await fetch(`/api/tasks/${taskId}`);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
return null; // Task not found
|
||||
}
|
||||
throw new Error("Failed to fetch task status");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
const queryResult = useQuery(
|
||||
{
|
||||
queryKey: ["task-status", taskId],
|
||||
queryFn: getTaskStatus,
|
||||
refetchInterval: (data) => {
|
||||
// Only poll if the task is still active
|
||||
if (!data) {
|
||||
return false; // Stop polling if no data
|
||||
}
|
||||
|
||||
const isActive =
|
||||
data.status === "pending" ||
|
||||
data.status === "running" ||
|
||||
data.status === "processing";
|
||||
|
||||
return isActive ? 3000 : false; // Poll every 3 seconds if active
|
||||
},
|
||||
refetchIntervalInBackground: true,
|
||||
staleTime: 0, // Always consider data stale to ensure fresh updates
|
||||
gcTime: 5 * 60 * 1000, // Keep in cache for 5 minutes
|
||||
enabled: !!taskId, // Only run if taskId is provided
|
||||
...options,
|
||||
},
|
||||
queryClient,
|
||||
);
|
||||
|
||||
return queryResult;
|
||||
};
|
||||
79
frontend/src/app/api/queries/useGetTasksQuery.ts
Normal file
79
frontend/src/app/api/queries/useGetTasksQuery.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import {
|
||||
type UseQueryOptions,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
export interface Task {
|
||||
task_id: string;
|
||||
status:
|
||||
| "pending"
|
||||
| "running"
|
||||
| "processing"
|
||||
| "completed"
|
||||
| "failed"
|
||||
| "error";
|
||||
total_files?: number;
|
||||
processed_files?: number;
|
||||
successful_files?: number;
|
||||
failed_files?: number;
|
||||
running_files?: number;
|
||||
pending_files?: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
duration_seconds?: number;
|
||||
result?: Record<string, unknown>;
|
||||
error?: string;
|
||||
files?: Record<string, Record<string, unknown>>;
|
||||
}
|
||||
|
||||
export interface TasksResponse {
|
||||
tasks: Task[];
|
||||
}
|
||||
|
||||
export const useGetTasksQuery = (
|
||||
options?: Omit<UseQueryOptions<Task[]>, "queryKey" | "queryFn">
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
async function getTasks(): Promise<Task[]> {
|
||||
const response = await fetch("/api/tasks");
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch tasks");
|
||||
}
|
||||
|
||||
const data: TasksResponse = await response.json();
|
||||
return data.tasks || [];
|
||||
}
|
||||
|
||||
const queryResult = useQuery(
|
||||
{
|
||||
queryKey: ["tasks"],
|
||||
queryFn: getTasks,
|
||||
refetchInterval: (query) => {
|
||||
// Only poll if there are tasks with pending or running status
|
||||
const data = query.state.data;
|
||||
if (!data || data.length === 0) {
|
||||
return false; // Stop polling if no tasks
|
||||
}
|
||||
|
||||
const hasActiveTasks = data.some(
|
||||
(task: Task) =>
|
||||
task.status === "pending" ||
|
||||
task.status === "running" ||
|
||||
task.status === "processing"
|
||||
);
|
||||
|
||||
return hasActiveTasks ? 3000 : false; // Poll every 3 seconds if active tasks exist
|
||||
},
|
||||
refetchIntervalInBackground: true,
|
||||
staleTime: 0, // Always consider data stale to ensure fresh updates
|
||||
gcTime: 5 * 60 * 1000, // Keep in cache for 5 minutes
|
||||
...options,
|
||||
},
|
||||
queryClient,
|
||||
);
|
||||
|
||||
return queryResult;
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue