Fix/workflow use nodes hooks (#21822)

This commit is contained in:
zxhlyh
2025-07-02 17:48:23 +08:00
committed by GitHub
parent 3bfa9767c0
commit 68f41bbaa8
7 changed files with 74 additions and 34 deletions

View File

@@ -3,7 +3,7 @@ import {
useCallback, useCallback,
useMemo, useMemo,
} from 'react' } from 'react'
import { useNodes } from 'reactflow' import { useStore as useReactflowStore } from 'reactflow'
import { RiApps2AddLine } from '@remixicon/react' import { RiApps2AddLine } from '@remixicon/react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { import {
@@ -22,7 +22,6 @@ import {
BlockEnum, BlockEnum,
InputVarType, InputVarType,
} from '@/app/components/workflow/types' } from '@/app/components/workflow/types'
import type { StartNodeType } from '@/app/components/workflow/nodes/start/types'
import { useToastContext } from '@/app/components/base/toast' import { useToastContext } from '@/app/components/base/toast'
import { usePublishWorkflow, useResetWorkflowVersionHistory } from '@/service/use-workflow' import { usePublishWorkflow, useResetWorkflowVersionHistory } from '@/service/use-workflow'
import type { PublishWorkflowParams } from '@/types/workflow' import type { PublishWorkflowParams } from '@/types/workflow'
@@ -42,9 +41,9 @@ const FeaturesTrigger = () => {
const publishedAt = useStore(s => s.publishedAt) const publishedAt = useStore(s => s.publishedAt)
const draftUpdatedAt = useStore(s => s.draftUpdatedAt) const draftUpdatedAt = useStore(s => s.draftUpdatedAt)
const toolPublished = useStore(s => s.toolPublished) const toolPublished = useStore(s => s.toolPublished)
const nodes = useNodes<StartNodeType>() const startVariables = useReactflowStore(
const startNode = nodes.find(node => node.data.type === BlockEnum.Start) s => s.getNodes().find(node => node.data.type === BlockEnum.Start)?.data.variables,
const startVariables = startNode?.data.variables )
const fileSettings = useFeatures(s => s.features.file) const fileSettings = useFeatures(s => s.features.file)
const variables = useMemo(() => { const variables = useMemo(() => {
const data = startVariables || [] const data = startVariables || []

View File

@@ -1,10 +1,10 @@
import { memo, useMemo } from 'react' import { memo, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { isEqual } from 'lodash-es'
import { import {
getConnectedEdges, getConnectedEdges,
getOutgoers, getOutgoers,
useEdges, useStore,
useStoreApi,
} from 'reactflow' } from 'reactflow'
import { useToolIcon } from '../../../../hooks' import { useToolIcon } from '../../../../hooks'
import BlockIcon from '../../../../block-icon' import BlockIcon from '../../../../block-icon'
@@ -26,12 +26,21 @@ const NextStep = ({
const { t } = useTranslation() const { t } = useTranslation()
const data = selectedNode.data const data = selectedNode.data
const toolIcon = useToolIcon(data) const toolIcon = useToolIcon(data)
const store = useStoreApi()
const branches = useMemo(() => { const branches = useMemo(() => {
return data._targetBranches || [] return data._targetBranches || []
}, [data]) }, [data])
const edges = useEdges() const edges = useStore(s => s.edges.map(edge => ({
const outgoers = getOutgoers(selectedNode as Node, store.getState().getNodes(), edges) id: edge.id,
source: edge.source,
sourceHandle: edge.sourceHandle,
target: edge.target,
targetHandle: edge.targetHandle,
})), isEqual)
const nodes = useStore(s => s.getNodes().map(node => ({
id: node.id,
data: node.data,
})), isEqual)
const outgoers = getOutgoers(selectedNode as Node, nodes as Node[], edges)
const connectedEdges = getConnectedEdges([selectedNode] as Node[], edges).filter(edge => edge.source === selectedNode!.id) const connectedEdges = getConnectedEdges([selectedNode] as Node[], edges).filter(edge => edge.source === selectedNode!.id)
const list = useMemo(() => { const list = useMemo(() => {

View File

@@ -1,30 +1,39 @@
import { memo } from 'react' import { memo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useShallow } from 'zustand/react/shallow'
import { RiCrosshairLine } from '@remixicon/react' import { RiCrosshairLine } from '@remixicon/react'
import type { XYPosition } from 'reactflow' import { useReactFlow, useStore } from 'reactflow'
import { useReactFlow, useStoreApi } from 'reactflow'
import TooltipPlus from '@/app/components/base/tooltip' import TooltipPlus from '@/app/components/base/tooltip'
import { useNodesSyncDraft } from '@/app/components/workflow-app/hooks' import { useNodesSyncDraft } from '@/app/components/workflow-app/hooks'
type NodePositionProps = { type NodePositionProps = {
nodePosition: XYPosition, nodeId: string
nodeWidth?: number | null,
nodeHeight?: number | null,
} }
const NodePosition = ({ const NodePosition = ({
nodePosition, nodeId,
nodeWidth,
nodeHeight,
}: NodePositionProps) => { }: NodePositionProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const reactflow = useReactFlow() const reactflow = useReactFlow()
const store = useStoreApi()
const { doSyncWorkflowDraft } = useNodesSyncDraft() const { doSyncWorkflowDraft } = useNodesSyncDraft()
const {
nodePosition,
nodeWidth,
nodeHeight,
} = useStore(useShallow((s) => {
const nodes = s.getNodes()
const currentNode = nodes.find(node => node.id === nodeId)!
return {
nodePosition: currentNode.position,
nodeWidth: currentNode.width,
nodeHeight: currentNode.height,
}
}))
const transform = useStore(s => s.transform)
if (!nodePosition || !nodeWidth || !nodeHeight) return null if (!nodePosition || !nodeWidth || !nodeHeight) return null
const workflowContainer = document.getElementById('workflow-container') const workflowContainer = document.getElementById('workflow-container')
const { transform } = store.getState()
const zoom = transform[2] const zoom = transform[2]
const { clientWidth, clientHeight } = workflowContainer! const { clientWidth, clientHeight } = workflowContainer!

View File

@@ -62,15 +62,14 @@ import { Stop } from '@/app/components/base/icons/src/vender/line/mediaAndDevice
type BasePanelProps = { type BasePanelProps = {
children: ReactNode children: ReactNode
} & Node id: Node['id']
data: Node['data']
}
const BasePanel: FC<BasePanelProps> = ({ const BasePanel: FC<BasePanelProps> = ({
id, id,
data, data,
children, children,
position,
width,
height,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { showMessageLogModal } = useAppStore(useShallow(state => ({ const { showMessageLogModal } = useAppStore(useShallow(state => ({
@@ -330,7 +329,7 @@ const BasePanel: FC<BasePanelProps> = ({
</Tooltip> </Tooltip>
) )
} }
<NodePosition nodePosition={position} nodeWidth={width} nodeHeight={height}></NodePosition> <NodePosition nodeId={id}></NodePosition>
<HelpLink nodeType={data.type} /> <HelpLink nodeType={data.type} />
<PanelOperator id={id} data={data} showHelpLink={false} /> <PanelOperator id={id} data={data} showHelpLink={false} />
<div className='mx-3 h-3.5 w-[1px] bg-divider-regular' /> <div className='mx-3 h-3.5 w-[1px] bg-divider-regular' />

View File

@@ -48,7 +48,9 @@ import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud'
type BaseNodeProps = { type BaseNodeProps = {
children: ReactElement children: ReactElement
} & NodeProps id: NodeProps['id']
data: NodeProps['data']
}
const BaseNode: FC<BaseNodeProps> = ({ const BaseNode: FC<BaseNodeProps> = ({
id, id,

View File

@@ -14,11 +14,14 @@ import BasePanel from './_base/components/workflow-panel'
const CustomNode = (props: NodeProps) => { const CustomNode = (props: NodeProps) => {
const nodeData = props.data const nodeData = props.data
const NodeComponent = NodeComponentMap[nodeData.type] const NodeComponent = useMemo(() => NodeComponentMap[nodeData.type], [nodeData.type])
return ( return (
<> <>
<BaseNode {...props}> <BaseNode
id={props.id}
data={props.data}
>
<NodeComponent /> <NodeComponent />
</BaseNode> </BaseNode>
</> </>
@@ -26,7 +29,12 @@ const CustomNode = (props: NodeProps) => {
} }
CustomNode.displayName = 'CustomNode' CustomNode.displayName = 'CustomNode'
export const Panel = memo((props: Node) => { export type PanelProps = {
type: Node['type']
id: Node['id']
data: Node['data']
}
export const Panel = memo((props: PanelProps) => {
const nodeClass = props.type const nodeClass = props.type
const nodeData = props.data const nodeData = props.data
const PanelComponent = useMemo(() => { const PanelComponent = useMemo(() => {
@@ -38,7 +46,11 @@ export const Panel = memo((props: Node) => {
if (nodeClass === CUSTOM_NODE) { if (nodeClass === CUSTOM_NODE) {
return ( return (
<BasePanel key={props.id} {...props}> <BasePanel
key={props.id}
id={props.id}
data={props.data}
>
<PanelComponent /> <PanelComponent />
</BasePanel> </BasePanel>
) )

View File

@@ -1,7 +1,7 @@
import type { FC } from 'react' import type { FC } from 'react'
import { useShallow } from 'zustand/react/shallow'
import { memo, useCallback, useEffect, useRef } from 'react' import { memo, useCallback, useEffect, useRef } from 'react'
import { useNodes } from 'reactflow' import { useStore as useReactflow } from 'reactflow'
import type { CommonNodeType } from '../types'
import { Panel as NodePanel } from '../nodes' import { Panel as NodePanel } from '../nodes'
import { useStore } from '../store' import { useStore } from '../store'
import EnvPanel from './env-panel' import EnvPanel from './env-panel'
@@ -61,8 +61,18 @@ const useResizeObserver = (
const Panel: FC<PanelProps> = ({ const Panel: FC<PanelProps> = ({
components, components,
}) => { }) => {
const nodes = useNodes<CommonNodeType>() const selectedNode = useReactflow(useShallow((s) => {
const selectedNode = nodes.find(node => node.data.selected) const nodes = s.getNodes()
const currentNode = nodes.find(node => node.data.selected)
if (currentNode) {
return {
id: currentNode.id,
type: currentNode.type,
data: currentNode.data,
}
}
}))
const showEnvPanel = useStore(s => s.showEnvPanel) const showEnvPanel = useStore(s => s.showEnvPanel)
const isRestoring = useStore(s => s.isRestoring) const isRestoring = useStore(s => s.isRestoring)
const showWorkflowVersionHistoryPanel = useStore(s => s.showWorkflowVersionHistoryPanel) const showWorkflowVersionHistoryPanel = useStore(s => s.showWorkflowVersionHistoryPanel)