diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx index 9f82bdf441..7e94099d6c 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx @@ -1,187 +1,8 @@ 'use client' import type { FC } from 'react' -import React, { useEffect, useRef, useState } from 'react' -import { useHover } from 'ahooks' -import cn from 'classnames' -import { useTranslation } from 'react-i18next' -import { type NodeOutPutVar, type ValueSelector, type Var, VarType } from '@/app/components/workflow/types' -import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' -import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows' -import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' -import { - SearchLg, -} from '@/app/components/base/icons/src/vender/line/general' -import { XCircle } from '@/app/components/base/icons/src/vender/solid/general' - -type ObjectChildrenProps = { - nodeId: string - title: string - data: Var[] - objPath: string[] - onChange: (value: ValueSelector) => void - onHovering?: (value: boolean) => void - itemWidth?: number -} - -type ItemProps = { - nodeId: string - title: string - objPath: string[] - itemData: Var - onChange: (value: ValueSelector) => void - onHovering?: (value: boolean) => void - itemWidth?: number -} - -const Item: FC = ({ - nodeId, - title, - objPath, - itemData, - onChange, - onHovering, - itemWidth, -}) => { - const isObj = itemData.type === VarType.object && itemData.children && itemData.children.length > 0 - const itemRef = useRef(null) - const [isItemHovering, setIsItemHovering] = useState(false) - const _ = useHover(itemRef, { - onChange: (hovering) => { - if (hovering) { - setIsItemHovering(true) - } - else { - if (isObj) { - setTimeout(() => { - setIsItemHovering(false) - }, 100) - } - else { - setIsItemHovering(false) - } - } - }, - }) - const [isChildrenHovering, setIsChildrenHovering] = useState(false) - const isHovering = isItemHovering || isChildrenHovering - const open = isObj && isHovering - useEffect(() => { - onHovering && onHovering(isHovering) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isHovering]) - const handleChosen = (e: React.MouseEvent) => { - e.stopPropagation() - onChange([nodeId, ...objPath, itemData.variable]) - } - return ( - { }} - placement='left-start' - > - -
-
- -
{itemData.variable}
-
-
{itemData.type}
- {isObj && ( - - )} -
-
- - {isObj && ( - // eslint-disable-next-line @typescript-eslint/no-use-before-define - - )} - -
- ) -} - -const ObjectChildren: FC = ({ - title, - nodeId, - objPath, - data, - onChange, - onHovering, - itemWidth, -}) => { - const currObjPath = objPath - const itemRef = useRef(null) - const [isItemHovering, setIsItemHovering] = useState(false) - const _ = useHover(itemRef, { - onChange: (hovering) => { - if (hovering) { - setIsItemHovering(true) - } - else { - setTimeout(() => { - setIsItemHovering(false) - }, 100) - } - }, - }) - const [isChildrenHovering, setIsChildrenHovering] = useState(false) - const isHovering = isItemHovering || isChildrenHovering - useEffect(() => { - onHovering && onHovering(isHovering) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isHovering]) - useEffect(() => { - onHovering && onHovering(isItemHovering) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isItemHovering]) - // absolute top-[-2px] - return ( -
-
{title}.{currObjPath.join('.')}
- { - (data && data.length > 0) - && data.map((v, i) => ( - - )) - } -
- ) -} +import React from 'react' +import VarReferenceVars from './var-reference-vars' +import { type NodeOutPutVar, type ValueSelector } from '@/app/components/workflow/types' type Props = { vars: NodeOutPutVar[] @@ -193,72 +14,16 @@ const VarReferencePopup: FC = ({ onChange, itemWidth, }) => { - const { t } = useTranslation() - const [searchText, setSearchText] = useState('') - const filteredVars = vars.filter((v) => { - if (!searchText) - return v - const children = v.vars.filter(v => v.variable.toLowerCase().includes(searchText.toLowerCase())) - return children.length > 0 - }).map((v) => { - if (!searchText) - return v - const children = v.vars.filter(v => v.variable.toLowerCase().includes(searchText.toLowerCase())) - return { - ...v, - vars: children, - } - }) // max-h-[300px] overflow-y-auto todo: use portal to handle long list return (
-
e.stopPropagation()} - > - - setSearchText(e.target.value)} - autoFocus - /> - { - searchText && ( -
setSearchText('')} - > - -
- ) - } -
- {filteredVars.length > 0 - ?
- - { - filteredVars.map((item, i) => ( -
-
{item.title}
- {item.vars.map((v, j) => ( - - ))} -
)) - } -
- :
{t('workflow.common.noVar')}
} +
) } diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx new file mode 100644 index 0000000000..b646accc3c --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx @@ -0,0 +1,265 @@ +'use client' +import type { FC } from 'react' +import React, { useEffect, useRef, useState } from 'react' +import { useHover } from 'ahooks' +import cn from 'classnames' +import { useTranslation } from 'react-i18next' +import { type NodeOutPutVar, type ValueSelector, type Var, VarType } from '@/app/components/workflow/types' +import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' +import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows' +import { + PortalToFollowElem, + PortalToFollowElemContent, + PortalToFollowElemTrigger, +} from '@/app/components/base/portal-to-follow-elem' +import { + SearchLg, +} from '@/app/components/base/icons/src/vender/line/general' +import { XCircle } from '@/app/components/base/icons/src/vender/solid/general' + +type ObjectChildrenProps = { + nodeId: string + title: string + data: Var[] + objPath: string[] + onChange: (value: ValueSelector) => void + onHovering?: (value: boolean) => void + itemWidth?: number +} + +type ItemProps = { + nodeId: string + title: string + objPath: string[] + itemData: Var + onChange: (value: ValueSelector) => void + onHovering?: (value: boolean) => void + itemWidth?: number +} + +const Item: FC = ({ + nodeId, + title, + objPath, + itemData, + onChange, + onHovering, + itemWidth, +}) => { + const isObj = itemData.type === VarType.object && itemData.children && itemData.children.length > 0 + const itemRef = useRef(null) + const [isItemHovering, setIsItemHovering] = useState(false) + const _ = useHover(itemRef, { + onChange: (hovering) => { + if (hovering) { + setIsItemHovering(true) + } + else { + if (isObj) { + setTimeout(() => { + setIsItemHovering(false) + }, 100) + } + else { + setIsItemHovering(false) + } + } + }, + }) + const [isChildrenHovering, setIsChildrenHovering] = useState(false) + const isHovering = isItemHovering || isChildrenHovering + const open = isObj && isHovering + useEffect(() => { + onHovering && onHovering(isHovering) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isHovering]) + const handleChosen = (e: React.MouseEvent) => { + e.stopPropagation() + onChange([nodeId, ...objPath, itemData.variable]) + } + return ( + { }} + placement='left-start' + > + +
+
+ +
{itemData.variable}
+
+
{itemData.type}
+ {isObj && ( + + )} +
+
+ + {isObj && ( + // eslint-disable-next-line @typescript-eslint/no-use-before-define + + )} + +
+ ) +} + +const ObjectChildren: FC = ({ + title, + nodeId, + objPath, + data, + onChange, + onHovering, + itemWidth, +}) => { + const currObjPath = objPath + const itemRef = useRef(null) + const [isItemHovering, setIsItemHovering] = useState(false) + const _ = useHover(itemRef, { + onChange: (hovering) => { + if (hovering) { + setIsItemHovering(true) + } + else { + setTimeout(() => { + setIsItemHovering(false) + }, 100) + } + }, + }) + const [isChildrenHovering, setIsChildrenHovering] = useState(false) + const isHovering = isItemHovering || isChildrenHovering + useEffect(() => { + onHovering && onHovering(isHovering) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isHovering]) + useEffect(() => { + onHovering && onHovering(isItemHovering) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isItemHovering]) + // absolute top-[-2px] + return ( +
+
{title}.{currObjPath.join('.')}
+ { + (data && data.length > 0) + && data.map((v, i) => ( + + )) + } +
+ ) +} + +type Props = { + searchBoxClassName?: string + vars: NodeOutPutVar[] + onChange: (value: ValueSelector) => void + itemWidth?: number +} +const VarReferenceVars: FC = ({ + searchBoxClassName, + vars, + onChange, + itemWidth, +}) => { + const { t } = useTranslation() + const [searchText, setSearchText] = useState('') + const filteredVars = vars.filter((v) => { + if (!searchText) + return v + const children = v.vars.filter(v => v.variable.toLowerCase().includes(searchText.toLowerCase())) + return children.length > 0 + }).map((v) => { + if (!searchText) + return v + const children = v.vars.filter(v => v.variable.toLowerCase().includes(searchText.toLowerCase())) + return { + ...v, + vars: children, + } + }) + // max-h-[300px] overflow-y-auto todo: use portal to handle long list + return ( + <> +
e.stopPropagation()} + > + + setSearchText(e.target.value)} + autoFocus + /> + { + searchText && ( +
setSearchText('')} + > + +
+ ) + } +
+ {filteredVars.length > 0 + ?
+ + { + filteredVars.map((item, i) => ( +
+
{item.title}
+ {item.vars.map((v, j) => ( + + ))} +
)) + } +
+ :
{t('workflow.common.noVar')}
} + + ) +} +export default React.memo(VarReferenceVars)