import { useMutation } from '@apollo/client'; import { useNavigate } from '@tanstack/react-router'; import { CalendarIcon } from 'lucide-react'; import { memo, useCallback, useState } from 'react'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Cron } from '@/components/ui/cron'; import { CronMode } from '@/components/ui/cron/types'; import { DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Separator } from '@/components/ui/separator'; import { Spinner } from '@/components/ui/spinner'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { INSERT_CRON } from '@/domains/recorder/schema/cron'; import { useInject } from '@/infra/di/inject'; import { type InsertCronMutation, type InsertCronMutationVariables, SubscriberTaskTypeEnum, } from '@/infra/graphql/gql/graphql'; import { IntlService } from '@/infra/intl/intl.service'; const SUBSCRIPTION_TASK_CRON_PRESETS = [ { label: 'Every hour', value: '0 0 * * * *', description: 'Runs at the top of every hour', category: 'common', }, { label: 'Daily at midnight', value: '0 0 0 * * *', description: 'Runs once daily at 00:00', category: 'daily', }, { label: 'Daily at 9 AM', value: '0 0 9 * * *', description: 'Runs daily at 9:00 AM', category: 'daily', }, { label: 'Every Sunday', value: '0 0 0 * * 0', description: 'Runs every Sunday at midnight', category: 'weekly', }, { label: 'First day of month', value: '0 0 0 1 * *', description: 'Runs on the 1st day of every month', category: 'monthly', }, { label: 'Every year', value: '0 0 0 1 1 *', description: 'Runs on January 1st every year', category: 'yearly', }, ]; const CRON_TABS = [ { tab: SubscriberTaskTypeEnum.SyncOneSubscriptionSources, label: 'Sync sources', description: 'Syncs subscription sources', }, { tab: SubscriberTaskTypeEnum.SyncOneSubscriptionFeedsIncremental, label: 'Feeds incremental', description: 'Syncs incremental subscription feeds', }, { tab: SubscriberTaskTypeEnum.SyncOneSubscriptionFeedsFull, label: 'Feeds full', description: 'Syncs all subscription feeds', }, ]; export type SubscriptionCronCreationViewCompletePayload = { id: number; }; export interface SubscriptionCronCreationViewProps { subscriptionId: number; onComplete: (payload: SubscriptionCronCreationViewCompletePayload) => void; } export interface SubscriptionCronFormProps { tab: (typeof CRON_TABS)[number]; timezone: string; onComplete: (payload: SubscriptionCronFormPayload) => void; } export interface SubscriptionCronFormPayload { cronExpr: string; } export const SubscriptionCronForm = memo( ({ tab, timezone, onComplete }: SubscriptionCronFormProps) => { const [cronExpr, setCronExpr] = useState(''); return ( {tab.label} {tab.description} ); } ); export const SubscriptionCronCreationView = memo( ({ subscriptionId, onComplete }: SubscriptionCronCreationViewProps) => { const intlService = useInject(IntlService); const [insertCron, { loading: loadingInsert }] = useMutation< InsertCronMutation, InsertCronMutationVariables >(INSERT_CRON, { onCompleted: (data) => { toast.success('Cron created'); onComplete(data.cronCreateOne); }, onError: (error) => { toast.error('Failed to sync subscription', { description: error.message, }); }, }); const loading = loadingInsert; return (
{CRON_TABS.map((tab) => ( {tab.label} ))}
{CRON_TABS.map((tab) => ( { insertCron({ variables: { data: { cronExpr: payload.cronExpr, cronTimezone: intlService.timezone, subscriberTaskCron: { subscriptionId, taskType: tab.tab, }, }, }, }); }} timezone={intlService.timezone} /> ))} {loading && (
Creating cron...
)}
); } ); export interface SubscriptionCronCreationDialogContentProps { subscriptionId: number; onCancel?: VoidFunction; } export const SubscriptionCronCreationDialogContent = memo( ({ subscriptionId, onCancel, }: SubscriptionCronCreationDialogContentProps) => { const navigate = useNavigate(); const handleCreationComplete = useCallback( (payload: SubscriptionCronCreationViewCompletePayload) => { navigate({ to: '/tasks/cron/detail/$id', params: { id: `${payload.id}`, }, }); }, [navigate] ); return ( Create Cron Create a cron to execute the subscription. ); } );