This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new 2ab8ee0f28 fix(frontend): make the computing-unit picker say which
picker it is, and let its button be clicked (#8590)
2ab8ee0f28 is described below
commit 2ab8ee0f2859339458cd8f44659db989910b201d
Author: Meng Wang <[email protected]>
AuthorDate: Fri Sep 18 18:52:08 2026 +0000
fix(frontend): make the computing-unit picker say which picker it is, and
let its button be clicked (#8590)
### What changes were proposed in this PR?
The warehouse picker (#8551) now sits beside the computing-unit picker,
and the pair showed nothing but a name each. Fixes #8587.
- **The trigger says what it is.** It gains the `deployment-unit` icon
its own dashboard tab uses — the warehouse trigger already carries
`cloud-server` — and its tooltip reads `Computing Unit: <name>`, the
shape the warehouse trigger uses: one tooltip on the control rather than
one on the badge and another on the name. The status stays where it
already lives, the badge's colour here and its words in the dropdown
rows.
- **With nothing selected, both the trigger and the run button name what
is missing** — `Computing Unit`, as the warehouse side says `Warehouse`
— instead of `Connect`, so the two pickers read the same way. The form
view's run button follows, since it mirrors the canvas's disable
conditions.
- **That button was disabled in exactly the state it exists for.** The
run button's guard ended in `selectedComputingUnit?.accessPrivilege !==
Privilege.WRITE`; with no unit selected that compares against
`undefined` and is always true, so the button offered to connect and
refused every click, leaving `runWorkflow()`'s create-unit branch
unreachable — the branch the form view's own comments describe as the
canvas's click target, and which its test reaches only by calling the
method directly. The privilege is now asked only of a unit that exists;
a unit shared read-only still refuses to run.
- **The two triggers stop looking like different controls.** Sized to
content between a min and a max they came out visibly different widths,
so both are now 200px; a name too long for it is ellipsised and read
from the tooltip, which carries it in full. The avatar, shrunk with a
`transform` that changes only what is drawn, kept its 32px box inside a
32px-tall button and inflated it, so it is sized for real instead. The
form view matches both pickers to its Run button's height, not just the
computing-unit one that rule predates. And the gap between the pickers
no longer widens whenever a unit is running: the container gap and the
auto margin that exist to push the metrics block away now apply to the
metrics block itself.
- **The badge stops claiming work that is not happening.**
`computeStatus()` returned `"processing"` with nothing selected, which
ant renders as a pulsing blue dot; it is now `"default"`.
### before:
<img width="1066" height="289" alt="Screenshot 2026-09-18 at 12 23
44 AM"
src="https://github.com/user-attachments/assets/ae6ac7ec-2e2b-4d5e-b676-220e4a0a861e"
/>
<img width="706" height="180" alt="Screenshot 2026-09-18 at 12 24 07 AM"
src="https://github.com/user-attachments/assets/6667d342-87f8-43fa-a85b-cd4217a9d9c8"
/>
<img width="696" height="177" alt="Screenshot 2026-09-18 at 12 24 40 AM"
src="https://github.com/user-attachments/assets/2750dfa8-e026-4fda-983c-f7f0271d1dac"
/>
### after:
<img width="805" height="246" alt="Screenshot 2026-09-18 at 12 33 45 AM"
src="https://github.com/user-attachments/assets/e93b7e1b-251a-4347-bfbd-a949761229de"
/>
<img width="747" height="234" alt="Screenshot 2026-09-18 at 12 32 57 AM"
src="https://github.com/user-attachments/assets/8249e697-d136-465d-b81c-d2e9867233b5"
/>
<img width="751" height="192" alt="Screenshot 2026-09-18 at 12 34 00 AM"
src="https://github.com/user-attachments/assets/a77aa290-dac4-4861-b472-2c1581565152"
/>
### Any related issues, documentation, discussions?
Closes #8587. Follows #8551 and #8589 (the warehouse side of the same
pair). Part of #6870.
### How was this PR tested?
- Vitest: new tests for the trigger's tooltip (long name, short name,
nothing selected), for the no-unit button being clickable, and for a
read-only unit still disabling it; the existing badge and label
assertions updated. The workspace suite passes in full: 3326 tests.
- Label width measured in a browser against the run button's clipping
width (~106px for text): `Computing Unit` is 101px on macOS, 96px on
Windows and Linux faces.
- The sizing and spacing changes are CSS and out of reach of jsdom; they
were checked in a running workspace and form view, with and without a
selection on each picker and with a unit running.
- Failure paths verified rather than assumed: the privilege guard, the
badge state, the tooltip and the label were each reverted on purpose and
the suite confirmed to fail for the expected reason before being
restored.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (claude-opus-5, claude-fable-5)
---
.../workspace/component/menu/menu.component.html | 2 +-
.../component/menu/menu.component.spec.ts | 53 ++++++++++++++++++++--
.../app/workspace/component/menu/menu.component.ts | 5 +-
.../computing-unit-selection.component.html | 24 +++++-----
.../computing-unit-selection.component.scss | 35 ++++++++++----
.../computing-unit-selection.component.spec.ts | 34 ++++++++++++--
.../computing-unit-selection.component.ts | 14 +++++-
.../workflow-form/workflow-form.component.html | 2 +-
.../workflow-form/workflow-form.component.scss | 6 ++-
.../workflow-form/workflow-form.component.spec.ts | 6 +--
.../workflow-form/workflow-form.component.ts | 7 +--
.../workflow-form/workflow-form.rendered.spec.ts | 4 +-
12 files changed, 150 insertions(+), 42 deletions(-)
diff --git a/frontend/src/app/workspace/component/menu/menu.component.html
b/frontend/src/app/workspace/component/menu/menu.component.html
index cf4c053894..fe8e50601c 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.html
+++ b/frontend/src/app/workspace/component/menu/menu.component.html
@@ -451,7 +451,7 @@
[nzPopoverTrigger]="'hover'"
[nzPopoverContent]="executionSettings"
nzPopoverPlacement="bottom"
- [disabled]="runDisable || (!workflowWebsocketService.isConnected &&
computingUnitStatus !== ComputingUnitState.NoComputingUnit) ||
displayParticularWorkflowVersion || selectedComputingUnit?.accessPrivilege !==
Privilege.WRITE"
+ [disabled]="runDisable || (!workflowWebsocketService.isConnected &&
computingUnitStatus !== ComputingUnitState.NoComputingUnit) ||
displayParticularWorkflowVersion || (selectedComputingUnit !== null &&
selectedComputingUnit.accessPrivilege !== Privilege.WRITE)"
id="run-button"
nz-button
nzType="primary">
diff --git a/frontend/src/app/workspace/component/menu/menu.component.spec.ts
b/frontend/src/app/workspace/component/menu/menu.component.spec.ts
index e23d4b9890..baea315819 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.spec.ts
+++ b/frontend/src/app/workspace/component/menu/menu.component.spec.ts
@@ -57,6 +57,8 @@ import { MockGuiConfigService } from
"../../../common/service/gui-config.service
import { JupyterPanelService } from
"../../service/jupyter-panel/jupyter-panel.service";
import type { Mocked } from "vitest";
import { WarehouseService } from
"../../../common/service/warehouse/warehouse.service";
+import { Privilege } from "../../../dashboard/type/share-access.interface";
+import { DashboardWorkflowComputingUnit } from
"../../../common/type/workflow-computing-unit";
describe("MenuComponent", () => {
let component: MenuComponent;
@@ -229,6 +231,49 @@ describe("MenuComponent", () => {
expect(navigate).toHaveBeenCalledWith(7);
});
+ describe("run button enablement (#8587)", () => {
+ const runButton = () => fixture.nativeElement.querySelector("#run-button")
as HTMLButtonElement;
+
+ const render = () => {
+ component.applyRunButtonBehavior(component.getRunButtonBehavior());
+ fixture.detectChanges();
+ };
+
+ beforeEach(() => {
+ component.isWorkflowValid = true;
+ component.isWorkflowEmpty = false;
+ Object.defineProperty(component.workflowWebsocketService, "isConnected",
{ get: () => true, configurable: true });
+ component.executionState = ExecutionState.Uninitialized;
+ });
+
+ it("leaves the no-unit button clickable, since that is the state it exists
to fix", () => {
+ // The privilege check asks a unit that does not exist; with no unit
+ // selected it used to be permanently true, so the button offered to
+ // connect and refused every click, leaving runWorkflow's create-unit
+ // branch unreachable.
+ component.computingUnitStatus = ComputingUnitState.NoComputingUnit;
+ component.selectedComputingUnit = null;
+
+ render();
+
+ expect(runButton().textContent?.trim()).toBe("Computing Unit");
+ expect(runButton().disabled).toBe(false);
+ });
+
+ it("still refuses to run on a unit the user may only read", () => {
+ component.computingUnitStatus = ComputingUnitState.Running;
+ component.selectedComputingUnit = {
+ computingUnit: { cuid: 1, name: "theirs" },
+ status: "Running",
+ accessPrivilege: Privilege.READ,
+ } as unknown as DashboardWorkflowComputingUnit;
+
+ render();
+
+ expect(runButton().disabled).toBe(true);
+ });
+ });
+
describe("getRunButtonBehavior", () => {
it("returns 'Invalid Workflow' when the workflow is invalid", () => {
component.isWorkflowValid = false;
@@ -252,14 +297,14 @@ describe("MenuComponent", () => {
expect(behavior.disable).toBe(true);
});
- it("returns 'Connect' when no computing unit is attached", () => {
+ it("returns 'Computing Unit' when no computing unit is attached", () => {
component.isWorkflowValid = true;
component.isWorkflowEmpty = false;
component.computingUnitStatus = ComputingUnitState.NoComputingUnit;
const behavior = component.getRunButtonBehavior();
- expect(behavior.text).toBe("Connect");
+ expect(behavior.text).toBe("Computing Unit");
expect(behavior.icon).toBe("plus-circle");
expect(behavior.disable).toBe(false);
});
@@ -441,8 +486,8 @@ describe("MenuComponent", () => {
const behavior = component.getRunButtonBehavior();
- // Same word the picker's own empty state shows, as CU repeats "Connect";
- // it also has to fit the run button's fixed width.
+ // Same word the picker's own empty state shows, as the computing-unit
+ // flow repeats its own; it also has to fit the run button's fixed width.
expect(behavior.text).toBe("Warehouse");
expect(behavior.icon).toBe("plus-circle");
expect(behavior.disable).toBe(false);
diff --git a/frontend/src/app/workspace/component/menu/menu.component.ts
b/frontend/src/app/workspace/component/menu/menu.component.ts
index fe8d2de53a..2ad2572ddd 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.ts
+++ b/frontend/src/app/workspace/component/menu/menu.component.ts
@@ -411,10 +411,11 @@ export class MenuComponent implements OnInit, OnDestroy {
};
}
- // no computing unit, show "Connect" button
+ // No computing unit: name the thing that is missing, the way the warehouse
+ // gate below does, and let the click open the create dialog.
if (this.computingUnitStatus === ComputingUnitState.NoComputingUnit) {
return {
- text: "Connect",
+ text: "Computing Unit",
icon: "plus-circle",
disable: false,
onClick: () => this.runWorkflow(),
diff --git
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.html
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.html
index 17224ec394..7511f52bc5 100644
---
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.html
+++
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.html
@@ -75,9 +75,8 @@
[avatar]="selected.ownerAvatar || ''"
userColor="grey"
[userName]="selected.ownerName || ''"
- [style.transform]="'scale(0.65)'"
- [style.opacity]="0.7"
- [style.padding-right.px]="2">
+ class="picker-avatar"
+ [style.opacity]="0.7">
</texera-user-avatar>
<i
nz-icon
@@ -151,32 +150,33 @@
[nzDropdownMenu]="menu"
[nzPlacement]="'bottomRight'"
(nzVisibleChange)="onDropdownVisibilityChange($event)"
- class="computing-units-dropdown-button">
+ class="computing-units-dropdown-button"
+ nz-tooltip
+ [nzTooltipTitle]="computingUnitButtonTooltip">
<div class="button-content">
<texera-user-avatar
*ngIf="selectedComputingUnit"
[avatar]="selectedComputingUnit ? selectedComputingUnit.ownerAvatar :
''"
userColor="grey"
[userName]="selectedComputingUnit ? selectedComputingUnit.ownerName :
''"
- [style.transform]="'scale(0.65)'"
- [style.opacity]="0.7"
- [style.padding-right.px]="2">
+ class="picker-avatar"
+ [style.opacity]="0.7">
</texera-user-avatar>
+ <i
+ nz-icon
+ nzType="deployment-unit"></i>
<nz-badge
[nzStatus]="computeStatus()"
- [nz-tooltip]="selectedComputingUnit ? selectedComputingUnit.status :
''"
[nzText]="''"></nz-badge>
<span
*ngIf="selectedComputingUnit"
- nz-tooltip
- class="unit-name-text"
- [nzTooltipTitle]="selectedComputingUnit.computingUnit.name">
+ class="unit-name-text">
{{selectedComputingUnit.computingUnit.name}}
</span>
<span
*ngIf="!selectedComputingUnit"
class="connect-text"
- >Connect</span
+ >Computing Unit</span
>
<i
nz-icon
diff --git
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.scss
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.scss
index ba5d4bad29..3913fec422 100644
---
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.scss
+++
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.scss
@@ -36,10 +36,13 @@
&.metrics-visible {
min-width: 290px;
max-width: none;
- gap: 10px;
- .computing-units-dropdown-button {
+ // Only the metrics block is pushed away; a gap on the container, or an
auto
+ // margin on the computing-unit button, also widened the space between the
+ // two pickers whenever a unit happened to be running.
+ .metrics-container {
margin-left: auto;
+ margin-right: 10px;
}
}
}
@@ -205,10 +208,13 @@
.warehouse-dropdown-button {
display: inline-flex;
align-items: center;
- min-width: 220px;
- max-width: 280px;
- // The gap between this picker and the computing-unit one that follows it;
- // the computing-unit trigger has none because nothing follows it.
+ // One width for both pickers. Sized to content between a min and a max they
+ // came out different — this one short ("Warehouse"), the computing-unit one
+ // long — which reads as a mistake when they sit side by side. A name too
long
+ // for it is ellipsised and read from the tooltip, which carries it in full.
+ width: 200px;
+ // The gap to the computing-unit picker that follows it; that one has none
+ // because nothing follows it.
margin-right: 4px;
padding: 0 8px;
overflow: hidden;
@@ -233,13 +239,26 @@
.computing-units-dropdown-button {
display: inline-flex;
align-items: center;
- min-width: 220px;
- max-width: 280px;
+ width: 200px;
padding: 0 8px;
overflow: hidden;
white-space: nowrap;
}
+// The avatar is 32px by default, and scaling it with a transform shrank only
+// what is drawn, not the box: a 32px child inflated a 32px-tall button. Sized
+// for real, it draws the same and leaves the button its height.
+.picker-avatar {
+ margin-right: 4px;
+
+ ::ng-deep .ant-avatar {
+ width: 21px;
+ height: 21px;
+ font-size: 12px;
+ line-height: 21px;
+ }
+}
+
.button-content {
display: flex;
align-items: center;
diff --git
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.spec.ts
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.spec.ts
index 1cdf2052e0..3e0153b268 100644
---
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.spec.ts
+++
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.spec.ts
@@ -1579,9 +1579,37 @@ describe("PowerButtonComponent", () => {
});
describe("status helpers", () => {
+ it("the trigger's tooltip names the picker and the unit, in the warehouse
trigger's shape", () => {
+ // Asserted through the rendered directive, not just the getter: the
+ // user-visible contract is one tooltip on the trigger, so a removed
+ // binding or a tooltip reintroduced on the name or badge must fail here.
+ component.selectedComputingUnit = makeComputingUnit({
+ name: "a-very-long-unit-name-that-truncates",
+ status: "Running",
+ });
+ fixture.detectChanges();
+
+ const trigger =
fixture.debugElement.query(By.css(".computing-units-dropdown-button"));
+ const tooltip = trigger.injector.get(NzTooltipDirective) as
NzTooltipDirective;
+ expect(tooltip.title).toBe("Computing Unit:
a-very-long-unit-name-that-truncates");
+
expect(fixture.debugElement.query(By.css(".unit-name-text[nz-tooltip]"))).toBeNull();
+
expect(fixture.debugElement.query(By.css(".computing-units-dropdown-button
nz-badge[nz-tooltip]"))).toBeNull();
+
+ // The status is not in it: the badge shows that here, in words in the
rows.
+ component.selectedComputingUnit = makeComputingUnit({ name: "cu",
status: "Pending" });
+ fixture.detectChanges();
+ expect(tooltip.title).toBe("Computing Unit: cu");
+
+ component.selectedComputingUnit = null;
+ fixture.detectChanges();
+ expect(tooltip.title).toBe("Computing Unit");
+ });
+
it("computeStatus maps selection + status onto badge states", () => {
component.selectedComputingUnit = null;
- expect(component.computeStatus()).toBe("processing");
+ // Not "processing": nothing is being processed when nothing is selected,
+ // and ant renders that as a pulsing blue dot claiming work (#8587).
+ expect(component.computeStatus()).toBe("default");
component.selectedComputingUnit = makeComputingUnit({ status: "Running"
});
expect(component.computeStatus()).toBe("success");
component.selectedComputingUnit = makeComputingUnit({ status: "Pending"
});
@@ -1944,13 +1972,13 @@ describe("PowerButtonComponent", () => {
expect(host.querySelector(".connect-text")).toBeNull();
});
- it("renders the 'Connect' label on the trigger when no unit is selected",
() => {
+ it("names the missing resource on the trigger when no unit is selected",
() => {
component.selectedComputingUnit = null;
component.allComputingUnits = [];
fixture.detectChanges();
const host = fixture.nativeElement as HTMLElement;
-
expect(host.querySelector(".connect-text")?.textContent).toContain("Connect");
+
expect(host.querySelector(".connect-text")?.textContent).toContain("Computing
Unit");
expect(host.querySelector(".unit-name-text")).toBeNull();
});
});
diff --git
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts
index 7ee2a14e42..e624563b3b 100644
---
a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts
+++
b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts
@@ -602,9 +602,21 @@ export class ComputingUnitSelectionComponent implements
OnInit {
return this.selectedComputingUnit != null &&
this.selectedComputingUnit.status === "Running";
}
+ /**
+ * `Computing Unit: <name>`, the shape the warehouse trigger uses: which
picker
+ * this is, plus the name it ellipsises. The status stays where it already
+ * lives — the badge's colour here, its words in the dropdown rows.
+ */
+ get computingUnitButtonTooltip(): string {
+ const selected = this.selectedComputingUnit;
+ return selected ? `Computing Unit: ${selected.computingUnit.name}` :
"Computing Unit";
+ }
+
computeStatus(): string {
if (!this.selectedComputingUnit) {
- return "processing";
+ // Nothing is being processed when nothing is selected; "processing"
would
+ // render a pulsing blue dot claiming work that is not happening.
+ return "default";
}
const status = this.selectedComputingUnit.status;
diff --git
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.html
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.html
index b0425bc0f6..b9058303cf 100644
---
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.html
+++
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.html
@@ -358,7 +358,7 @@
<!-- One button in this page's own style. Its DISABLE conditions
follow the operator canvas
(menu.component's getRunButtonBehavior) exactly -- disabled for
an invalid or empty
graph, while a unit's socket comes up ("Connecting"), and before
a unit is chosen
- ("Connect") -- so the reader is never sent to press a button that
does nothing. The
+ ("Computing Unit") -- so the reader is never sent to press a
button that does nothing. The
labels and icons are this page's own simplified Run/Stop set,
shorter than the canvas's
("Invalid" not "Invalid Workflow", a caret-right Run), and it
drops the canvas's
Pause/Resume/Submitting: a run in flight simply shows "Stop". -->
diff --git
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.scss
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.scss
index fac1e8e948..3889c57e24 100644
---
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.scss
+++
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.scss
@@ -456,8 +456,10 @@ $shell: #fafafa;
min-width: 0;
}
- /* Matched to Run's height so the pair reads as one row of controls. */
- ::ng-deep .computing-units-dropdown-button {
+ /* Matched to Run's height so the row of controls reads as one. Both
pickers, not just the
+ computing-unit one this rule predates. */
+ ::ng-deep .computing-units-dropdown-button,
+ ::ng-deep .warehouse-dropdown-button {
height: 40px;
}
}
diff --git
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.spec.ts
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.spec.ts
index b6d780ac44..50edda7f4b 100644
---
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.spec.ts
+++
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.spec.ts
@@ -1500,10 +1500,10 @@ describe("WorkflowFormComponent", () => {
expect((component as any).selectedUnit).toEqual({ accessPrivilege:
"WRITE" });
});
- it("offers Connect before a unit is chosen", () => {
+ it("names the missing computing unit before one is chosen", () => {
build(formViewWorkflow).ngOnInit();
- expect(component.runButtonState).toEqual({ label: "Connect", icon:
"plus-circle", disabled: true });
+ expect(component.runButtonState).toEqual({ label: "Computing Unit",
icon: "plus-circle", disabled: true });
});
it("offers Run once a unit is up and the graph is valid", () => {
@@ -1629,7 +1629,7 @@ describe("WorkflowFormComponent", () => {
it("does nothing when the button is disabled", () => {
build(formViewWorkflow).ngOnInit();
- // Default state is "Connect" (disabled): no unit chosen.
+ // Default state is "Computing Unit" (disabled): no unit chosen.
component.onRun();
diff --git
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts
index c297a829f0..2b9433c482 100644
---
a/frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts
+++
b/frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts
@@ -1526,8 +1526,9 @@ export class WorkflowFormComponent implements OnInit,
OnDestroy {
);
}
- /** 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. */
+ /** No unit chosen yet: the button names what is missing and stays disabled,
because the unit is
+ * picked in the embedded selector -- unlike the canvas, where that button
is itself the click
+ * target for creating one. */
public get hasNoComputingUnit(): boolean {
return this.computingUnitStatus === ComputingUnitState.NoComputingUnit;
}
@@ -1564,7 +1565,7 @@ export class WorkflowFormComponent implements OnInit,
OnDestroy {
return { label: "Empty", icon: "info-circle", disabled: true };
}
if (this.hasNoComputingUnit) {
- return { label: "Connect", icon: "plus-circle", disabled: true };
+ return { label: "Computing Unit", icon: "plus-circle", disabled: true };
}
// A unit is chosen and connected, but shared to this reader read-only:
the canvas gates
// execution on write access to the unit, so the form disables Run rather
than sending a request
diff --git
a/frontend/src/app/workspace/component/workflow-form/workflow-form.rendered.spec.ts
b/frontend/src/app/workspace/component/workflow-form/workflow-form.rendered.spec.ts
index fba4071a25..0cbc713d49 100644
---
a/frontend/src/app/workspace/component/workflow-form/workflow-form.rendered.spec.ts
+++
b/frontend/src/app/workspace/component/workflow-form/workflow-form.rendered.spec.ts
@@ -716,8 +716,8 @@ describe("WorkflowFormComponent (rendered template)", () =>
{
finishLoad();
expect(el(".runbar .run")).not.toBeNull();
- // Default state: no unit chosen, so the button reads Connect and is
disabled.
- expect(el(".runbar .run")?.textContent?.trim()).toContain("Connect");
+ // Default state: no unit chosen, so the button names what is missing and
is disabled.
+ expect(el(".runbar .run")?.textContent?.trim()).toContain("Computing
Unit");
expect((el(".runbar .run") as HTMLButtonElement).disabled).toBe(true);
expect(el(".runbar texera-computing-unit-selection")).not.toBeNull();
// At rest there is nothing to count and no run note.