mengw15 commented on code in PR #8516:
URL: https://github.com/apache/texera/pull/8516#discussion_r3994462288


##########
frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts:
##########
@@ -510,11 +551,43 @@ export class WorkflowFormComponent implements OnInit, 
OnDestroy {
   }
 
   /**
-   * Show the workflow rather than edit it: the graph shape and its properties 
are read-only
-   * on this page. A later PR's authoring mode makes properties editable with 
write access.
+   * Whether this page may hold the graph unlocked: a writer in edit mode, and 
no run in flight. The
+   * run rule is the canvas's own (a run locks the graph until it ends), kept 
here too so that entering
+   * edit mode mid-run cannot undo it. Every other state is locked, so a 
reader, or a writer merely
+   * viewing, cannot change the workflow through this page.
    */
+  private mayUnlock(): boolean {
+    return this.authoring && this.canEdit && !this.isRunning;
+  }
+
+  /** Lock or unlock editing from the current state (see mayUnlock); the one 
reducer for both directions. */
   private applyEditability(): void {
-    this.workflowActionService.disableWorkflowModification();
+    if (this.mayUnlock()) {
+      this.workflowActionService.enableWorkflowModification();
+    } else {
+      this.workflowActionService.disableWorkflowModification();
+    }
+  }
+
+  /**
+   * The lock is a root-level flag with writers that know nothing of this 
page: the execute service
+   * unlocks it whenever a run ends (completed, failed, killed, reset), the 
computing-unit selector
+   * unlocks it when it finds no run on the chosen unit, and any future caller 
may too. Rather than
+   * chase each one, clamp at the one place they all report to: whenever the 
flag turns on while this
+   * page must stay locked, turn it off again. In edit mode the canvas rule 
then stands unchanged:
+   * locked while a run is in flight, unlocked once it ends -- the execute 
service flips the lock
+   * before it emits the new state, so that unlock is clamped here (this page 
still sees "running")
+   * and given back by the execution-state handler, which re-applies the rule 
with the new state.
+   */
+  private clampEditability(): void {
+    this.workflowActionService
+      .getWorkflowModificationEnabledStream()
+      .pipe(untilDestroyed(this))
+      .subscribe(enabled => {
+        if (enabled && !this.mayUnlock()) {
+          this.workflowActionService.disableWorkflowModification();

Review Comment:
   Confirmed, and it is reachable through the undo path: the editor binds 
ctrl+z on a document-level keydown with no `interactive` gate, so the only 
thing stopping an undo on this page is 
`UndoRedoService.workFlowModificationEnabled` — and the outer 
`enableWorkflowModification()` re-enables it after the clamp's nested disable 
(`undoRedoService.enableWorkFlowModification()` runs after the emission). So: 
edit a property in edit mode, Done, run, run ends — ctrl+z then replays that 
edit onto the shared graph from a page in view mode.
   
   One correction to the comment above: the result toggle stays safe — 
OperatorMenuService recomputes from `checkWorkflowModificationEnabled()` (the 
flag, already false by then), not from the event payload.
   
   Deferring the clamp's disable by one microtask (e.g. 
`observeOn(asapScheduler)`) would let the enable call finish first; the disable 
then runs as a clean top-level call and every consumer, the undo/redo flag 
included, converges on locked.
   



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