feat: task ui & custom filter mutation
This commit is contained in:
@@ -26,7 +26,7 @@ import { memo, useCallback } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
export type SubscriptionSyncViewCompletePayload = {
|
||||
taskId: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export interface SubscriptionSyncViewProps {
|
||||
@@ -43,7 +43,7 @@ export const SubscriptionSyncView = memo(
|
||||
>(SYNC_SUBSCRIPTION_FEEDS_INCREMENTAL, {
|
||||
onCompleted: (data) => {
|
||||
toast.success('Sync completed');
|
||||
onComplete(data.subscriptionSyncOneFeedsIncremental);
|
||||
onComplete(data.subscriptionsSyncOneFeedsIncremental);
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Failed to sync subscription', {
|
||||
@@ -58,7 +58,7 @@ export const SubscriptionSyncView = memo(
|
||||
>(SYNC_SUBSCRIPTION_FEEDS_FULL, {
|
||||
onCompleted: (data) => {
|
||||
toast.success('Sync completed');
|
||||
onComplete(data.subscriptionSyncOneFeedsFull);
|
||||
onComplete(data.subscriptionsSyncOneFeedsFull);
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Failed to sync subscription', {
|
||||
@@ -73,7 +73,7 @@ export const SubscriptionSyncView = memo(
|
||||
>(SYNC_SUBSCRIPTION_SOURCES, {
|
||||
onCompleted: (data) => {
|
||||
toast.success('Sync completed');
|
||||
onComplete(data.subscriptionSyncOneSources);
|
||||
onComplete(data.subscriptionsSyncOneSources);
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Failed to sync subscription', {
|
||||
@@ -89,7 +89,11 @@ export const SubscriptionSyncView = memo(
|
||||
<Button
|
||||
size="lg"
|
||||
variant="outline"
|
||||
onClick={() => syncSubscriptionSources({ variables: { id } })}
|
||||
onClick={() =>
|
||||
syncSubscriptionSources({
|
||||
variables: { filter: { id: { eq: id } } },
|
||||
})
|
||||
}
|
||||
>
|
||||
<RefreshCcwIcon className="h-4 w-4" />
|
||||
<span>Sources</span>
|
||||
@@ -98,7 +102,9 @@ export const SubscriptionSyncView = memo(
|
||||
size="lg"
|
||||
variant="outline"
|
||||
onClick={() =>
|
||||
syncSubscriptionFeedsIncremental({ variables: { id } })
|
||||
syncSubscriptionFeedsIncremental({
|
||||
variables: { filter: { id: { eq: id } } },
|
||||
})
|
||||
}
|
||||
>
|
||||
<RefreshCcwIcon className="h-4 w-4" />
|
||||
@@ -107,7 +113,11 @@ export const SubscriptionSyncView = memo(
|
||||
<Button
|
||||
size="lg"
|
||||
variant="outline"
|
||||
onClick={() => syncSubscriptionFeedsFull({ variables: { id } })}
|
||||
onClick={() =>
|
||||
syncSubscriptionFeedsFull({
|
||||
variables: { filter: { id: { eq: id } } },
|
||||
})
|
||||
}
|
||||
>
|
||||
<RefreshCcwIcon className="h-4 w-4" />
|
||||
<span>Full Feeds</span>
|
||||
@@ -138,7 +148,7 @@ export const SubscriptionSyncDialogContent = memo(
|
||||
navigate({
|
||||
to: '/tasks/detail/$id',
|
||||
params: {
|
||||
id: `${payload.taskId}`,
|
||||
id: `${payload.id}`,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -25,13 +25,9 @@ import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
} from '@/infra/errors/apollo';
|
||||
import type {
|
||||
GetSubscriptionsQuery,
|
||||
SubscriptionsUpdateInput,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import type { GetSubscriptionsQuery } from '@/infra/graphql/gql/graphql';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useDebouncedSkeleton } from '@/presentation/hooks/use-debounded-skeleton';
|
||||
import { useEvent } from '@/presentation/hooks/use-event';
|
||||
import { cn } from '@/presentation/utils';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
@@ -39,7 +35,6 @@ import { useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
type PaginationState,
|
||||
type Row,
|
||||
type SortingState,
|
||||
type VisibilityState,
|
||||
flexRender,
|
||||
@@ -131,29 +126,6 @@ function SubscriptionManageRouteComponent() {
|
||||
|
||||
const subscriptions = data?.subscriptions;
|
||||
|
||||
const handleUpdateRecord = useEvent(
|
||||
(row: Row<SubscriptionDto>) => async (data: SubscriptionsUpdateInput) => {
|
||||
await updateSubscription({
|
||||
variables: {
|
||||
data,
|
||||
filters: {
|
||||
id: {
|
||||
eq: row.original.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const handleDeleteRecord = useEvent(
|
||||
(row: Row<SubscriptionDto>) => async () => {
|
||||
await deleteSubscription({
|
||||
variables: { filters: { id: { eq: row.original.id } } },
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
const cs: ColumnDef<SubscriptionDto>[] = [
|
||||
{
|
||||
@@ -166,7 +138,18 @@ function SubscriptionManageRouteComponent() {
|
||||
<Switch
|
||||
checked={enabled}
|
||||
onCheckedChange={(enabled) =>
|
||||
handleUpdateRecord(row)({ enabled: enabled })
|
||||
updateSubscription({
|
||||
variables: {
|
||||
data: {
|
||||
enabled,
|
||||
},
|
||||
filters: {
|
||||
id: {
|
||||
eq: row.original.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@@ -242,7 +225,11 @@ function SubscriptionManageRouteComponent() {
|
||||
params: { id: `${row.original.id}` },
|
||||
});
|
||||
}}
|
||||
onDelete={handleDeleteRecord(row)}
|
||||
onDelete={() =>
|
||||
deleteSubscription({
|
||||
variables: { filters: { id: { eq: row.original.id } } },
|
||||
})
|
||||
}
|
||||
>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
@@ -257,7 +244,7 @@ function SubscriptionManageRouteComponent() {
|
||||
},
|
||||
];
|
||||
return cs;
|
||||
}, [handleUpdateRecord, handleDeleteRecord, navigate]);
|
||||
}, [updateSubscription, deleteSubscription, navigate]);
|
||||
|
||||
const table = useReactTable({
|
||||
data: useMemo(() => subscriptions?.nodes ?? [], [subscriptions]),
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { memo } from 'react';
|
||||
|
||||
export const TaskActionsView = memo(() => {
|
||||
return null;
|
||||
});
|
||||
@@ -12,14 +12,18 @@ import { DetailEmptyView } from '@/components/ui/detail-empty-view';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { GET_TASKS } from '@/domains/recorder/schema/tasks';
|
||||
import { GET_TASKS, RETRY_TASKS } from '@/domains/recorder/schema/tasks';
|
||||
import { getApolloQueryError } from '@/infra/errors/apollo';
|
||||
import { apolloErrorToMessage } from '@/infra/errors/apollo';
|
||||
import {
|
||||
type GetTasksQuery,
|
||||
type GetTasksQueryVariables,
|
||||
type RetryTasksMutation,
|
||||
type RetryTasksMutationVariables,
|
||||
SubscriberTaskStatusEnum,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import {
|
||||
createFileRoute,
|
||||
useCanGoBack,
|
||||
@@ -28,6 +32,7 @@ import {
|
||||
} from '@tanstack/react-router';
|
||||
import { format } from 'date-fns';
|
||||
import { ArrowLeft, RefreshCw } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { getStatusBadge } from './-status-badge';
|
||||
|
||||
export const Route = createFileRoute('/_app/tasks/detail/$id')({
|
||||
@@ -76,6 +81,28 @@ function TaskDetailRouteComponent() {
|
||||
|
||||
const task = data?.subscriberTasks?.nodes?.[0];
|
||||
|
||||
const [retryTasks] = useMutation<
|
||||
RetryTasksMutation,
|
||||
RetryTasksMutationVariables
|
||||
>(RETRY_TASKS, {
|
||||
onCompleted: async () => {
|
||||
const refetchResult = await refetch();
|
||||
const error = getApolloQueryError(refetchResult);
|
||||
if (error) {
|
||||
toast.error('Failed to retry task', {
|
||||
description: apolloErrorToMessage(error),
|
||||
});
|
||||
return;
|
||||
}
|
||||
toast.success('Task retried successfully');
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Failed to retry task', {
|
||||
description: apolloErrorToMessage(error),
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
if (loading) {
|
||||
return <DetailCardSkeleton />;
|
||||
}
|
||||
@@ -123,6 +150,21 @@ function TaskDetailRouteComponent() {
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{getStatusBadge(task.status)}
|
||||
{task.status ===
|
||||
(SubscriberTaskStatusEnum.Killed ||
|
||||
SubscriberTaskStatusEnum.Failed) && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
retryTasks({
|
||||
variables: { filters: { id: { eq: task.id } } },
|
||||
})
|
||||
}
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
@@ -5,14 +5,23 @@ import { DetailEmptyView } from '@/components/ui/detail-empty-view';
|
||||
import { DropdownMenuActions } from '@/components/ui/dropdown-menu-actions';
|
||||
import { QueryErrorView } from '@/components/ui/query-error-view';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { GET_TASKS, type TaskDto } from '@/domains/recorder/schema/tasks';
|
||||
import {
|
||||
DELETE_TASKS,
|
||||
GET_TASKS,
|
||||
RETRY_TASKS,
|
||||
type TaskDto,
|
||||
} from '@/domains/recorder/schema/tasks';
|
||||
import {
|
||||
type DeleteTasksMutation,
|
||||
type DeleteTasksMutationVariables,
|
||||
type GetTasksQuery,
|
||||
type RetryTasksMutation,
|
||||
type RetryTasksMutationVariables,
|
||||
SubscriberTaskStatusEnum,
|
||||
} from '@/infra/graphql/gql/graphql';
|
||||
import type { RouteStateDataOption } from '@/infra/routes/traits';
|
||||
import { useDebouncedSkeleton } from '@/presentation/hooks/use-debounded-skeleton';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useMutation, useQuery } from '@apollo/client';
|
||||
import { createFileRoute, useNavigate } from '@tanstack/react-router';
|
||||
import {
|
||||
type ColumnDef,
|
||||
@@ -26,7 +35,13 @@ import {
|
||||
import { format } from 'date-fns';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
|
||||
import { DropdownMenuItem } from '@/components/ui/dropdown-menu';
|
||||
import {
|
||||
apolloErrorToMessage,
|
||||
getApolloQueryError,
|
||||
} from '@/infra/errors/apollo';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { getStatusBadge } from './-status-badge';
|
||||
|
||||
export const Route = createFileRoute('/_app/tasks/manage')({
|
||||
@@ -70,6 +85,42 @@ function TaskManageRouteComponent() {
|
||||
|
||||
const tasks = data?.subscriberTasks;
|
||||
|
||||
const [deleteTasks] = useMutation<
|
||||
DeleteTasksMutation,
|
||||
DeleteTasksMutationVariables
|
||||
>(DELETE_TASKS, {
|
||||
onCompleted: async () => {
|
||||
const refetchResult = await refetch();
|
||||
const error = getApolloQueryError(refetchResult);
|
||||
if (error) {
|
||||
toast.error('Failed to delete tasks', {
|
||||
description: apolloErrorToMessage(error),
|
||||
});
|
||||
return;
|
||||
}
|
||||
toast.success('Tasks deleted');
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Failed to delete tasks', {
|
||||
description: error.message,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const [retryTasks] = useMutation<
|
||||
RetryTasksMutation,
|
||||
RetryTasksMutationVariables
|
||||
>(RETRY_TASKS, {
|
||||
onCompleted: () => {
|
||||
toast.success('Tasks retried');
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Failed to retry tasks', {
|
||||
description: error.message,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const columns = useMemo(() => {
|
||||
const cs: ColumnDef<TaskDto>[] = [
|
||||
{
|
||||
@@ -167,7 +218,39 @@ function TaskManageRouteComponent() {
|
||||
params: { id: task.id },
|
||||
});
|
||||
}}
|
||||
/>
|
||||
showDelete
|
||||
onDelete={() =>
|
||||
deleteTasks({
|
||||
variables: {
|
||||
filters: {
|
||||
id: {
|
||||
eq: task.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
{task.status ===
|
||||
(SubscriberTaskStatusEnum.Killed ||
|
||||
SubscriberTaskStatusEnum.Failed) && (
|
||||
<DropdownMenuItem
|
||||
onSelect={() =>
|
||||
retryTasks({
|
||||
variables: {
|
||||
filters: {
|
||||
id: {
|
||||
eq: task.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
Retry
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuActions>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user