Skip to content

Commit 6b24965

Browse files
authored
feat: add repo and workflow defaults on task details page (#13)
1 parent 67c1e10 commit 6b24965

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

src/renderer/components/TaskDetail.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ export function TaskDetail({ task: initialTask }: TaskDetailProps) {
3636
runTask,
3737
cancelTask,
3838
clearTaskLogs,
39+
getRepoWorkingDir,
40+
setRepoPath,
3941
} = useTaskExecutionStore();
4042
const { repositories } = useIntegrationStore();
4143
const { updateTask, tasks } = useTaskStore();
@@ -65,6 +67,17 @@ export function TaskDetail({ task: initialTask }: TaskDetailProps) {
6567
return "";
6668
});
6769

70+
// Initialize repoPath from mapping if task has repository_config
71+
useEffect(() => {
72+
if (task.repository_config && !repoPath) {
73+
const repoKey = `${task.repository_config.organization}/${task.repository_config.repository}`;
74+
const savedPath = getRepoWorkingDir(repoKey);
75+
if (savedPath) {
76+
setRepoPath(task.id, savedPath);
77+
}
78+
}
79+
}, [task.id, task.repository_config, repoPath, getRepoWorkingDir, setRepoPath]);
80+
6881
const titleRef = useRef<HTMLElement>(null);
6982
const originalTitleRef = useRef(task.title);
7083
const descriptionRef = useRef<HTMLDivElement>(null);
@@ -91,6 +104,16 @@ export function TaskDetail({ task: initialTask }: TaskDetailProps) {
91104
}
92105
}, [workflows.length, fetchWorkflows]);
93106

107+
// Default to first workflow if not set
108+
useEffect(() => {
109+
if (workflows.length > 0 && !task.workflow) {
110+
const defaultWorkflow = workflows.find((w) => w.is_active && w.is_default) || workflows[0];
111+
if (defaultWorkflow) {
112+
void updateTask(task.id, { workflow: defaultWorkflow.id });
113+
}
114+
}
115+
}, [workflows, task.workflow, task.id, updateTask]);
116+
94117
useEffect(() => {
95118
setStatusBar({
96119
statusText: isRunning ? "Agent running..." : "Task details",
@@ -114,7 +137,8 @@ export function TaskDetail({ task: initialTask }: TaskDetailProps) {
114137

115138
// Simple event handlers that delegate to store actions
116139
const handleSelectRepo = () => {
117-
selectRepositoryForTask(task.id);
140+
const repoKey = selectedRepo && selectedRepo !== "__none__" ? selectedRepo : undefined;
141+
selectRepositoryForTask(task.id, repoKey);
118142
};
119143

120144
const handleRunTask = () => {

src/renderer/stores/taskExecutionStore.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ interface TaskExecutionState {
6262
interface TaskExecutionStore {
6363
// State per task ID
6464
taskStates: Record<string, TaskExecutionState>;
65+
// Repository (org/repo) to working directory mapping
66+
repoToCwd: Record<string, string>;
6567

6668
// Basic state accessors
6769
getTaskState: (taskId: string) => TaskExecutionState;
@@ -79,8 +81,12 @@ interface TaskExecutionStore {
7981
setProgress: (taskId: string, progress: AgentTaskProgress | null) => void;
8082
clearTaskState: (taskId: string) => void;
8183

84+
// Repository to working directory mapping
85+
getRepoWorkingDir: (repoKey: string) => string | null;
86+
setRepoWorkingDir: (repoKey: string, path: string) => void;
87+
8288
// High-level task execution actions
83-
selectRepositoryForTask: (taskId: string) => Promise<void>;
89+
selectRepositoryForTask: (taskId: string, repoKey?: string) => Promise<void>;
8490
runTask: (taskId: string, task: Task) => Promise<void>;
8591
cancelTask: (taskId: string) => Promise<void>;
8692
clearTaskLogs: (taskId: string) => void;
@@ -105,12 +111,26 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
105111
persist(
106112
(set, get) => ({
107113
taskStates: {},
114+
repoToCwd: {},
108115

109116
getTaskState: (taskId: string) => {
110117
const state = get();
111118
return state.taskStates[taskId] || { ...defaultTaskState };
112119
},
113120

121+
getRepoWorkingDir: (repoKey: string) => {
122+
return get().repoToCwd[repoKey] || null;
123+
},
124+
125+
setRepoWorkingDir: (repoKey: string, path: string) => {
126+
set((state) => ({
127+
repoToCwd: {
128+
...state.repoToCwd,
129+
[repoKey]: path,
130+
},
131+
}));
132+
},
133+
114134
updateTaskState: (
115135
taskId: string,
116136
updates: Partial<TaskExecutionState>,
@@ -338,7 +358,7 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
338358
},
339359

340360
// High-level task execution actions
341-
selectRepositoryForTask: async (taskId: string) => {
361+
selectRepositoryForTask: async (taskId: string, repoKey?: string) => {
342362
const store = get();
343363
try {
344364
const selected = await window.electronAPI?.selectDirectory();
@@ -372,11 +392,15 @@ export const useTaskExecutionStore = create<TaskExecutionStore>()(
372392
const { response } = result;
373393
if (response === 0) {
374394
// Let user reselect and validate again
375-
return store.selectRepositoryForTask(taskId);
395+
return store.selectRepositoryForTask(taskId, repoKey);
376396
}
377397
return;
378398
}
379399
store.setRepoPath(taskId, selected);
400+
// Save mapping for future tasks with the same repository
401+
if (repoKey) {
402+
store.setRepoWorkingDir(repoKey, selected);
403+
}
380404
}
381405
} catch (err) {
382406
store.addLog(

0 commit comments

Comments
 (0)