First swing.
This commit is contained in:
78
src/hooks/useOperations.ts
Normal file
78
src/hooks/useOperations.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { operationsApi } from '../services/api';
|
||||
import type { Operation } from '../services/api';
|
||||
|
||||
export function useOperations(instanceName: string | null | undefined) {
|
||||
return useQuery({
|
||||
queryKey: ['instances', instanceName, 'operations'],
|
||||
queryFn: () => operationsApi.list(instanceName!),
|
||||
enabled: !!instanceName,
|
||||
refetchInterval: 2000, // Poll every 2 seconds
|
||||
});
|
||||
}
|
||||
|
||||
export function useOperation(operationId: string | null | undefined) {
|
||||
const [operation, setOperation] = useState<Operation | null>(null);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
useEffect(() => {
|
||||
if (!operationId) return;
|
||||
|
||||
// Fetch initial state
|
||||
operationsApi.get(operationId).then(setOperation).catch(setError);
|
||||
|
||||
// Set up SSE stream
|
||||
const eventSource = operationsApi.createStream(operationId);
|
||||
|
||||
eventSource.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
setOperation(data);
|
||||
|
||||
// Invalidate relevant queries when operation completes
|
||||
if (data.status === 'completed' || data.status === 'failed') {
|
||||
eventSource.close();
|
||||
// Invalidate queries based on operation type
|
||||
if (data.instance_name) {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['instances', data.instance_name]
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err : new Error('Failed to parse operation update'));
|
||||
}
|
||||
};
|
||||
|
||||
eventSource.onerror = () => {
|
||||
setError(new Error('Operation stream failed'));
|
||||
eventSource.close();
|
||||
};
|
||||
|
||||
return () => {
|
||||
eventSource.close();
|
||||
};
|
||||
}, [operationId, queryClient]);
|
||||
|
||||
const cancelMutation = useMutation({
|
||||
mutationFn: () => {
|
||||
if (!operation?.instance_name) {
|
||||
throw new Error('Cannot cancel operation: instance name not available');
|
||||
}
|
||||
return operationsApi.cancel(operationId!, operation.instance_name);
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Operation state will be updated via SSE
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
operation,
|
||||
error,
|
||||
isLoading: !operation && !error,
|
||||
cancel: cancelMutation.mutate,
|
||||
isCancelling: cancelMutation.isPending,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user