diff --git a/crates/server/src/routes/task_attempts.rs b/crates/server/src/routes/task_attempts.rs index 86673f60..c6ddfd8a 100644 --- a/crates/server/src/routes/task_attempts.rs +++ b/crates/server/src/routes/task_attempts.rs @@ -592,6 +592,7 @@ pub async fn create_github_pr( #[derive(serde::Deserialize)] pub struct OpenEditorRequest { editor_type: Option, + file_path: Option, } pub async fn open_task_attempt_in_editor( @@ -601,7 +602,7 @@ pub async fn open_task_attempt_in_editor( ) -> Result>, ApiError> { // Get the task attempt to access the worktree path let attempt = &task_attempt; - let path = attempt.container_ref.as_ref().ok_or_else(|| { + let base_path = attempt.container_ref.as_ref().ok_or_else(|| { tracing::error!( "No container ref found for task attempt {}", task_attempt.id @@ -611,18 +612,25 @@ pub async fn open_task_attempt_in_editor( )) })?; + // If a specific file path is provided, use it; otherwise use the base path + let path = if let Some(file_path) = payload.as_ref().and_then(|req| req.file_path.as_ref()) { + std::path::Path::new(base_path).join(file_path) + } else { + std::path::PathBuf::from(base_path) + }; + let editor_config = { let config = deployment.config().read().await; let editor_type_str = payload.as_ref().and_then(|req| req.editor_type.as_deref()); config.editor.with_override(editor_type_str) }; - match editor_config.open_file(path) { + match editor_config.open_file(&path.to_string_lossy()) { Ok(_) => { tracing::info!( "Opened editor for task attempt {} at path: {}", task_attempt.id, - path + path.display() ); Ok(ResponseJson(ApiResponse::success(()))) } diff --git a/frontend/src/components/DiffCard.tsx b/frontend/src/components/DiffCard.tsx index e91d3737..d5d44161 100644 --- a/frontend/src/components/DiffCard.tsx +++ b/frontend/src/components/DiffCard.tsx @@ -2,6 +2,11 @@ import { DiffFile, DiffModeEnum, DiffView } from '@git-diff-view/react'; import { ThemeMode } from 'shared/types'; import '../styles/diff-style-overrides.css'; import { useConfig } from './config-provider'; +import { useContext } from 'react'; +import { TaskSelectedAttemptContext } from './context/taskDetailsContext'; +import { Button } from './ui/button'; +import { FolderOpen } from 'lucide-react'; +import { attemptsApi } from '@/lib/api'; type Props = { diffFile: DiffFile; @@ -10,26 +15,51 @@ type Props = { const DiffCard = ({ diffFile, key }: Props) => { const { config } = useConfig(); + const { selectedAttempt } = useContext(TaskSelectedAttemptContext); let theme: 'light' | 'dark' | undefined = 'light'; if (config?.theme === ThemeMode.DARK) { theme = 'dark'; } + const handleOpenInIDE = async () => { + if (!selectedAttempt?.id) return; + try { + await attemptsApi.openEditor( + selectedAttempt.id, + undefined, + diffFile._newFileName + ); + } catch (error) { + console.error('Failed to open file in IDE:', error); + } + }; + return (
-

- {diffFile._newFileName}{' '} - - +{diffFile.additionLength} - {' '} - - -{diffFile.deletionLength} - -

+
+

+ {diffFile._newFileName}{' '} + + +{diffFile.additionLength} + {' '} + + -{diffFile.deletionLength} + +

+ +
=> { + const requestBody: any = {}; + if (editorType) requestBody.editor_type = editorType; + if (filePath) requestBody.file_path = filePath; + const response = await makeRequest( `/api/task-attempts/${attemptId}/open-editor`, { method: 'POST', - body: JSON.stringify(editorType ? { editor_type: editorType } : null), + body: JSON.stringify( + Object.keys(requestBody).length > 0 ? requestBody : null + ), } ); return handleApiResponse(response);