Copilot commented on code in PR #8440:
URL: https://github.com/apache/texera/pull/8440#discussion_r3947713123
##########
frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts:
##########
@@ -164,6 +200,70 @@ export class WorkflowFormComponent implements OnInit,
OnDestroy {
this.wid = wid;
this.load(wid);
+ // The run clock, reusing the operator canvas's source outright rather
than timing anything
+ // here: the engine is the only thing that knows when the run really
began, so a stopwatch
+ // started at the click would drift and would be wrong after a reload.
+ this.workflowWebsocketService
+ .subscribeToEvent("ExecutionDurationUpdateEvent")
+ .pipe(
+ tap(event => (this.executionDuration = event.duration)),
+ switchMap(event => (event.isRunning ? timer(1000, 1000) : EMPTY)),
+ untilDestroyed(this)
+ )
+ .subscribe(() => {
+ this.executionDuration += 1000;
+ this.cdr.markForCheck();
+ });
+
+ // The run button's state is read from getters, so a change in
unit/connection/validity has to
+ // repaint the view. markForCheck, not detectChanges: a synchronous pass
can be thrown out of by
+ // an unrelated component's NG0100, killing the subscription.
+ this.computingUnitStatusService
+ .getSelectedComputingUnit()
+ .pipe(untilDestroyed(this))
+ .subscribe(() => this.cdr.markForCheck());
Review Comment:
The selected unit is discarded here, so the form never applies the
computing-unit permission gate. A shared unit with `READ` or `NONE` privilege
still reaches the enabled `Run` state and sends an execution request, whereas
the canvas explicitly disables execution unless
`selectedComputingUnit.accessPrivilege === Privilege.WRITE`
(`menu.component.html:430`); this also contradicts this component's statement
at lines 896-898 that execution is gated on computing-unit access. Retain the
selected unit and include its write privilege in the run-button disabled state.
##########
frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts:
##########
@@ -511,6 +616,154 @@ export class WorkflowFormComponent implements OnInit,
OnDestroy {
return rendered.resolved.binding.id;
}
+ //
---------------------------------------------------------------------------
+ // Instruction: the author's one piece of guidance, shown as rendered
markdown
+ //
---------------------------------------------------------------------------
+
+ public get hasInstruction(): boolean {
+ return this.instructionBody.trim().length > 0;
+ }
+
+ private async renderInstruction(): Promise<void> {
+ // Capture the body this render is for: parsing can resolve on a later
microtask, and a fresh
+ // readConfig() may start another render meanwhile. If the configured body
changed while we were
+ // parsing, this result is stale -- drop it so the newer render's output
stands.
+ const body = this.instructionBody;
+ const html = body.trim() ? await
Promise.resolve(this.markdownService.parse(body)) : "";
+ if (body !== this.instructionBody) {
+ return;
+ }
+ this.instructionPreviewHtml = html;
+ this.cdr.detectChanges();
+ }
+
+ public toggleInstruction(): void {
+ this.instructionOpen = !this.instructionOpen;
+ }
+
+ //
---------------------------------------------------------------------------
+ // Running the same workflow the canvas runs, through the same execute/kill
service. The canvas
+ // wraps its run with completion-email options
(executeWorkflowWithEmailNotification); this page
+ // runs plainly (executeWorkflow), so a form-started run does not send that
email.
+ //
---------------------------------------------------------------------------
+
+ public get isRunning(): boolean {
+ return (
+ this.executionState !== ExecutionState.Uninitialized &&
+ this.executionState !== ExecutionState.Completed &&
+ this.executionState !== ExecutionState.Failed &&
+ this.executionState !== ExecutionState.Killed &&
+ this.executionState !== ExecutionState.Terminated
+ );
+ }
+
+ /**
+ * A unit is picked but its socket is still coming up -- the same window the
operator canvas shows
+ * "Connecting" and disables its run button. Read from the exact condition
the canvas uses
+ * (menu.component's getRunButtonBehavior), so the two stay in step.
+ */
+ public get isConnecting(): boolean {
+ return (
+ this.computingUnitStatus !== ComputingUnitState.NoComputingUnit &&
!this.workflowWebsocketService.isConnected
+ );
+ }
+
+ /** No unit chosen yet: the button shows a disabled "Connect" hint and the
unit is picked in the
+ * embedded selector -- unlike the canvas, where the Connect button is
itself the click target. */
+ public get hasNoComputingUnit(): boolean {
+ return this.computingUnitStatus === ComputingUnitState.NoComputingUnit;
+ }
+
+ /**
+ * The Run button's label, icon and disabled state. It shares the operator
canvas's disable
+ * conditions -- an invalid or empty workflow, a unit still connecting, or
no unit chosen each
+ * disable it and say why -- but deliberately simplifies the execution
states a reader needs down
+ * to Run and Stop, with no pause/resume: while a run is in flight the
button stops (kills) it,
+ * otherwise it runs. (The canvas offers Pause/Resume/Submitting and a
clickable Connect; a form
+ * reader does not, and picks the unit in the embedded selector instead.)
+ */
+ public get runButtonState(): { label: string; icon: string; disabled:
boolean } {
+ if (this.isRunning) {
+ return { label: "Stop", icon: "stop", disabled: false };
+ }
+ if (!this.isWorkflowValid) {
+ return { label: "Invalid", icon: "warning", disabled: true };
+ }
+ if (this.isWorkflowEmpty) {
+ return { label: "Empty", icon: "info-circle", disabled: true };
+ }
+ if (this.isConnecting) {
+ return { label: "Connecting", icon: "loading", disabled: true };
+ }
+ if (this.hasNoComputingUnit) {
+ return { label: "Connect", icon: "plus-circle", disabled: true };
+ }
+ return { label: "Run", icon: "caret-right", disabled: false };
+ }
Review Comment:
`isRunning` is checked before `isConnecting`, so if the workflow socket
drops during an active run this returns an enabled Stop button. Clicking it
calls `killWorkflow()`, whose request is sent through the disconnected socket
and is not delivered; the canvas disables its kill/run controls in this state.
Check the connection state first so the button remains disabled as `Connecting`
until the socket reconnects.
--
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]