Skip to content

Commit

Permalink
Switch to direct file downloads without zipping
Browse files Browse the repository at this point in the history
- Remove jszip dependency
- Use File System Access API to save files with directory structure
- Fallback to individual file downloads when API not supported
  • Loading branch information
openhands-agent committed Nov 14, 2024
1 parent 4c8c100 commit de504f0
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 21 deletions.
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,4 @@
"public"
]
}
}
}
60 changes: 40 additions & 20 deletions frontend/src/utils/download-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,18 @@ export async function downloadFiles(initialPath?: string, options?: DownloadOpti
// First, recursively get all files
const files = await getAllFiles(initialPath || "", progress, options);

// Create a zip file using JSZip
const JSZip = (await import("jszip")).default;
const zip = new JSZip();
// Create a directory picker if the browser supports it
let directoryHandle: FileSystemDirectoryHandle | null = null;
if ('showDirectoryPicker' in window) {
try {
directoryHandle = await window.showDirectoryPicker();
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
throw new Error("Download cancelled");
}
console.warn('Directory picker not supported or cancelled, falling back to individual downloads');

Check warning on line 74 in frontend/src/utils/download-files.ts

View workflow job for this annotation

GitHub Actions / Lint frontend

Unexpected console statement
}
}

// Download each file
for (const path of files) {
Expand All @@ -76,8 +85,34 @@ export async function downloadFiles(initialPath?: string, options?: DownloadOpti
progress.currentFile = path;
const content = await OpenHands.getFile(path);

// Add file to zip, preserving directory structure
zip.file(path, content);
if (directoryHandle) {
// Save to the selected directory preserving structure
const pathParts = path.split('/').filter(Boolean);
let currentHandle = directoryHandle;

// Create subdirectories as needed
for (let i = 0; i < pathParts.length - 1; i++) {
currentHandle = await currentHandle.getDirectoryHandle(pathParts[i], { create: true });
}

// Create and write the file
const fileName = pathParts[pathParts.length - 1];
const fileHandle = await currentHandle.getFileHandle(fileName, { create: true });
const writable = await fileHandle.createWritable();
await writable.write(content);
await writable.close();
} else {
// Fallback: Download directly using <a> tag
const blob = new Blob([content], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = path.split('/').pop() || 'file';
document.body.appendChild(link);
link.click();
link.parentNode?.removeChild(link);
URL.revokeObjectURL(url);
}

// Update progress
progress.filesDownloaded++;
Expand All @@ -88,21 +123,6 @@ export async function downloadFiles(initialPath?: string, options?: DownloadOpti
console.error(`Error downloading file ${path}:`, error);

Check warning on line 123 in frontend/src/utils/download-files.ts

View workflow job for this annotation

GitHub Actions / Lint frontend

Unexpected console statement
}
}

if (options?.signal?.aborted) {
throw new Error("Download cancelled");
}

// Generate and download the zip file
const blob = await zip.generateAsync({ type: "blob" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", initialPath ? `${initialPath.replace(/\/$/, "")}.zip` : "workspace.zip");
document.body.appendChild(link);
link.click();
link.parentNode?.removeChild(link);
URL.revokeObjectURL(url);
} catch (error) {
if (error instanceof Error && error.message === "Download cancelled") {
throw error;
Expand Down

0 comments on commit de504f0

Please sign in to comment.