Skip to content

fix(frontend): make a result cell's download work off the canvas - #8539

Open
yangzhang75 wants to merge 2 commits into
apache:mainfrom
yangzhang75:fix/cell-download-honours-export-switch
Open

yangzhang75 wants to merge 2 commits into
apache:mainfrom
yangzhang75:fix/cell-download-honours-export-switch

Conversation

@yangzhang75

@yangzhang75 yangzhang75 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

The download button on a result cell did nothing when pressed from the Form View: the dialog opened, Export closed it, and no file arrived — no request, no error, no message.

An export scopes itself to the operators selected on the canvas unless the caller asked for all of them. That is the right scope for the two callers that read the canvas: the top menu asks for everything, the context menu exports the selection. The third caller is the download button on a result cell, and a cell belongs to one operator, whoever happens to be selected. The same cell is also mounted on the Form View, where the selection holds the step the user is configuring and holds nothing at all until they click one. There the export found an empty scope, so performExport returned at its operatorIds.length === 0 check before sending anything. The dialog's own checks read the same empty selection, so a restricted operator went unreported there too.

A caller that knows which operators it is exporting now says so, and both the dialog and the service prefer that over the selection:

  • workflow-result-export.service.ts: a trailing optional requestedOperatorIds on exportWorkflowExecutionResult, threaded to performExport. Precedence is exportAll (whole workflow) > caller-named > canvas selection.
  • result-exportation.component.ts: reads operatorIds off the modal data; getOperatorIdsToCheck() returns it when present, and onClickExportResult forwards it.
  • result-table-frame.component.ts: the cell's dialog names the operator whose results the frame is showing.

Nothing changes for the menu or the context menu, which name no operators and keep the old scope. Ten lines of logic in three files.

Any related issues, documentation, discussions?

Closes #8538, which has a recording of the before state.

One thing that PR does not change: export-execution-result-enabled still defaults to false in gui.conf, and performExport returns on that switch before it reaches any of this. A deployment with the switch off sees no change from this PR; every deployment that has it on gets a working cell download. Whether that default should flip is a separate question and is noted at the end of the issue.

How was this PR tested?

  • Nine new unit tests across the three spec files: the service prefers a named scope over the selection and works with an empty selection, falls back to the selection when none is named, and still lets exportAll win; the dialog names none by default, checks the named operator, and hands it to the export; the frame names its operator, and names none when it has none.
  • Mutation check, each restored afterwards: dropping the named scope in the service, in the dialog, or in the frame each turns exactly one named test red.
  • Coverage on the three changed files: 100% lines, functions and branches, except one pre-existing unreachable branch elsewhere in result-table-frame.component.ts that this PR does not touch.
  • ng test --watch=false: 223 files, 6065 passed, 1 skipped (pre-existing), 0 failed. ng build --configuration=production (AOT): clean. eslint and prettier --check on all six files: clean.
  • Exercised in a running instance built from this branch on top of main: a Form View workflow whose result column holds binary files. With the fix, the cell download sends POST /api/executions/result/export/local and returns the bytes (4096 bytes, HDF5 magic 89 48 44 46, byte-exact) while the canvas selection is empty. With the three production hunks reverted on the same stack, the same click sends no request and produces no file within two minutes.

After the fix: downloading a result file from the Form View

Screen.Recording.2026-09-16.at.7.05.42.PM.mov

Was this PR authored or co-authored using generative AI tooling?

Yes. Generated-by: Claude Code (Claude Opus 5, Anthropic). Co-authored with Claude; the author reviewed the change before submission.

🤖 Generated with Claude Code

@github-actions github-actions Bot added fix frontend Changes related to the frontend GUI labels Sep 14, 2026
@Yicong-Huang Yicong-Huang added release/v1.3 back porting to release/v1.3 release/v1.2 back porting to release/v1.2 labels Sep 14, 2026
@github-actions
github-actions Bot requested a review from mengw15 September 14, 2026 01:05
@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

Based on the git blame history of the changed files, we recommend the following reviewers:

  • Contributors with relevant context: @aglinxinyuan, @PG1204, @Yicong-Huang
    You can notify them by mentioning @aglinxinyuan, @PG1204, @Yicong-Huang in a comment.

@github-actions
github-actions Bot requested a review from xuang7 September 14, 2026 01:05
@github-actions

github-actions Bot commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Backport auto-label report

This fix: PR was checked against each actively-supported release branch. A release/* label nominates a backport target; the branch's release manager approving this PR is what sends the fix there. The required Backport Approvals check stays red until every label below is approved, so each manager either approves or removes their own label — which is why the labels left on a merged PR are exactly the branches it reached.

Release branch Analysis
release/v1.3 Already labeled — this fix is queued to backport here. @mengw15 decides: approving sends the fix here, removing this label declines it. The merge waits on one or the other.
release/v1.2 Already labeled — this fix is queued to backport here. @xuang7 decides: approving sends the fix here, removing this label declines it. The merge waits on one or the other.

Auto-label run.

@codecov-commenter

codecov-commenter commented Sep 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.91%. Comparing base (3733b2a) to head (b1510c3).
⚠️ Report is 16 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8539      +/-   ##
============================================
- Coverage     92.94%   92.91%   -0.04%     
  Complexity     4883     4883              
============================================
  Files          1232     1235       +3     
  Lines         51628    51981     +353     
  Branches       6354     6393      +39     
============================================
+ Hits          47988    48297     +309     
- Misses         2076     2108      +32     
- Partials       1564     1576      +12     
Flag Coverage Δ *Carryforward flag
access-control-service 71.78% <ø> (ø) Carriedforward from 74e6d31
agent-service 99.32% <ø> (ø) Carriedforward from 74e6d31
amber 88.98% <ø> (ø) Carriedforward from 74e6d31
computing-unit-managing-service 54.61% <ø> (ø) Carriedforward from 74e6d31
config-service 87.37% <ø> (ø) Carriedforward from 74e6d31
file-service 81.53% <ø> (ø) Carriedforward from 74e6d31
frontend 96.58% <100.00%> (-0.14%) ⬇️
notebook-migration-service 83.73% <ø> (ø) Carriedforward from 74e6d31
pyamber 98.47% <ø> (ø) Carriedforward from 74e6d31
workflow-compiling-service 74.09% <ø> (ø) Carriedforward from 74e6d31

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yangzhang75
yangzhang75 force-pushed the fix/cell-download-honours-export-switch branch from 39e828d to 0698dc6 Compare September 14, 2026 02:47
@yangzhang75
yangzhang75 marked this pull request as ready for review September 14, 2026 19:19
@yangzhang75
yangzhang75 marked this pull request as draft September 16, 2026 21:38
@yangzhang75
yangzhang75 force-pushed the fix/cell-download-honours-export-switch branch from 0698dc6 to 3910c41 Compare September 17, 2026 02:03
@yangzhang75 yangzhang75 changed the title fix(frontend): disable the per-cell result download when result export is switched off fix(frontend): make a result cell's download work off the canvas Sep 17, 2026
An export scopes itself to the operators selected on the canvas unless the
caller asked for all of them. That is the right scope for the two callers that
read the canvas: the top menu asks for everything, the context menu exports the
selection. The third caller is the download button on a result cell, and a cell
belongs to one operator, whoever happens to be selected. The same cell is also
mounted on the Form View, where the selection holds the step the user is
configuring and holds nothing at all until they click one. There the export
found an empty scope, so `performExport` returned before sending anything and
the dialog closed: a download button that did nothing, with no request, no
error and no message. The dialog's own checks read the same empty selection, so
a restricted operator went unreported there too -- with a scope of nothing,
there was nothing to report.

A caller that knows which operators it is exporting now says so, and both the
dialog and the service prefer that over the selection. The cell names the one
operator whose results it is showing. Nothing changes for the menu or the
context menu, which name none and keep the old scope.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@yangzhang75
yangzhang75 force-pushed the fix/cell-download-honours-export-switch branch from 3910c41 to 74e6d31 Compare September 17, 2026 06:38
@yangzhang75
yangzhang75 marked this pull request as ready for review September 17, 2026 06:55
@yangzhang75

Copy link
Copy Markdown
Contributor Author

/request-review: @kunwp1

@github-actions
github-actions Bot requested a review from kunwp1 September 17, 2026 06:58
@mengw15

mengw15 commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Dropping the backport labels (they were auto-added from the fix: title, before the rewrite).

The reproduction in #8538 goes through the Form View — its step 2 opens /user/workflow/<id>/form with nothing selected — and the Form View mount of result-table-frame (workflow-form.component.html) came in with #8376 on 2026-09-04, after the v1.3 cut. Neither release branch has it.

@mengw15 mengw15 removed release/v1.2 back porting to release/v1.2 release/v1.3 back porting to release/v1.3 labels Sep 17, 2026

@kunwp1 kunwp1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some comments! Overall looks good! Some comments are not directly related to this PR but I want you to fix them because it's a simple fix.

… older gaps

Review on apache#8539. The dialog already resolves which operators an export covers,
because it reports on them: what a blocking dataset blocks, what kind of output
is on offer. The export then derived that scope a second time, from an exportAll
flag and the canvas selection. Two answers to one question, agreeing today only
because the two implementations happen to line up.

The dialog now hands over the scope it resolved, so what is exported is what the
dialog said it would export. `exportAll` and both unreachable default parameter
values are gone with it, the parameter is `operatorIds`, and the three-way
scope expression in the service collapses to using what it was given. Which list
the dialog resolves, for each way of opening it, is now the dialog's own spec
rather than the service's.

Four fixes to older code, each asked for in the same review:

* A result cell's export carried the string "getWorkflowMetadata" as the workflow
  name: the accessor was read without being called, so `.name` was the function's
  own name. Every export from a cell has been labelled that.
* The download button rendered whether or not result export is switched on for
  the deployment. Every action behind it returns without sending a request when
  it is off, so it is not rendered now, the way the top menu and the context menu
  already treat the same switch.
* `sourceTriggered` arrives absent from a result cell, which sends no trigger of
  its own, so it read as undefined through a field typed string.
* The dialog built the whole-workflow scope by mapping over every operator; the
  graph already offers `getAllOperatorIDs()`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
@yangzhang75
yangzhang75 requested a review from kunwp1 September 18, 2026 22:47
kunwp1

This comment was marked as outdated.

kunwp1

This comment was marked as outdated.

@kunwp1 kunwp1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

private sanitizer: DomSanitizer,
private workflowStatusService: WorkflowStatusService,
private guiConfigService: GuiConfigService
public guiConfigService: GuiConfigService

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protected is enough here.

@xuang7
xuang7 removed their request for review September 21, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix frontend Changes related to the frontend GUI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A result cell's download button does nothing off the canvas

5 participants