mirror of
https://github.com/langgenius/dify.git
synced 2026-04-28 22:48:07 +08:00
Made-with: Cursor # Conflicts: # api/README.md # api/controllers/console/app/workflow_draft_variable.py # api/core/agent/cot_agent_runner.py # api/core/agent/fc_agent_runner.py # api/core/app/apps/advanced_chat/app_runner.py # api/core/plugin/backwards_invocation/model.py # api/core/prompt/advanced_prompt_transform.py # api/core/workflow/nodes/base/node.py # api/core/workflow/nodes/llm/llm_utils.py # api/core/workflow/nodes/llm/node.py # api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py # api/core/workflow/nodes/question_classifier/question_classifier_node.py # api/core/workflow/runtime/graph_runtime_state.py # api/extensions/storage/base_storage.py # api/factories/variable_factory.py # api/pyproject.toml # api/services/variable_truncator.py # api/uv.lock # web/app/account/oauth/authorize/page.tsx # web/app/components/app/configuration/config-var/config-modal/field.tsx # web/app/components/base/alert.tsx # web/app/components/base/chat/chat/answer/human-input-content/executed-action.tsx # web/app/components/base/chat/chat/answer/more.tsx # web/app/components/base/chat/chat/answer/operation.tsx # web/app/components/base/chat/chat/answer/workflow-process.tsx # web/app/components/base/chat/chat/citation/index.tsx # web/app/components/base/chat/chat/citation/popup.tsx # web/app/components/base/chat/chat/citation/progress-tooltip.tsx # web/app/components/base/chat/chat/citation/tooltip.tsx # web/app/components/base/chat/chat/question.tsx # web/app/components/base/chat/embedded-chatbot/inputs-form/index.tsx # web/app/components/base/chat/embedded-chatbot/inputs-form/view-form-dropdown.tsx # web/app/components/base/markdown-blocks/form.tsx # web/app/components/base/prompt-editor/plugins/hitl-input-block/component-ui.tsx # web/app/components/base/tag-management/panel.tsx # web/app/components/base/tag-management/trigger.tsx # web/app/components/header/account-setting/index.tsx # web/app/components/header/account-setting/members-page/transfer-ownership-modal/index.tsx # web/app/components/header/account-setting/model-provider-page/provider-added-card/index.tsx # web/app/signin/utils/post-login-redirect.ts # web/eslint-suppressions.json # web/package.json # web/pnpm-lock.yaml
183 lines
5.8 KiB
TypeScript
183 lines
5.8 KiB
TypeScript
'use client'
|
|
import type { FC } from 'react'
|
|
import type { WorkflowNodesMap } from '../workflow-variable-block/node'
|
|
import type { FormInputItem } from '@/app/components/workflow/nodes/human-input/types'
|
|
import type { Type } from '@/app/components/workflow/nodes/llm/types'
|
|
import type { NodeOutPutVar, ValueSelector, Var } from '@/app/components/workflow/types'
|
|
import { useBoolean } from 'ahooks'
|
|
import * as React from 'react'
|
|
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { InputVarType } from '@/app/components/workflow/types'
|
|
import ActionButton from '../../../action-button'
|
|
import { VariableX } from '../../../icons/src/vender/workflow'
|
|
import Modal from '../../../modal'
|
|
import InputField from './input-field'
|
|
import VariableBlock from './variable-block'
|
|
|
|
type HITLInputComponentUIProps = {
|
|
nodeId: string
|
|
varName: string
|
|
formInput?: FormInputItem
|
|
onChange: (input: FormInputItem) => void
|
|
onRename: (payload: FormInputItem, oldName: string) => void
|
|
onRemove: (varName: string) => void
|
|
workflowNodesMap: WorkflowNodesMap
|
|
nodeOutputVars?: NodeOutPutVar[]
|
|
environmentVariables?: Var[]
|
|
conversationVariables?: Var[]
|
|
ragVariables?: Var[]
|
|
getVarType?: (payload: {
|
|
nodeId: string
|
|
valueSelector: ValueSelector
|
|
}) => Type
|
|
readonly?: boolean
|
|
}
|
|
|
|
const HITLInputComponentUI: FC<HITLInputComponentUIProps> = ({
|
|
nodeId,
|
|
varName,
|
|
formInput = {
|
|
type: InputVarType.paragraph,
|
|
output_variable_name: varName,
|
|
default: {
|
|
type: 'constant',
|
|
selector: [],
|
|
value: '',
|
|
},
|
|
},
|
|
onChange,
|
|
onRename,
|
|
onRemove,
|
|
workflowNodesMap = {},
|
|
nodeOutputVars,
|
|
getVarType,
|
|
environmentVariables,
|
|
conversationVariables,
|
|
ragVariables,
|
|
readonly,
|
|
}) => {
|
|
const { t } = useTranslation()
|
|
const [isShowEditModal, {
|
|
setTrue: showEditModal,
|
|
setFalse: hideEditModal,
|
|
}] = useBoolean(false)
|
|
|
|
// Lexical delegate the click make it unable to add click by the method of react
|
|
const editBtnRef = useRef<HTMLDivElement>(null)
|
|
useEffect(() => {
|
|
const editBtn = editBtnRef.current
|
|
if (editBtn)
|
|
editBtn.addEventListener('click', showEditModal)
|
|
|
|
return () => {
|
|
if (editBtn)
|
|
editBtn.removeEventListener('click', showEditModal)
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [])
|
|
|
|
const removeBtnRef = useRef<HTMLDivElement>(null)
|
|
useEffect(() => {
|
|
const removeBtn = removeBtnRef.current
|
|
const removeHandler = () => onRemove(varName)
|
|
if (removeBtn)
|
|
removeBtn.addEventListener('click', removeHandler)
|
|
|
|
return () => {
|
|
if (removeBtn)
|
|
removeBtn.removeEventListener('click', removeHandler)
|
|
}
|
|
}, [onRemove, varName])
|
|
|
|
const handleChange = useCallback((newPayload: FormInputItem) => {
|
|
if (varName === newPayload.output_variable_name)
|
|
onChange(newPayload)
|
|
else
|
|
onRename(newPayload, varName)
|
|
hideEditModal()
|
|
}, [hideEditModal, onChange, onRename, varName])
|
|
|
|
const isDefaultValueVariable = useMemo(() => {
|
|
return formInput.default?.type === 'variable'
|
|
}, [formInput.default?.type])
|
|
|
|
return (
|
|
<div
|
|
className="group 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"
|
|
>
|
|
<div className="absolute left-2.5 top-[-12px]">
|
|
<div className="absolute bottom-1 h-[1.5px] w-full bg-background-default-subtle"></div>
|
|
<div className="relative flex items-center space-x-0.5 px-1 text-text-accent-light-mode-only">
|
|
<VariableX className="size-3" />
|
|
<div className="system-xs-medium">{varName}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex w-full items-center gap-x-0.5 pr-5">
|
|
<div className="min-w-0 grow">
|
|
{/* Default Value Info */}
|
|
{isDefaultValueVariable && (
|
|
<VariableBlock
|
|
variables={formInput.default?.selector}
|
|
workflowNodesMap={workflowNodesMap}
|
|
nodeOutputVars={nodeOutputVars}
|
|
getVarType={getVarType}
|
|
environmentVariables={environmentVariables}
|
|
conversationVariables={conversationVariables}
|
|
ragVariables={ragVariables}
|
|
/>
|
|
)}
|
|
{!isDefaultValueVariable && (
|
|
<div className="max-w-full truncate text-components-input-text-filled system-xs-medium">{formInput.default?.value}</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Actions */}
|
|
{!readonly && (
|
|
<div className="hidden h-full shrink-0 items-center space-x-1 group-hover:flex">
|
|
<div className="flex h-full items-center" ref={editBtnRef}>
|
|
<ActionButton
|
|
size="s"
|
|
data-testid="action-btn-edit"
|
|
aria-label={t('operation.edit', { ns: 'common' })}
|
|
>
|
|
<span className="i-ri-edit-line size-4 text-text-tertiary" />
|
|
</ActionButton>
|
|
</div>
|
|
|
|
<div className="flex h-full items-center" ref={removeBtnRef}>
|
|
<ActionButton
|
|
size="s"
|
|
data-testid="action-btn-remove"
|
|
aria-label={t('operation.remove', { ns: 'common' })}
|
|
>
|
|
<span className="i-ri-delete-bin-line size-4 text-text-tertiary" />
|
|
</ActionButton>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{isShowEditModal && (
|
|
<Modal
|
|
isShow
|
|
onClose={hideEditModal}
|
|
wrapperClassName="z-[999]"
|
|
className="max-w-[372px] !p-0"
|
|
>
|
|
<InputField
|
|
nodeId={nodeId}
|
|
isEdit
|
|
payload={formInput}
|
|
onChange={handleChange}
|
|
onCancel={hideEditModal}
|
|
/>
|
|
</Modal>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default React.memo(HITLInputComponentUI)
|