feat: introduce useInputFieldPanel hook to manage input field panel state and refactor related components

This commit is contained in:
twwu 2025-08-06 10:32:57 +08:00
parent 6faa4b107b
commit ec6fabb222
11 changed files with 95 additions and 26 deletions

View File

@ -12,7 +12,7 @@ import { useBoolean } from 'ahooks'
import Toast from '@/app/components/base/toast'
import { usePipeline } from '../../../../hooks/use-pipeline'
import { useTranslation } from 'react-i18next'
import { useStore } from '@/app/components/workflow/store'
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
const VARIABLE_PREFIX = 'rag'
@ -30,7 +30,7 @@ export const useFieldList = ({
allVariableNames,
}: useFieldListProps) => {
const { t } = useTranslation()
const setInputFieldEditPanelProps = useStore(s => s.setInputFieldEditPanelProps)
const { toggleInputFieldEditPanel } = useInputFieldPanel()
const [inputFields, setInputFields] = useState<InputVar[]>(initialInputFields)
const inputFieldsRef = useRef<InputVar[]>(inputFields)
const [removedVar, setRemovedVar] = useState<ValueSelector>([])
@ -60,9 +60,9 @@ export const useFieldList = ({
const editingFieldIndex = useRef<number>(-1)
const handleCloseInputFieldEditor = useCallback(() => {
setInputFieldEditPanelProps?.(null)
toggleInputFieldEditPanel?.(null)
editingFieldIndex.current = -1
}, [setInputFieldEditPanelProps])
}, [toggleInputFieldEditPanel])
const handleRemoveField = useCallback((index: number) => {
const itemToRemove = inputFieldsRef.current[index]
@ -112,7 +112,7 @@ export const useFieldList = ({
const handleOpenInputFieldEditor = useCallback((id?: string) => {
const index = inputFieldsRef.current.findIndex(field => field.variable === id)
editingFieldIndex.current = index
setInputFieldEditPanelProps?.({
toggleInputFieldEditPanel?.({
onClose: handleCloseInputFieldEditor,
onSubmit: handleSubmitField,
initialData: inputFieldsRef.current[index],

View File

@ -21,17 +21,19 @@ import Button from '@/app/components/base/button'
import Divider from '@/app/components/base/divider'
import Tooltip from '@/app/components/base/tooltip'
import cn from '@/utils/classnames'
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
const InputFieldPanel = () => {
const { t } = useTranslation()
const nodes = useNodes<DataSourceNodeType>()
const setShowInputFieldPanel = useStore(state => state.setShowInputFieldPanel)
const {
closeAllInputFieldPanels,
toggleInputFieldPreviewPanel,
isPreviewing,
isEditing,
} = useInputFieldPanel()
const ragPipelineVariables = useStore(state => state.ragPipelineVariables)
const setRagPipelineVariables = useStore(state => state.setRagPipelineVariables)
const showInputFieldPreviewPanel = useStore(state => state.showInputFieldPreviewPanel)
const setShowInputFieldPreviewPanel = useStore(state => state.setShowInputFieldPreviewPanel)
const inputFieldEditPanelProps = useStore(state => state.inputFieldEditPanelProps)
const setInputFieldEditPanelProps = useStore(state => state.setInputFieldEditPanelProps)
const getInputFieldsMap = () => {
const inputFieldsMap: Record<string, InputVar[]> = {}
@ -86,14 +88,12 @@ const InputFieldPanel = () => {
}, [setRagPipelineVariables, handleSyncWorkflowDraft])
const closePanel = useCallback(() => {
setShowInputFieldPanel?.(false)
setShowInputFieldPreviewPanel?.(false)
setInputFieldEditPanelProps?.(null)
}, [setShowInputFieldPanel, setShowInputFieldPreviewPanel, setInputFieldEditPanelProps])
closeAllInputFieldPanels()
}, [closeAllInputFieldPanels])
const togglePreviewPanel = useCallback(() => {
setShowInputFieldPreviewPanel?.(!showInputFieldPreviewPanel)
}, [showInputFieldPreviewPanel, setShowInputFieldPreviewPanel])
toggleInputFieldPreviewPanel()
}, [toggleInputFieldPreviewPanel])
const allVariableNames = useMemo(() => {
return ragPipelineVariables?.map(variable => variable.variable) || []
@ -110,10 +110,10 @@ const InputFieldPanel = () => {
size='small'
className={cn(
'shrink-0 gap-x-px px-1.5',
showInputFieldPreviewPanel && 'bg-state-accent-active text-text-accent',
isPreviewing && 'bg-state-accent-active text-text-accent',
)}
onClick={togglePreviewPanel}
disabled={!!inputFieldEditPanelProps}
disabled={isEditing}
>
<RiEyeLine className='size-3.5' />
<span className='px-[3px]'>{t('datasetPipeline.operations.preview')}</span>
@ -151,7 +151,7 @@ const InputFieldPanel = () => {
nodeId={key}
LabelRightContent={<Datasource nodeData={datasourceNodeDataMap[key]} />}
inputFields={inputFields}
readonly={showInputFieldPreviewPanel || !!inputFieldEditPanelProps}
readonly={isPreviewing || isEditing}
labelClassName='pt-1 pb-1'
handleInputFieldsChange={updateInputFields}
allVariableNames={allVariableNames}
@ -165,7 +165,7 @@ const InputFieldPanel = () => {
nodeId='shared'
LabelRightContent={<GlobalInputs />}
inputFields={inputFieldsMap.current.shared || []}
readonly={showInputFieldPreviewPanel || !!inputFieldEditPanelProps}
readonly={isPreviewing || isEditing}
labelClassName='pt-2 pb-1'
handleInputFieldsChange={updateInputFields}
allVariableNames={allVariableNames}

View File

@ -6,16 +6,16 @@ import DataSource from './data-source'
import Divider from '@/app/components/base/divider'
import ProcessDocuments from './process-documents'
import type { Datasource } from '../../test-run/types'
import { useStore } from '@/app/components/workflow/store'
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
const PreviewPanel = () => {
const { t } = useTranslation()
const [datasource, setDatasource] = useState<Datasource>()
const setShowInputFieldPreviewPanel = useStore(state => state.setShowInputFieldPreviewPanel)
const { toggleInputFieldPreviewPanel } = useInputFieldPanel()
const handleClosePreviewPanel = useCallback(() => {
setShowInputFieldPreviewPanel(false)
}, [setShowInputFieldPreviewPanel])
toggleInputFieldPreviewPanel()
}, [toggleInputFieldPreviewPanel])
return (
<div className='mr-1 flex h-full w-[480px] flex-col overflow-y-auto rounded-2xl border-y-[0.5px] border-l-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl shadow-shadow-shadow-5'>

View File

@ -7,9 +7,11 @@ import { useTranslation } from 'react-i18next'
const InputFieldButton = () => {
const { t } = useTranslation()
const setShowInputFieldPanel = useStore(state => state.setShowInputFieldPanel)
const setShowEnvPanel = useStore(state => state.setShowEnvPanel)
const handleClick = useCallback(() => {
setShowInputFieldPanel?.(true)
}, [setShowInputFieldPanel])
setShowEnvPanel(false)
}, [setShowInputFieldPanel, setShowEnvPanel])
return (
<Button

View File

@ -6,3 +6,4 @@ export * from './use-pipeline-start-run'
export * from './use-pipeline-init'
export * from './use-get-run-and-trace-url'
export * from './use-DSL'
export * from './use-input-field-panel'

View File

@ -0,0 +1,54 @@
import { useCallback, useMemo } from 'react'
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
import type { InputFieldEditorProps } from '../components/panel/input-field/editor'
export const useInputFieldPanel = () => {
const workflowStore = useWorkflowStore()
const showInputFieldPreviewPanel = useStore(state => state.showInputFieldPreviewPanel)
const inputFieldEditPanelProps = useStore(state => state.inputFieldEditPanelProps)
const isPreviewing = useMemo(() => {
return showInputFieldPreviewPanel
}, [showInputFieldPreviewPanel])
const isEditing = useMemo(() => {
return !!inputFieldEditPanelProps
}, [inputFieldEditPanelProps])
const closeAllInputFieldPanels = useCallback(() => {
const {
setShowInputFieldPanel,
setShowInputFieldPreviewPanel,
setInputFieldEditPanelProps,
} = workflowStore.getState()
setShowInputFieldPanel?.(false)
setShowInputFieldPreviewPanel?.(false)
setInputFieldEditPanelProps?.(null)
}, [workflowStore])
const toggleInputFieldPreviewPanel = useCallback(() => {
const {
showInputFieldPreviewPanel,
setShowInputFieldPreviewPanel,
} = workflowStore.getState()
setShowInputFieldPreviewPanel?.(!showInputFieldPreviewPanel)
}, [workflowStore])
const toggleInputFieldEditPanel = useCallback((editContent: InputFieldEditorProps | null) => {
const {
setInputFieldEditPanelProps,
} = workflowStore.getState()
setInputFieldEditPanelProps?.(editContent)
}, [workflowStore])
return {
closeAllInputFieldPanels,
toggleInputFieldPreviewPanel,
toggleInputFieldEditPanel,
isPreviewing,
isEditing,
}
}

View File

@ -5,6 +5,7 @@ import {
} from '@/app/components/workflow/types'
import { useWorkflowInteractions } from '@/app/components/workflow/hooks'
import {
useInputFieldPanel,
useNodesSyncDraft,
} from '.'
@ -12,6 +13,7 @@ export const usePipelineStartRun = () => {
const workflowStore = useWorkflowStore()
const { handleCancelDebugAndPreviewPanel } = useWorkflowInteractions()
const { doSyncWorkflowDraft } = useNodesSyncDraft()
const { closeAllInputFieldPanels } = useInputFieldPanel()
const handleWorkflowStartRunInWorkflow = useCallback(async () => {
const {
@ -28,6 +30,7 @@ export const usePipelineStartRun = () => {
} = workflowStore.getState()
setShowEnvPanel(false)
closeAllInputFieldPanels()
if (showDebugAndPreviewPanel) {
handleCancelDebugAndPreviewPanel()

View File

@ -4,17 +4,20 @@ import { Env } from '@/app/components/base/icons/src/vender/line/others'
import { useStore } from '@/app/components/workflow/store'
import useTheme from '@/hooks/use-theme'
import cn from '@/utils/classnames'
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
const EnvButton = ({ disabled }: { disabled: boolean }) => {
const { theme } = useTheme()
const setShowChatVariablePanel = useStore(s => s.setShowChatVariablePanel)
const setShowEnvPanel = useStore(s => s.setShowEnvPanel)
const setShowDebugAndPreviewPanel = useStore(s => s.setShowDebugAndPreviewPanel)
const { closeAllInputFieldPanels } = useInputFieldPanel()
const handleClick = () => {
setShowEnvPanel(true)
setShowChatVariablePanel(false)
setShowDebugAndPreviewPanel(false)
closeAllInputFieldPanels()
}
return (

View File

@ -18,6 +18,7 @@ import RunAndHistory from './run-and-history'
import EditingTitle from './editing-title'
import EnvButton from './env-button'
import VersionHistoryButton from './version-history-button'
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
export type HeaderInNormalProps = {
components?: {
@ -41,6 +42,7 @@ const HeaderInNormal = ({
const nodes = useNodes<StartNodeType>()
const selectedNode = nodes.find(node => node.data.selected)
const { handleBackupDraft } = useWorkflowRun()
const { closeAllInputFieldPanels } = useInputFieldPanel()
const onStartRestoring = useCallback(() => {
workflowStore.setState({ isRestoring: true })
@ -53,6 +55,7 @@ const HeaderInNormal = ({
setShowDebugAndPreviewPanel(false)
setShowVariableInspectPanel(false)
setShowChatVariablePanel(false)
closeAllInputFieldPanels()
}, [workflowStore, handleBackupDraft, selectedNode, handleNodeSelect, setShowWorkflowVersionHistoryPanel, setShowEnvPanel, setShowDebugAndPreviewPanel, setShowVariableInspectPanel, setShowChatVariablePanel])
return (

View File

@ -38,6 +38,7 @@ import {
useWorkflowStore,
} from '@/app/components/workflow/store'
import type { WorkflowRunHistoryResponse } from '@/types/workflow'
import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks'
export type ViewHistoryProps = {
withText?: boolean
@ -65,6 +66,7 @@ const ViewHistory = ({
const setControlMode = useStore(s => s.setControlMode)
const historyWorkflowData = useStore(s => s.historyWorkflowData)
const { handleBackupDraft } = useWorkflowRun()
const { closeAllInputFieldPanels } = useInputFieldPanel()
const fetcher = historyFetcher ?? (noop as Fetcher<WorkflowRunHistoryResponse, string>)
const {
@ -168,6 +170,7 @@ const ViewHistory = ({
showInputsPanel: false,
showEnvPanel: false,
})
closeAllInputFieldPanels()
handleBackupDraft()
setOpen(false)
handleNodesCancelSelected()

View File

@ -44,7 +44,6 @@ import {
import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants'
import { CUSTOM_LOOP_START_NODE } from '@/app/components/workflow/nodes/loop-start/constants'
import { basePath } from '@/utils/var'
import { canFindTool } from '@/utils'
import { MAX_PARALLEL_LIMIT } from '@/config'
import { useNodesMetaData } from '.'
@ -527,6 +526,7 @@ export const useWorkflowReadOnly = () => {
getWorkflowReadOnly,
}
}
export const useNodesReadOnly = () => {
const workflowStore = useWorkflowStore()
const workflowRunningData = useStore(s => s.workflowRunningData)