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-7310-e1ca490513fb816f5c289f243d4f8cd2fbff6c9b in repository https://gitbox.apache.org/repos/asf/texera.git
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);
