refactor: streamline HITL input components by consolidating props and enhancing variable handling

This commit is contained in:
twwu 2025-12-25 10:50:20 +08:00
parent ec0c144eb2
commit 1c4c1b5cb1
11 changed files with 357 additions and 96 deletions

View File

@ -304,15 +304,8 @@ const PromptEditor: FC<PromptEditorProps> = ({
{
hitlInputBlock?.show && (
<>
<HITLInputBlock />
<HITLInputBlockReplacementBlock
nodeId={hitlInputBlock.nodeId}
nodeTitle={hitlInputBlock.nodeTitle}
formInputs={hitlInputBlock.formInputs}
onFormInputsChange={hitlInputBlock.onFormInputsChange}
onFormInputItemRename={hitlInputBlock.onFormInputItemRename}
onFormInputItemRemove={hitlInputBlock.onFormInputItemRemove}
/>
<HITLInputBlock {...hitlInputBlock} />
<HITLInputBlockReplacementBlock {...hitlInputBlock} />
</>
)
}

View File

@ -1,45 +1,56 @@
'use client'
import type { FC } from 'react'
import React, { useCallback, useEffect, useRef } from 'react'
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
import { VariableX } from '../../../icons/src/vender/workflow'
import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import { BlockEnum, InputVarType } from '@/app/components/workflow/types'
import { Variable02 } from '../../../icons/src/vender/solid/development'
import { InputVarType } from '@/app/components/workflow/types'
import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types'
import ActionButton from '../../../action-button'
import { RiDeleteBinLine, RiEditLine } from '@remixicon/react'
import InputField from './input-field'
import { useBoolean } from 'ahooks'
import Modal from '../../../modal'
import type { WorkflowNodesMap } from '../workflow-variable-block/node'
import type { ValueSelector, Var } from '@/app/components/workflow/types'
import type { Type } from '@/app/components/workflow/nodes/llm/types'
import VariableBlock from './variable-block'
type Props = {
type HITLInputComponentUIProps = {
nodeId: string
nodeTitle: string
varName: string
isSelected: boolean
formInput?: FormInputItem
onChange: (input: FormInputItem) => void
onRename: (payload: FormInputItem, oldName: string) => void
onRemove: (varName: string) => void
workflowNodesMap: WorkflowNodesMap
environmentVariables?: Var[]
conversationVariables?: Var[]
ragVariables?: Var[]
getVarType?: (payload: {
nodeId: string,
valueSelector: ValueSelector,
}) => Type
}
const ComponentUI: FC<Props> = ({
const HITLInputComponentUI: FC<HITLInputComponentUIProps> = ({
nodeId,
nodeTitle,
varName,
// isSelected,
formInput = {
type: InputVarType.textInput,
type: InputVarType.paragraph,
output_variable_name: varName,
placeholder: {
type: 'constant',
selector: [],
value: '',
},
} as FormInputItem,
},
onChange,
onRename,
onRemove,
workflowNodesMap = {},
getVarType,
environmentVariables,
conversationVariables,
ragVariables,
}) => {
const [isShowEditModal, {
setTrue: showEditModal,
@ -79,6 +90,10 @@ const ComponentUI: FC<Props> = ({
hideEditModal()
}, [hideEditModal, onChange, onRename, varName])
const isPlaceholderVariable = useMemo(() => {
return formInput.placeholder.type === 'variable'
}, [formInput.placeholder.type])
return (
<div
className='relative flex h-8 w-full select-none items-center rounded-[8px] border-[1.5px] border-components-input-border-active bg-background-default-hover pl-1.5 pr-0.5'
@ -92,18 +107,20 @@ const ComponentUI: FC<Props> = ({
</div>
<div className='flex w-full items-center justify-between'>
{/* Node info */}
<div className='flex h-[18px] items-center rounded-[5px] border-[0.5px] border-components-panel-border-subtle bg-components-badge-white-to-dark px-1 shadow-xs'>
<div className='flex items-center space-x-0.5 text-text-secondary'>
<VarBlockIcon type={BlockEnum.HumanInput} />
<div className='system-xs-medium'>{nodeTitle}</div>
</div>
<div className='system-xs-regular mx-px text-divider-deep'>/</div>
<div className='flex items-center space-x-0.5 text-text-accent'>
<Variable02 className='size-3.5' />
<div className='system-xs-medium'>{varName}</div>
</div>
</div>
{/* Placeholder Info */}
{isPlaceholderVariable && (
<VariableBlock
variables={formInput.placeholder.selector}
workflowNodesMap={workflowNodesMap}
getVarType={getVarType}
environmentVariables={environmentVariables}
conversationVariables={conversationVariables}
ragVariables={ragVariables}
/>
)}
{!isPlaceholderVariable && (
<div className='system-xs-medium text-text-quaternary'>{formInput.placeholder.value}</div>
)}
{/* Actions */}
<div className='flex h-full items-center space-x-1 pr-[24px]'>
@ -141,4 +158,4 @@ const ComponentUI: FC<Props> = ({
)
}
export default React.memo(ComponentUI)
export default React.memo(HITLInputComponentUI)

View File

@ -4,29 +4,43 @@ import { DELETE_HITL_INPUT_BLOCK_COMMAND } from './'
import ComponentUi from './component-ui'
import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types'
import { produce } from 'immer'
import type { WorkflowNodesMap } from '../workflow-variable-block/node'
import type { ValueSelector, Var } from '@/app/components/workflow/types'
import type { Type } from '@/app/components/workflow/nodes/llm/types'
type Props = {
type HITLInputComponentProps = {
nodeKey: string
nodeId: string
nodeTitle: string
varName: string
formInputs?: FormInputItem[]
onChange: (inputs: FormInputItem[]) => void
onRename: (payload: FormInputItem, oldName: string) => void
onRemove: (varName: string) => void
workflowNodesMap: WorkflowNodesMap
environmentVariables?: Var[]
conversationVariables?: Var[]
ragVariables?: Var[]
getVarType?: (payload: {
nodeId: string,
valueSelector: ValueSelector,
}) => Type
}
const HITLInputComponent: FC<Props> = ({
const HITLInputComponent: FC<HITLInputComponentProps> = ({
nodeKey,
nodeId,
nodeTitle,
varName,
formInputs = [],
onChange,
onRename,
onRemove,
workflowNodesMap = {},
getVarType,
environmentVariables,
conversationVariables,
ragVariables,
}) => {
const [ref, isSelected] = useSelectOrDelete(nodeKey, DELETE_HITL_INPUT_BLOCK_COMMAND)
const [ref] = useSelectOrDelete(nodeKey, DELETE_HITL_INPUT_BLOCK_COMMAND)
const payload = formInputs.find(item => item.output_variable_name === varName)
const handleChange = useCallback((newPayload: FormInputItem) => {
@ -50,13 +64,16 @@ const HITLInputComponent: FC<Props> = ({
>
<ComponentUi
nodeId={nodeId}
nodeTitle={nodeTitle}
varName={varName}
isSelected={isSelected}
formInput={payload}
onChange={handleChange}
onRename={onRename}
onRemove={onRemove}
workflowNodesMap={workflowNodesMap}
getVarType={getVarType}
environmentVariables={environmentVariables}
conversationVariables={conversationVariables}
ragVariables={ragVariables}
/>
</div>
)

View File

@ -2,6 +2,7 @@ import {
memo,
useCallback,
useEffect,
useMemo,
} from 'react'
import type { TextNode } from 'lexical'
import { $applyNodeReplacement } from 'lexical'
@ -9,43 +10,55 @@ import { mergeRegister } from '@lexical/utils'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { decoratorTransform } from '../../utils'
import type { HITLInputBlockType } from '../../types'
import { $createHITLInputNode } from './node'
import {
QueryBlockNode,
} from '../query-block/node'
import { $createHITLInputNode, HITLInputNode } from './node'
import { CustomTextNode } from '../custom-text/node'
import { HITL_INPUT_REG } from '@/config'
const REGEX = new RegExp(HITL_INPUT_REG)
const HITLInputReplacementBlock = ({
// onInsert,
nodeId,
nodeTitle,
formInputs,
onFormInputsChange,
onFormInputItemRename,
onFormInputItemRemove,
workflowNodesMap,
getVarType,
variables,
}: HITLInputBlockType) => {
const [editor] = useLexicalComposerContext()
const environmentVariables = useMemo(() => variables?.find(o => o.nodeId === 'env')?.vars || [], [variables])
const conversationVariables = useMemo(() => variables?.find(o => o.nodeId === 'conversation')?.vars || [], [variables])
const ragVariables = useMemo(() => variables?.reduce<any[]>((acc, curr) => {
if (curr.nodeId === 'rag')
acc.push(...curr.vars)
else
acc.push(...curr.vars.filter(v => v.isRagVariable))
return acc
}, []), [variables])
useEffect(() => {
if (!editor.hasNodes([QueryBlockNode]))
throw new Error('QueryBlockNodePlugin: QueryBlockNode not registered on editor')
if (!editor.hasNodes([HITLInputNode]))
throw new Error('HITLInputNodePlugin: HITLInputNode not registered on editor')
}, [editor])
const createHITLInputBlockNode = useCallback((textNode: TextNode): QueryBlockNode => {
const createHITLInputBlockNode = useCallback((textNode: TextNode): HITLInputNode => {
const varName = textNode.getTextContent().split('.')[1].replace(/#}}$/, '')
return $applyNodeReplacement($createHITLInputNode(
varName,
nodeId,
nodeTitle,
formInputs || [],
onFormInputsChange!,
onFormInputItemRename,
onFormInputItemRemove!,
workflowNodesMap,
getVarType,
environmentVariables,
conversationVariables,
ragVariables,
))
}, [nodeId, nodeTitle, formInputs, onFormInputsChange, onFormInputItemRename, onFormInputItemRemove])
}, [nodeId, formInputs, onFormInputsChange, onFormInputItemRename, onFormInputItemRemove, workflowNodesMap, getVarType, environmentVariables, conversationVariables, ragVariables])
const getMatch = useCallback((text: string) => {
const matchArr = REGEX.exec(text)

View File

@ -8,7 +8,7 @@ import {
createCommand,
} from 'lexical'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import type { QueryBlockType } from '../../types'
import type { HITLInputBlockType } from '../../types'
import type {
HITLNodeProps,
} from './node'
@ -20,6 +20,7 @@ import { mergeRegister } from '@lexical/utils'
export const INSERT_HITL_INPUT_BLOCK_COMMAND = createCommand('INSERT_HITL_INPUT_BLOCK_COMMAND')
export const DELETE_HITL_INPUT_BLOCK_COMMAND = createCommand('DELETE_HITL_INPUT_BLOCK_COMMAND')
export const UPDATE_WORKFLOW_NODES_MAP = createCommand('UPDATE_WORKFLOW_NODES_MAP')
export type HITLInputProps = {
onInsert?: () => void
@ -28,9 +29,17 @@ export type HITLInputProps = {
const HITLInputBlock = memo(({
onInsert,
onDelete,
}: QueryBlockType) => {
workflowNodesMap,
getVarType,
}: HITLInputBlockType) => {
const [editor] = useLexicalComposerContext()
useEffect(() => {
editor.update(() => {
editor.dispatchCommand(UPDATE_WORKFLOW_NODES_MAP, workflowNodesMap)
})
}, [editor, workflowNodesMap])
useEffect(() => {
if (!editor.hasNodes([HITLInputNode]))
throw new Error('HITLInputBlockPlugin: HITLInputBlock not registered on editor')
@ -41,7 +50,6 @@ const HITLInputBlock = memo(({
const {
variableName,
nodeId,
nodeTitle,
formInputs,
onFormInputsChange,
onFormInputItemRename,
@ -50,11 +58,12 @@ const HITLInputBlock = memo(({
const currentHITLNode = $createHITLInputNode(
variableName,
nodeId,
nodeTitle,
formInputs,
onFormInputsChange,
onFormInputItemRename,
onFormInputItemRemove,
workflowNodesMap,
getVarType,
)
$insertNodes([currentHITLNode])

View File

@ -2,15 +2,22 @@ import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical'
import { DecoratorNode } from 'lexical'
import HILTInputBlockComponent from './component'
import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types'
import type { WorkflowNodesMap } from '../workflow-variable-block/node'
import type { GetVarType } from '../../types'
import type { Var } from '@/app/components/workflow/types'
export type HITLNodeProps = {
variableName: string
nodeId: string
nodeTitle: string
formInputs: FormInputItem[]
onFormInputsChange: (inputs: FormInputItem[]) => void
onFormInputItemRename: (payload: FormInputItem, oldName: string) => void
onFormInputItemRemove: (varName: string) => void
workflowNodesMap: WorkflowNodesMap
getVarType?: GetVarType
environmentVariables?: Var[]
conversationVariables?: Var[]
ragVariables?: Var[]
}
export type SerializedNode = SerializedLexicalNode & HITLNodeProps
@ -18,11 +25,15 @@ export type SerializedNode = SerializedLexicalNode & HITLNodeProps
export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
__variableName: string
__nodeId: string
__nodeTitle: string
__formInputs?: FormInputItem[]
__onFormInputsChange: (inputs: FormInputItem[]) => void
__onFormInputItemRename: (payload: FormInputItem, oldName: string) => void
__onFormInputItemRemove: (varName: string) => void
__workflowNodesMap: WorkflowNodesMap
__getVarType?: GetVarType
__environmentVariables?: Var[]
__conversationVariables?: Var[]
__ragVariables?: Var[]
isIsolated(): boolean {
return true // This is necessary for drag-and-drop to work correctly
@ -41,11 +52,6 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
return self.__variableName
}
getNodeTitle(): string {
const self = this.getLatest()
return self.__nodeTitle
}
getNodeId(): string {
const self = this.getLatest()
return self.__nodeId
@ -71,15 +77,44 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
return self.__onFormInputItemRemove
}
getWorkflowNodesMap(): WorkflowNodesMap {
const self = this.getLatest()
return self.__workflowNodesMap
}
getGetVarType(): GetVarType | undefined {
const self = this.getLatest()
return self.__getVarType
}
getEnvironmentVariables(): Var[] {
const self = this.getLatest()
return self.__environmentVariables || []
}
getConversationVariables(): Var[] {
const self = this.getLatest()
return self.__conversationVariables || []
}
getRagVariables(): Var[] {
const self = this.getLatest()
return self.__ragVariables || []
}
static clone(node: HITLInputNode): HITLInputNode {
return new HITLInputNode(
node.__variableName,
node.__nodeId,
node.__nodeTitle,
node.__formInputs || [],
node.__onFormInputsChange,
node.__onFormInputItemRename,
node.__onFormInputItemRemove,
node.__workflowNodesMap,
node.__getVarType,
node.__environmentVariables,
node.__conversationVariables,
node.__ragVariables,
node.__key,
)
}
@ -91,22 +126,30 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
constructor(
varName: string,
nodeId: string,
nodeTitle: string,
formInputs: FormInputItem[],
onFormInputsChange: (inputs: FormInputItem[]) => void,
onFormInputItemRename: (payload: FormInputItem, oldName: string) => void,
onFormInputItemRemove: (varName: string) => void,
workflowNodesMap: WorkflowNodesMap,
getVarType?: GetVarType,
environmentVariables?: Var[],
conversationVariables?: Var[],
ragVariables?: Var[],
key?: NodeKey,
) {
super(key)
this.__variableName = varName
this.__nodeId = nodeId
this.__nodeTitle = nodeTitle
this.__formInputs = formInputs
this.__onFormInputsChange = onFormInputsChange
this.__onFormInputItemRename = onFormInputItemRename
this.__onFormInputItemRemove = onFormInputItemRemove
this.__workflowNodesMap = workflowNodesMap
this.__getVarType = getVarType
this.__environmentVariables = environmentVariables
this.__conversationVariables = conversationVariables
this.__ragVariables = ragVariables
}
createDOM(): HTMLElement {
@ -124,11 +167,15 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
nodeKey={this.getKey()}
varName={this.getVariableName()}
nodeId={this.getNodeId()}
nodeTitle={this.getNodeTitle()}
formInputs={this.getFormInputs()}
onChange={this.getOnFormInputsChange()}
onRename={this.getOnFormInputItemRename()}
onRemove={this.getOnFormInputItemRemove()}
workflowNodesMap={this.getWorkflowNodesMap()}
getVarType={this.getGetVarType()}
environmentVariables={this.getEnvironmentVariables()}
conversationVariables={this.getConversationVariables()}
ragVariables={this.getRagVariables()}
/>
}
@ -136,11 +183,15 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
const node = $createHITLInputNode(
serializedNode.variableName,
serializedNode.nodeId,
serializedNode.nodeTitle,
serializedNode.formInputs,
serializedNode.onFormInputsChange,
serializedNode.onFormInputItemRename,
serializedNode.onFormInputItemRemove,
serializedNode.workflowNodesMap,
serializedNode.getVarType,
serializedNode.environmentVariables,
serializedNode.conversationVariables,
serializedNode.ragVariables,
)
return node
@ -152,11 +203,15 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
version: 1,
variableName: this.getVariableName(),
nodeId: this.getNodeId(),
nodeTitle: this.getNodeTitle(),
formInputs: this.getFormInputs(),
onFormInputsChange: this.getOnFormInputsChange(),
onFormInputItemRename: this.getOnFormInputItemRename(),
onFormInputItemRemove: this.getOnFormInputItemRemove(),
workflowNodesMap: this.getWorkflowNodesMap(),
getVarType: this.getGetVarType(),
environmentVariables: this.getEnvironmentVariables(),
conversationVariables: this.getConversationVariables(),
ragVariables: this.getRagVariables(),
}
}
@ -168,20 +223,28 @@ export class HITLInputNode extends DecoratorNode<React.JSX.Element> {
export function $createHITLInputNode(
variableName: string,
nodeId: string,
nodeTitle: string,
formInputs: FormInputItem[],
onFormInputsChange: (inputs: FormInputItem[]) => void,
onFormInputItemRename: (payload: FormInputItem, oldName: string) => void,
onFormInputItemRemove: (varName: string) => void,
workflowNodesMap: WorkflowNodesMap,
getVarType?: GetVarType,
environmentVariables?: Var[],
conversationVariables?: Var[],
ragVariables?: Var[],
): HITLInputNode {
return new HITLInputNode(
variableName,
nodeId,
nodeTitle,
formInputs,
onFormInputsChange,
onFormInputItemRename,
onFormInputItemRemove,
workflowNodesMap,
getVarType,
environmentVariables,
conversationVariables,
ragVariables,
)
}

View File

@ -0,0 +1,145 @@
import {
memo,
useEffect,
useMemo,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
import {
COMMAND_PRIORITY_EDITOR,
} from 'lexical'
import { mergeRegister } from '@lexical/utils'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import type { WorkflowNodesMap } from '../workflow-variable-block/node'
import {
isConversationVar,
isENV,
isGlobalVar,
isRagVariableVar,
isSystemVar,
} from '@/app/components/workflow/nodes/_base/components/variable/utils'
import Tooltip from '@/app/components/base/tooltip'
import { isExceptionVariable } from '@/app/components/workflow/utils'
import VarFullPathPanel from '@/app/components/workflow/nodes/_base/components/variable/var-full-path-panel'
import { Type } from '@/app/components/workflow/nodes/llm/types'
import type { ValueSelector, Var } from '@/app/components/workflow/types'
import {
VariableLabelInEditor,
} from '@/app/components/workflow/nodes/_base/components/variable/variable-label'
import { UPDATE_WORKFLOW_NODES_MAP } from '../workflow-variable-block'
import { HITLInputNode } from './node'
type HITLInputVariableBlockComponentProps = {
variables: string[]
workflowNodesMap: WorkflowNodesMap
environmentVariables?: Var[]
conversationVariables?: Var[]
ragVariables?: Var[]
getVarType?: (payload: {
nodeId: string,
valueSelector: ValueSelector,
}) => Type
}
const HITLInputVariableBlockComponent = ({
variables,
workflowNodesMap = {},
getVarType,
environmentVariables,
conversationVariables,
ragVariables,
}: HITLInputVariableBlockComponentProps) => {
const { t } = useTranslation()
const [editor] = useLexicalComposerContext()
const variablesLength = variables.length
const isRagVar = isRagVariableVar(variables)
const isShowAPart = variablesLength > 2 && !isRagVar
const varName = (
() => {
const isSystem = isSystemVar(variables)
const varName = variables[variablesLength - 1]
return `${isSystem ? 'sys.' : ''}${varName}`
}
)()
const [localWorkflowNodesMap, setLocalWorkflowNodesMap] = useState<WorkflowNodesMap>(workflowNodesMap)
const node = localWorkflowNodesMap![variables[isRagVar ? 1 : 0]]
const isException = isExceptionVariable(varName, node?.type)
const variableValid = useMemo(() => {
let variableValid = true
const isEnv = isENV(variables)
const isChatVar = isConversationVar(variables)
const isGlobal = isGlobalVar(variables)
if (isGlobal)
return true
if (isEnv) {
if (environmentVariables)
variableValid = environmentVariables.some(v => v.variable === `${variables?.[0] ?? ''}.${variables?.[1] ?? ''}`)
}
else if (isChatVar) {
if (conversationVariables)
variableValid = conversationVariables.some(v => v.variable === `${variables?.[0] ?? ''}.${variables?.[1] ?? ''}`)
}
else if (isRagVar) {
if (ragVariables)
variableValid = ragVariables.some(v => v.variable === `${variables?.[0] ?? ''}.${variables?.[1] ?? ''}.${variables?.[2] ?? ''}`)
}
else {
variableValid = !!node
}
return variableValid
}, [variables, node, environmentVariables, conversationVariables, isRagVar, ragVariables])
useEffect(() => {
if (!editor.hasNodes([HITLInputNode]))
throw new Error('HITLInputNodePlugin: HITLInputNode not registered on editor')
return mergeRegister(
editor.registerCommand(
UPDATE_WORKFLOW_NODES_MAP,
(workflowNodesMap: WorkflowNodesMap) => {
setLocalWorkflowNodesMap(workflowNodesMap)
return true
},
COMMAND_PRIORITY_EDITOR,
),
)
}, [editor])
const Item = (
<VariableLabelInEditor
nodeType={node?.type}
nodeTitle={node?.title}
variables={variables}
isExceptionVariable={isException}
errorMsg={!variableValid ? t('workflow.errorMsg.invalidVariable') : undefined}
notShowFullPath={isShowAPart}
/>
)
if (!node)
return Item
return (
<Tooltip
noDecoration
popupContent={
<VarFullPathPanel
nodeName={node.title}
path={variables.slice(1)}
varType={getVarType ? getVarType({
nodeId: variables[0],
valueSelector: variables,
}) : Type.string}
nodeType={node?.type}
/>}
disabled={!isShowAPart}
>
<div>{Item}</div>
</Tooltip>
)
}
export default memo(HITLInputVariableBlockComponent)

View File

@ -40,7 +40,7 @@ const WorkflowVariableBlockReplacementBlock = ({
const nodePathString = textNode.getTextContent().slice(3, -3)
return $applyNodeReplacement($createWorkflowVariableBlockNode(nodePathString.split('.'), workflowNodesMap, getVarType, variables?.find(o => o.nodeId === 'env')?.vars || [], variables?.find(o => o.nodeId === 'conversation')?.vars || [], ragVariables))
}, [onInsert, workflowNodesMap, getVarType, variables])
}, [onInsert, workflowNodesMap, getVarType, variables, ragVariables])
const getMatch = useCallback((text: string) => {
const matchArr = REGEX.exec(text)

View File

@ -84,11 +84,15 @@ export type WorkflowVariableBlockType = {
export type HITLInputBlockType = {
show?: boolean
nodeId: string
nodeTitle: string
formInputs?: FormInputItem[]
variables?: NodeOutPutVar[]
workflowNodesMap?: Record<string, Pick<Node['data'], 'title' | 'type' | 'height' | 'width' | 'position'>>
getVarType?: GetVarType
onFormInputsChange?: (inputs: FormInputItem[]) => void
onFormInputItemRemove: (varName: string) => void
onFormInputItemRename: (payload: FormInputItem, oldName: string) => void
onInsert?: () => void
onDelete?: () => void
}
export type MenuTextMatch = {

View File

@ -14,9 +14,8 @@ import { isMac } from '../../../utils'
import { useBoolean } from 'ahooks'
import { cn } from '@/utils/classnames'
type Props = {
type FormContentProps = {
nodeId: string
nodeTitle: string
value: string
onChange: (value: string) => void
formInputs: FormInputItem[]
@ -35,9 +34,8 @@ const CtrlKey: FC = () => {
return <Key className={cn('mr-0', !isMac() && 'w-7')}>{isMac() ? '⌘' : 'Ctrl'}</Key>
}
const FormContent: FC<Props> = ({
const FormContent: FC<FormContentProps> = ({
nodeId,
nodeTitle,
value,
onChange,
formInputs,
@ -67,7 +65,6 @@ const FormContent: FC<Props> = ({
onInsert(INSERT_HITL_INPUT_BLOCK_COMMAND, {
variableName: payload.output_variable_name,
nodeId,
nodeTitle,
formInputs: newFormInputs,
onFormInputsChange,
onFormInputItemRename,
@ -91,6 +88,23 @@ const FormContent: FC<Props> = ({
setFalse: setBlur,
}] = useBoolean(false)
const workflowNodesMap = availableNodes.reduce((acc: any, node) => {
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 = {
title: t('workflow.blocks.start'),
type: BlockEnum.Start,
}
}
return acc
}, {})
return (
<div className={cn('flex grow flex-col rounded-[10px] border border-components-input-bg-normal bg-components-input-bg-normal pt-1', isFocus && 'border-components-input-border-active bg-components-input-bg-active', !isFocus && 'pb-[32px]')}>
<PromptEditor
@ -105,31 +119,18 @@ const FormContent: FC<Props> = ({
show: true,
formInputs,
nodeId,
nodeTitle,
onFormInputsChange,
onFormInputItemRename,
onFormInputItemRemove,
variables: availableVars || [],
workflowNodesMap,
getVarType,
}}
workflowVariableBlock={{
show: true,
variables: availableVars || [],
getVarType: getVarType as any,
workflowNodesMap: availableNodes.reduce((acc: any, node) => {
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 = {
title: t('workflow.blocks.start'),
type: BlockEnum.Start,
}
}
return acc
}, {}),
workflowNodesMap,
}}
editable
shortcutPopups={[{

View File

@ -115,7 +115,6 @@ const Panel: FC<NodePanelProps<HumanInputNodeType>> = ({
nodeId={id}
value={inputs.form_content}
onChange={handleFormContentChange}
nodeTitle={inputs.title}
formInputs={inputs.inputs}
onFormInputsChange={handleFormInputsChange}
onFormInputItemRename={handleFormInputItemRename}