From 4be8d5d1d747115c6fdf598a79b1fb8d13631d6d Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Sat, 30 May 2026 10:09:29 -0400 Subject: [PATCH] feat: display queued messages and allow submit while session is processing --- .../chat/view/subcomponents/ChatComposer.tsx | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/components/chat/view/subcomponents/ChatComposer.tsx b/src/components/chat/view/subcomponents/ChatComposer.tsx index 2701e7b..2893cbb 100644 --- a/src/components/chat/view/subcomponents/ChatComposer.tsx +++ b/src/components/chat/view/subcomponents/ChatComposer.tsx @@ -11,7 +11,7 @@ import type { SetStateAction, TouchEvent, } from 'react'; -import { ImageIcon, MessageSquareIcon, XIcon, ArrowDownIcon } from 'lucide-react'; +import { ImageIcon, MessageSquareIcon, XIcon, ArrowDownIcon, ClockIcon } from 'lucide-react'; import type { PendingPermissionRequest, PermissionMode, Provider } from '../../types/types'; import CommandMenu from './CommandMenu'; import ClaudeStatus from './ClaudeStatus'; @@ -45,6 +45,11 @@ interface SlashCommand { [key: string]: unknown; } +interface QueuedMessage { + id: string; + text: string; +} + interface ChatComposerProps { pendingPermissionRequests: PendingPermissionRequest[]; handlePermissionDecision: ( @@ -101,6 +106,8 @@ interface ChatComposerProps { placeholder: string; isTextareaExpanded: boolean; sendByCtrlEnter?: boolean; + messageQueue?: QueuedMessage[]; + onRemoveQueued?: (id: string) => void; } export default function ChatComposer({ @@ -156,6 +163,8 @@ export default function ChatComposer({ placeholder, isTextareaExpanded, sendByCtrlEnter, + messageQueue = [], + onRemoveQueued, }: ChatComposerProps) { const { t } = useTranslation('chat'); const textareaRect = textareaRef.current?.getBoundingClientRect(); @@ -165,12 +174,10 @@ export default function ChatComposer({ bottom: textareaRect ? window.innerHeight - textareaRect.top + 8 : 90, }; - // Detect if the AskUserQuestion interactive panel is active const hasQuestionPanel = pendingPermissionRequests.some( (r) => r.toolName === 'AskUserQuestion' ); - // Hide the thinking/status bar while any permission request is pending const hasPendingPermissions = pendingPermissionRequests.length > 0; return ( @@ -194,6 +201,32 @@ export default function ChatComposer({ )} + {/* Queued messages — shown when user sends while session is processing */} + {messageQueue.length > 0 && ( +
+ {messageQueue.map((q) => ( +
+ + {q.text} + Queued + {onRemoveQueued && ( + + )} +
+ ))} +
+ )} + {!hasQuestionPanel &&
{isUserScrolledUp && hasMessages && (
@@ -396,10 +429,12 @@ export default function ChatComposer({ input.trim() ? 'opacity-0' : 'opacity-100' }`} > - {sendByCtrlEnter ? t('input.hintText.ctrlEnter') : t('input.hintText.enter')} + {isLoading + ? t('input.hintText.queue', { defaultValue: 'Enter to queue' }) + : sendByCtrlEnter ? t('input.hintText.ctrlEnter') : t('input.hintText.enter')}
{ event.preventDefault();