Gallery has no bulk export — user with 5 designs selected can bulk-delete or bulk-favorite but not bulk-export, has to open each one in the workspace to export #254

Closed
opened 2026-10-04 03:36:29 +00:00 by Mark · 1 comment
Owner

Finding

src/pages/Gallery.tsx's multi-select state has bulk delete (per confirmBulkDelete) and presumably bulk favorite. But there's no bulk export.

grep -n 'bulkExport\|exportSelected' src/pages/Gallery.tsx returns 0.

A user with 5 designs selected:

  • Clicks "Export 5" button (if it existed)
  • All 5 designs export as PES files
  • They get 5 downloads

Currently:

  • Clicks each design's "Open" button → workspace
  • Clicks workspace's "Export" → ExportDialog
  • Downloads the file
  • Closes the ExportDialog
  • Returns to gallery
  • Repeat 4 more times

5 navigation hops per design = 25 total.

Where

  • Gallery multi-select: src/pages/Gallery.tsx (selectedDesigns Set)
  • No bulk export: grep -n 'bulkExport' src/ returns 0
  • Workspace's ExportDialog: src/components/workspace/ExportDialog.tsx (per-design export)
  • The export service: src/lib/easystitch-client.ts:exportPES

Suggested fix shape

Add a "Export 5" button to the multi-select toolbar (next to "Delete 5"):

<button
  onClick={onBulkExport}
  data-testid="bulk-export"
  title="Export selected designs"
>
  <Download size={14} />
  Export {selectedDesigns.size}
</button>

onBulkExport:

  1. Iterate selectedDesigns in parallel (using Promise.all).
  2. For each design, call exportPES(...) via the easystitch-client.
  3. Trigger a download for each file (create a temporary <a> element with the Blob URL).
  4. Show a toast: "Exported 5 designs as PES".

A more polished version uses the JSZip library to package the 5 PES files into a single .zip for a single download. The user gets one zip file with all 5 designs.

import JSZip from 'jszip';
const zip = new JSZip();
await Promise.all(Array.from(selectedDesigns).map(async (id) => {
  const design = designs.find((d) => d.id === id);
  const result = await exportPES(...);
  zip.file(design.filename, result.blob);
}));
const zipBlob = await zip.generateAsync({ type: 'blob' });
saveAs(zipBlob, 'designs.zip');

The zip approach is the standard for bulk export in design tools.

Severity

Low. The user can export one at a time. Power users with many designs notice.

Discovered by

Gap analysis (2026-10-02) of gallery bulk actions.

  • The bulk delete (per confirmBulkDelete) is the pattern to mirror.
  • The Gallery → Editor bridge (#111) and the Editor's ExportDialog are the per-design flow.
  • The zip approach is the standard; without it, the user gets 5 separate downloads.
## Finding `src/pages/Gallery.tsx`'s multi-select state has bulk delete (per `confirmBulkDelete`) and presumably bulk favorite. But there's no bulk export. `grep -n 'bulkExport\|exportSelected' src/pages/Gallery.tsx` returns 0. A user with 5 designs selected: - Clicks "Export 5" button (if it existed) - All 5 designs export as PES files - They get 5 downloads Currently: - Clicks each design's "Open" button → workspace - Clicks workspace's "Export" → ExportDialog - Downloads the file - Closes the ExportDialog - Returns to gallery - Repeat 4 more times 5 navigation hops per design = 25 total. ## Where - Gallery multi-select: `src/pages/Gallery.tsx` (selectedDesigns Set) - No bulk export: `grep -n 'bulkExport' src/` returns 0 - Workspace's ExportDialog: `src/components/workspace/ExportDialog.tsx` (per-design export) - The export service: `src/lib/easystitch-client.ts:exportPES` ## Suggested fix shape Add a "Export 5" button to the multi-select toolbar (next to "Delete 5"): ```tsx <button onClick={onBulkExport} data-testid="bulk-export" title="Export selected designs" > <Download size={14} /> Export {selectedDesigns.size} </button> ``` `onBulkExport`: 1. Iterate `selectedDesigns` in parallel (using `Promise.all`). 2. For each design, call `exportPES(...)` via the easystitch-client. 3. Trigger a download for each file (create a temporary `<a>` element with the Blob URL). 4. Show a toast: "Exported 5 designs as PES". A more polished version uses the `JSZip` library to package the 5 PES files into a single `.zip` for a single download. The user gets one zip file with all 5 designs. ```ts import JSZip from 'jszip'; const zip = new JSZip(); await Promise.all(Array.from(selectedDesigns).map(async (id) => { const design = designs.find((d) => d.id === id); const result = await exportPES(...); zip.file(design.filename, result.blob); })); const zipBlob = await zip.generateAsync({ type: 'blob' }); saveAs(zipBlob, 'designs.zip'); ``` The zip approach is the standard for bulk export in design tools. ## Severity Low. The user can export one at a time. Power users with many designs notice. ## Discovered by Gap analysis (2026-10-02) of gallery bulk actions. ## Related - The bulk delete (per `confirmBulkDelete`) is the pattern to mirror. - The Gallery → Editor bridge (#111) and the Editor's ExportDialog are the per-design flow. - The zip approach is the standard; without it, the user gets 5 separate downloads.
Author
Owner

Closed by 06b0603.

Added Export {count} button to the Gallery SelectionToolbar (next to Delete). The handler iterates selected designs in parallel via Promise.allSettled, calls exportPES per design using each snapshot's stitch objects + machine profile, and triggers a download per file.

5-file batch download (no JSZip dep). Skipped designs (no snapshot) and partial failures get a per-summary toast. isExporting greys out the button mid-batch.

Files: src/pages/Gallery.tsx, src/components/gallery/SelectionToolbar.tsx, src/components/gallery/issue-254-bulk-export.test.tsx. 5 new tests + 1316 pre-existing all green; tsc --noEmit clean.

Closed by 06b0603. Added Export {count} button to the Gallery SelectionToolbar (next to Delete). The handler iterates selected designs in parallel via Promise.allSettled, calls exportPES per design using each snapshot's stitch objects + machine profile, and triggers a download per file. 5-file batch download (no JSZip dep). Skipped designs (no snapshot) and partial failures get a per-summary toast. isExporting greys out the button mid-batch. Files: src/pages/Gallery.tsx, src/components/gallery/SelectionToolbar.tsx, src/components/gallery/issue-254-bulk-export.test.tsx. 5 new tests + 1316 pre-existing all green; tsc --noEmit clean.
Mark closed this issue 2026-10-04 10:09:55 +00:00
Sign in to join this conversation.
No description provided.