Skip to content

Commit 5cfe87c

Browse files
committed
feat(code): allow new task creation in command center
1 parent ca43354 commit 5cfe87c

4 files changed

Lines changed: 78 additions & 5 deletions

File tree

apps/code/src/renderer/features/command-center/components/CommandCenterPanel.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { TaskInput } from "@features/task-detail/components/TaskInput";
12
import { ArrowsOut, Plus, X } from "@phosphor-icons/react";
23
import { Flex, Text } from "@radix-ui/themes";
34
import type { Task } from "@shared/types";
@@ -15,6 +16,48 @@ interface CommandCenterPanelProps {
1516

1617
function EmptyCell({ cellIndex }: { cellIndex: number }) {
1718
const [selectorOpen, setSelectorOpen] = useState(false);
19+
const [isCreating, setIsCreating] = useState(false);
20+
const assignTask = useCommandCenterStore((s) => s.assignTask);
21+
22+
const handleTaskCreated = useCallback(
23+
(task: Task) => {
24+
assignTask(cellIndex, task.id);
25+
},
26+
[assignTask, cellIndex],
27+
);
28+
29+
if (isCreating) {
30+
return (
31+
<Flex direction="column" height="100%">
32+
<Flex
33+
align="center"
34+
justify="between"
35+
px="2"
36+
py="1"
37+
className="shrink-0 border-gray-6 border-b"
38+
>
39+
<Text
40+
size="1"
41+
weight="medium"
42+
className="font-mono text-[11px] text-gray-11"
43+
>
44+
New task
45+
</Text>
46+
<button
47+
type="button"
48+
onClick={() => setIsCreating(false)}
49+
className="flex h-5 w-5 items-center justify-center rounded text-gray-10 transition-colors hover:bg-gray-4 hover:text-gray-12"
50+
title="Cancel"
51+
>
52+
<X size={12} />
53+
</button>
54+
</Flex>
55+
<Flex direction="column" className="min-h-0 flex-1">
56+
<TaskInput onTaskCreated={handleTaskCreated} />
57+
</Flex>
58+
</Flex>
59+
);
60+
}
1861

1962
return (
2063
<Flex align="center" justify="center" height="100%">
@@ -23,6 +66,7 @@ function EmptyCell({ cellIndex }: { cellIndex: number }) {
2366
cellIndex={cellIndex}
2467
open={selectorOpen}
2568
onOpenChange={setSelectorOpen}
69+
onNewTask={() => setIsCreating(true)}
2670
>
2771
<button
2872
type="button"

apps/code/src/renderer/features/command-center/components/TaskSelector.tsx

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Popover } from "@radix-ui/themes";
1+
import { Plus } from "@phosphor-icons/react";
2+
import { Popover, Separator } from "@radix-ui/themes";
23
import { type ReactNode, useCallback } from "react";
34
import { useAvailableTasks } from "../hooks/useAvailableTasks";
45
import { useCommandCenterStore } from "../stores/commandCenterStore";
@@ -7,13 +8,15 @@ interface TaskSelectorProps {
78
cellIndex: number;
89
open: boolean;
910
onOpenChange: (open: boolean) => void;
11+
onNewTask: () => void;
1012
children: ReactNode;
1113
}
1214

1315
export function TaskSelector({
1416
cellIndex,
1517
open,
1618
onOpenChange,
19+
onNewTask,
1720
children,
1821
}: TaskSelectorProps) {
1922
const availableTasks = useAvailableTasks();
@@ -27,6 +30,11 @@ export function TaskSelector({
2730
[assignTask, cellIndex, onOpenChange],
2831
);
2932

33+
const handleNewTask = useCallback(() => {
34+
onOpenChange(false);
35+
onNewTask();
36+
}, [onOpenChange, onNewTask]);
37+
3038
return (
3139
<Popover.Root open={open} onOpenChange={onOpenChange}>
3240
<Popover.Trigger>{children}</Popover.Trigger>
@@ -36,6 +44,15 @@ export function TaskSelector({
3644
sideOffset={4}
3745
style={{ padding: 4, minWidth: 240, maxHeight: 300 }}
3846
>
47+
<button
48+
type="button"
49+
onClick={handleNewTask}
50+
className="flex w-full items-center gap-1.5 rounded-sm px-2 py-1.5 text-left font-mono text-[11px] text-gray-12 transition-colors hover:bg-gray-3"
51+
>
52+
<Plus size={12} />
53+
Create new task
54+
</button>
55+
<Separator size="4" className="my-1" />
3956
<div className="overflow-y-auto" style={{ maxHeight: 280 }}>
4057
{availableTasks.length === 0 ? (
4158
<div className="px-2 py-3 text-center font-mono text-[11px] text-gray-10">

apps/code/src/renderer/features/task-detail/components/TaskInput.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ import { type WorkspaceMode, WorkspaceModeSelect } from "./WorkspaceModeSelect";
3131

3232
const DOT_FILL = "var(--gray-6)";
3333

34-
export function TaskInput() {
34+
interface TaskInputProps {
35+
onTaskCreated?: (task: import("@shared/types").Task) => void;
36+
}
37+
38+
export function TaskInput({ onTaskCreated }: TaskInputProps = {}) {
3539
const trpcReact = useTRPC();
3640
const { view } = useNavigationStore();
3741
const { data: mostRecentRepo } = useQuery(
@@ -131,6 +135,7 @@ export function TaskInput() {
131135
executionMode: currentExecutionMode,
132136
model: currentModel,
133137
reasoningLevel: currentReasoningLevel,
138+
onTaskCreated,
134139
});
135140

136141
const handleCycleMode = useCallback(() => {

apps/code/src/renderer/features/task-detail/hooks/useTaskCreation.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { useConnectivity } from "@hooks/useConnectivity";
99
import type { WorkspaceMode } from "@main/services/workspace/schemas";
1010
import { get } from "@renderer/di/container";
1111
import { RENDERER_TOKENS } from "@renderer/di/tokens";
12-
import type { ExecutionMode } from "@shared/types";
12+
import type { ExecutionMode, Task } from "@shared/types";
1313
import { useNavigationStore } from "@stores/navigationStore";
1414
import { logger } from "@utils/logger";
1515
import { useCallback, useState } from "react";
@@ -30,6 +30,7 @@ interface UseTaskCreationOptions {
3030
adapter?: "claude" | "codex";
3131
model?: string;
3232
reasoningLevel?: string;
33+
onTaskCreated?: (task: Task) => void;
3334
}
3435

3536
interface UseTaskCreationReturn {
@@ -91,6 +92,7 @@ export function useTaskCreation({
9192
adapter,
9293
model,
9394
reasoningLevel,
95+
onTaskCreated,
9496
}: UseTaskCreationOptions): UseTaskCreationReturn {
9597
const [isCreatingTask, setIsCreatingTask] = useState(false);
9698
const { navigateToTask } = useNavigationStore();
@@ -140,8 +142,12 @@ export function useTaskCreation({
140142
// Invalidate tasks query
141143
invalidateTasks(task);
142144

143-
// Navigate to the new task
144-
navigateToTask(task);
145+
// Navigate to the new task or notify caller
146+
if (onTaskCreated) {
147+
onTaskCreated(task);
148+
} else {
149+
navigateToTask(task);
150+
}
145151

146152
// Clear editor
147153
editor.clear();
@@ -176,6 +182,7 @@ export function useTaskCreation({
176182
reasoningLevel,
177183
invalidateTasks,
178184
navigateToTask,
185+
onTaskCreated,
179186
]);
180187

181188
return {

0 commit comments

Comments
 (0)