fix(app): enable image drop on new workspace screen (#850)

Wrap the screen in FileDropZone so dragged images are forwarded into the
composer, matching the new-draft screen.
This commit is contained in:
Mohamed Boudra
2026-05-09 23:29:00 +08:00
committed by GitHub
parent 47f26e99db
commit 407c4ca554
@@ -9,6 +9,7 @@ import { useQuery } from "@tanstack/react-query";
import { ChevronDown, GitBranch, GitPullRequest } from "lucide-react-native"; import { ChevronDown, GitBranch, GitPullRequest } from "lucide-react-native";
import { Composer } from "@/components/composer"; import { Composer } from "@/components/composer";
import { splitComposerAttachmentsForSubmit } from "@/components/composer-attachments"; import { splitComposerAttachmentsForSubmit } from "@/components/composer-attachments";
import { FileDropZone } from "@/components/file-drop-zone";
import { Combobox, ComboboxItem } from "@/components/ui/combobox"; import { Combobox, ComboboxItem } from "@/components/ui/combobox";
import type { ComboboxOption as ComboboxOptionType } from "@/components/ui/combobox"; import type { ComboboxOption as ComboboxOptionType } from "@/components/ui/combobox";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
@@ -639,6 +640,9 @@ export function NewWorkspaceScreen({
const handleAddImagesCallback = useCallback((addImages: (images: ImageAttachment[]) => void) => { const handleAddImagesCallback = useCallback((addImages: (images: ImageAttachment[]) => void) => {
addImagesRef.current = addImages; addImagesRef.current = addImages;
}, []); }, []);
const handleFilesDropped = useCallback((files: ImageAttachment[]) => {
addImagesRef.current?.(files);
}, []);
const renderPickerOption = useCallback( const renderPickerOption = useCallback(
({ ({
@@ -713,82 +717,84 @@ export function NewWorkspaceScreen({
: "No matching refs."; : "No matching refs.";
return ( return (
<View style={styles.container}> <FileDropZone onFilesDropped={handleFilesDropped}>
<ScreenHeader <View style={styles.container}>
left={ <ScreenHeader
<> left={
<SidebarMenuToggle /> <>
<View style={styles.headerTitleContainer}> <SidebarMenuToggle />
<Text style={styles.headerTitle} numberOfLines={1}> <View style={styles.headerTitleContainer}>
New workspace <Text style={styles.headerTitle} numberOfLines={1}>
</Text> New workspace
<Text style={styles.headerProjectTitle} numberOfLines={1}> </Text>
{workspaceTitle} <Text style={styles.headerProjectTitle} numberOfLines={1}>
</Text> {workspaceTitle}
</View> </Text>
</> </View>
} </>
leftStyle={styles.headerLeft} }
borderless leftStyle={styles.headerLeft}
/> borderless
<View style={contentStyle}> />
<TitlebarDragRegion /> <View style={contentStyle}>
<View style={styles.centered}> <TitlebarDragRegion />
<Composer <View style={styles.centered}>
agentId={`new-workspace:${serverId}:${sourceDirectory}`} <Composer
serverId={serverId} agentId={`new-workspace:${serverId}:${sourceDirectory}`}
isPaneFocused={true} serverId={serverId}
onSubmitMessage={handleSubmitNewWorkspace} isPaneFocused={true}
allowEmptySubmit={true} onSubmitMessage={handleSubmitNewWorkspace}
submitButtonAccessibilityLabel="Create" allowEmptySubmit={true}
submitIcon="return" submitButtonAccessibilityLabel="Create"
isSubmitLoading={pendingAction !== null} submitIcon="return"
submitBehavior="preserve-and-lock" isSubmitLoading={pendingAction !== null}
blurOnSubmit={true} submitBehavior="preserve-and-lock"
value={chatDraft.text} blurOnSubmit={true}
onChangeText={chatDraft.setText} value={chatDraft.text}
attachments={chatDraft.attachments} onChangeText={chatDraft.setText}
onChangeAttachments={chatDraft.setAttachments} attachments={chatDraft.attachments}
cwd={sourceDirectory} onChangeAttachments={chatDraft.setAttachments}
clearDraft={handleClearDraft} cwd={sourceDirectory}
autoFocus clearDraft={handleClearDraft}
commandDraftConfig={composerState?.commandDraftConfig} autoFocus
statusControls={statusControlsWithDisabled} commandDraftConfig={composerState?.commandDraftConfig}
onAddImages={handleAddImagesCallback} statusControls={statusControlsWithDisabled}
/> onAddImages={handleAddImagesCallback}
<Animated.View testID="new-workspace-ref-picker-row" style={optionsRowStyle}> />
<View> <Animated.View testID="new-workspace-ref-picker-row" style={optionsRowStyle}>
<RefPickerTrigger <View>
pickerAnchorRef={pickerAnchorRef} <RefPickerTrigger
onPress={openPicker} pickerAnchorRef={pickerAnchorRef}
disabled={isPending} onPress={openPicker}
badgePressableStyle={badgePressableStyle} disabled={isPending}
selectedItem={selectedItem} badgePressableStyle={badgePressableStyle}
triggerLabel={triggerLabel} selectedItem={selectedItem}
iconColor={theme.colors.foregroundMuted} triggerLabel={triggerLabel}
iconSize={theme.iconSize.sm} iconColor={theme.colors.foregroundMuted}
/> iconSize={theme.iconSize.sm}
<Combobox />
options={options} <Combobox
value={selectedOptionId} options={options}
onSelect={handleSelectOption} value={selectedOptionId}
searchable onSelect={handleSelectOption}
searchPlaceholder="Search branches and PRs" searchable
title="Start from" searchPlaceholder="Search branches and PRs"
open={pickerOpen} title="Start from"
onOpenChange={handlePickerOpenChange} open={pickerOpen}
onSearchQueryChange={setPickerSearchQuery} onOpenChange={handlePickerOpenChange}
desktopPlacement="bottom-start" onSearchQueryChange={setPickerSearchQuery}
anchorRef={pickerAnchorRef} desktopPlacement="bottom-start"
emptyText={pickerEmptyText} anchorRef={pickerAnchorRef}
renderOption={renderPickerOption} emptyText={pickerEmptyText}
/> renderOption={renderPickerOption}
</View> />
</Animated.View> </View>
{errorMessage ? <Text style={styles.errorText}>{errorMessage}</Text> : null} </Animated.View>
{errorMessage ? <Text style={styles.errorText}>{errorMessage}</Text> : null}
</View>
</View> </View>
</View> </View>
</View> </FileDropZone>
); );
} }