From c80d7a8165e0202cd192119fb1120ce2838268ff Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 14 Apr 2026 17:28:31 +0700 Subject: [PATCH] =?UTF-8?q?fix:=20require=20content=20to=20create=20worksp?= =?UTF-8?q?ace=20=E2=80=94=20no=20more=20empty=20submissions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace allowEmptySubmit/emptySubmitLabel with hasExternalContent prop that treats GitHub items the same as text and images in submit gating. --- .../app/src/components/agent-input-submit.ts | 4 +- packages/app/src/components/composer.tsx | 13 +++--- packages/app/src/components/message-input.tsx | 42 ++++--------------- .../app/src/screens/new-workspace-screen.tsx | 3 +- .../workspace/workspace-draft-agent-tab.tsx | 1 - 5 files changed, 17 insertions(+), 46 deletions(-) diff --git a/packages/app/src/components/agent-input-submit.ts b/packages/app/src/components/agent-input-submit.ts index eb711d082..a89df2cfb 100644 --- a/packages/app/src/components/agent-input-submit.ts +++ b/packages/app/src/components/agent-input-submit.ts @@ -3,7 +3,7 @@ export type AgentInputSubmitResult = "noop" | "queued" | "submitted" | "failed"; export interface AgentInputSubmitActionInput { message: string; imageAttachments?: TImage[]; - allowEmptySubmit?: boolean; + hasExternalContent?: boolean; forceSend?: boolean; isAgentRunning: boolean; canSubmit: boolean; @@ -23,7 +23,7 @@ export async function submitAgentInput( const trimmedMessage = input.message.trim(); const imageAttachments = input.imageAttachments; - if (!trimmedMessage && !imageAttachments?.length && !input.allowEmptySubmit) { + if (!trimmedMessage && !imageAttachments?.length && !input.hasExternalContent) { return "noop"; } diff --git a/packages/app/src/components/composer.tsx b/packages/app/src/components/composer.tsx index c191aaff2..4badcb167 100644 --- a/packages/app/src/components/composer.tsx +++ b/packages/app/src/components/composer.tsx @@ -65,9 +65,8 @@ interface ComposerProps { serverId: string; isInputActive: boolean; onSubmitMessage?: (payload: MessagePayload) => Promise; - allowEmptySubmit?: boolean; - /** Label to show on the submit button when the input is empty and allowEmptySubmit is true. */ - emptySubmitLabel?: string; + /** When true, the submit button is enabled even without text or images (e.g. external attachment selected). */ + hasExternalContent?: boolean; /** Externally controlled loading state. When true, disables the submit button. */ isSubmitLoading?: boolean; /** When true, blurs the input immediately when submitting. */ @@ -105,8 +104,7 @@ export function Composer({ serverId, isInputActive, onSubmitMessage, - allowEmptySubmit = false, - emptySubmitLabel, + hasExternalContent = false, isSubmitLoading = false, blurOnSubmit = false, value, @@ -354,7 +352,7 @@ export function Composer({ await submitAgentInput({ message, imageAttachments, - allowEmptySubmit, + hasExternalContent, forceSend, isAgentRunning: agentState.status === "running", // Parent-managed submits are still valid submit paths even when the @@ -746,8 +744,7 @@ export function Composer({ value={userInput} onChangeText={setUserInput} onSubmit={handleSubmit} - allowEmptySubmit={allowEmptySubmit} - emptySubmitLabel={emptySubmitLabel} + hasExternalContent={hasExternalContent} isSubmitDisabled={isProcessing || isSubmitLoading} isSubmitLoading={isProcessing || isSubmitLoading} images={selectedImages} diff --git a/packages/app/src/components/message-input.tsx b/packages/app/src/components/message-input.tsx index 2a3d24f6d..4837473f6 100644 --- a/packages/app/src/components/message-input.tsx +++ b/packages/app/src/components/message-input.tsx @@ -62,9 +62,8 @@ export interface MessageInputProps { value: string; onChangeText: (text: string) => void; onSubmit: (payload: MessagePayload) => void; - allowEmptySubmit?: boolean; - /** Label to show on the submit button when the input is empty and allowEmptySubmit is true. */ - emptySubmitLabel?: string; + /** When true, the submit button is enabled even without text or images (e.g. external attachment selected). */ + hasExternalContent?: boolean; isSubmitDisabled?: boolean; isSubmitLoading?: boolean; images?: ImageAttachment[]; @@ -201,8 +200,7 @@ export const MessageInput = forwardRef(funct value, onChangeText, onSubmit, - allowEmptySubmit = false, - emptySubmitLabel, + hasExternalContent = false, isSubmitDisabled = false, isSubmitLoading = false, images = [], @@ -573,7 +571,7 @@ export const MessageInput = forwardRef(funct const handleSendMessage = useCallback(() => { const trimmed = value.trim(); - if (!trimmed && images.length === 0 && !allowEmptySubmit) return; + if (!trimmed && images.length === 0 && !hasExternalContent) return; const payload = { text: trimmed, images: images.length > 0 ? images : undefined, @@ -583,7 +581,7 @@ export const MessageInput = forwardRef(funct inputHeightRef.current = MIN_INPUT_HEIGHT; setInputHeight(MIN_INPUT_HEIGHT); onHeightChange?.(MIN_INPUT_HEIGHT); - }, [value, images, onSubmit, isAgentRunning, onHeightChange, allowEmptySubmit]); + }, [value, images, onSubmit, isAgentRunning, onHeightChange, hasExternalContent]); const handleQueueMessage = useCallback(() => { if (!onQueue) return; @@ -935,10 +933,8 @@ export const MessageInput = forwardRef(funct const hasImages = images.length > 0; const hasRealContent = value.trim().length > 0 || hasImages; - const hasSendableContent = hasRealContent || allowEmptySubmit; + const hasSendableContent = hasRealContent || hasExternalContent; const shouldShowSendButton = hasSendableContent || isSubmitLoading; - const showEmptySubmitLabel = - allowEmptySubmit && emptySubmitLabel && !hasRealContent && !isSubmitLoading; const canPressLoadingButton = isSubmitLoading && typeof onSubmitLoadingPress === "function"; const isSendButtonDisabled = disabled || (!canPressLoadingButton && (isSubmitDisabled || isSubmitLoading)); @@ -1170,19 +1166,15 @@ export const MessageInput = forwardRef(funct {isSubmitLoading ? ( - ) : showEmptySubmitLabel ? ( - {emptySubmitLabel} ) : ( )} @@ -1190,11 +1182,7 @@ export const MessageInput = forwardRef(funct - {showEmptySubmitLabel - ? emptySubmitLabel - : defaultActionQueues - ? "Queue" - : "Send"} + {defaultActionQueues ? "Queue" : "Send"} {sendKeys ? : null} @@ -1379,18 +1367,6 @@ const styles = StyleSheet.create(((theme: any) => ({ alignItems: "center", justifyContent: "center", }, - emptySubmitButton: { - height: 28, - borderRadius: theme.borderRadius.full, - backgroundColor: theme.colors.accent, - alignItems: "center", - justifyContent: "center", - paddingHorizontal: theme.spacing[3], - }, - emptySubmitLabel: { - color: "white", - fontSize: theme.fontSize.sm, - }, iconButtonHovered: { backgroundColor: theme.colors.surface2, }, diff --git a/packages/app/src/screens/new-workspace-screen.tsx b/packages/app/src/screens/new-workspace-screen.tsx index 4771dad16..de0fdf1a2 100644 --- a/packages/app/src/screens/new-workspace-screen.tsx +++ b/packages/app/src/screens/new-workspace-screen.tsx @@ -289,8 +289,7 @@ export function NewWorkspaceScreen({ serverId={serverId} isInputActive={true} onSubmitMessage={handleCreateChatAgent} - allowEmptySubmit - emptySubmitLabel="Create" + hasExternalContent={selectedGithubItem !== null} isSubmitLoading={pendingAction === "chat"} blurOnSubmit={true} value={chatDraft.text} diff --git a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx index bd4ddb440..3730863bc 100644 --- a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx +++ b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx @@ -287,7 +287,6 @@ export function WorkspaceDraftAgentTab({ serverId={serverId} isInputActive={isPaneFocused} onSubmitMessage={handleCreateFromInput} - allowEmptySubmit={false} isSubmitLoading={isSubmitting} blurOnSubmit={true} value={draftInput.text}