diff --git a/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx b/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx index 92c531bd9f..dd2dd96356 100644 --- a/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx +++ b/web/app/components/workflow/nodes/question-classifier/components/class-list.tsx @@ -1,6 +1,6 @@ 'use client' import type { FC } from 'react' -import React, { useCallback } from 'react' +import React, { useCallback, useEffect, useRef, useState } from 'react' import { produce } from 'immer' import { useTranslation } from 'react-i18next' import { useEdgesInteractions } from '../../../hooks' @@ -11,9 +11,13 @@ import type { ValueSelector, Var } from '@/app/components/workflow/types' import { ReactSortable } from 'react-sortablejs' import { noop } from 'lodash-es' import cn from '@/utils/classnames' +import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid/general' const i18nPrefix = 'workflow.nodes.questionClassifiers' +// Layout constants +const HANDLE_SIDE_WIDTH = 3 // Width offset for drag handle spacing + type Props = { nodeId: string list: Topic[] @@ -33,6 +37,10 @@ const ClassList: FC = ({ }) => { const { t } = useTranslation() const { handleEdgeDeleteByDeleteBranch } = useEdgesInteractions() + const listContainerRef = useRef(null) + const [shouldScrollToEnd, setShouldScrollToEnd] = useState(false) + const prevListLength = useRef(list.length) + const [collapsed, setCollapsed] = useState(false) const handleClassChange = useCallback((index: number) => { return (value: Topic) => { @@ -48,7 +56,10 @@ const ClassList: FC = ({ draft.push({ id: `${Date.now()}`, name: '' }) }) onChange(newList) - }, [list, onChange]) + setShouldScrollToEnd(true) + if (collapsed) + setCollapsed(false) + }, [list, onChange, collapsed]) const handleRemoveClass = useCallback((index: number) => { return () => { @@ -61,57 +72,96 @@ const ClassList: FC = ({ }, [list, onChange, handleEdgeDeleteByDeleteBranch, nodeId]) const topicCount = list.length - const handleSideWidth = 3 - // Todo Remove; edit topic name + + // Scroll to the newly added item after the list updates + useEffect(() => { + if (shouldScrollToEnd && list.length > prevListLength.current) + setShouldScrollToEnd(false) + prevListLength.current = list.length + }, [list.length, shouldScrollToEnd]) + + const handleCollapse = useCallback(() => { + setCollapsed(!collapsed) + }, [collapsed]) + return ( <> - ({ ...item }))} - setList={handleSortTopic} - handle='.handle' - ghostClass='bg-components-panel-bg' - animation={150} - disabled={readonly} - className='space-y-2' - > - { - list.map((item, index) => { - const canDrag = (() => { - if (readonly) - return false +
+
+ {t(`${i18nPrefix}.class`)} * + {list.length > 0 && ( + + )} +
+
- return topicCount >= 2 - })() - return ( -
-
- -
-
- ) - }) - } -
- {!readonly && ( - + {!collapsed && ( +
+ ({ ...item }))} + setList={handleSortTopic} + handle='.handle' + ghostClass='bg-components-panel-bg' + animation={150} + disabled={readonly} + className='space-y-2' + > + { + list.map((item, index) => { + const canDrag = (() => { + if (readonly) + return false + + return topicCount >= 2 + })() + return ( +
+
+ +
+
+ ) + }) + } +
+
+ )} + {!readonly && !collapsed && ( +
+ +
)} ) diff --git a/web/app/components/workflow/nodes/question-classifier/node.tsx b/web/app/components/workflow/nodes/question-classifier/node.tsx index 87ec68b021..2da37929c8 100644 --- a/web/app/components/workflow/nodes/question-classifier/node.tsx +++ b/web/app/components/workflow/nodes/question-classifier/node.tsx @@ -1,8 +1,8 @@ import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' +import type { TFunction } from 'i18next' import type { NodeProps } from 'reactflow' -import InfoPanel from '../_base/components/info-panel' import { NodeSourceHandle } from '../_base/components/node-handle' import type { QuestionClassifierNodeType } from './types' import { @@ -10,9 +10,57 @@ import { } from '@/app/components/header/account-setting/model-provider-page/hooks' import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' import ReadonlyInputWithSelectVar from '../_base/components/readonly-input-with-select-var' +import Tooltip from '@/app/components/base/tooltip' const i18nPrefix = 'workflow.nodes.questionClassifiers' +const MAX_CLASS_TEXT_LENGTH = 50 + +type TruncatedClassItemProps = { + topic: { id: string; name: string } + index: number + nodeId: string + t: TFunction +} + +const TruncatedClassItem: FC = ({ topic, index, nodeId, t }) => { + const truncatedText = topic.name.length > MAX_CLASS_TEXT_LENGTH + ? `${topic.name.slice(0, MAX_CLASS_TEXT_LENGTH)}...` + : topic.name + + const shouldShowTooltip = topic.name.length > MAX_CLASS_TEXT_LENGTH + + const content = ( +
+ +
+ ) + + return ( +
+
+ {`${t(`${i18nPrefix}.class`)} ${index + 1}`} +
+ {shouldShowTooltip + ? ( + +
+ } + > + {content} + + ) + : content} + + ) +} + const Node: FC> = (props) => { const { t } = useTranslation() @@ -41,27 +89,26 @@ const Node: FC> = (props) => { { !!topics.length && (
- {topics.map((topic, index) => ( -
- - } - /> - -
- ))} +
+ {topics.map((topic, index) => ( +
+ + +
+ ))} +
) } diff --git a/web/app/components/workflow/nodes/question-classifier/panel.tsx b/web/app/components/workflow/nodes/question-classifier/panel.tsx index 8b6bc533f2..0e54d2712b 100644 --- a/web/app/components/workflow/nodes/question-classifier/panel.tsx +++ b/web/app/components/workflow/nodes/question-classifier/panel.tsx @@ -89,19 +89,14 @@ const Panel: FC> = ({ config={inputs.vision?.configs} onConfigChange={handleVisionResolutionChange} /> - - - +