From df1b08065eca169b562c546306898db17b1daef6 Mon Sep 17 00:00:00 2001 From: TianYun Date: Wed, 10 Jun 2026 11:21:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E6=88=90=E4=BD=BF=E7=94=A8=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=BA=93=E7=9A=84=E7=BB=84=E4=BB=B6=E6=9D=A5=E6=B8=B2?= =?UTF-8?q?=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/MultiSelectToolbar.tsx | 9 +- .../__tests__/MultiSelectToolbar.test.tsx | 10 +- .../composer/GenerationComposer.tsx | 108 +++++++++------- src/components/nodes/GroupNode.tsx | 119 +++++++++--------- 4 files changed, 134 insertions(+), 112 deletions(-) diff --git a/src/components/MultiSelectToolbar.tsx b/src/components/MultiSelectToolbar.tsx index ef9c57ac..132883e7 100644 --- a/src/components/MultiSelectToolbar.tsx +++ b/src/components/MultiSelectToolbar.tsx @@ -22,6 +22,11 @@ export function MultiSelectToolbar() { [selectedNodes] ); + const hasSelectedRegularNode = useMemo( + () => selectedNodes.some((node) => node.type !== "group"), + [selectedNodes] + ); + // Check if any selected nodes are in a group const selectedNodeGroups = useMemo(() => { const groupIds = new Set(selectedNodes.map((n) => n.groupId).filter(Boolean)); @@ -150,7 +155,9 @@ export function MultiSelectToolbar() { removeNodesFromGroup(nodeIds); }; - if (!toolbarPosition || selectedNodes.length < 2) return null; + const shouldHideForRegroupIntent = hasSelectedGroupNode && hasSelectedRegularNode; + + if (!toolbarPosition || selectedNodes.length < 2 || shouldHideForRegroupIntent) return null; return (
{ expect(mockCreateGroup).toHaveBeenCalledWith(["node-1", "node-2"]); }); - it("should show create group button when a selected group is included", () => { + it("should not render when selected nodes include a group and regular nodes", () => { mockUseWorkflowStore.mockImplementation((selector) => { return selector(createDefaultState({ nodes: [ @@ -418,17 +418,15 @@ describe("MultiSelectToolbar", () => { })); }); - render( + const { container } = render( ); - const createGroupButton = screen.getByTitle("创建分组"); - fireEvent.click(createGroupButton); - + expect(container.firstChild).toBeNull(); + expect(screen.queryByTitle("创建分组")).not.toBeInTheDocument(); expect(screen.queryByTitle("从分组中移除")).not.toBeInTheDocument(); - expect(mockCreateGroup).toHaveBeenCalledWith(["group-node-group-1", "node-3"]); }); it("should show ungroup button when selected nodes are in a group", () => { diff --git a/src/components/composer/GenerationComposer.tsx b/src/components/composer/GenerationComposer.tsx index 05651351..2f073213 100644 --- a/src/components/composer/GenerationComposer.tsx +++ b/src/components/composer/GenerationComposer.tsx @@ -12,10 +12,9 @@ import { type MouseEvent, type ReactNode, } from "react"; -import { createPortal } from "react-dom"; import { CloseOutlined, DownOutlined, FileTextOutlined, RightOutlined } from "@ant-design/icons"; import { useReactFlow, useViewport, ViewportPortal } from "@xyflow/react"; -import { message, Modal, Popover, Segmented, Tooltip } from "antd"; +import { Dropdown, message, Modal, Popover, Segmented, Tooltip } from "antd"; import { useProviderApiKeys, useWorkflowStore } from "@/store/workflowStore"; import { useModelStore } from "@/store/modelStore"; import { @@ -2891,49 +2890,74 @@ export function GenerationComposer() { return t("composer.describeContent"); }, [connectedInputs, context.mode, context.selectedCount, isEaseCurveNode, isVideoStitchNode, promptForSubmit, t]); + useEffect(() => { + if (shouldRenderInlineComposer) return; + assistTriggerIndexRef.current = null; + setAssistMenu(null); + setAssistMenuPosition(null); + }, [shouldRenderInlineComposer]); + const hideComposerForModal = isModalOpen && !modelDialogOpen; - const assistMenuOverlay = assistMenu && assistMenuPosition && typeof document !== "undefined" - ? createPortal( -
{ + if (nextOpen) return; + assistTriggerIndexRef.current = null; + setAssistMenu(null); + setAssistMenuPosition(null); }} - onPointerDownCapture={stopCanvasEvent} - onMouseDownCapture={stopCanvasEvent} - onClick={stopCanvasEvent} - onWheelCapture={stopCanvasEvent} + trigger={["click"]} + placement="top" + overlayClassName="z-[10080]" + menu={{ items: [] }} + popupRender={() => ( +
+
+ {assistMenu === "command" ? t("composer.commands") : t("composer.referenceMaterials")} +
+
+ {activeAssistItems.map((item, itemIndex) => { + const isActive = itemIndex === assistMenuActiveIndex; + return ( + + ); + })} +
+
+ )} > -
- {assistMenu === "command" ? t("composer.commands") : t("composer.referenceMaterials")} -
-
- {activeAssistItems.map((item, itemIndex) => { - const isActive = itemIndex === assistMenuActiveIndex; - return ( - - ); - })} -
-
, - document.body +