diff --git a/web/app/components/workflow/hooks/use-make-group.ts b/web/app/components/workflow/hooks/use-make-group.ts index eb5502b679..321f0e393a 100644 --- a/web/app/components/workflow/hooks/use-make-group.ts +++ b/web/app/components/workflow/hooks/use-make-group.ts @@ -2,6 +2,7 @@ import type { PredecessorHandle } from '../utils' import { useMemo } from 'react' import { useStore as useReactFlowStore } from 'reactflow' import { shallow } from 'zustand/shallow' +import { BlockEnum } from '../types' import { getCommonPredecessorHandles } from '../utils' export type MakeGroupAvailability = { @@ -24,9 +25,9 @@ type MinimalEdge = { export const checkMakeGroupAvailability = ( selectedNodeIds: string[], edges: MinimalEdge[], + hasGroupNode = false, ): MakeGroupAvailability => { - // Make group requires selecting at least 2 nodes. - if (selectedNodeIds.length <= 1) { + if (selectedNodeIds.length <= 1 || hasGroupNode) { return { canMakeGroup: false, branchEntryNodeIds: [], @@ -109,8 +110,6 @@ export const checkMakeGroupAvailability = ( } export const useMakeGroupAvailability = (selectedNodeIds: string[]): MakeGroupAvailability => { - // Subscribe to the minimal edge state we need (source/sourceHandle/target) to avoid - // snowball rerenders caused by subscribing to the entire `edges` objects. const edgeKeys = useReactFlowStore((state) => { const delimiter = '\u0000' const keys = state.edges.map(edge => `${edge.source}${delimiter}${edge.sourceHandle || 'source'}${delimiter}${edge.target}`) @@ -118,8 +117,11 @@ export const useMakeGroupAvailability = (selectedNodeIds: string[]): MakeGroupAv return keys }, shallow) + const hasGroupNode = useReactFlowStore((state) => { + return state.getNodes().some(node => node.selected && node.data.type === BlockEnum.Group) + }) + return useMemo(() => { - // Reconstruct a minimal edge list from `edgeKeys` for downstream graph checks. const delimiter = '\u0000' const edges = edgeKeys.map((key) => { const [source, handleId, target] = key.split(delimiter) @@ -131,6 +133,6 @@ export const useMakeGroupAvailability = (selectedNodeIds: string[]): MakeGroupAv } }) - return checkMakeGroupAvailability(selectedNodeIds, edges) - }, [edgeKeys, selectedNodeIds]) + return checkMakeGroupAvailability(selectedNodeIds, edges, hasGroupNode) + }, [edgeKeys, selectedNodeIds, hasGroupNode]) } diff --git a/web/app/components/workflow/hooks/use-nodes-interactions.ts b/web/app/components/workflow/hooks/use-nodes-interactions.ts index b52fabae1e..e440beaed4 100644 --- a/web/app/components/workflow/hooks/use-nodes-interactions.ts +++ b/web/app/components/workflow/hooks/use-nodes-interactions.ts @@ -2550,23 +2550,24 @@ export const useNodesInteractions = () => { return nodes.some(node => node.data._isBundled) }, [store]) - // Check if the current box selection can be grouped const getCanMakeGroup = useCallback(() => { const { getNodes, edges } = store.getState() const nodes = getNodes() - const bundledNodeIds = nodes.filter(node => node.data._isBundled).map(node => node.id) + const bundledNodes = nodes.filter(node => node.data._isBundled) - if (bundledNodeIds.length <= 1) + if (bundledNodes.length <= 1) return false + const bundledNodeIds = bundledNodes.map(node => node.id) const minimalEdges = edges.map(edge => ({ id: edge.id, source: edge.source, sourceHandle: edge.sourceHandle || 'source', target: edge.target, })) + const hasGroupNode = bundledNodes.some(node => node.data.type === BlockEnum.Group) - const { canMakeGroup } = checkMakeGroupAvailability(bundledNodeIds, minimalEdges) + const { canMakeGroup } = checkMakeGroupAvailability(bundledNodeIds, minimalEdges, hasGroupNode) return canMakeGroup }, [store]) @@ -2574,19 +2575,20 @@ export const useNodesInteractions = () => { const { getNodes, setNodes, edges, setEdges } = store.getState() const nodes = getNodes() const bundledNodes = nodes.filter(node => node.data._isBundled) - const bundledNodeIds = bundledNodes.map(node => node.id) - if (bundledNodeIds.length <= 1) + if (bundledNodes.length <= 1) return + const bundledNodeIds = bundledNodes.map(node => node.id) const minimalEdges = edges.map(edge => ({ id: edge.id, source: edge.source, sourceHandle: edge.sourceHandle || 'source', target: edge.target, })) + const hasGroupNode = bundledNodes.some(node => node.data.type === BlockEnum.Group) - const { canMakeGroup } = checkMakeGroupAvailability(bundledNodeIds, minimalEdges) + const { canMakeGroup } = checkMakeGroupAvailability(bundledNodeIds, minimalEdges, hasGroupNode) if (!canMakeGroup) return diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx index c834f29ab3..3074b80774 100644 --- a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx @@ -594,7 +594,7 @@ const BasePanel: FC = ({ ) } { - !needsToolAuth && !currentDataSource && !currentTriggerPlugin && ( + !needsToolAuth && !currentDataSource && !currentTriggerPlugin && data.type !== BlockEnum.Group && (
= ({
) } - + {data.type !== BlockEnum.Group && } - {tabType === TabType.settings && ( + {(tabType === TabType.settings || data.type === BlockEnum.Group) && (
{cloneElement(children as any, {