Skip to content

Commit 086c2de

Browse files
committed
feat: add directory prompt on run and cloud mode gating
When clicking "Run (Local)" without a directory set: - Tasks WITH repository_config: Prompt "Do you have it locally?" → "I have it locally" opens folder picker → "Clone for me" triggers clone flow with progress UI - Tasks WITHOUT repository_config: Prompt "Select working directory" → Opens folder picker Cloud mode changes: - Disable Cloud mode toggle for tasks without repository_config - Show tooltip: "Cloud mode requires a connected repository" Technical changes: - Updated runTask() in taskExecutionStore to prompt before showing error - Integrated with existing clone flow and progress UI (PR #128) - Persist selected directories via taskDirectoryStore (PR #130, #131) - Removed noisy directory source badges (simplified UX) This creates a frictionless flow where engineers can easily point to existing repos or clone them on-demand, while still supporting directory-only tasks for non-git workflows.
1 parent 677f962 commit 086c2de

File tree

4 files changed

+168
-168
lines changed

4 files changed

+168
-168
lines changed

src/renderer/features/task-detail/components/TaskActions.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface TaskActionsProps {
77
isCloningRepo: boolean;
88
cloneProgress: { message: string; percent: number } | null;
99
runMode: "local" | "cloud";
10+
hasRepositoryConfig: boolean;
1011
onRunTask: () => void;
1112
onCancel: () => void;
1213
onRunModeChange: (mode: "local" | "cloud") => void;
@@ -17,6 +18,7 @@ export const TaskActions: React.FC<TaskActionsProps> = ({
1718
isCloningRepo,
1819
cloneProgress,
1920
runMode,
21+
hasRepositoryConfig,
2022
onRunTask,
2123
onCancel,
2224
onRunModeChange,
@@ -58,12 +60,18 @@ export const TaskActions: React.FC<TaskActionsProps> = ({
5860
>
5961
<span className="truncate">{getRunButtonLabel()}</span>
6062
</Button>
61-
<Tooltip content="Toggle between Local or Cloud Agent">
63+
<Tooltip
64+
content={
65+
!hasRepositoryConfig
66+
? "Cloud mode requires a connected repository"
67+
: "Toggle between Local or Cloud Agent"
68+
}
69+
>
6270
<IconButton
6371
size="2"
6472
variant="classic"
6573
color={runMode === "cloud" ? "blue" : "gray"}
66-
disabled={isRunning || isCloningRepo}
74+
disabled={isRunning || isCloningRepo || !hasRepositoryConfig}
6775
onClick={() =>
6876
onRunModeChange(runMode === "local" ? "cloud" : "local")
6977
}

src/renderer/features/task-detail/components/TaskDetailPanel.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ export function TaskDetailPanel({ taskId, task }: TaskDetailPanelProps) {
9090
? { status: execution.state.progress.status }
9191
: undefined
9292
}
93-
derivedPath={taskData.derivedPath}
94-
defaultWorkspace={taskData.defaultWorkspace}
9593
/>
9694
</Flex>
9795

@@ -101,6 +99,7 @@ export function TaskDetailPanel({ taskId, task }: TaskDetailPanelProps) {
10199
isCloningRepo={repository.isCloning}
102100
cloneProgress={taskData.cloneProgress}
103101
runMode={execution.state.runMode}
102+
hasRepositoryConfig={!!taskData.task.repository_config}
104103
onRunTask={execution.actions.run}
105104
onCancel={execution.actions.cancel}
106105
onRunModeChange={execution.actions.onRunModeChange}

src/renderer/features/task-detail/components/TaskMetadata.tsx

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,42 @@
1-
import { Button, Code, DataList, Link, Text, Tooltip } from "@radix-ui/themes";
1+
import { FolderPicker } from "@features/folder-picker/components/FolderPicker";
2+
import { useTaskExecutionStore } from "@features/task-detail/stores/taskExecutionStore";
3+
import { Cross2Icon } from "@radix-ui/react-icons";
4+
import {
5+
Box,
6+
Button,
7+
Code,
8+
DataList,
9+
Flex,
10+
IconButton,
11+
Link,
12+
Text,
13+
Tooltip,
14+
} from "@radix-ui/themes";
215
import type { Task } from "@shared/types";
316
import { format, formatDistanceToNow } from "date-fns";
417
import type React from "react";
5-
import { FolderPicker } from "@features/folder-picker/components/FolderPicker";
6-
import { useTaskExecutionStore } from "@features/task-detail/stores/taskExecutionStore";
718

819
interface TaskMetadataProps {
920
task: Task;
1021
progress?: { status: string };
11-
derivedPath: string | null;
12-
defaultWorkspace: string | null;
1322
}
1423

1524
export const TaskMetadata: React.FC<TaskMetadataProps> = ({
1625
task,
1726
progress,
18-
derivedPath,
19-
defaultWorkspace,
2027
}) => {
21-
const { setRepoPath, revalidateRepo } = useTaskExecutionStore();
28+
const { setRepoPath, revalidateRepo, getTaskState } = useTaskExecutionStore();
29+
const taskState = getTaskState(task.id);
2230

2331
const handleWorkingDirectoryChange = async (newPath: string) => {
2432
setRepoPath(task.id, newPath);
2533
await revalidateRepo(task.id);
2634
};
2735

36+
const handleClearDirectory = () => {
37+
setRepoPath(task.id, null);
38+
};
39+
2840
return (
2941
<>
3042
<DataList.Root>
@@ -73,16 +85,28 @@ export const TaskMetadata: React.FC<TaskMetadataProps> = ({
7385
<DataList.Item>
7486
<DataList.Label>Working directory</DataList.Label>
7587
<DataList.Value>
76-
<FolderPicker
77-
value={derivedPath || ""}
78-
onChange={handleWorkingDirectoryChange}
79-
placeholder={
80-
!defaultWorkspace
81-
? "No workspace configured"
82-
: "Select working directory..."
83-
}
84-
size="2"
85-
/>
88+
<Flex gap="2" align="center" width="100%">
89+
<Box style={{ flex: 1, minWidth: 0 }}>
90+
<FolderPicker
91+
value={taskState.repoPath || ""}
92+
onChange={handleWorkingDirectoryChange}
93+
placeholder="Not set - click Run to select"
94+
size="2"
95+
/>
96+
</Box>
97+
{taskState.repoPath && (
98+
<Tooltip content="Clear directory selection">
99+
<IconButton
100+
size="2"
101+
variant="ghost"
102+
color="gray"
103+
onClick={handleClearDirectory}
104+
>
105+
<Cross2Icon />
106+
</IconButton>
107+
</Tooltip>
108+
)}
109+
</Flex>
86110
</DataList.Value>
87111
</DataList.Item>
88112

0 commit comments

Comments
 (0)