diff --git a/src/web-ui/src/component-library/components/InputDialog/InputDialog.scss b/src/web-ui/src/component-library/components/InputDialog/InputDialog.scss index 6e328e8..c6d8b9a 100644 --- a/src/web-ui/src/component-library/components/InputDialog/InputDialog.scss +++ b/src/web-ui/src/component-library/components/InputDialog/InputDialog.scss @@ -2,29 +2,46 @@ * InputDialog styles */ .input-dialog { - padding: 4px; + display: flex; + flex-direction: column; - &__description { - margin: 0 0 20px 0; - font-size: 14px; - line-height: 1.6; - color: var(--text-secondary); + &__body { + padding: 20px 20px 16px; } - &__input-wrapper { - margin-bottom: 24px; + &__description { + margin: 0 0 12px 0; + font-size: 12px; + line-height: 1.5; + color: var(--color-text-muted); } &__actions { display: flex; justify-content: flex-end; - gap: 12px; - padding-top: 4px; + align-items: center; + gap: 8px; + padding: 10px 20px 12px; + border-top: 1px solid var(--border-subtle); + + // Give buttons explicit borders for visual consistency with the input field + .btn { + min-width: 68px; + border: 1px solid var(--border-base); + + &-primary { + border-color: rgba(96, 165, 250, 0.4); + } + } } } -.modal--small .modal__content { - min-width: 320px; +.modal--small { + max-width: 360px; + + .modal__content { + min-width: 0; + } } .modal-overlay:has(.input-dialog) { diff --git a/src/web-ui/src/component-library/components/InputDialog/InputDialog.tsx b/src/web-ui/src/component-library/components/InputDialog/InputDialog.tsx index 0cc1881..a3258b5 100644 --- a/src/web-ui/src/component-library/components/InputDialog/InputDialog.tsx +++ b/src/web-ui/src/component-library/components/InputDialog/InputDialog.tsx @@ -114,11 +114,10 @@ export const InputDialog: React.FC = ({ showCloseButton={true} >
- {description && ( -

{description}

- )} - -
+
+ {description && ( +

{description}

+ )} = ({
, + document.body ); }; \ No newline at end of file diff --git a/src/web-ui/src/tools/terminal/components/ConnectedTerminal.tsx b/src/web-ui/src/tools/terminal/components/ConnectedTerminal.tsx index f2fbffe..dc3db2a 100644 --- a/src/web-ui/src/tools/terminal/components/ConnectedTerminal.tsx +++ b/src/web-ui/src/tools/terminal/components/ConnectedTerminal.tsx @@ -46,26 +46,28 @@ const ConnectedTerminal: React.FC = memo(({ const [title, setTitle] = useState(initialSession?.name || 'Terminal'); const [exitCode, setExitCode] = useState(null); const [isExited, setIsExited] = useState(false); - const [isTerminalReady, setIsTerminalReady] = useState(false); const lastSentSizeRef = useRef<{ cols: number; rows: number } | null>(null); // Buffer output until the terminal is ready. + // Use a ref (not state) to avoid stale closure issues with isTerminalReady. + const isTerminalReadyRef = useRef(false); const outputQueueRef = useRef([]); const handleOutput = useCallback((data: string) => { - if (!isTerminalReady || !terminalRef.current) { + if (!isTerminalReadyRef.current || !terminalRef.current) { outputQueueRef.current.push(data); return; } terminalRef.current.write(data); - }, [isTerminalReady]); + }, []); // No state deps - reads from refs which are always current const flushOutputQueue = useCallback(() => { const queue = outputQueueRef.current; if (queue.length === 0) return; - queue.forEach(data => terminalRef.current?.write(data)); + // Clear first to prevent orphaned items if new data arrives during flush outputQueueRef.current = []; + queue.forEach(data => terminalRef.current?.write(data)); }, []); const handleReady = useCallback(() => { @@ -129,9 +131,11 @@ const ConnectedTerminal: React.FC = memo(({ }, [onTitleChange]); const handleTerminalReady = useCallback(() => { - console.log('[ConnectedTerminal] handleTerminalReady called'); - setIsTerminalReady(true); - + // Set the ref synchronously first so handleOutput immediately writes directly + // instead of queuing. This eliminates the stale-closure window where new data + // would be queued after flushOutputQueue() cleared the queue but before React + // re-rendered and updated onOutputRef.current. + isTerminalReadyRef.current = true; flushOutputQueue(); }, [flushOutputQueue]);