@agentforge-ai/cli 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/default/README.md +81 -81
- package/dist/default/convex/agents.ts +204 -0
- package/dist/default/convex/apiKeys.ts +133 -0
- package/dist/default/convex/cronJobs.ts +224 -0
- package/dist/default/convex/files.ts +103 -0
- package/dist/default/convex/folders.ts +110 -0
- package/dist/default/convex/heartbeat.ts +371 -0
- package/dist/default/convex/logs.ts +66 -0
- package/dist/default/convex/mastraIntegration.ts +184 -0
- package/dist/default/convex/mcpConnections.ts +127 -0
- package/dist/default/convex/messages.ts +90 -0
- package/dist/default/convex/projects.ts +114 -0
- package/dist/default/convex/sessions.ts +174 -0
- package/dist/default/convex/settings.ts +79 -0
- package/dist/default/convex/skills.ts +178 -0
- package/dist/default/convex/threads.ts +100 -0
- package/dist/default/convex/usage.ts +195 -0
- package/dist/default/convex/vault.ts +383 -0
- package/dist/default/dashboard/app/main.tsx +7 -3
- package/dist/default/dashboard/app/routes/agents.tsx +103 -161
- package/dist/default/dashboard/app/routes/chat.tsx +163 -317
- package/dist/default/dashboard/app/routes/connections.tsx +247 -386
- package/dist/default/dashboard/app/routes/cron.tsx +127 -286
- package/dist/default/dashboard/app/routes/files.tsx +184 -167
- package/dist/default/dashboard/app/routes/index.tsx +63 -96
- package/dist/default/dashboard/app/routes/projects.tsx +106 -225
- package/dist/default/dashboard/app/routes/sessions.tsx +87 -253
- package/dist/default/dashboard/app/routes/settings.tsx +316 -532
- package/dist/default/dashboard/app/routes/skills.tsx +329 -216
- package/dist/default/dashboard/app/routes/usage.tsx +107 -150
- package/dist/default/dashboard/tsconfig.json +3 -2
- package/dist/default/dashboard/vite.config.ts +6 -0
- package/dist/index.js +279 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/default/README.md +81 -81
- package/templates/default/convex/agents.ts +204 -0
- package/templates/default/convex/apiKeys.ts +133 -0
- package/templates/default/convex/cronJobs.ts +224 -0
- package/templates/default/convex/files.ts +103 -0
- package/templates/default/convex/folders.ts +110 -0
- package/templates/default/convex/heartbeat.ts +371 -0
- package/templates/default/convex/logs.ts +66 -0
- package/templates/default/convex/mastraIntegration.ts +184 -0
- package/templates/default/convex/mcpConnections.ts +127 -0
- package/templates/default/convex/messages.ts +90 -0
- package/templates/default/convex/projects.ts +114 -0
- package/templates/default/convex/sessions.ts +174 -0
- package/templates/default/convex/settings.ts +79 -0
- package/templates/default/convex/skills.ts +178 -0
- package/templates/default/convex/threads.ts +100 -0
- package/templates/default/convex/usage.ts +195 -0
- package/templates/default/convex/vault.ts +383 -0
- package/templates/default/dashboard/app/main.tsx +7 -3
- package/templates/default/dashboard/app/routes/agents.tsx +103 -161
- package/templates/default/dashboard/app/routes/chat.tsx +163 -317
- package/templates/default/dashboard/app/routes/connections.tsx +247 -386
- package/templates/default/dashboard/app/routes/cron.tsx +127 -286
- package/templates/default/dashboard/app/routes/files.tsx +184 -167
- package/templates/default/dashboard/app/routes/index.tsx +63 -96
- package/templates/default/dashboard/app/routes/projects.tsx +106 -225
- package/templates/default/dashboard/app/routes/sessions.tsx +87 -253
- package/templates/default/dashboard/app/routes/settings.tsx +316 -532
- package/templates/default/dashboard/app/routes/skills.tsx +329 -216
- package/templates/default/dashboard/app/routes/usage.tsx +107 -150
- package/templates/default/dashboard/tsconfig.json +3 -2
- package/templates/default/dashboard/vite.config.ts +6 -0
|
@@ -1,322 +1,163 @@
|
|
|
1
1
|
import { createFileRoute } from '@tanstack/react-router';
|
|
2
2
|
import { DashboardLayout } from '../components/DashboardLayout';
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { Input } from '../components/ui/input';
|
|
8
|
-
import { Label } from '../components/ui/label';
|
|
9
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../components/ui/select';
|
|
10
|
-
import { Switch } from '../components/ui/switch';
|
|
11
|
-
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../components/ui/table';
|
|
12
|
-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../components/ui/tooltip';
|
|
13
|
-
import { Clock, Play, Pause, Plus, History, AlertCircle, Trash2, Edit } from 'lucide-react';
|
|
14
|
-
// import { useQuery, useMutation } from 'convex/react';
|
|
15
|
-
// import { api } from '../../convex/_generated/api';
|
|
3
|
+
import { useState, useMemo } from 'react';
|
|
4
|
+
import { useQuery, useMutation } from 'convex/react';
|
|
5
|
+
import { api } from '@convex/_generated/api';
|
|
6
|
+
import { Clock, Play, Pause, Plus, History, Trash2, Edit, X, AlertCircle } from 'lucide-react';
|
|
16
7
|
|
|
17
|
-
export const Route = createFileRoute('/cron')({ component:
|
|
8
|
+
export const Route = createFileRoute('/cron')({ component: CronPage });
|
|
18
9
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
status: 'enabled' | 'disabled';
|
|
26
|
-
lastRun: string | null;
|
|
27
|
-
nextRun: string;
|
|
28
|
-
};
|
|
10
|
+
function CronPage() {
|
|
11
|
+
const cronJobs = useQuery(api.cronJobs.list, {}) ?? [];
|
|
12
|
+
const agents = useQuery(api.agents.list, {}) ?? [];
|
|
13
|
+
const createCron = useMutation(api.cronJobs.create);
|
|
14
|
+
const removeCron = useMutation(api.cronJobs.remove);
|
|
15
|
+
const toggleCron = useMutation(api.cronJobs.toggleEnabled);
|
|
29
16
|
|
|
30
|
-
const initialCronJobs: CronJob[] = [
|
|
31
|
-
{
|
|
32
|
-
id: 'cron_1',
|
|
33
|
-
name: 'Daily Report',
|
|
34
|
-
schedule: '0 9 * * *',
|
|
35
|
-
scheduleReadable: 'Every day at 9:00 AM',
|
|
36
|
-
agent: 'reporting-agent',
|
|
37
|
-
status: 'enabled',
|
|
38
|
-
lastRun: '2026-02-15 09:00:12',
|
|
39
|
-
nextRun: '2026-02-16 09:00:00',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: 'cron_2',
|
|
43
|
-
name: 'Hourly Sync',
|
|
44
|
-
schedule: '0 * * * *',
|
|
45
|
-
scheduleReadable: 'Every hour',
|
|
46
|
-
agent: 'sync-agent',
|
|
47
|
-
status: 'disabled',
|
|
48
|
-
lastRun: '2026-02-15 14:00:05',
|
|
49
|
-
nextRun: '2026-02-15 16:00:00',
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
id: 'cron_3',
|
|
53
|
-
name: 'Nightly Cleanup',
|
|
54
|
-
schedule: '0 2 * * *',
|
|
55
|
-
scheduleReadable: 'Every day at 2:00 AM',
|
|
56
|
-
agent: 'cleanup-agent',
|
|
57
|
-
status: 'enabled',
|
|
58
|
-
lastRun: '2026-02-15 02:00:08',
|
|
59
|
-
nextRun: '2026-02-16 02:00:00',
|
|
60
|
-
},
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
function CronPageComponent() {
|
|
64
|
-
// const cronJobs = useQuery(api.cronJobs.list) ?? [];
|
|
65
|
-
// const createCronJob = useMutation(api.cronJobs.create);
|
|
66
|
-
// const updateCronJob = useMutation(api.cronJobs.update);
|
|
67
|
-
// const deleteCronJob = useMutation(api.cronJobs.delete);
|
|
68
|
-
|
|
69
|
-
const [cronJobs, setCronJobs] = useState<CronJob[]>(initialCronJobs);
|
|
70
17
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
71
|
-
const [
|
|
72
|
-
const [selectedJobHistory, setSelectedJobHistory] = useState<CronJob | null>(null);
|
|
18
|
+
const [historyJobId, setHistoryJobId] = useState<string | null>(null);
|
|
73
19
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
const updatedJob = { ...editingJob, ...jobData };
|
|
77
|
-
setCronJobs(cronJobs.map(j => j.id === editingJob.id ? updatedJob : j));
|
|
78
|
-
// updateCronJob({ id: updatedJob.id, ...jobData });
|
|
79
|
-
} else {
|
|
80
|
-
const newJob = { ...jobData, id: `cron_${Date.now()}` };
|
|
81
|
-
setCronJobs([...cronJobs, newJob]);
|
|
82
|
-
// createCronJob(jobData);
|
|
83
|
-
}
|
|
20
|
+
const handleCreate = async (data: any) => {
|
|
21
|
+
await createCron(data);
|
|
84
22
|
setIsModalOpen(false);
|
|
85
|
-
setEditingJob(null);
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const handleToggleStatus = (job: CronJob) => {
|
|
89
|
-
const newStatus = job.status === 'enabled' ? 'disabled' : 'enabled';
|
|
90
|
-
const updatedJob = { ...job, status: newStatus };
|
|
91
|
-
setCronJobs(cronJobs.map(j => j.id === job.id ? updatedJob : j));
|
|
92
|
-
// updateCronJob({ id: job.id, status: newStatus });
|
|
93
23
|
};
|
|
94
24
|
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
// deleteCronJob({ id });
|
|
25
|
+
const handleDelete = async (id: any) => {
|
|
26
|
+
if (confirm('Delete this cron job?')) {
|
|
27
|
+
await removeCron({ id });
|
|
99
28
|
}
|
|
100
29
|
};
|
|
101
30
|
|
|
102
|
-
const openEditModal = (job: CronJob) => {
|
|
103
|
-
setEditingJob(job);
|
|
104
|
-
setIsModalOpen(true);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const openCreateModal = () => {
|
|
108
|
-
setEditingJob(null);
|
|
109
|
-
setIsModalOpen(true);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
31
|
return (
|
|
113
32
|
<DashboardLayout>
|
|
114
|
-
<div className="
|
|
115
|
-
<div className="flex justify-between items-center
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
<CronJobForm
|
|
124
|
-
job={editingJob}
|
|
125
|
-
onSave={handleSaveJob}
|
|
126
|
-
onClose={() => setIsModalOpen(false)}
|
|
127
|
-
/>
|
|
128
|
-
</Dialog>
|
|
33
|
+
<div className="space-y-6">
|
|
34
|
+
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
|
|
35
|
+
<div>
|
|
36
|
+
<h1 className="text-3xl font-bold">Scheduled Tasks</h1>
|
|
37
|
+
<p className="text-muted-foreground">Automate agent execution with cron schedules.</p>
|
|
38
|
+
</div>
|
|
39
|
+
<button onClick={() => setIsModalOpen(true)} className="bg-primary text-primary-foreground px-4 py-2 rounded-lg hover:bg-primary/90 flex items-center gap-2">
|
|
40
|
+
<Plus className="w-4 h-4" /> New Schedule
|
|
41
|
+
</button>
|
|
129
42
|
</div>
|
|
130
43
|
|
|
131
|
-
|
|
132
|
-
<
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
</
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
<
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
<Button variant="ghost" size="icon" onClick={() => setSelectedJobHistory(job)}>
|
|
185
|
-
<History className="h-4 w-4" />
|
|
186
|
-
</Button>
|
|
187
|
-
<Button variant="ghost" size="icon" onClick={() => openEditModal(job)}>
|
|
188
|
-
<Edit className="h-4 w-4" />
|
|
189
|
-
</Button>
|
|
190
|
-
<Button variant="destructive" size="icon" onClick={() => handleDeleteJob(job.id)}>
|
|
191
|
-
<Trash2 className="h-4 w-4" />
|
|
192
|
-
</Button>
|
|
193
|
-
</TableCell>
|
|
194
|
-
</TableRow>
|
|
195
|
-
))}
|
|
196
|
-
</TableBody>
|
|
197
|
-
</Table>
|
|
198
|
-
) : (
|
|
199
|
-
<div className="text-center py-12 text-muted-foreground">
|
|
200
|
-
<Clock className="mx-auto h-12 w-12" />
|
|
201
|
-
<h3 className="mt-4 text-lg font-semibold">No Cron Jobs Scheduled</h3>
|
|
202
|
-
<p className="mt-2 text-sm">Get started by adding a new cron job.</p>
|
|
203
|
-
</div>
|
|
204
|
-
)}
|
|
205
|
-
</CardContent>
|
|
206
|
-
</Card>
|
|
44
|
+
{cronJobs.length === 0 ? (
|
|
45
|
+
<div className="text-center py-16 bg-card border border-border rounded-lg">
|
|
46
|
+
<Clock className="w-16 h-16 text-muted-foreground/30 mx-auto mb-4" />
|
|
47
|
+
<h3 className="text-lg font-semibold mb-2">No scheduled tasks</h3>
|
|
48
|
+
<p className="text-muted-foreground mb-4">Create a cron job to run agents on a schedule.</p>
|
|
49
|
+
<button onClick={() => setIsModalOpen(true)} className="bg-primary text-primary-foreground px-4 py-2 rounded-lg hover:bg-primary/90">
|
|
50
|
+
<Plus className="w-4 h-4 inline mr-2" />Create Schedule
|
|
51
|
+
</button>
|
|
52
|
+
</div>
|
|
53
|
+
) : (
|
|
54
|
+
<div className="bg-card border border-border rounded-lg overflow-hidden">
|
|
55
|
+
<table className="w-full text-sm">
|
|
56
|
+
<thead className="bg-muted/50">
|
|
57
|
+
<tr>
|
|
58
|
+
<th className="text-left px-4 py-3 font-medium text-muted-foreground">Name</th>
|
|
59
|
+
<th className="text-left px-4 py-3 font-medium text-muted-foreground">Schedule</th>
|
|
60
|
+
<th className="text-left px-4 py-3 font-medium text-muted-foreground">Agent</th>
|
|
61
|
+
<th className="text-left px-4 py-3 font-medium text-muted-foreground">Status</th>
|
|
62
|
+
<th className="text-left px-4 py-3 font-medium text-muted-foreground">Last Run</th>
|
|
63
|
+
<th className="text-right px-4 py-3 font-medium text-muted-foreground">Actions</th>
|
|
64
|
+
</tr>
|
|
65
|
+
</thead>
|
|
66
|
+
<tbody>
|
|
67
|
+
{cronJobs.map((job: any) => (
|
|
68
|
+
<tr key={job._id} className="border-t border-border hover:bg-muted/30">
|
|
69
|
+
<td className="px-4 py-3">
|
|
70
|
+
<div>
|
|
71
|
+
<p className="font-medium">{job.name}</p>
|
|
72
|
+
{job.description && <p className="text-xs text-muted-foreground">{job.description}</p>}
|
|
73
|
+
</div>
|
|
74
|
+
</td>
|
|
75
|
+
<td className="px-4 py-3 font-mono text-xs">{job.schedule}</td>
|
|
76
|
+
<td className="px-4 py-3 text-muted-foreground">{job.agentId}</td>
|
|
77
|
+
<td className="px-4 py-3">
|
|
78
|
+
<span className={`text-xs px-2 py-0.5 rounded-full ${job.isEnabled ? 'bg-green-500/10 text-green-500' : 'bg-muted text-muted-foreground'}`}>
|
|
79
|
+
{job.isEnabled ? 'Enabled' : 'Disabled'}
|
|
80
|
+
</span>
|
|
81
|
+
</td>
|
|
82
|
+
<td className="px-4 py-3 text-xs text-muted-foreground">{job.lastRun ? new Date(job.lastRun).toLocaleString() : 'Never'}</td>
|
|
83
|
+
<td className="px-4 py-3 text-right">
|
|
84
|
+
<div className="flex items-center justify-end gap-1">
|
|
85
|
+
<button onClick={() => toggleCron({ id: job._id })} className="p-1.5 rounded hover:bg-muted" title={job.isEnabled ? 'Pause' : 'Resume'}>
|
|
86
|
+
{job.isEnabled ? <Pause className="w-4 h-4 text-muted-foreground" /> : <Play className="w-4 h-4 text-green-500" />}
|
|
87
|
+
</button>
|
|
88
|
+
<button onClick={() => handleDelete(job._id)} className="p-1.5 rounded hover:bg-destructive/10"><Trash2 className="w-4 h-4 text-destructive" /></button>
|
|
89
|
+
</div>
|
|
90
|
+
</td>
|
|
91
|
+
</tr>
|
|
92
|
+
))}
|
|
93
|
+
</tbody>
|
|
94
|
+
</table>
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
207
97
|
|
|
208
|
-
|
|
209
|
-
<CardHeader>
|
|
210
|
-
<CardTitle className="flex items-center">
|
|
211
|
-
<History className="mr-2 h-5 w-5" />
|
|
212
|
-
Execution History
|
|
213
|
-
</CardTitle>
|
|
214
|
-
</CardHeader>
|
|
215
|
-
<CardContent>
|
|
216
|
-
{selectedJobHistory ? (
|
|
217
|
-
<div>
|
|
218
|
-
<h4 className="font-semibold mb-2">{selectedJobHistory.name}</h4>
|
|
219
|
-
<ul className="space-y-2 text-sm text-muted-foreground">
|
|
220
|
-
{[...Array(5)].map((_, i) => (
|
|
221
|
-
<li key={i} className="flex items-center justify-between p-2 bg-background rounded-md border">
|
|
222
|
-
<span>Run #{15 - i}</span>
|
|
223
|
-
<span className="text-xs">{(new Date(Date.now() - i * 3600000)).toLocaleString()}</span>
|
|
224
|
-
<span className="text-green-500">Success</span>
|
|
225
|
-
</li>
|
|
226
|
-
))}
|
|
227
|
-
</ul>
|
|
228
|
-
</div>
|
|
229
|
-
) : (
|
|
230
|
-
<div className="text-center py-10 text-muted-foreground">
|
|
231
|
-
<AlertCircle className="mx-auto h-10 w-10" />
|
|
232
|
-
<p className="mt-4 text-sm">Select a job to view its execution history.</p>
|
|
233
|
-
</div>
|
|
234
|
-
)}
|
|
235
|
-
</CardContent>
|
|
236
|
-
</Card>
|
|
237
|
-
</div>
|
|
98
|
+
{isModalOpen && <CronModal agents={agents} onSave={handleCreate} onClose={() => setIsModalOpen(false)} />}
|
|
238
99
|
</div>
|
|
239
100
|
</DashboardLayout>
|
|
240
101
|
);
|
|
241
102
|
}
|
|
242
103
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
onSave: (jobData: Omit<CronJob, 'id'>) => void;
|
|
246
|
-
onClose: () => void;
|
|
247
|
-
}
|
|
104
|
+
function CronModal({ agents, onSave, onClose }: { agents: any[]; onSave: (data: any) => void; onClose: () => void }) {
|
|
105
|
+
const [form, setForm] = useState({ name: '', description: '', schedule: '0 9 * * *', agentId: agents[0]?.id || '', prompt: '' });
|
|
248
106
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
107
|
+
const presets = [
|
|
108
|
+
{ label: 'Every minute', value: '* * * * *' },
|
|
109
|
+
{ label: 'Every hour', value: '0 * * * *' },
|
|
110
|
+
{ label: 'Daily at 9 AM', value: '0 9 * * *' },
|
|
111
|
+
{ label: 'Weekly (Mon 9 AM)', value: '0 9 * * 1' },
|
|
112
|
+
{ label: 'Monthly (1st at 9 AM)', value: '0 9 1 * *' },
|
|
113
|
+
];
|
|
254
114
|
|
|
255
|
-
const handleSubmit = (e:
|
|
115
|
+
const handleSubmit = (e: any) => {
|
|
256
116
|
e.preventDefault();
|
|
257
|
-
|
|
258
|
-
// This is a simplified readable schedule. A real implementation would use a library.
|
|
259
|
-
const scheduleReadable = schedulePreset === 'custom' ? `Custom: ${customSchedule}` : `Every ${schedulePreset.split(' ')[1]}`;
|
|
260
|
-
|
|
261
|
-
onSave({
|
|
262
|
-
name,
|
|
263
|
-
agent,
|
|
264
|
-
schedule,
|
|
265
|
-
scheduleReadable,
|
|
266
|
-
status: job?.status || 'enabled',
|
|
267
|
-
lastRun: job?.lastRun || null,
|
|
268
|
-
nextRun: job?.nextRun || 'Calculating...',
|
|
269
|
-
});
|
|
117
|
+
onSave(form);
|
|
270
118
|
};
|
|
271
119
|
|
|
272
120
|
return (
|
|
273
|
-
<
|
|
274
|
-
<
|
|
275
|
-
<
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
<
|
|
121
|
+
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center p-4">
|
|
122
|
+
<div className="bg-card border border-border rounded-lg shadow-xl w-full max-w-lg">
|
|
123
|
+
<div className="flex justify-between items-center p-4 border-b border-border">
|
|
124
|
+
<h2 className="text-lg font-bold">New Scheduled Task</h2>
|
|
125
|
+
<button onClick={onClose} className="text-muted-foreground hover:text-foreground"><X className="h-5 w-5" /></button>
|
|
126
|
+
</div>
|
|
127
|
+
<form onSubmit={handleSubmit} className="p-6 space-y-4">
|
|
128
|
+
<div>
|
|
129
|
+
<label className="block text-sm font-medium mb-1">Name</label>
|
|
130
|
+
<input type="text" value={form.name} onChange={(e) => setForm(prev => ({ ...prev, name: e.target.value }))} className="w-full bg-background border border-border rounded-md px-3 py-2 text-sm" placeholder="e.g. Daily Report" required />
|
|
282
131
|
</div>
|
|
283
|
-
<div
|
|
284
|
-
<
|
|
285
|
-
<
|
|
132
|
+
<div>
|
|
133
|
+
<label className="block text-sm font-medium mb-1">Description</label>
|
|
134
|
+
<input type="text" value={form.description} onChange={(e) => setForm(prev => ({ ...prev, description: e.target.value }))} className="w-full bg-background border border-border rounded-md px-3 py-2 text-sm" placeholder="Optional description" />
|
|
286
135
|
</div>
|
|
287
|
-
<div
|
|
288
|
-
<
|
|
289
|
-
<
|
|
290
|
-
<
|
|
291
|
-
|
|
292
|
-
</SelectTrigger>
|
|
293
|
-
<SelectContent>
|
|
294
|
-
<SelectItem value="0 * * * *">Every Hour</SelectItem>
|
|
295
|
-
<SelectItem value="0 0 * * *">Every Day (midnight)</SelectItem>
|
|
296
|
-
<SelectItem value="0 0 * * 1">Every Week (Monday)</SelectItem>
|
|
297
|
-
<SelectItem value="custom">Custom Cron Expression</SelectItem>
|
|
298
|
-
</SelectContent>
|
|
299
|
-
</Select>
|
|
136
|
+
<div>
|
|
137
|
+
<label className="block text-sm font-medium mb-1">Agent</label>
|
|
138
|
+
<select value={form.agentId} onChange={(e) => setForm(prev => ({ ...prev, agentId: e.target.value }))} className="w-full bg-background border border-border rounded-md px-3 py-2 text-sm" required>
|
|
139
|
+
{agents.length === 0 ? <option value="">No agents available</option> : agents.map((a: any) => <option key={a.id} value={a.id}>{a.name}</option>)}
|
|
140
|
+
</select>
|
|
300
141
|
</div>
|
|
301
|
-
|
|
302
|
-
<
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
value={
|
|
307
|
-
|
|
308
|
-
className="col-span-3"
|
|
309
|
-
placeholder="* * * * *"
|
|
310
|
-
required
|
|
311
|
-
/>
|
|
142
|
+
<div>
|
|
143
|
+
<label className="block text-sm font-medium mb-1">Cron Schedule</label>
|
|
144
|
+
<input type="text" value={form.schedule} onChange={(e) => setForm(prev => ({ ...prev, schedule: e.target.value }))} className="w-full bg-background border border-border rounded-md px-3 py-2 text-sm font-mono" required />
|
|
145
|
+
<div className="flex flex-wrap gap-1 mt-2">
|
|
146
|
+
{presets.map(p => (
|
|
147
|
+
<button key={p.value} type="button" onClick={() => setForm(prev => ({ ...prev, schedule: p.value }))} className={`text-xs px-2 py-1 rounded border ${form.schedule === p.value ? 'bg-primary text-primary-foreground border-primary' : 'bg-muted border-border text-muted-foreground hover:text-foreground'}`}>{p.label}</button>
|
|
148
|
+
))}
|
|
312
149
|
</div>
|
|
313
|
-
|
|
150
|
+
</div>
|
|
151
|
+
<div>
|
|
152
|
+
<label className="block text-sm font-medium mb-1">Prompt</label>
|
|
153
|
+
<textarea value={form.prompt} onChange={(e) => setForm(prev => ({ ...prev, prompt: e.target.value }))} rows={3} className="w-full bg-background border border-border rounded-md px-3 py-2 text-sm" placeholder="What should the agent do?" required />
|
|
154
|
+
</div>
|
|
155
|
+
</form>
|
|
156
|
+
<div className="p-4 border-t border-border flex justify-end gap-2">
|
|
157
|
+
<button onClick={onClose} className="px-4 py-2 rounded-lg bg-muted text-muted-foreground text-sm">Cancel</button>
|
|
158
|
+
<button onClick={handleSubmit} disabled={!form.name || !form.agentId || !form.prompt} className="px-4 py-2 rounded-lg bg-primary text-primary-foreground text-sm hover:bg-primary/90 disabled:opacity-50">Create Schedule</button>
|
|
314
159
|
</div>
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
<Button type="submit">Save Job</Button>
|
|
318
|
-
</DialogFooter>
|
|
319
|
-
</form>
|
|
320
|
-
</DialogContent>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
321
162
|
);
|
|
322
163
|
}
|