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 02fe9c7cb5 chore(frontend): remove the workspace toolbar "Import
Workflow" button (#7310)
02fe9c7cb5 is described below
commit 02fe9c7cb5dabe5374b3e858660e0b85890da57d
Author: Eugene Gu <[email protected]>
AuthorDate: Tue Aug 4 16:36:43 2026 -0700
chore(frontend): remove the workspace toolbar "Import Workflow" button
(#7310)
### What changes were proposed in this PR?
This PR removes the "Import Workflow" button from the workspace toolbar.
The button imported a workflow JSON file into the currently opened
workflow, but it fabricated the workflow's metadata from scratch: it set
`wid` to `undefined`, renamed the workflow to the imported file's name,
and reset `description` and the published state. Because `wid` was
wiped, the auto-persist that fired after the import sent no wid to
`/workflow/persist`, so the backend inserted a brand-new workflow: every
import silently created a duplicate workflow in the user's list and
switched the editor URL to it, while the originally opened workflow's
content had already been overwritten (#6846).
In discussion #6873 the button should simply be removed instead of
patched: the dashboard workflow-list page already has an upload button
that covers "create a workflow from a JSON file" (single JSON or a zip
of several), so the toolbar button provides no capability that is lost
by removing it.
Concretely:
- `menu.component.html`: remove the `<nz-upload>` block wrapping the
import button.
- `menu.component.ts`: remove the `onClickImportWorkflow` handler and
the imports only it used (`NzUploadFile`/`NzUploadComponent` from
ng-zorro, `NzUploadComponent` in the standalone `imports` array,
`DEFAULT_WORKFLOW_NAME`).
- `menu.component.scss`: remove the now-dead `nz-upload` selector.
- `menu.component.spec.ts`: add regression tests asserting the toolbar
renders no `nz-upload` control / no `button[title="import workflow"]`,
and the component defines no `onClickImportWorkflow` member.
No backend changes. The dashboard upload feature is untouched.
After (import button removed):
<img width="1512" height="900" alt="Screenshot 2026-08-04 at 1 50 51 PM"
src="https://github.com/user-attachments/assets/84bdcfa7-ac66-42f9-8f1e-dfe255f4a7da"
/>
### Any related issues, documentation, discussions?
Fixes #6846. Implements the outcome of discussion #6873.
### How was this PR tested?
New regression tests were written first and confirmed failing against
the pre-change code, then passing after the removal; a mutation check
(temporarily re-adding the button) confirmed the tests catch a
re-introduction. The full `menu.component.spec.ts` passes (57/57), all
specs under `workspace/component/menu` and
`workspace/component/left-panel` pass (116/116), `tsc --noEmit` reports
zero errors, and the CI-equivalent production build (`ng build
--configuration=production`) completes with zero errors. Manually
verified in the local dev environment that the toolbar no longer shows
the import button and that the dashboard workflow-list upload button
still creates a workflow from a JSON file.
### Was this PR authored or co-authored using generative AI tooling?
Co-authored by: Claude Code (Claude Fable 5)
---
.../workspace/component/menu/menu.component.html | 12 -----
.../workspace/component/menu/menu.component.scss | 1 -
.../component/menu/menu.component.spec.ts | 17 +++++++
.../app/workspace/component/menu/menu.component.ts | 58 +---------------------
4 files changed, 18 insertions(+), 70 deletions(-)
diff --git a/frontend/src/app/workspace/component/menu/menu.component.html
b/frontend/src/app/workspace/component/menu/menu.component.html
index 85a856eaba..33fbf539f6 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.html
+++ b/frontend/src/app/workspace/component/menu/menu.component.html
@@ -121,18 +121,6 @@
nz-icon
nzType="delete"></i>
</button>
- <nz-upload
- [nzDisabled]="!isWorkflowModifiable"
- [nzBeforeUpload]="onClickImportWorkflow">
- <button
- nz-button
- [disabled]="!isWorkflowModifiable"
- title="import workflow">
- <i
- nz-icon
- nzType="upload"></i>
- </button>
- </nz-upload>
<button
(click)="onClickExportWorkflow()"
nz-button
diff --git a/frontend/src/app/workspace/component/menu/menu.component.scss
b/frontend/src/app/workspace/component/menu/menu.component.scss
index 414a1c9cef..1b3c45a52d 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.scss
+++ b/frontend/src/app/workspace/component/menu/menu.component.scss
@@ -81,7 +81,6 @@
#user-buttons,
#execution-buttons,
nz-button-group,
-nz-upload,
texera-computing-unit-selection {
display: inline-flex;
align-items: center;
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 caa86bf614..f766651b26 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.spec.ts
+++ b/frontend/src/app/workspace/component/menu/menu.component.spec.ts
@@ -373,6 +373,23 @@ describe("MenuComponent", () => {
expect(setNameSpy).toHaveBeenCalledWith("renamed");
});
+ // Regression coverage for #6846 (resolved by discussion #6873): the
toolbar's
+ // import button wiped `wid` before auto-persist and thereby created a
spurious
+ // duplicate workflow, so it was removed. Creating a workflow from a JSON
file
+ // is covered by the dashboard workflow-list upload button instead.
+ describe("import workflow removal", () => {
+ it("does not render an import upload control in the toolbar", () => {
+ const element: HTMLElement = fixture.nativeElement;
+
+ expect(element.querySelector("nz-upload")).toBeNull();
+ expect(element.querySelector("button[title='import
workflow']")).toBeNull();
+ });
+
+ it("does not define an onClickImportWorkflow handler", () => {
+ expect((component as any).onClickImportWorkflow).toBeUndefined();
+ });
+ });
+
describe("onClickExportWorkflow (save)", () => {
it("serializes the workflow content as JSON and downloads it under the
workflow name", () => {
const fakeContent = {
diff --git a/frontend/src/app/workspace/component/menu/menu.component.ts
b/frontend/src/app/workspace/component/menu/menu.component.ts
index a205b2b8bb..8e5f16199d 100644
--- a/frontend/src/app/workspace/component/menu/menu.component.ts
+++ b/frontend/src/app/workspace/component/menu/menu.component.ts
@@ -21,10 +21,7 @@ import { DatePipe, Location, NgIf, NgFor, NgTemplateOutlet }
from "@angular/comm
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from
"@angular/core";
import { Router, RouterLink } from "@angular/router";
import { UserService } from "../../../common/service/user/user.service";
-import {
- DEFAULT_WORKFLOW_NAME,
- WorkflowPersistService,
-} from "../../../common/service/workflow-persist/workflow-persist.service";
+import { WorkflowPersistService } from
"../../../common/service/workflow-persist/workflow-persist.service";
import { Workflow, WorkflowContent } from "../../../common/type/workflow";
import { ExecuteWorkflowService } from
"../../service/execute-workflow/execute-workflow.service";
import { UndoRedoService } from "../../service/undo-redo/undo-redo.service";
@@ -38,7 +35,6 @@ import { UntilDestroy, untilDestroyed } from
"@ngneat/until-destroy";
import { WorkflowUtilService } from
"../../service/workflow-graph/util/workflow-util.service";
import { WorkflowVersionService } from
"../../../dashboard/service/user/workflow-version/workflow-version.service";
import { UserProjectService } from
"../../../dashboard/service/user/project/user-project.service";
-import { NzUploadFile, NzUploadComponent } from "ng-zorro-antd/upload";
import { saveAs } from "file-saver";
import { NotificationService } from
"src/app/common/service/notification/notification.service";
import { OperatorMenuService } from
"../../service/operator-menu/operator-menu.service";
@@ -108,7 +104,6 @@ import { NzTooltipDirective } from "ng-zorro-antd/tooltip";
CoeditorUserIconComponent,
UserIconComponent,
RouterLink,
- NzUploadComponent,
NzDropdownDirective,
NzDropdownMenuComponent,
NzMenuDirective,
@@ -584,57 +579,6 @@ export class MenuComponent implements OnInit, OnDestroy {
this.workflowActionService.deleteOperatorsAndLinks(allOperatorIDs);
}
- public onClickImportWorkflow = (file: NzUploadFile): boolean => {
- const reader = new FileReader();
- reader.readAsText(file as any);
- reader.onload = () => {
- try {
- const result = reader.result;
- if (typeof result !== "string") {
- throw new Error("incorrect format: file is not a string");
- }
-
- const workflowContent = JSON.parse(result) as WorkflowContent;
-
- // set the workflow name using the file name without the extension
- const fileExtensionIndex = file.name.lastIndexOf(".");
- var workflowName: string;
- if (fileExtensionIndex === -1) {
- workflowName = file.name;
- } else {
- workflowName = file.name.substring(0, fileExtensionIndex);
- }
- if (workflowName.trim() === "") {
- workflowName = DEFAULT_WORKFLOW_NAME;
- }
-
- const workflow: Workflow = {
- content: workflowContent,
- name: workflowName,
- description: undefined,
- wid: undefined,
- creationTime: undefined,
- lastModifiedTime: undefined,
- readonly: false,
- isPublished: 0,
- };
-
- this.workflowActionService.enableWorkflowModification();
- // load the fetched workflow
- this.workflowActionService.reloadWorkflow(workflow, true);
- // clear stack
- this.undoRedoService.clearUndoStack();
- this.undoRedoService.clearRedoStack();
- } catch (error) {
- this.notificationService.error(
- "An error occurred when importing the workflow. Please import a
workflow json file."
- );
- console.error(error);
- }
- };
- return false;
- };
-
public onClickExportWorkflow(): void {
const workflowContent: WorkflowContent =
this.workflowActionService.getWorkflowContent();
const workflowContentJson = JSON.stringify(workflowContent, null, 2);