feat(cron): allow users to associate cron jobs with specific agents (#835)

This commit is contained in:
Tao Yiping
2026-04-12 11:51:29 +08:00
committed by GitHub
Unverified
parent 49518300dc
commit 87ab12849c
9 changed files with 429 additions and 10 deletions

View File

@@ -20,6 +20,7 @@ import {
History,
Pause,
ChevronDown,
Bot,
} from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
@@ -32,6 +33,8 @@ import { ConfirmDialog } from '@/components/ui/confirm-dialog';
import { hostApiFetch } from '@/lib/host-api';
import { useCronStore } from '@/stores/cron';
import { useGatewayStore } from '@/stores/gateway';
import { useAgentsStore } from '@/stores/agents';
import { useChatStore } from '@/stores/chat';
import { LoadingSpinner } from '@/components/common/LoadingSpinner';
import { formatRelativeTime, cn } from '@/lib/utils';
import { toast } from 'sonner';
@@ -243,9 +246,12 @@ interface TaskDialogProps {
function TaskDialog({ job, configuredChannels, onClose, onSave }: TaskDialogProps) {
const { t } = useTranslation('cron');
const [saving, setSaving] = useState(false);
const agents = useAgentsStore((s) => s.agents);
const [name, setName] = useState(job?.name || '');
const [message, setMessage] = useState(job?.message || '');
const [selectedAgentId, setSelectedAgentId] = useState(job?.agentId || useChatStore.getState().currentAgentId);
const [agentIdChanged, setAgentIdChanged] = useState(false);
// Extract cron expression string from CronSchedule object or use as-is if string
const initialSchedule = (() => {
const s = job?.schedule;
@@ -405,6 +411,7 @@ function TaskDialog({ job, configuredChannels, onClose, onSave }: TaskDialogProp
schedule: finalSchedule,
delivery: finalDelivery,
enabled,
...(agentIdChanged ? { agentId: selectedAgentId } : {}),
});
onClose();
toast.success(job ? t('toast.updated') : t('toast.created'));
@@ -453,6 +460,26 @@ function TaskDialog({ job, configuredChannels, onClose, onSave }: TaskDialogProp
/>
</div>
{/* Agent */}
<div className="space-y-2.5">
<Label htmlFor="agent" className="text-[14px] text-foreground/80 font-bold">{t('dialog.agent')}</Label>
<SelectField
id="agent"
value={selectedAgentId}
onChange={(e) => {
setSelectedAgentId(e.target.value);
setAgentIdChanged(true);
}}
className="h-[44px] rounded-xl border-black/10 dark:border-white/10 bg-[#eeece3] dark:bg-muted text-[13px]"
>
{agents.map((agent) => (
<option key={agent.id} value={agent.id}>
{agent.name}
</option>
))}
</SelectField>
</div>
{/* Schedule */}
<div className="space-y-2.5">
<Label className="text-[14px] text-foreground/80 font-bold">{t('dialog.schedule')}</Label>
@@ -685,6 +712,8 @@ interface CronJobCardProps {
function CronJobCard({ job, deliveryAccountName, onToggle, onEdit, onDelete, onTrigger }: CronJobCardProps) {
const { t } = useTranslation('cron');
const [triggering, setTriggering] = useState(false);
const agents = useAgentsStore((s) => s.agents);
const agentName = agents.find((a) => a.id === job.agentId)?.name ?? job.agentId;
const handleTrigger = async (e: React.MouseEvent) => {
e.stopPropagation();
@@ -787,6 +816,11 @@ function CronJobCard({ job, deliveryAccountName, onToggle, onEdit, onDelete, onT
{t('card.next')}: {new Date(job.nextRun).toLocaleString()}
</span>
)}
<span className="flex items-center gap-1.5">
<Bot className="h-3.5 w-3.5" />
{agentName}
</span>
</div>
{/* Last Run Error */}