From 5b433aa2d12e8ba177cd50580b7c9c019ea5aab9 Mon Sep 17 00:00:00 2001 From: twwu Date: Wed, 6 Aug 2025 16:59:22 +0800 Subject: [PATCH] feat: add useFloatingRight hook and integrate it into InputFieldEditorPanel and PreviewPanel for dynamic positioning --- .../panel/input-field/editor/index.tsx | 22 +++++++++-- .../components/panel/input-field/hooks.ts | 39 +++++++++++++++++++ .../panel/input-field/preview/index.tsx | 15 ++++++- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 web/app/components/rag-pipeline/components/panel/input-field/hooks.ts diff --git a/web/app/components/rag-pipeline/components/panel/input-field/editor/index.tsx b/web/app/components/rag-pipeline/components/panel/input-field/editor/index.tsx index 2e51d91806..67d589c3ff 100644 --- a/web/app/components/rag-pipeline/components/panel/input-field/editor/index.tsx +++ b/web/app/components/rag-pipeline/components/panel/input-field/editor/index.tsx @@ -1,11 +1,13 @@ import { RiCloseLine } from '@remixicon/react' import InputFieldForm from './form' import { convertFormDataToINputField, convertToInputFieldFormData } from './utils' -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import type { InputVar } from '@/models/pipeline' import type { FormData } from './form/types' import type { MoreInfo } from '@/app/components/workflow/types' +import { useFloatingRight } from '../hooks' +import cn from '@/utils/classnames' export type InputFieldEditorProps = { onClose: () => void @@ -19,7 +21,12 @@ const InputFieldEditorPanel = ({ initialData, }: InputFieldEditorProps) => { const { t } = useTranslation() - const formData = convertToInputFieldFormData(initialData) + + const { floatingRight, floatingRightWidth } = useFloatingRight(400) + + const formData = useMemo(() => { + return convertToInputFieldFormData(initialData) + }, [initialData]) const handleSubmit = useCallback((value: FormData, moreInfo?: MoreInfo) => { const inputFieldData = convertFormDataToINputField(value) @@ -27,7 +34,16 @@ const InputFieldEditorPanel = ({ }, [onSubmit]) return ( -
+
{initialData ? t('datasetPipeline.inputFieldPanel.editInputField') : t('datasetPipeline.inputFieldPanel.addInputField')}
diff --git a/web/app/components/rag-pipeline/components/panel/input-field/hooks.ts b/web/app/components/rag-pipeline/components/panel/input-field/hooks.ts new file mode 100644 index 0000000000..174d8741ee --- /dev/null +++ b/web/app/components/rag-pipeline/components/panel/input-field/hooks.ts @@ -0,0 +1,39 @@ +import { useEffect, useMemo, useState } from 'react' +import { useStore } from '@/app/components/workflow/store' +import { useStore as useReactflow } from 'reactflow' +import { useShallow } from 'zustand/react/shallow' + +export const useFloatingRight = (targetElementWidth: number) => { + const [floatingRight, setFloatingRight] = useState(false) + const nodePanelWidth = useStore(state => state.nodePanelWidth) + const workflowCanvasWidth = useStore(state => state.workflowCanvasWidth) + const otherPanelWidth = useStore(state => state.otherPanelWidth) + + const selectedNodeId = useReactflow(useShallow((s) => { + const nodes = s.getNodes() + const currentNode = nodes.find(node => node.data.selected) + + if (currentNode) + return currentNode.id + })) + + useEffect(() => { + if (typeof workflowCanvasWidth === 'number') { + const inputFieldPanelWidth = 400 + const marginRight = 4 + const leftWidth = workflowCanvasWidth - (selectedNodeId ? nodePanelWidth : 0) - otherPanelWidth - inputFieldPanelWidth - marginRight + setFloatingRight(leftWidth < targetElementWidth + marginRight) + } + }, [workflowCanvasWidth, nodePanelWidth, otherPanelWidth, selectedNodeId, targetElementWidth]) + + const floatingRightWidth = useMemo(() => { + if (!floatingRight) return targetElementWidth + const width = Math.min(targetElementWidth, (selectedNodeId ? nodePanelWidth : 0) + otherPanelWidth) + return width + }, [floatingRight, selectedNodeId, nodePanelWidth, otherPanelWidth, targetElementWidth]) + + return { + floatingRight, + floatingRightWidth, + } +} diff --git a/web/app/components/rag-pipeline/components/panel/input-field/preview/index.tsx b/web/app/components/rag-pipeline/components/panel/input-field/preview/index.tsx index 42fa0b6ddd..43b63b183a 100644 --- a/web/app/components/rag-pipeline/components/panel/input-field/preview/index.tsx +++ b/web/app/components/rag-pipeline/components/panel/input-field/preview/index.tsx @@ -7,18 +7,31 @@ import Divider from '@/app/components/base/divider' import ProcessDocuments from './process-documents' import type { Datasource } from '../../test-run/types' import { useInputFieldPanel } from '@/app/components/rag-pipeline/hooks' +import cn from '@/utils/classnames' +import { useFloatingRight } from '../hooks' const PreviewPanel = () => { const { t } = useTranslation() const [datasource, setDatasource] = useState() const { toggleInputFieldPreviewPanel } = useInputFieldPanel() + const { floatingRight, floatingRightWidth } = useFloatingRight(480) + const handleClosePreviewPanel = useCallback(() => { toggleInputFieldPreviewPanel() }, [toggleInputFieldPreviewPanel]) return ( -
+