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 +