mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 09:28:04 +08:00
revert: revert human input relevant code (#31766)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@ -1,85 +0,0 @@
|
||||
import type { DeliveryMethod, HumanInputNodeType, UserAction } from '../types'
|
||||
import { produce } from 'immer'
|
||||
import { useState } from 'react'
|
||||
import { useUpdateNodeInternals } from 'reactflow'
|
||||
import {
|
||||
useNodesReadOnly,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { useEdgesInteractions } from '@/app/components/workflow/hooks/use-edges-interactions'
|
||||
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
|
||||
import useFormContent from './use-form-content'
|
||||
|
||||
const useConfig = (id: string, payload: HumanInputNodeType) => {
|
||||
const updateNodeInternals = useUpdateNodeInternals()
|
||||
const { nodesReadOnly: readOnly } = useNodesReadOnly()
|
||||
const { inputs, setInputs } = useNodeCrud<HumanInputNodeType>(id, payload)
|
||||
const formContentHook = useFormContent(id, payload)
|
||||
const { handleEdgeDeleteByDeleteBranch, handleEdgeSourceHandleChange } = useEdgesInteractions()
|
||||
const [structuredOutputCollapsed, setStructuredOutputCollapsed] = useState(true)
|
||||
|
||||
const handleDeliveryMethodChange = (methods: DeliveryMethod[]) => {
|
||||
setInputs({
|
||||
...inputs,
|
||||
delivery_methods: methods,
|
||||
})
|
||||
}
|
||||
|
||||
const handleUserActionAdd = (newAction: UserAction) => {
|
||||
setInputs({
|
||||
...inputs,
|
||||
user_actions: [...inputs.user_actions, newAction],
|
||||
})
|
||||
}
|
||||
|
||||
const handleUserActionChange = (index: number, updatedAction: UserAction) => {
|
||||
const newActions = produce(inputs.user_actions, (draft) => {
|
||||
if (draft[index])
|
||||
draft[index] = updatedAction
|
||||
})
|
||||
setInputs({
|
||||
...inputs,
|
||||
user_actions: newActions,
|
||||
})
|
||||
|
||||
// Update edges to use the new handle
|
||||
const oldAction = inputs.user_actions[index]
|
||||
|
||||
if (oldAction && oldAction.id !== updatedAction.id) {
|
||||
handleEdgeSourceHandleChange(id, oldAction.id, updatedAction.id)
|
||||
updateNodeInternals(id) // Update handles
|
||||
}
|
||||
}
|
||||
|
||||
const handleUserActionDelete = (actionId: string) => {
|
||||
const newActions = inputs.user_actions.filter(action => action.id !== actionId)
|
||||
setInputs({
|
||||
...inputs,
|
||||
user_actions: newActions,
|
||||
})
|
||||
// Delete edges connected to this action
|
||||
handleEdgeDeleteByDeleteBranch(id, actionId)
|
||||
}
|
||||
|
||||
const handleTimeoutChange = ({ timeout, unit }: { timeout: number, unit: 'hour' | 'day' }) => {
|
||||
setInputs({
|
||||
...inputs,
|
||||
timeout,
|
||||
timeout_unit: unit,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
readOnly,
|
||||
inputs,
|
||||
handleDeliveryMethodChange,
|
||||
handleUserActionAdd,
|
||||
handleUserActionChange,
|
||||
handleUserActionDelete,
|
||||
handleTimeoutChange,
|
||||
structuredOutputCollapsed,
|
||||
setStructuredOutputCollapsed,
|
||||
...formContentHook,
|
||||
}
|
||||
}
|
||||
|
||||
export default useConfig
|
||||
@ -1,65 +0,0 @@
|
||||
import type { FormInputItem, HumanInputNodeType } from '../types'
|
||||
import { produce } from 'immer'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
||||
import useNodeCrud from '../../_base/hooks/use-node-crud'
|
||||
|
||||
const useFormContent = (id: string, payload: HumanInputNodeType) => {
|
||||
const [editorKey, setEditorKey] = useState(0)
|
||||
const { inputs, setInputs } = useNodeCrud<HumanInputNodeType>(id, payload)
|
||||
const { handleOutVarRenameChange } = useWorkflow()
|
||||
const inputsRef = useRef(inputs)
|
||||
useEffect(() => {
|
||||
inputsRef.current = inputs
|
||||
}, [inputs])
|
||||
const handleFormContentChange = useCallback((value: string) => {
|
||||
setInputs({
|
||||
...inputs,
|
||||
form_content: value,
|
||||
})
|
||||
}, [inputs, setInputs])
|
||||
|
||||
const handleFormInputsChange = useCallback((formInputs: FormInputItem[]) => {
|
||||
setInputs({
|
||||
...inputs,
|
||||
inputs: formInputs,
|
||||
})
|
||||
setEditorKey(editorKey => editorKey + 1)
|
||||
}, [inputs, setInputs])
|
||||
|
||||
const handleFormInputItemRename = useCallback((payload: FormInputItem, oldName: string) => {
|
||||
const inputs = inputsRef.current
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.form_content = draft.form_content.replaceAll(`{{#$output.${oldName}#}}`, `{{#$output.${payload.output_variable_name}#}}`)
|
||||
draft.inputs = draft.inputs.map(item => item.output_variable_name === oldName ? payload : item)
|
||||
if (!draft.inputs.find(item => item.output_variable_name === payload.output_variable_name))
|
||||
draft.inputs = [...draft.inputs, payload]
|
||||
})
|
||||
setInputs(newInputs)
|
||||
setEditorKey(editorKey => editorKey + 1)
|
||||
|
||||
// Update downstream nodes that reference this variable
|
||||
if (oldName !== payload.output_variable_name)
|
||||
handleOutVarRenameChange(id, [id, oldName], [id, payload.output_variable_name])
|
||||
}, [setInputs, handleOutVarRenameChange, id])
|
||||
|
||||
const handleFormInputItemRemove = useCallback((varName: string) => {
|
||||
const inputs = inputsRef.current
|
||||
const newInputs = produce(inputs, (draft) => {
|
||||
draft.form_content = draft.form_content.replaceAll(`{{#$output.${varName}#}}`, '')
|
||||
draft.inputs = draft.inputs.filter(item => item.output_variable_name !== varName)
|
||||
})
|
||||
setInputs(newInputs)
|
||||
setEditorKey(editorKey => editorKey + 1)
|
||||
}, [setInputs])
|
||||
|
||||
return {
|
||||
editorKey,
|
||||
handleFormContentChange,
|
||||
handleFormInputsChange,
|
||||
handleFormInputItemRename,
|
||||
handleFormInputItemRemove,
|
||||
}
|
||||
}
|
||||
|
||||
export default useFormContent
|
||||
@ -1,128 +0,0 @@
|
||||
import type { HumanInputNodeType } from '../types'
|
||||
import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
|
||||
import type { InputVar } from '@/app/components/workflow/types'
|
||||
import type { HumanInputFormData } from '@/types/workflow'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import { fetchHumanInputNodeStepRunForm, submitHumanInputNodeStepRunForm } from '@/service/workflow'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
import useNodeCrud from '../../_base/hooks/use-node-crud'
|
||||
import { isOutput } from '../utils'
|
||||
|
||||
const i18nPrefix = 'nodes.humanInput'
|
||||
|
||||
type Params = {
|
||||
id: string
|
||||
payload: HumanInputNodeType
|
||||
runInputData: Record<string, string>
|
||||
getInputVars: (textList: string[]) => InputVar[]
|
||||
setRunInputData: (data: Record<string, string>) => void
|
||||
}
|
||||
const useSingleRunFormParams = ({
|
||||
id,
|
||||
payload,
|
||||
runInputData,
|
||||
getInputVars,
|
||||
setRunInputData,
|
||||
}: Params) => {
|
||||
const { t } = useTranslation()
|
||||
const { inputs } = useNodeCrud<HumanInputNodeType>(id, payload)
|
||||
const [showGeneratedForm, setShowGeneratedForm] = useState(false)
|
||||
const [formData, setFormData] = useState<HumanInputFormData | null>(null)
|
||||
const [requiredInputs, setRequiredInputs] = useState<Record<string, string>>({})
|
||||
const generatedInputs = useMemo(() => {
|
||||
const defaultInputs = inputs.inputs.reduce((acc, input) => {
|
||||
if (input.default.type === 'variable') {
|
||||
acc.push(`{{#${input.default.selector.join('.')}#}}`)
|
||||
}
|
||||
return acc
|
||||
}, [] as string[])
|
||||
const allInputs = getInputVars([...defaultInputs, inputs.form_content || '']).filter(item => !isOutput(item.value_selector || []))
|
||||
return allInputs
|
||||
}, [getInputVars, inputs.form_content, inputs.inputs])
|
||||
|
||||
const forms = useMemo(() => {
|
||||
const forms: FormProps[] = [{
|
||||
label: t(`${i18nPrefix}.singleRun.label`, { ns: 'workflow' })!,
|
||||
inputs: generatedInputs,
|
||||
values: runInputData,
|
||||
onChange: setRunInputData,
|
||||
}]
|
||||
return forms
|
||||
}, [t, generatedInputs, runInputData, setRunInputData])
|
||||
|
||||
const getDependentVars = () => {
|
||||
return generatedInputs.map((item) => {
|
||||
// Guard against null/undefined variable to prevent app crash
|
||||
if (!item.variable || typeof item.variable !== 'string')
|
||||
return []
|
||||
|
||||
return item.variable.slice(1, -1).split('.')
|
||||
}).filter(arr => arr.length > 0)
|
||||
}
|
||||
|
||||
const appDetail = useAppStore(s => s.appDetail)
|
||||
const appId = appDetail?.id
|
||||
const isWorkflowMode = appDetail?.mode === AppModeEnum.WORKFLOW
|
||||
const fetchURL = useMemo(() => {
|
||||
if (!appId)
|
||||
return ''
|
||||
if (!isWorkflowMode) {
|
||||
return `/apps/${appId}/advanced-chat/workflows/draft/human-input/nodes/${id}/form`
|
||||
}
|
||||
else {
|
||||
return `/apps/${appId}/workflows/draft/human-input/nodes/${id}/form`
|
||||
}
|
||||
}, [appId, id, isWorkflowMode])
|
||||
|
||||
const handleFetchFormContent = useCallback(async (inputs: Record<string, string>) => {
|
||||
if (!fetchURL)
|
||||
return null
|
||||
let requestParamsObj: Record<string, string> = {}
|
||||
Object.keys(inputs).forEach((key) => {
|
||||
if (inputs[key] === undefined) {
|
||||
delete inputs[key]
|
||||
}
|
||||
})
|
||||
requestParamsObj = { ...inputs }
|
||||
const data = await fetchHumanInputNodeStepRunForm(fetchURL, { inputs: requestParamsObj! })
|
||||
setFormData(data)
|
||||
setRequiredInputs(requestParamsObj)
|
||||
return data
|
||||
}, [fetchURL])
|
||||
|
||||
const handleSubmitHumanInputForm = useCallback(async (formData: {
|
||||
inputs: Record<string, string> | undefined
|
||||
form_inputs: Record<string, string> | undefined
|
||||
action: string
|
||||
}) => {
|
||||
await submitHumanInputNodeStepRunForm(fetchURL, {
|
||||
inputs: requiredInputs,
|
||||
form_inputs: formData.inputs,
|
||||
action: formData.action,
|
||||
})
|
||||
}, [fetchURL, requiredInputs])
|
||||
|
||||
const handleShowGeneratedForm = async (formValue: Record<string, string>) => {
|
||||
setShowGeneratedForm(true)
|
||||
await handleFetchFormContent(formValue)
|
||||
}
|
||||
|
||||
const handleHideGeneratedForm = () => {
|
||||
setShowGeneratedForm(false)
|
||||
}
|
||||
|
||||
return {
|
||||
forms,
|
||||
getDependentVars,
|
||||
showGeneratedForm,
|
||||
handleShowGeneratedForm,
|
||||
handleHideGeneratedForm,
|
||||
formData,
|
||||
handleFetchFormContent,
|
||||
handleSubmitHumanInputForm,
|
||||
}
|
||||
}
|
||||
|
||||
export default useSingleRunFormParams
|
||||
Reference in New Issue
Block a user