The GitHub Actions job "Required Checks" on texera.git/main has failed. Run started by GitHub user github-merge-queue[bot] (triggered by github-merge-queue[bot]).
Head commit for run: 310ab88e4c78da14182284199bde34a1d22d489b / Eugene Gu <[email protected]> chore(frontend): downloading workflows as a ZIP no longer saves each one individually (#7611) ### What changes were proposed in this PR? Selecting several workflows and using the toolbar's "Download added workflow as a ZIP file" action saved one loose `.json` file per selected workflow **in addition to** the archive, so N selected workflows produced N+1 downloads. Root cause is in `frontend/src/app/dashboard/service/user/download/download.service.ts`. `downloadWorkflow(id, name)` both retrieves a workflow and saves it to disk — the save is the `tap(this.saveFile.bind(this))` at the end of the pipe — which is exactly what the per-row download action needs. `createWorkflowsZip` reused that same method purely to obtain each blob, so the save fired for every entry before the blob was added to the archive. This is a regression rather than intended behaviour: before #2920 (`57984370c`, "Refactor Frontend to Centralize Downloads Using DownloadService") the bulk path assembled the zip inline and called `saveAs` exactly once. That refactor moved the logic into `DownloadService` and reused `downloadWorkflow` for retrieval, inheriting its save side effect. The fix splits retrieval from saving: - new private `retrieveWorkflowItem(id, name)` returns the `DownloadableItem` (blob + file name) **without** saving — it is the former body of `downloadWorkflow` minus the `tap`; - `downloadWorkflow` is now `retrieveWorkflowItem(...).pipe(tap(this.saveFile.bind(this)))`, i.e. behaviour is unchanged for the three per-row callers (`user-workflow-list-item.component.ts`, `list-item.component.ts`, `card-item.component.ts`), which subscribe without a value handler and rely solely on that side effect; - `createWorkflowsZip` calls `retrieveWorkflowItem` directly. `A.pipe(map, tap)` and `A.pipe(map).pipe(tap)` compose the same chain, so the emitted value, timing, subscription semantics and error propagation of `downloadWorkflow` are unchanged. The public API is untouched and no call site needed updating. **Before** — three workflows selected, then "Download as ZIP": the archive plus `test1.json`, `test2.json`, `test3.json`, four files in total. <img width="1493" height="755" alt="Screenshot 2026-08-12 at 3 48 45 PM" src="https://github.com/user-attachments/assets/7a7b8cb0-330a-452f-b853-b7aabfc04acd" /> **After** — same three workflows, same action: only `workflowExports-*.zip`. <img width="1482" height="750" alt="Screenshot 2026-08-12 at 4 43 38 PM" src="https://github.com/user-attachments/assets/bdc64245-91bc-4fa0-a06d-2b80e2871706" /> ### Any related issues, documentation, discussions? Closes #7608 ### How was this PR tested? Seven cases were added to `frontend/src/app/dashboard/service/user/download/download.service.spec.ts` (23 → 30). Three of them fail on `main` and pass with this change. Pinning the fix: - `saves only the zip, not one JSON per workflow, when several workflows are zipped` — three workflows, asserts `saveAs` is called exactly once with the archive, and that no `Alpha.json` / `Beta.json` / `Gamma.json` was saved - `saves only the zip for a single-workflow selection` — the N=1 boundary, which a plain "one extra file" check would miss Guarding the other direction, so the bug cannot be "fixed" by deleting the save: - `still saves the file when a single workflow is downloaded on its own` — passes before and after; it fails if `downloadWorkflow` stops saving, which would break the per-row download action Edge cases: - `saves nothing when one of the workflows fails to retrieve` — the archive aborts as a whole, so the workflows that did come back must not be left behind as loose files (previously they were already saved by the time `forkJoin` errored) - `writes the workflow content into the zip entries` — reads an entry back out of the produced archive and parses it, since the pre-existing tests only asserted entry *names* - `does not save anything when the standalone workflow download fails` — error propagates, nothing is written; mirrors the existing dataset / single-file error cases - `saves nothing for an empty selection` — `forkJoin([])` completes without emitting, so nothing is retrieved and no empty archive is written (the toolbar already guards this case) ``` cd frontend node --max-old-space-size=8192 ./node_modules/@angular/cli/bin/ng test --watch=false \ --include="src/app/dashboard/service/user/download/download.service.spec.ts" ``` `Test Files 1 passed (1)` / `Tests 30 passed (30)`. Reverting only the source change makes exactly three of them fail. The specs of the three components that depend on `downloadWorkflow` still saving were also run and pass unchanged (`list-item`, `card-item`, `user-workflow-list-item`). Manually verified against a local stack, as shown in the screenshots above: create three workflows, select them, click the ZIP download action, and compare the browser's download list before and after the change. ### Was this PR authored or co-authored using generative AI tooling? Co-authored by: Claude Code (Claude Opus 5) Report URL: https://github.com/apache/texera/actions/runs/31668191644 With regards, GitHub Actions via GitBox
