The GitHub Actions job "Required Checks" on 
texera.git/gh-readonly-queue/main/pr-8845-57faa6b85c72bdd258b8e735c4be13171b5f8443
 has succeeded.
Run started by GitHub user mengw15 (triggered by mengw15).

Head commit for run:
3726dd7b1de85c649a3d953cfa4ee17479c89df6 / yangzhang75 <[email protected]>
fix(workflow-form): rebuild the cards on compilation only when it changed 
something they show (#8845)

### What changes were proposed in this PR?

Closes #8844. Part of the Form View feature (#8011); from the #8439
refinements. Found on the #8761 demo (#8843).

A compilation result rebuilt every card on the Form View, including the
compilation a card's own write triggers. Three things followed from
that, all visible with a Projection's drag-reorder list (#8761) and with
any tick box: the controls were redrawn under the reader's eyes after
every click (the row buttons flicker); the keyboard focus went with the
replaced node, so a keyboard reader landed on the body about a second
after every Move up / Move down; and a click made in the last 150 ms
before the rebuild was lost, since the rebuild ended that card's pending
debounced write and re-seeded the card from the operator, which still
held the previous state (the row "jumps back"). The canvas's property
panel redraws only when an operator's schema changes.

The form now does the same:

- A compilation rebuilds the cards only when it changed something they
show: a card's operator schema (the column enums compilation writes into
it, which turn an attribute box into a dropdown), the set of inputs (an
operator deleted on the canvas makes its card broken; a property exposed
or removed), or an operator value a card does not hold (a co-editor's
edit), including the operator's other properties, which a card is seeded
with as the context a custom widget reads to decide what it shows (the
HuggingFace picker reads `task`): nothing but a rebuild re-seeds those,
so a sibling changed on the canvas or by a co-editor would have left the
card showing the old one (Copilot). Every property an input is bound to
is left out of that context, this card's own and any other card's on the
same step, since each is compared against the card that shows it:
counting them as context too would make one card's edit a change to
every other card of that step, and a form with two inputs from one step
would rebuild wholesale on every compilation its own typing triggers --
the churn this PR exists to stop (Copilot). The keys are compared
sorted, so a rewrite that only reorders them is not a change, and a
card's own edit, written back or still on its way, is not a reason: the
two agree once it is written. The result picker and the shown results
still follow the graph on every compilation.
- Before any rebuild, from any source, a card's unwritten edit is
written, so a rebuild can no longer lose one.
- An empty string and an absent value count as the same value in the
comparison (formly's blank default for a property the operator never
had), so such a card is not rebuilt on every compilation.

### Any related issues, documentation, discussions?

Closes #8844. The drag-reorder list #8843 (#8761) brings to the form is
where this is plain to see: every drop writes and compiles, and the rows
redraw about a second later; a second drop made just before that redraw
is undone. The cause is the form's own compile handling, present since
the cards were first built from the compiled schema; on main alone a
tick box goes through the same redraw, focus drop and lost second click,
which take a keyboard or a stopwatch to notice. The Before/After below
is therefore recorded on top of #8843 (before: #8843 alone; after: #8843
plus this); this PR does not depend on #8843 and applies to main as is.
Known limitation, unchanged: a card still shows a co-editor's edit of
the same property only after the rebuild that edit's compilation
triggers (tracked as a follow-up).

### How was this PR tested?

Unit tests (vitest), the form's spec: a compilation that changes nothing
a card shows leaves the cards alone (same card objects) while the result
picker is still refreshed; a changed operator schema, an operator gone
from the graph, an operator value changed under a card (a co-editor's
edit), another property of a card's operator changed (the widget
context), a changed set of inputs (one exposed; a shown one turned
broken) each rebuild; the same properties in another order do not, nor
does a change to the card's own property while its edit is still on its
way, nor one card's edit when two inputs come from the same step (both
card objects survive it); an author's broken card is left alone; the
card's own edit does not rebuild while pending nor once written;
formly's blank and an absent value count as the same; an unwritten edit
is written, once, before a rebuild from any source replaces the card; a
read-only viewer's card has no write to flush; the typing hold still
holds a needed rebuild until the focus leaves. Each guard was
deletion-checked (every compilation rebuilding; the schema check, the
context check, the exclusion of every bound property from it, that the
exclusion covers the other cards of the step and not only this one, the
context's key sort, the pending check, the broken-set check, the blank
normalisation, the pre-rebuild flush, the pending mark, the pending
reset and the result-picker refresh each removed; a broken card checked
against a schema) and turned a named test red. eslint, prettier and the
production (AOT) build pass; the full frontend suite passes; every
statement, function and branch this PR adds is covered.

Checked on a flag-on instance (main-demo; before = main, and main +
#8843; after = the same plus this), a Projection's columns and its Drop
Option exposed on the form. The tick box on main: 0.3 s after a tick the
box still has the focus; 2.8 s later it is a new DOM node and the focus
is on the body; two ticks 700 ms apart end in the state after the first
(the second undone). With this change the box is the same node three
seconds later, still focused, and both ticks land. The drag-reorder rows
on main + #8843: after a drop the rows are replaced about a second
later; with this change they are the same nodes, and the order still
reaches a canvas tab open beside the form within a second, a drop made
on the canvas panel still reaches the form (a value the card does not
hold rebuilds it), and the saved workflow carries the order.

#### Video

**Before**


https://github.com/user-attachments/assets/eac466c3-c0c9-4969-b39a-a6da41ec54ff

**After**



https://github.com/user-attachments/assets/3ecd6342-7d6b-405c-bd83-f45415c2bcba



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

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

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5.1 <[email protected]>

Report URL: https://github.com/apache/texera/actions/runs/39091988742

With regards,
GitHub Actions via GitBox

Reply via email to