diff --git a/frontend/src/components/tasks/TaskDetailsPanel.tsx b/frontend/src/components/tasks/TaskDetailsPanel.tsx index 8ebfb767..cd54e1ba 100644 --- a/frontend/src/components/tasks/TaskDetailsPanel.tsx +++ b/frontend/src/components/tasks/TaskDetailsPanel.tsx @@ -64,6 +64,7 @@ interface TaskDetailsPanelProps { onClose: () => void; onEditTask?: (task: TaskWithAttemptStatus) => void; onDeleteTask?: (taskId: string) => void; + isDialogOpen?: boolean; // New prop to indicate if any dialog is open } const statusLabels: Record = { @@ -141,6 +142,7 @@ export function TaskDetailsPanel({ onClose, onEditTask, onDeleteTask, + isDialogOpen = false, }: TaskDetailsPanelProps) { const [taskAttempts, setTaskAttempts] = useState([]); const [selectedAttempt, setSelectedAttempt] = useState( @@ -187,7 +189,7 @@ export function TaskDetailsPanel({ // Handle ESC key locally to prevent global navigation useEffect(() => { - if (!isOpen) return; + if (!isOpen || isDialogOpen) return; // Don't handle ESC if dialog is open const handleKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") { @@ -199,7 +201,7 @@ export function TaskDetailsPanel({ document.addEventListener("keydown", handleKeyDown, true); // Use capture phase return () => document.removeEventListener("keydown", handleKeyDown, true); - }, [isOpen, onClose]); + }, [isOpen, onClose, isDialogOpen]); // Available executors const availableExecutors = [ diff --git a/frontend/src/components/tasks/TaskFormDialog.tsx b/frontend/src/components/tasks/TaskFormDialog.tsx index a83074e9..87067ccb 100644 --- a/frontend/src/components/tasks/TaskFormDialog.tsx +++ b/frontend/src/components/tasks/TaskFormDialog.tsx @@ -132,6 +132,14 @@ export function TaskFormDialog({ // Handle keyboard shortcuts useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { + // ESC to close dialog (prevent it from reaching TaskDetailsPanel) + if (event.key === 'Escape') { + event.preventDefault() + event.stopPropagation() + handleCancel() + return + } + // Command/Ctrl + Enter to Create & Start (only in create mode) if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') { if (!isEditMode && onCreateAndStartTask && title.trim() && !isSubmitting && !isSubmittingAndStart) { @@ -142,10 +150,10 @@ export function TaskFormDialog({ } if (isOpen) { - document.addEventListener('keydown', handleKeyDown) - return () => document.removeEventListener('keydown', handleKeyDown) + document.addEventListener('keydown', handleKeyDown, true) // Use capture phase to get priority + return () => document.removeEventListener('keydown', handleKeyDown, true) } - }, [isOpen, isEditMode, onCreateAndStartTask, title, isSubmitting, isSubmittingAndStart, handleCreateAndStart]) + }, [isOpen, isEditMode, onCreateAndStartTask, title, isSubmitting, isSubmittingAndStart, handleCreateAndStart, handleCancel]) return ( diff --git a/frontend/src/components/ui/dialog.tsx b/frontend/src/components/ui/dialog.tsx index ffd051c9..d7f0a2ba 100644 --- a/frontend/src/components/ui/dialog.tsx +++ b/frontend/src/components/ui/dialog.tsx @@ -21,7 +21,7 @@ const Dialog = React.forwardRef< if (!open) return null return ( -
+
onOpenChange?.(false)} @@ -29,7 +29,7 @@ const Dialog = React.forwardRef<
- - - setIsProjectSettingsOpen(false)} - onSuccess={handleProjectSettingsSuccess} - project={project} - /> - {/* Tasks View */} {tasks.length === 0 ? (
@@ -421,8 +404,27 @@ export function ProjectTasks() { onClose={handleClosePanel} onEditTask={handleEditTask} onDeleteTask={handleDeleteTask} + isDialogOpen={isTaskDialogOpen || isProjectSettingsOpen} /> )} + + {/* Dialogs - rendered at main container level to avoid stacking issues */} + + + setIsProjectSettingsOpen(false)} + onSuccess={handleProjectSettingsSuccess} + project={project} + />
); }