Copilot commented on code in PR #8845:
URL: https://github.com/apache/texera/pull/8845#discussion_r4197183793


##########
frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts:
##########
@@ -838,24 +852,84 @@ export class WorkflowFormComponent implements OnInit, 
OnDestroy {
    * exposed property. Each input gets its own form keyed by binding id.
    */
   private buildForm(): void {
+    // A rebuild ends every card's write-back subscription, so an edit whose 
debounced write has not
+    // fired yet is written now, and the rebuilt card is seeded with it rather 
than without it.
+    this.rendered.forEach(card => card.pendingWrite && card.flushWrite?.());
     this.formsRebuilt.next();
     this.rendered = this.visibleFields
       .map(field => this.renderField(field))
       .filter((r): r is RenderedField => r !== undefined);
   }
 
+  /**
+   * A compilation result 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), or an
+   * operator value a card does not hold (a co-editor's edit; the card's own 
edit, written back or
+   * still on its way, is not that). Most compilations change none of these -- 
the one a card's own
+   * write triggers, for one -- and used to rebuild every card regardless: the 
controls were redrawn
+   * under the reader's eyes, the focus went with them, and a click made in 
the last moments before
+   * the rebuild was lost, since the rebuild cancelled that card's pending 
write. The canvas's
+   * property panel redraws only for a schema change; the form does the same. 
The result picker and
+   * the shown results still follow the graph either way.
+   */
+  private onCompilationChanged(): void {
+    if (this.cardsNeedRebuild()) {
+      this.rebuildFormOrDefer(false);
+      return;
+    }
+    this.refreshShownResults();
+    this.rebuildResultChoices();
+    this.cdr.markForCheck();
+  }
+
+  private cardsNeedRebuild(): boolean {
+    const fields = this.visibleOf(this.formBindingService.resolveFields());
+    const sameInputs =
+      fields.length === this.rendered.length &&
+      fields.every((field, i) => {
+        const shown = this.rendered[i].resolved;
+        return field.binding.id === shown.binding.id && (field.brokenReason ?? 
"") === (shown.brokenReason ?? "");
+      });
+    if (!sameInputs) {
+      return true;
+    }
+    return this.rendered.some(card => {
+      const { binding, brokenReason } = card.resolved;
+      if (brokenReason) {
+        return false;
+      }
+      if (this.schemaKeyFor(binding.operatorID) !== card.schemaKey) {
+        return true;
+      }
+      // The card's own edit is on its way to the operator; the two agree once 
it is written.
+      if (card.pendingWrite) {
+        return false;
+      }
+      return !sameValue(
+        card.model[binding.id],
+        this.formBindingService.readValue(binding.operatorID, 
binding.propertyKey)
+      );

Review Comment:
   This only compares the exposed property's value, but each card is seeded 
with every operator property as widget context (lines 970–979). For example, 
the Hugging Face picker reads sibling `task` from `field.model`; if a 
canvas/co-editor changes `task` while `modelId` stays unchanged and the schema 
is unchanged, this returns false and the card keeps loading/showing the old 
task. Compare a stored snapshot of the operator's contextual properties as 
well, excluding or normalizing the card's own pending property so its write 
does not cause a rebuild.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to