Skip to content

Commit 8a32128

Browse files
alexrrouseAlex Rouse
andauthored
feat(ui): Add drag and drop support for opening sessions from finder. (aaif-goose#3070)
Co-authored-by: Alex Rouse <alex.rouse@block.xyz>
1 parent bdb10e7 commit 8a32128

2 files changed

Lines changed: 74 additions & 0 deletions

File tree

ui/desktop/forge.config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ let cfg = {
2121
schemes: ["goose"]
2222
}
2323
],
24+
// macOS Info.plist extensions for drag-and-drop support
25+
extendInfo: {
26+
// Document types for drag-and-drop support onto dock icon
27+
CFBundleDocumentTypes: [
28+
{
29+
CFBundleTypeName: "Folders",
30+
CFBundleTypeRole: "Viewer",
31+
LSHandlerRank: "Alternate",
32+
LSItemContentTypes: ["public.directory", "public.folder"]
33+
}
34+
]
35+
},
2436
// macOS specific configuration
2537
osxSign: {
2638
entitlements: 'entitlements.plist',

ui/desktop/src/main.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Tray,
1212
App,
1313
globalShortcut,
14+
Event,
1415
} from 'electron';
1516
import type { OpenDialogReturnValue } from 'electron';
1617
import { Buffer } from 'node:buffer';
@@ -330,6 +331,67 @@ app.on('open-url', async (_event, url) => {
330331
}
331332
});
332333

334+
// Handle macOS drag-and-drop onto dock icon
335+
app.on('will-finish-launching', () => {
336+
if (process.platform === 'darwin') {
337+
app.setAboutPanelOptions({
338+
applicationName: 'Goose',
339+
applicationVersion: app.getVersion(),
340+
});
341+
}
342+
});
343+
344+
// Handle drag-and-drop onto dock icon
345+
app.on('open-file', async (event, filePath) => {
346+
event.preventDefault();
347+
await handleFileOpen(filePath);
348+
});
349+
350+
// Handle multiple files/folders
351+
app.on('open-files', async (event: Event, filePaths: string[]) => {
352+
event.preventDefault();
353+
for (const filePath of filePaths) {
354+
await handleFileOpen(filePath);
355+
}
356+
});
357+
358+
async function handleFileOpen(filePath: string) {
359+
try {
360+
if (!filePath || typeof filePath !== 'string') {
361+
return;
362+
}
363+
364+
const stats = fsSync.lstatSync(filePath);
365+
let targetDir = filePath;
366+
367+
// If it's a file, use its parent directory
368+
if (stats.isFile()) {
369+
targetDir = path.dirname(filePath);
370+
}
371+
372+
// Add to recent directories
373+
addRecentDir(targetDir);
374+
375+
// Create new window for the directory
376+
const newWindow = await createChat(app, undefined, targetDir);
377+
378+
// Focus the new window
379+
if (newWindow) {
380+
newWindow.show();
381+
newWindow.focus();
382+
newWindow.moveTop();
383+
}
384+
} catch (error) {
385+
console.error('Failed to handle file open:', error);
386+
387+
// Show user-friendly error notification
388+
new Notification({
389+
title: 'Goose',
390+
body: `Could not open directory: ${path.basename(filePath)}`,
391+
}).show();
392+
}
393+
}
394+
333395
declare var MAIN_WINDOW_VITE_DEV_SERVER_URL: string;
334396
declare var MAIN_WINDOW_VITE_NAME: string;
335397

0 commit comments

Comments
 (0)