Browse Source

feat: Variable click jumps to source node (#13623)

tags/1.4.1
wellCh4n 5 months ago
parent
commit
276c02f341
No account linked to committer's email address

+ 5
- 3
web/app/components/base/prompt-editor/hooks.ts View File

@@ -74,9 +74,11 @@ export const useSelectOrDelete: UseSelectOrDeleteHandler = (nodeKey: string, com
)

const handleSelect = useCallback((e: MouseEvent) => {
e.stopPropagation()
clearSelection()
setSelected(true)
if (!e.metaKey && !e.ctrlKey) {
e.stopPropagation()
clearSelection()
setSelected(true)
}
}, [setSelected, clearSelection])

useEffect(() => {

+ 29
- 0
web/app/components/base/prompt-editor/plugins/workflow-variable-block/component.tsx View File

@@ -1,5 +1,6 @@
import {
memo,
useCallback,
useEffect,
useState,
} from 'react'
@@ -13,6 +14,7 @@ import {
RiErrorWarningFill,
RiMoreLine,
} from '@remixicon/react'
import { useReactFlow, useStoreApi } from 'reactflow'
import { useSelectOrDelete } from '../../hooks'
import type { WorkflowNodesMap } from './node'
import { WorkflowVariableBlockNode } from './node'
@@ -66,6 +68,9 @@ const WorkflowVariableBlockComponent = ({
const isChatVar = isConversationVar(variables)
const isException = isExceptionVariable(varName, node?.type)

const reactflow = useReactFlow()
const store = useStoreApi()

useEffect(() => {
if (!editor.hasNodes([WorkflowVariableBlockNode]))
throw new Error('WorkflowVariableBlockPlugin: WorkflowVariableBlock not registered on editor')
@@ -83,6 +88,26 @@ const WorkflowVariableBlockComponent = ({
)
}, [editor])

const handleVariableJump = useCallback(() => {
const workflowContainer = document.getElementById('workflow-container')
const {
clientWidth,
clientHeight,
} = workflowContainer!

const {
setViewport,
} = reactflow
const { transform } = store.getState()
const zoom = transform[2]
const position = node.position
setViewport({
x: (clientWidth - 400 - node.width! * zoom) / 2 - position!.x * zoom,
y: (clientHeight - node.height! * zoom) / 2 - position!.y * zoom,
zoom: transform[2],
})
}, [node, reactflow, store])

const Item = (
<div
className={cn(
@@ -90,6 +115,10 @@ const WorkflowVariableBlockComponent = ({
isSelected ? ' border-state-accent-solid bg-state-accent-hover' : ' border-components-panel-border-subtle bg-components-badge-white-to-dark',
!node && !isEnv && !isChatVar && '!border-state-destructive-solid !bg-state-destructive-hover',
)}
onClick={(e) => {
e.stopPropagation()
handleVariableJump()
}}
ref={ref}
>
{!isEnv && !isChatVar && (

+ 1
- 1
web/app/components/base/prompt-editor/types.ts View File

@@ -64,7 +64,7 @@ export type GetVarType = (payload: {
export type WorkflowVariableBlockType = {
show?: boolean
variables?: NodeOutPutVar[]
workflowNodesMap?: Record<string, Pick<Node['data'], 'title' | 'type'>>
workflowNodesMap?: Record<string, Pick<Node['data'], 'title' | 'type' | 'height' | 'width' | 'position'>>
onInsert?: () => void
onDelete?: () => void
getVarType?: GetVarType

+ 3
- 0
web/app/components/workflow/nodes/_base/components/input-support-select-var.tsx View File

@@ -91,6 +91,9 @@ const Editor: FC<Props> = ({
acc[node.id] = {
title: node.data.title,
type: node.data.type,
width: node.width,
height: node.height,
position: node.position,
}
if (node.data.type === BlockEnum.Start) {
acc.sys = {

+ 3
- 0
web/app/components/workflow/nodes/_base/components/prompt/editor.tsx View File

@@ -259,6 +259,9 @@ const Editor: FC<Props> = ({
acc[node.id] = {
title: node.data.title,
type: node.data.type,
width: node.width,
height: node.height,
position: node.position,
}
if (node.data.type === BlockEnum.Start) {
acc.sys = {

+ 33
- 3
web/app/components/workflow/nodes/_base/components/variable-tag.tsx View File

@@ -1,5 +1,5 @@
import { useMemo } from 'react'
import { useNodes } from 'reactflow'
import { useCallback, useMemo } from 'react'
import { useNodes, useReactFlow, useStoreApi } from 'reactflow'
import { capitalize } from 'lodash-es'
import { useTranslation } from 'react-i18next'
import { RiErrorWarningFill } from '@remixicon/react'
@@ -48,12 +48,42 @@ const VariableTag = ({
const variableName = isSystemVar(valueSelector) ? valueSelector.slice(0).join('.') : valueSelector.slice(1).join('.')
const isException = isExceptionVariable(variableName, node?.data.type)

const reactflow = useReactFlow()
const store = useStoreApi()

const handleVariableJump = useCallback(() => {
const workflowContainer = document.getElementById('workflow-container')
const {
clientWidth,
clientHeight,
} = workflowContainer!

const {
setViewport,
} = reactflow
const { transform } = store.getState()
const zoom = transform[2]
const position = node.position
setViewport({
x: (clientWidth - 400 - node.width! * zoom) / 2 - position!.x * zoom,
y: (clientHeight - node.height! * zoom) / 2 - position!.y * zoom,
zoom: transform[2],
})
}, [node, reactflow, store])

const { t } = useTranslation()
return (
<Tooltip popupContent={!isValid && t('workflow.errorMsg.invalidVariable')}>
<div className={cn('border-[rgba(16, 2440,0.08)] inline-flex h-6 max-w-full items-center rounded-md border-[0.5px] border-divider-subtle bg-components-badge-white-to-dark px-1.5 text-xs shadow-xs',
!isValid && 'border-red-400 !bg-[#FEF3F2]',
)}>
)}
onClick={(e) => {
if (e.metaKey || e.ctrlKey) {
e.stopPropagation()
handleVariableJump()
}
}}
>
{(!isEnv && !isChatVar && <>
{node && (
<>

+ 37
- 3
web/app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx View File

@@ -9,7 +9,7 @@ import {
RiMoreLine,
} from '@remixicon/react'
import produce from 'immer'
import { useStoreApi } from 'reactflow'
import { useReactFlow, useStoreApi } from 'reactflow'
import RemoveButton from '../remove-button'
import useAvailableVarList from '../../hooks/use-available-var-list'
import VarReferencePopup from './var-reference-popup'
@@ -111,6 +111,9 @@ const VarReferencePicker: FC<Props> = ({
passedInAvailableNodes,
filterVar,
})

const reactflow = useReactFlow()

const startNode = availableNodes.find((node: any) => {
return node.data.type === BlockEnum.Start
})
@@ -172,7 +175,11 @@ const VarReferencePicker: FC<Props> = ({
if (isSystemVar(value as ValueSelector))
return startNode?.data

return getNodeInfoById(availableNodes, outputVarNodeId)?.data
const node = getNodeInfoById(availableNodes, outputVarNodeId)?.data
return {
...node,
id: outputVarNodeId,
}
}, [value, hasValue, isConstant, isIterationVar, iterationNode, availableNodes, outputVarNodeId, startNode, isLoopVar, loopNode])

const isShowAPart = (value as ValueSelector).length > 2
@@ -237,6 +244,28 @@ const VarReferencePicker: FC<Props> = ({
onChange([], varKindType)
}, [onChange, varKindType])

const handleVariableJump = useCallback((nodeId: string) => {
const currentNodeIndex = availableNodes.findIndex(node => node.id === nodeId)
const currentNode = availableNodes[currentNodeIndex]

const workflowContainer = document.getElementById('workflow-container')
const {
clientWidth,
clientHeight,
} = workflowContainer!
const {
setViewport,
} = reactflow
const { transform } = store.getState()
const zoom = transform[2]
const position = currentNode.position
setViewport({
x: (clientWidth - 400 - currentNode.width! * zoom) / 2 - position.x * zoom,
y: (clientHeight - currentNode.height! * zoom) / 2 - position.y * zoom,
zoom: transform[2],
})
}, [availableNodes, reactflow, store])

const type = getCurrentVariableType({
parentNode: isInIteration ? iterationNode : loopNode,
valueSelector: value as ValueSelector,
@@ -357,7 +386,12 @@ const VarReferencePicker: FC<Props> = ({
? (
<>
{isShowNodeName && !isEnv && !isChatVar && (
<div className='flex items-center'>
<div className='flex items-center' onClick={(e) => {
if (e.metaKey || e.ctrlKey) {
e.stopPropagation()
handleVariableJump(outputVarNode?.id)
}
}}>
<div className='h-3 px-[1px]'>
{outputVarNode?.type && <VarBlockIcon
className='!text-text-primary'

+ 3
- 0
web/app/components/workflow/nodes/if-else/components/condition-list/condition-input.tsx View File

@@ -37,6 +37,9 @@ const ConditionInput = ({
acc[node.id] = {
title: node.data.title,
type: node.data.type,
width: node.width,
height: node.height,
position: node.position,
}
if (node.data.type === BlockEnum.Start) {
acc.sys = {

+ 2
- 0
web/app/components/workflow/types.ts View File

@@ -2,6 +2,7 @@ import type {
Edge as ReactFlowEdge,
Node as ReactFlowNode,
Viewport,
XYPosition,
} from 'reactflow'
import type { Resolution, TransferMethod } from '@/types/app'
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
@@ -83,6 +84,7 @@ export type CommonNodeType<T = {}> = {
type: BlockEnum
width?: number
height?: number
position?: XYPosition
_loopLength?: number
_loopIndex?: number
isInLoop?: boolean

Loading…
Cancel
Save