Skip to content

Commit 2362e01

Browse files
authored
fix: Drag-and-drop file attach broken (#1620)
## Problem Drag and drop to attach files is broken. <!-- Who is this for and what problem does it solve? --> <!-- Closes #ISSUE_ID --> ## Changes 1. Expose webUtils.getPathForFile from preload via contextBridge 2. Add getFilePath utility that uses the bridge with a File.path fallback 3. Replace all File.path casts in drop handlers (SessionView, TaskInput, useTiptapEditor, AttachmentMenu) 4. Add Window.electronUtils type declaration <!-- What did you change and why? --> <!-- If there are frontend changes, include screenshots. --> ## How did you test this? Manually <!-- Describe what you tested -- manual steps, automated tests, or both. --> <!-- If you're an agent, only list tests you actually ran. -->
1 parent 0772f2c commit 2362e01

7 files changed

Lines changed: 34 additions & 5 deletions

File tree

apps/code/src/main/preload.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { exposeElectronTRPC } from "@posthog/electron-trpc/main";
2+
import { contextBridge, webUtils } from "electron";
23
import "electron-log/preload";
34

5+
contextBridge.exposeInMainWorld("electronUtils", {
6+
getPathForFile: (file: File) => webUtils.getPathForFile(file),
7+
});
8+
49
process.once("loaded", async () => {
510
exposeElectronTRPC();
611
});

apps/code/src/renderer/features/message-editor/components/AttachmentMenu.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { IconButton, Popover } from "@radix-ui/themes";
44
import { trpcClient, useTRPC } from "@renderer/trpc/client";
55
import { toast } from "@renderer/utils/toast";
66
import { useQuery } from "@tanstack/react-query";
7+
import { getFilePath } from "@utils/getFilePath";
78
import { getFileName } from "@utils/path";
89
import { useRef, useState } from "react";
910
import type { FileAttachment, MentionChip } from "../utils/content";
@@ -69,7 +70,7 @@ export function AttachmentMenu({
6970
try {
7071
const attachments = await Promise.all(
7172
files.map(async (file) => {
72-
const filePath = (file as globalThis.File & { path?: string }).path;
73+
const filePath = getFilePath(file);
7374
if (filePath) {
7475
return { id: filePath, label: file.name } satisfies FileAttachment;
7576
}

apps/code/src/renderer/features/message-editor/tiptap/useTiptapEditor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { toast } from "@renderer/utils/toast";
44
import { useSettingsStore } from "@stores/settingsStore";
55
import type { EditorView } from "@tiptap/pm/view";
66
import { useEditor } from "@tiptap/react";
7+
import { getFilePath } from "@utils/getFilePath";
78
import type React from "react";
89
import { useCallback, useEffect, useRef, useState } from "react";
910
import { usePromptHistoryStore } from "../stores/promptHistoryStore";
@@ -270,8 +271,7 @@ export function useTiptapEditor(options: UseTiptapEditorOptions) {
270271
const newAttachments: FileAttachment[] = [];
271272
for (let i = 0; i < files.length; i++) {
272273
const file = files[i];
273-
// In Electron, File objects have a 'path' property
274-
const path = (file as unknown as { path?: string }).path;
274+
const path = getFilePath(file);
275275
if (path) {
276276
newAttachments.push({ id: path, label: file.name });
277277
}

apps/code/src/renderer/features/sessions/components/SessionView.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
isJsonRpcNotification,
2121
isJsonRpcResponse,
2222
} from "@shared/types/session-events";
23+
import { getFilePath } from "@utils/getFilePath";
2324
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2425
import { useHotkeys } from "react-hotkeys-hook";
2526
import { getSessionService } from "../service/service";
@@ -328,7 +329,7 @@ export function SessionView({
328329

329330
for (let i = 0; i < files.length; i++) {
330331
const file = files[i];
331-
const filePath = (file as File & { path?: string }).path;
332+
const filePath = getFilePath(file);
332333
if (filePath) {
333334
editorRef.current?.addAttachment({
334335
id: filePath,

apps/code/src/renderer/features/task-detail/components/TaskInput.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { useAuthStore } from "@renderer/features/auth/stores/authStore";
2929
import { useTRPC } from "@renderer/trpc/client";
3030
import { useNavigationStore } from "@stores/navigationStore";
3131
import { useQuery } from "@tanstack/react-query";
32+
import { getFilePath } from "@utils/getFilePath";
3233
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3334
import { useHotkeys } from "react-hotkeys-hook";
3435
import { usePreviewConfig } from "../hooks/usePreviewConfig";
@@ -344,7 +345,7 @@ export function TaskInput({
344345

345346
for (let i = 0; i < files.length; i++) {
346347
const file = files[i];
347-
const filePath = (file as File & { path?: string }).path;
348+
const filePath = getFilePath(file);
348349
if (filePath) {
349350
editorRef.current?.addAttachment({
350351
id: filePath,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
11
import "@main/services/types";
22

33
// No legacy IPC interfaces - all communication now uses tRPC
4+
5+
declare global {
6+
interface Window {
7+
electronUtils?: {
8+
getPathForFile: (file: File) => string;
9+
};
10+
}
11+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Get the filesystem path for a File from a drag-and-drop or file input event.
3+
*
4+
* In Electron 32+ with contextIsolation, File.path is empty. The preload
5+
* script exposes webUtils.getPathForFile as window.electronUtils.getPathForFile
6+
* to bridge this gap.
7+
*/
8+
export function getFilePath(file: File): string {
9+
if (window.electronUtils?.getPathForFile) {
10+
return window.electronUtils.getPathForFile(file);
11+
}
12+
return (file as File & { path?: string }).path ?? "";
13+
}

0 commit comments

Comments
 (0)