This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-8771-3ba45ee5a5f641388d1a9eda90afa26a62d70d30 in repository https://gitbox.apache.org/repos/asf/texera.git
commit 7ddf661aaa35e1d161ddfb9b6e02193f64636b33 Author: Suryaa Charan <[email protected]> AuthorDate: Wed Oct 21 21:24:05 2026 +0000 feat(frontend): explain the Kill button and where to find results and errors (#8771) ### What changes were proposed in this PR? Two small hints in the workspace: - **Kill button tooltip:** "Stop this run. A stopped run can't be resumed." It was an icon-only button with no explanation. - **Empty Result panel:** the heading now says why it is empty: "No operator is selected." or "This operator has no results yet." With nothing selected it also says "Click an operator to see its results. If a run fails, its errors show here." It always adds "Errors an operator hits while running show in that operator's Console." A failed run's errors only appear in the Static Error tab when nothing is selected, and errors during a run pause it and go to the operator's Console. Neither hint shows while previewing a workflow version. Before and after, with nothing selected (top) and an operator selected (middle). The bottom row (a failed UDF showing its Static Error tab when clicked) is no longer part of this PR: on main that error still arrives as "unknown operator", because `ControlError` drops the worker that #8668 attaches. That will be fixed in the backend in a separate PR. <img width="1648" height="854" alt="texera-8771-before-after-v2" src="https://github.com/user-attachments/assets/b1034c28-ce7d-4baf-b2f2-cfd935bc503e" /> The tooltip is a native `title`, which browsers don't draw in screenshots. I checked it in the running app: hovering the red button shows "Stop this run. A stopped run can't be resumed." ### Any related issues, documentation, discussions? Part of #8736. Split out of #8737. ### How was this PR tested? New specs in `result-panel.component.spec.ts` (nothing selected, an operator selected, version preview) and `menu.component.spec.ts` (the tooltip). ``` cd frontend yarn test --include src/app/workspace/component/result-panel/result-panel.component.spec.ts --include src/app/workspace/component/menu/menu.component.spec.ts yarn test yarn format:ci ``` ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Claude Code (Claude Opus 5.5) --------- Co-authored-by: suryaacharan <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]> --- .../workspace/component/menu/menu.component.html | 1 + .../component/menu/menu.component.spec.ts | 8 +++++ .../result-panel/result-panel.component.html | 10 +++++- .../result-panel/result-panel.component.spec.ts | 41 +++++++++++++++++++++- 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/workspace/component/menu/menu.component.html b/frontend/src/app/workspace/component/menu/menu.component.html index c5bde9d41d..32ecd7707d 100644 --- a/frontend/src/app/workspace/component/menu/menu.component.html +++ b/frontend/src/app/workspace/component/menu/menu.component.html @@ -438,6 +438,7 @@ </button> <button (click)="handleKill()" + title="Stop this run. A stopped run can't be resumed." [disabled]=" executionState === ExecutionState.Uninitialized || executionState === ExecutionState.Completed || 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 3a5f8440b8..736f3602b0 100644 --- a/frontend/src/app/workspace/component/menu/menu.component.spec.ts +++ b/frontend/src/app/workspace/component/menu/menu.component.spec.ts @@ -1891,6 +1891,14 @@ describe("MenuComponent", () => { expect(run).toHaveBeenCalled(); expect(kill).toHaveBeenCalled(); }); + + it("explains the kill button with a tooltip", () => { + fixture.detectChanges(); + + expect(q("button[nzdanger]").nativeElement.getAttribute("title")).toBe( + "Stop this run. A stopped run can't be resumed." + ); + }); }); describe("toolbar", () => { diff --git a/frontend/src/app/workspace/component/result-panel/result-panel.component.html b/frontend/src/app/workspace/component/result-panel/result-panel.component.html index d2c6a53549..f46c02358f 100644 --- a/frontend/src/app/workspace/component/result-panel/result-panel.component.html +++ b/frontend/src/app/workspace/component/result-panel/result-panel.component.html @@ -98,8 +98,16 @@ <div *ngIf="frameComponentConfigs.size === 0"> <nz-tab nzTitle="Result"> <div style="text-align: center"> - <h4>No results available to display.</h4> + <h4 *ngIf="previewWorkflowVersion">No results available to display.</h4> + <h4 *ngIf="!previewWorkflowVersion && !currentOperatorId">No operator is selected.</h4> + <h4 *ngIf="!previewWorkflowVersion && currentOperatorId">This operator has no results yet.</h4> <p>Tip: enable the eye icon on the operator and execute the workflow to view its results.</p> + <ng-container *ngIf="!previewWorkflowVersion"> + <p *ngIf="!currentOperatorId"> + Click an operator to see its results. If a run fails, its errors show here. + </p> + <p>Errors an operator hits while running show in that operator's Console.</p> + </ng-container> </div> </nz-tab> </div> diff --git a/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts b/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts index abe5fe1eb2..58c880c73a 100644 --- a/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts +++ b/frontend/src/app/workspace/component/result-panel/result-panel.component.spec.ts @@ -750,7 +750,46 @@ describe("ResultPanelComponent", () => { component.frameComponentConfigs.clear(); fixture.detectChanges(); - expect((fixture.nativeElement as HTMLElement).textContent).toContain("No results available to display."); + expect((fixture.nativeElement as HTMLElement).textContent).toContain("No operator is selected."); + }); + + it("with nothing selected, says to click an operator and where errors show", () => { + component.width = DEFAULT_WIDTH; + component.currentOperatorId = undefined; + component.frameComponentConfigs.clear(); + fixture.detectChanges(); + + const text = (fixture.nativeElement as HTMLElement).textContent ?? ""; + expect(text).toContain("No operator is selected."); + expect(text).toContain("Click an operator to see its results. If a run fails, its errors show here."); + expect(text).toContain("Errors an operator hits while running show in that operator's Console."); + expect(text).not.toContain("Click an empty spot"); + }); + + it("with an operator already selected, does not say to click an operator", () => { + component.width = DEFAULT_WIDTH; + component.currentOperatorId = "op-1"; + component.frameComponentConfigs.clear(); + fixture.detectChanges(); + + const text = (fixture.nativeElement as HTMLElement).textContent ?? ""; + expect(text).toContain("This operator has no results yet."); + expect(text).not.toContain("No operator is selected."); + expect(text).not.toContain("Click an operator"); + expect(text).toContain("Errors an operator hits while running show in that operator's Console."); + }); + + it("while previewing a workflow version, shows no click hints", () => { + component.width = DEFAULT_WIDTH; + component.currentOperatorId = undefined; + component.previewWorkflowVersion = true; + component.frameComponentConfigs.clear(); + fixture.detectChanges(); + + const text = (fixture.nativeElement as HTMLElement).textContent ?? ""; + expect(text).toContain("No results available to display."); + expect(text).not.toContain("Click an operator"); + expect(text).not.toContain("Errors an operator hits"); }); it("renders a tab per frame when frames are present", () => {
