Skip to content

fix(workflow-form): redraw a result's chart in place, and drop the key that was meant to rebuild it - #9021

Open
yangzhang75 wants to merge 2 commits into
apache:mainfrom
yangzhang75:fix/form-result-frame-churn
Open

yangzhang75 wants to merge 2 commits into
apache:mainfrom
yangzhang75:fix/form-result-frame-churn

Conversation

@yangzhang75

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

Closes #8759. Part of the Form View feature (#8011); from the #8439 refinements (the result-frame item, raised in the #8441 review and deferred there).

Two things about the chart frame a result card shows, neither of which a reader can see today. The issue reads as a visible fault -- a chart recreated on every emission, flickering through a run -- and that is not what happens: it was written from the code, and the code cannot do it. What is really there is a latent ordering bug and a piece of machinery that never fires.

The frame audited before it filtered. VisualizationFrameContentComponent redraws on the result-update stream, throttled with auditTime, and the filter for its own operator ran after the audit. An update event carries only the operators whose result changed, so a window that closed on another operator's event handed the filter that event, which dropped it -- and this operator's pending redraw went with it. The last update of a run could leave the previous picture showing for good. The filter now runs first, so only this operator's updates enter the audit and what comes out is the redraw it was waiting on. The canvas result panel mounts the same component and gains the same reliability.

The Form View keyed each chart frame on a per-operator version, bumped on every result update, so that a changed result would rebuild the frame rather than reuse it (the frame reads its content once, at creation). It could not do that. Every visualisation operator takes its whole input before it draws (process_table, single-snapshot output ports), so the update that carries a picture is the same one that mounts the frame, and a second one never arrives. A re-run does not need the key either: it replaces the snapshot inside the operator's result service, which lives until the page is left, and a result that is cleared takes the frame down through vizHasContent. The key, the map behind it and the *ngFor that carried it go.

So: no visible change. A latent correctness fix, and the removal of code that cannot run.

Any related issues, documentation, discussions?

Closes #8759, which came out of the #8441 review (where the key was introduced, with the Copilot threads about it left open for this fix). Part of #8439 and the Form View feature #8011.

The issue's "expected" -- bump the key only for a genuinely new result, and handle clearResults -- is not what this does, because measuring showed there is nothing for a key to do. clearResults() runs when a workspace is torn down and when a computing unit is switched, not during a run.

Worth knowing, not changed here: the backend emits an update only for an operator whose tuple count changed, so a single-row visualiser that replaces its HTML at the same count produces no event at all, on the canvas and the form alike. That is a separate gap and a follow-up candidate.

How was this PR tested?

Unit tests (vitest). The frame's spec: a redraw pending for this operator survives a later emission for another operator -- this operator's update, half the window, another operator's event, the rest of the window, and the picture that lands is this operator's new one -- which is the case the old order lost; the existing redraw-after-the-window and ignore-other-operators tests still pass. The form's spec: a result update re-limits the shown results and re-fits the visualisations and rebuilds nothing, and the test that pinned the removed key is gone with it.

By hand, on two dev builds of the same base commit, one with this change and one without: a slow Python UDF source (40 rows, one every 0.4 s, batch size 1) feeding a pie chart, both results shown on the Form View. Counted off the websocket, the chart's operator receives two result updates per run and only the last carries a picture; counted in the DOM, the chart component is mounted exactly once per run -- on both builds, and twice over two runs on both builds. That measurement is why the key is described above as machinery that never fires, and why this PR has no before/after recording: there is nothing on screen to tell the two builds apart.

Each guard was deletion-checked and turned a named test red (the audit/filter order; the redraw itself). eslint, prettier and the production (AOT) build pass; the full frontend suite passes.

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

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

🤖 Generated with Claude Code

https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY

@github-actions

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: @EmilySun621, @aglinxinyuan
    You can notify them by mentioning @EmilySun621, @aglinxinyuan in a comment.

@github-actions github-actions Bot added fix frontend Changes related to the frontend GUI labels Oct 19, 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 Oct 19, 2026
@github-actions
github-actions Bot requested review from mengw15 and xuang7 October 19, 2026 05:12
@github-actions

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 Change detected on this branch — label added; 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. Review requested.
✅ release/v1.2 Change detected on this branch — label added; 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. Review requested.

Auto-label run.

@codecov-commenter

codecov-commenter commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.77%. Comparing base (ada1cfe) to head (1a216cd).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #9021      +/-   ##
============================================
+ Coverage     91.75%   91.77%   +0.02%     
  Complexity     5024     5024              
============================================
  Files          1281     1281              
  Lines         56747    56740       -7     
  Branches       7452     7449       -3     
============================================
+ Hits          52067    52072       +5     
+ Misses         2802     2792      -10     
+ Partials       1878     1876       -2     
Flag Coverage Δ *Carryforward flag
access-control-service 77.44% <ø> (ø) Carriedforward from ada1cfe
agent-service 99.53% <ø> (ø) Carriedforward from ada1cfe
amber 85.78% <ø> (ø) Carriedforward from ada1cfe
computing-unit-managing-service 64.05% <ø> (ø) Carriedforward from ada1cfe
config-service 87.73% <ø> (ø) Carriedforward from ada1cfe
file-service 82.31% <ø> (ø) Carriedforward from ada1cfe
frontend 96.42% <100.00%> (+0.04%) ⬆️
notebook-migration-service 83.77% <ø> (ø) Carriedforward from ada1cfe
pyamber 98.44% <ø> (ø) Carriedforward from ada1cfe
workflow-compiling-service 78.30% <ø> (ø) Carriedforward from ada1cfe

*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.

@mengw15 mengw15 removed release/v1.2 back porting to release/v1.2 release/v1.3 back porting to release/v1.3 labels Oct 19, 2026
@mengw15
mengw15 requested a balanced review from Copilot October 19, 2026 22:22

Copilot AI 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.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

3 open issues
What changed in this PR

Fixes a latent redraw ordering issue in visualization frames and removes the unused “result version key” mechanism from the Form View chart frames.

Changes:

  • Reorders RxJS operators in VisualizationFrameContentComponent so per-operator filtering happens before auditTime, preventing missed redraws.
  • Removes per-operator resultVersion / resultKey / trackByKey logic and simplifies the Form View template to render the visualization frame directly.
  • Updates/adjusts unit tests to cover the redraw ordering case and remove the now-obsolete keying behavior.
File Description
frontend/​src/​app/​workspace/​component/​workflow-form/​workflow-form.component.ts Removes result-version keying logic and updates result-update handling/comments.
frontend/​src/​app/​workspace/​component/​workflow-form/​workflow-form.component.html Drops the *ngFor keyed frame workaround and renders the visualization panel content directly.
frontend/​src/​app/​workspace/​component/​workflow-form/​workflow-form.component.spec.ts Removes tests for the deleted keying API and refocuses result-update assertions.
frontend/​src/​app/​workspace/​component/​visualization-panel-content/​visualization-frame-content.component.ts Filters result-update events before throttling to avoid losing pending redraws.
frontend/​src/​app/​workspace/​component/​visualization-panel-content/​visualization-frame-content.component.spec.ts Adds coverage for the “interleaving operator update” redraw-loss scenario.

Review effort: Lite

yangzhang75 added a commit to yangzhang75/texera that referenced this pull request Nov 2, 2026
…and tidy the subscription (review)

Copilot on apache#9021: the unit test's "rebuilds nothing" was only a name, so the rendered spec now
holds the frame's component instance and host element across two updates for its step and checks
both are the same objects afterwards; the frame's three .pipe() calls are one pipe, so the
filter-before-audit order is visible in one place; and the result-update comment is cut to the
invariant, with the measurements left on apache#8759.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
yangzhang75 and others added 2 commits November 12, 2026 13:28
…y that was meant to rebuild it

The visualization frame audited before it filtered. An update event carries
only the operators whose result changed, so a window that closed on another
operator's event was handed that event by the filter and dropped, taking this
operator's pending redraw with it: the last update of a run could leave the
previous picture showing for good. Filter first. The canvas result panel uses
the same frame and gains the same reliability.

The Form View keyed each chart frame by a per-operator version, bumped on every
result update, meaning to rebuild the frame rather than reuse it. It could not
do that. Every visualisation operator takes its whole input before it draws
(`process_table`, single-snapshot output), so the update that carries a picture
is the one that mounts the frame, and a second one never arrives; measured on a
run, the chart's operator sees two updates, one picture and one frame, with the
key and without it. A re-run replaces the snapshot inside the operator's result
service, which lives until the page is left, so there is no new frame to key on
there either. The machinery never fired, so it goes.

No visible change: this fixes a latent ordering bug and removes code that
cannot run.

Closes apache#8759

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
…and tidy the subscription (review)

Copilot on apache#9021: the unit test's "rebuilds nothing" was only a name, so the rendered spec now
holds the frame's component instance and host element across two updates for its step and checks
both are the same objects afterwards; the frame's three .pipe() calls are one pipe, so the
filter-before-audit order is visible in one place; and the result-update comment is cut to the
invariant, with the measurements left on apache#8759.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01FVvP3ttj22f9LB4p9u2anY
@yangzhang75
yangzhang75 force-pushed the fix/form-result-frame-churn branch from 0b43bf1 to 1a216cd Compare November 12, 2026 21:43

This branch has not been deployed

No deployments
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.

fix(workflow-form): a result update rebuilds the visualization frame on every emission

5 participants