Skip to content

Commit 250ba6d

Browse files
committed
Merge branch 'development' into staging
2 parents b120a17 + e2108e5 commit 250ba6d

27 files changed

Lines changed: 1091 additions & 801 deletions

src/client/app/tasks/page.js

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function TasksPageContent() {
4545
const [oneTimeTasks, setOneTimeTasks] = useState([])
4646
const [recurringTasks, setRecurringTasks] = useState([])
4747
const [triggeredTasks, setTriggeredTasks] = useState([])
48+
const [swarmTasks, setSwarmTasks] = useState([])
4849
const [recurringInstances, setRecurringInstances] = useState([])
4950
const [integrations, setIntegrations] = useState([])
5051
const [allTools, setAllTools] = useState([])
@@ -110,10 +111,13 @@ function TasksPageContent() {
110111
const oneTime = []
111112
const recurring = []
112113
const triggered = []
114+
const swarm = []
113115
const instances = []
114116

115117
rawTasks.forEach((task) => {
116-
if (task.schedule?.type === "recurring") {
118+
if (task.task_type === "swarm") {
119+
swarm.push(task)
120+
} else if (task.schedule?.type === "recurring") {
117121
recurring.push(task)
118122
// Process past runs from `runs` array
119123
if (task.runs && Array.isArray(task.runs)) {
@@ -163,6 +167,7 @@ function TasksPageContent() {
163167
setOneTimeTasks(oneTime)
164168
setRecurringTasks(recurring)
165169
setTriggeredTasks(triggered)
170+
setSwarmTasks(swarm)
166171
setRecurringInstances(instances)
167172

168173
const integrationsRes = await fetch("/api/settings/integrations")
@@ -353,7 +358,11 @@ Description: ${event.description || "No description."}`
353358
}, [oneTimeTasks, searchQuery])
354359

355360
const filteredActiveWorkflows = useMemo(() => {
356-
const allWorkflows = [...recurringTasks, ...triggeredTasks]
361+
const allWorkflows = [
362+
...swarmTasks,
363+
...recurringTasks,
364+
...triggeredTasks
365+
]
357366
if (!searchQuery.trim()) {
358367
return allWorkflows
359368
}
@@ -365,7 +374,7 @@ Description: ${event.description || "No description."}`
365374
.toLowerCase()
366375
.includes(searchQuery.toLowerCase()))
367376
)
368-
}, [recurringTasks, triggeredTasks, searchQuery])
377+
}, [swarmTasks, recurringTasks, triggeredTasks, searchQuery])
369378

370379
const filteredCalendarTasks = useMemo(() => {
371380
const allCalendarTasks = [...oneTimeTasks, ...recurringInstances]
@@ -547,30 +556,6 @@ Description: ${event.description || "No description."}`
547556
)
548557
}
549558
onRerun={(taskId) =>
550-
handleAction(
551-
() =>
552-
fetch(
553-
`/api/tasks/rerun`,
554-
{
555-
method: "POST",
556-
body: JSON.stringify(
557-
{
558-
taskId
559-
}
560-
),
561-
headers: {
562-
"Content-Type":
563-
"application/json"
564-
}
565-
}
566-
),
567-
"Task re-run."
568-
)
569-
}
570-
onAnswerClarifications={(
571-
taskId,
572-
answers
573-
) =>
574559
handleAction(
575560
() =>
576561
fetch(

src/client/components/tasks/CreateTaskInput.js

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,51 @@
11
"use client"
22
import React, { useState, useRef, useEffect } from "react"
3-
import { IconLoader, IconSend } from "@tabler/icons-react"
3+
import { IconLoader, IconSend, IconUsersGroup } from "@tabler/icons-react"
44
import { cn } from "@utils/cn"
55
import { BorderTrail } from "@components/ui/border-trail"
66
import { TextLoop } from "@components/ui/TextLoop"
77
import toast from "react-hot-toast"
88

99
const CreateTaskInput = ({ onTaskAdded, prompt, setPrompt }) => {
10+
const [isSwarmMode, setIsSwarmMode] = useState(false)
1011
const [isSaving, setIsSaving] = useState(false)
1112
const textareaRef = useRef(null)
1213

1314
useEffect(() => {
1415
const textarea = textareaRef.current
1516
if (textarea) {
1617
textarea.style.height = "auto"
17-
textarea.style.height = `${Math.min(textarea.scrollHeight, 100)}px`
18+
textarea.style.height = `${Math.min(textarea.scrollHeight, 150)}px`
1819
}
1920
}, [prompt])
2021

2122
const handleAddTask = async () => {
23+
setIsSaving(true)
24+
let payload = {}
25+
2226
if (!prompt.trim()) {
2327
toast.error("Please describe the task.")
28+
setIsSaving(false)
2429
return
2530
}
26-
setIsSaving(true)
31+
payload = {
32+
prompt: prompt,
33+
is_swarm: isSwarmMode
34+
}
35+
2736
try {
2837
const response = await fetch("/api/tasks/add", {
2938
method: "POST",
3039
headers: { "Content-Type": "application/json" },
31-
body: JSON.stringify({ prompt, assignee: "ai" })
40+
body: JSON.stringify(payload)
3241
})
3342
const data = await response.json()
3443
if (!response.ok)
3544
throw new Error(data.error || "Failed to add task")
36-
toast.success(data.message || "Task added!")
45+
toast.success(
46+
data.message ||
47+
(isSwarmMode ? "Swarm task initiated!" : "Task added!")
48+
)
3749
setPrompt("")
3850
onTaskAdded()
3951
} catch (error) {
@@ -47,7 +59,8 @@ const CreateTaskInput = ({ onTaskAdded, prompt, setPrompt }) => {
4759
<div className="p-4 flex-shrink-0 bg-transparent">
4860
<div
4961
className={cn(
50-
"relative flex bg-brand-black rounded-full p-1 transition-all overflow-hidden min-h-[50px]"
62+
"relative flex bg-brand-black p-1 transition-all overflow-hidden",
63+
"rounded-full min-h-[50px]"
5164
)}
5265
>
5366
<BorderTrail size={100} className="bg-brand-orange px-4" />
@@ -69,33 +82,62 @@ const CreateTaskInput = ({ onTaskAdded, prompt, setPrompt }) => {
6982
placeholder=" "
7083
className="w-full rounded-l-full bg-transparent text-white placeholder-transparent border-1 border-brand-orange focus:ring-0 focus:ring-brand-black text-sm z-10 overflow-y-auto self-stretch py-2"
7184
/>
85+
7286
{!prompt && (
7387
<div className="absolute top-1/2 left-4 right-12 -translate-y-1/2 text-neutral-500 pointer-events-none z-0 overflow-hidden">
7488
<TextLoop className="text-sm px-2 whitespace-normal md:whitespace-nowrap">
75-
<span>Create a task...</span>
89+
<span>
90+
{isSwarmMode
91+
? "Describe a swarm task..."
92+
: "Create a task..."}
93+
</span>
7694
<span>
7795
Summarize my unread emails from today
7896
</span>
7997
<span>
8098
Draft a follow-up to the project proposal
8199
</span>
82100
<span>
83-
Schedule a meeting with the design team
101+
{isSwarmMode
102+
? "Research these topics: AI, ML, and Data Science"
103+
: "Schedule a meeting with the design team"}
84104
</span>
85105
</TextLoop>
86106
</div>
87107
)}
88-
<button
89-
onClick={handleAddTask}
90-
disabled={isSaving || !prompt.trim()}
91-
className="p-3 bg-brand-orange rounded-r-full h-full text-brand-black disabled:opacity-50 hover:bg-opacity-80 transition-colors z-10 flex-shrink-0"
92-
>
93-
{isSaving ? (
94-
<IconLoader size={18} className="animate-spin" />
95-
) : (
96-
<IconSend size={18} />
97-
)}
98-
</button>
108+
<div className={cn("flex items-center gap-2 z-10")}>
109+
<button
110+
onClick={() => setIsSwarmMode(!isSwarmMode)}
111+
className={cn(
112+
"p-3 rounded-full h-full transition-colors",
113+
isSwarmMode
114+
? "bg-blue-600 text-white"
115+
: "bg-neutral-800 text-neutral-300 hover:bg-neutral-700"
116+
)}
117+
data-tooltip-id="tasks-tooltip"
118+
data-tooltip-content={
119+
isSwarmMode
120+
? "Switch to Single Task Mode"
121+
: "Switch to Swarm Mode"
122+
}
123+
>
124+
<IconUsersGroup size={18} />
125+
</button>
126+
<button
127+
onClick={handleAddTask}
128+
disabled={isSaving || !prompt.trim()}
129+
className="p-3 bg-brand-orange rounded-full h-full text-brand-black disabled:opacity-50 hover:bg-opacity-80 transition-colors flex-shrink-0"
130+
>
131+
{isSaving ? (
132+
<IconLoader
133+
size={18}
134+
className="animate-spin"
135+
/>
136+
) : (
137+
<IconSend size={18} />
138+
)}
139+
</button>
140+
</div>
99141
</div>
100142
</div>
101143
</div>

src/client/components/tasks/ExecutionUpdate.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,34 @@ const CollapsibleSection = ({
2626
return (
2727
<div
2828
className={cn(
29-
"border-l-2 pl-3 transition-colors",
30-
isExpanded ? colorClass : "border-neutral-700"
29+
"border-l-4 pl-3 mb-2 rounded-md",
30+
colorClass,
31+
"bg-neutral-900/60"
3132
)}
3233
>
3334
<button
34-
onClick={() => setIsExpanded(!isExpanded)}
35-
className="flex items-center gap-2 w-full text-left text-sm font-semibold"
35+
className="flex items-center gap-2 w-full text-left focus:outline-none"
36+
onClick={() => setIsExpanded((prev) => !prev)}
3637
>
37-
{icon}
38-
<span className="flex-grow">{title}</span>
38+
<span>{icon}</span>
39+
<span className="font-semibold">{title}</span>
3940
<IconChevronDown
4041
size={16}
4142
className={cn(
42-
"transform transition-transform duration-200",
43-
isExpanded ? "rotate-180" : "rotate-0"
43+
"ml-auto transition-transform",
44+
isExpanded ? "rotate-180" : ""
4445
)}
4546
/>
4647
</button>
47-
<AnimatePresence>
48+
<AnimatePresence initial={false}>
4849
{isExpanded && (
4950
<motion.div
50-
initial={{ height: 0, opacity: 0, marginTop: 0 }}
51-
animate={{ height: "auto", opacity: 1, marginTop: 8 }}
52-
exit={{ height: 0, opacity: 0, marginTop: 0 }}
53-
className="overflow-hidden"
51+
initial={{ height: 0, opacity: 0 }}
52+
animate={{ height: "auto", opacity: 1 }}
53+
exit={{ height: 0, opacity: 0 }}
54+
transition={{ duration: 0.2 }}
5455
>
55-
{children}
56+
<div className="mt-2">{children}</div>
5657
</motion.div>
5758
)}
5859
</AnimatePresence>

0 commit comments

Comments
 (0)