feat: add useFloatingRight hook and integrate it into InputFieldEditorPanel and PreviewPanel for dynamic positioning

This commit is contained in:
twwu 2025-08-06 16:59:22 +08:00
parent 218e778099
commit 5b433aa2d1
3 changed files with 72 additions and 4 deletions

View File

@ -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 (
<div className='relative mr-1 flex h-fit max-h-full w-[400px] flex-col overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-2xl shadow-shadow-shadow-9'>
<div
className={cn(
'relative mr-1 flex h-fit max-h-full w-[400px] flex-col overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-2xl shadow-shadow-shadow-9',
'transition-all duration-300 ease-in-out',
floatingRight && 'absolute right-0 z-[100]',
)}
style={{
width: `${floatingRightWidth}px`,
}}
>
<div className='system-xl-semibold flex items-center pb-1 pl-4 pr-11 pt-3.5 text-text-primary'>
{initialData ? t('datasetPipeline.inputFieldPanel.editInputField') : t('datasetPipeline.inputFieldPanel.addInputField')}
</div>

View File

@ -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,
}
}

View File

@ -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<Datasource>()
const { toggleInputFieldPreviewPanel } = useInputFieldPanel()
const { floatingRight, floatingRightWidth } = useFloatingRight(480)
const handleClosePreviewPanel = useCallback(() => {
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'>
<div
className={cn(
'mr-1 flex h-full 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',
'transition-all duration-300 ease-in-out',
floatingRight && 'absolute right-0 z-[100]',
)}
style={{
width: `${floatingRightWidth}px`,
}}
>
<div className='flex items-center gap-x-2 px-4 pt-1'>
<div className='grow py-1'>
<Badge className='border-text-accent-secondary bg-components-badge-bg-dimm text-text-accent-secondary'>