mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-21 23:33:07 +00:00
Feature: Add PR review comments and resolution, improve AI prompt handling (#790)
* feat: Add PR review comments and resolution endpoints, improve prompt handling * Feature: File Editor (#789) * feat: Add file management feature * feat: Add auto-save functionality to file editor * fix: Replace HardDriveDownload icon with Save icon for consistency * fix: Prevent recursive copy/move and improve shell injection prevention * refactor: Extract editor settings form into separate component * ``` fix: Improve error handling and stabilize async operations - Add error event handlers to GraphQL process spawns to prevent unhandled rejections - Replace execAsync with execFile for safer command execution and better control - Fix timeout cleanup in withTimeout generator to prevent memory leaks - Improve outdated comment detection logic by removing redundant condition - Use resolveModelString for consistent model string handling - Replace || with ?? for proper falsy value handling in dialog initialization - Add comments clarifying branch name resolution logic for local branches with slashes - Add catch handler for project selection to handle async errors gracefully ``` * refactor: Extract PR review comments logic to dedicated service * fix: Improve robustness and UX for PR review and file operations * fix: Consolidate exec utilities and improve type safety * refactor: Replace ScrollArea with div and improve file tree layout
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import { createLogger } from '@automaker/utils/logger';
|
||||
import {
|
||||
X,
|
||||
@@ -90,6 +91,7 @@ interface TerminalPanelProps {
|
||||
onSplitHorizontal: () => void;
|
||||
onSplitVertical: () => void;
|
||||
onNewTab?: () => void;
|
||||
onRunCommandInNewTab?: (command: string) => void; // Run a script command in a new terminal tab
|
||||
onNavigateUp?: () => void; // Navigate to terminal pane above
|
||||
onNavigateDown?: () => void; // Navigate to terminal pane below
|
||||
onNavigateLeft?: () => void; // Navigate to terminal pane on the left
|
||||
@@ -120,6 +122,7 @@ export function TerminalPanel({
|
||||
onSplitHorizontal,
|
||||
onSplitVertical,
|
||||
onNewTab,
|
||||
onRunCommandInNewTab,
|
||||
onNavigateUp,
|
||||
onNavigateDown,
|
||||
onNavigateLeft,
|
||||
@@ -135,6 +138,7 @@ export function TerminalPanel({
|
||||
onToggleMaximize,
|
||||
branchName,
|
||||
}: TerminalPanelProps) {
|
||||
const navigate = useNavigate();
|
||||
const terminalRef = useRef<HTMLDivElement>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const xtermRef = useRef<XTerminal | null>(null);
|
||||
@@ -2071,7 +2075,11 @@ export function TerminalPanel({
|
||||
{/* Quick scripts dropdown */}
|
||||
<TerminalScriptsDropdown
|
||||
onRunCommand={sendCommand}
|
||||
onRunCommandInNewTab={onRunCommandInNewTab}
|
||||
isConnected={connectionStatus === 'connected'}
|
||||
onOpenSettings={() =>
|
||||
navigate({ to: '/project-settings', search: { section: 'commands-scripts' } })
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Settings popover */}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { ScrollText, Play, Settings2 } from 'lucide-react';
|
||||
import { ScrollText, Play, Settings2, SquareArrowOutUpRight } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -17,6 +17,8 @@ import { DEFAULT_TERMINAL_SCRIPTS } from '../project-settings-view/terminal-scri
|
||||
interface TerminalScriptsDropdownProps {
|
||||
/** Callback to send a command + newline to the terminal */
|
||||
onRunCommand: (command: string) => void;
|
||||
/** Callback to run a command in a new terminal tab */
|
||||
onRunCommandInNewTab?: (command: string) => void;
|
||||
/** Whether the terminal is connected and ready */
|
||||
isConnected: boolean;
|
||||
/** Optional callback to navigate to project settings scripts section */
|
||||
@@ -25,11 +27,13 @@ interface TerminalScriptsDropdownProps {
|
||||
|
||||
/**
|
||||
* Dropdown menu in the terminal header bar that provides quick-access
|
||||
* to user-configured project scripts. Clicking a script inserts the
|
||||
* command into the terminal and presses Enter.
|
||||
* to user-configured project scripts. Each script is a split button:
|
||||
* clicking the left side runs the command in the current terminal,
|
||||
* clicking the "new tab" icon on the right runs it in a new tab.
|
||||
*/
|
||||
export function TerminalScriptsDropdown({
|
||||
onRunCommand,
|
||||
onRunCommandInNewTab,
|
||||
isConnected,
|
||||
onOpenSettings,
|
||||
}: TerminalScriptsDropdownProps) {
|
||||
@@ -53,6 +57,14 @@ export function TerminalScriptsDropdown({
|
||||
[isConnected, onRunCommand]
|
||||
);
|
||||
|
||||
const handleRunScriptInNewTab = useCallback(
|
||||
(command: string) => {
|
||||
if (!isConnected || !onRunCommandInNewTab) return;
|
||||
onRunCommandInNewTab(command);
|
||||
},
|
||||
[isConnected, onRunCommandInNewTab]
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
@@ -82,7 +94,7 @@ export function TerminalScriptsDropdown({
|
||||
key={script.id}
|
||||
onClick={() => handleRunScript(script.command)}
|
||||
disabled={!isConnected}
|
||||
className="gap-2"
|
||||
className="gap-2 pr-1"
|
||||
>
|
||||
<Play className={cn('h-3.5 w-3.5 shrink-0 text-brand-500')} />
|
||||
<div className="flex flex-col min-w-0 flex-1">
|
||||
@@ -91,17 +103,43 @@ export function TerminalScriptsDropdown({
|
||||
{script.command}
|
||||
</span>
|
||||
</div>
|
||||
{onRunCommandInNewTab && (
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
'shrink-0 ml-1 p-1 rounded-sm border-l border-border',
|
||||
'text-muted-foreground hover:text-foreground hover:bg-accent/80',
|
||||
'transition-colors',
|
||||
!isConnected && 'pointer-events-none opacity-50'
|
||||
)}
|
||||
title="Run in new tab"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
handleRunScriptInNewTab(script.command);
|
||||
}}
|
||||
onPointerDown={(e) => {
|
||||
// Prevent the DropdownMenuItem from handling this pointer event
|
||||
e.stopPropagation();
|
||||
}}
|
||||
onPointerUp={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<SquareArrowOutUpRight className="h-3 w-3" />
|
||||
</button>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
{onOpenSettings && (
|
||||
<>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={onOpenSettings} className="gap-2 text-muted-foreground">
|
||||
<Settings2 className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="text-sm">Configure Scripts...</span>
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={onOpenSettings}
|
||||
className="gap-2 text-muted-foreground"
|
||||
disabled={!onOpenSettings}
|
||||
>
|
||||
<Settings2 className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="text-sm">Edit Commands & Scripts</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user