From 474c1fd3ed81fee152db17e19fea3b44a8eaf83c Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 28 Mar 2026 11:33:32 -0700 Subject: [PATCH 1/3] feat(ui): handle image paste --- .../home/components/user-input/user-input.tsx | 26 +++++++++++++++++++ .../user-input/hooks/use-file-attachments.ts | 1 + 2 files changed, 27 insertions(+) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx index 809c157945b..91d5dd67ae3 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx @@ -522,6 +522,31 @@ export function UserInput({ [isInitialView] ) + const handlePaste = useCallback( + (e: React.ClipboardEvent) => { + const items = e.clipboardData?.items + if (!items) return + + const imageFiles: File[] = [] + for (const item of Array.from(items)) { + if (item.kind === 'file' && item.type.startsWith('image/')) { + const file = item.getAsFile() + if (file) imageFiles.push(file) + } + } + + if (imageFiles.length === 0) return + + e.preventDefault() + const dt = new DataTransfer() + for (const file of imageFiles) { + dt.items.add(file) + } + filesRef.current.processFiles(dt.files) + }, + [] + ) + const handleScroll = useCallback((e: React.UIEvent) => { if (overlayRef.current) { overlayRef.current.scrollTop = e.currentTarget.scrollTop @@ -661,6 +686,7 @@ export function UserInput({ onChange={handleInputChange} onKeyDown={handleKeyDown} onInput={handleInput} + onPaste={handlePaste} onCut={mentionTokensWithContext.handleCut} onSelect={handleSelectAdjust} onMouseUp={handleSelectAdjust} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts index 24d21ea5173..499b62d1a51 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/user-input/hooks/use-file-attachments.ts @@ -320,5 +320,6 @@ export function useFileAttachments(props: UseFileAttachmentsProps) { handleDragOver, handleDrop, clearAttachedFiles, + processFiles, } } From 82e180237068c74d1963e07aca6c9ab95f48514c Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 28 Mar 2026 11:48:06 -0700 Subject: [PATCH 2/3] Fix lint --- .../home/components/user-input/user-input.tsx | 39 +++++++++---------- apps/sim/lib/auth/hybrid.ts | 2 +- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx index 91d5dd67ae3..3fb58aceb18 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/user-input.tsx @@ -522,30 +522,27 @@ export function UserInput({ [isInitialView] ) - const handlePaste = useCallback( - (e: React.ClipboardEvent) => { - const items = e.clipboardData?.items - if (!items) return - - const imageFiles: File[] = [] - for (const item of Array.from(items)) { - if (item.kind === 'file' && item.type.startsWith('image/')) { - const file = item.getAsFile() - if (file) imageFiles.push(file) - } + const handlePaste = useCallback((e: React.ClipboardEvent) => { + const items = e.clipboardData?.items + if (!items) return + + const imageFiles: File[] = [] + for (const item of Array.from(items)) { + if (item.kind === 'file' && item.type.startsWith('image/')) { + const file = item.getAsFile() + if (file) imageFiles.push(file) } + } - if (imageFiles.length === 0) return + if (imageFiles.length === 0) return - e.preventDefault() - const dt = new DataTransfer() - for (const file of imageFiles) { - dt.items.add(file) - } - filesRef.current.processFiles(dt.files) - }, - [] - ) + e.preventDefault() + const dt = new DataTransfer() + for (const file of imageFiles) { + dt.items.add(file) + } + filesRef.current.processFiles(dt.files) + }, []) const handleScroll = useCallback((e: React.UIEvent) => { if (overlayRef.current) { diff --git a/apps/sim/lib/auth/hybrid.ts b/apps/sim/lib/auth/hybrid.ts index 3f2311e7927..c793fe5d900 100644 --- a/apps/sim/lib/auth/hybrid.ts +++ b/apps/sim/lib/auth/hybrid.ts @@ -25,7 +25,7 @@ const BEARER_PREFIX = 'Bearer ' export function hasExternalApiCredentials(headers: Headers): boolean { if (headers.has(API_KEY_HEADER)) return true const auth = headers.get('authorization') - return auth !== null && auth.startsWith(BEARER_PREFIX) + return auth?.startsWith(BEARER_PREFIX) } export interface AuthResult { From 50211b50bad5e05789d6321519a6346960f1fcca Mon Sep 17 00:00:00 2001 From: Theodore Li Date: Sat, 28 Mar 2026 13:49:42 -0700 Subject: [PATCH 3/3] Fix type error --- apps/sim/lib/auth/hybrid.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sim/lib/auth/hybrid.ts b/apps/sim/lib/auth/hybrid.ts index c793fe5d900..67fc19a36af 100644 --- a/apps/sim/lib/auth/hybrid.ts +++ b/apps/sim/lib/auth/hybrid.ts @@ -25,7 +25,7 @@ const BEARER_PREFIX = 'Bearer ' export function hasExternalApiCredentials(headers: Headers): boolean { if (headers.has(API_KEY_HEADER)) return true const auth = headers.get('authorization') - return auth?.startsWith(BEARER_PREFIX) + return auth?.startsWith(BEARER_PREFIX) ?? false } export interface AuthResult {