| @@ -73,6 +73,7 @@ type Props = { | |||
| titleTooltip?: ReactNode | |||
| inputClassName?: string | |||
| editorContainerClassName?: string | |||
| placeholder?: string | |||
| placeholderClassName?: string | |||
| titleClassName?: string | |||
| required?: boolean | |||
| @@ -108,6 +109,7 @@ const Editor: FC<Props> = ({ | |||
| gradientBorder = true, | |||
| titleTooltip, | |||
| inputClassName, | |||
| placeholder, | |||
| placeholderClassName, | |||
| titleClassName, | |||
| editorContainerClassName, | |||
| @@ -223,6 +225,7 @@ const Editor: FC<Props> = ({ | |||
| <div className={cn(isExpand ? 'grow' : 'max-h-[536px]', 'relative min-h-[56px] overflow-y-auto px-3', editorContainerClassName)}> | |||
| <PromptEditor | |||
| key={controlPromptEditorRerenderKey} | |||
| placeholder={placeholder} | |||
| placeholderClassName={placeholderClassName} | |||
| instanceId={instanceId} | |||
| compact | |||
| @@ -2,28 +2,31 @@ | |||
| import type { FC } from 'react' | |||
| import React, { useCallback } from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
| import { | |||
| RiDeleteBinLine, | |||
| } from '@remixicon/react' | |||
| import type { Topic } from '../types' | |||
| import TextEditor from '../../_base/components/editor/text-editor' | |||
| import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' | |||
| import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list' | |||
| import type { ValueSelector, Var } from '@/app/components/workflow/types' | |||
| const i18nPrefix = 'workflow.nodes.questionClassifiers' | |||
| type Props = { | |||
| nodeId: string | |||
| payload: Topic | |||
| onChange: (payload: Topic) => void | |||
| onRemove: () => void | |||
| index: number | |||
| readonly?: boolean | |||
| filterVar: (payload: Var, valueSelector: ValueSelector) => boolean | |||
| } | |||
| const ClassItem: FC<Props> = ({ | |||
| nodeId, | |||
| payload, | |||
| onChange, | |||
| onRemove, | |||
| index, | |||
| readonly, | |||
| filterVar, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| @@ -31,35 +34,26 @@ const ClassItem: FC<Props> = ({ | |||
| onChange({ ...payload, name: value }) | |||
| }, [onChange, payload]) | |||
| const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { | |||
| onlyLeafNodeVar: false, | |||
| hideChatVar: false, | |||
| hideEnv: false, | |||
| filterVar, | |||
| }) | |||
| return ( | |||
| <TextEditor | |||
| isInNode | |||
| title={<div> | |||
| <div className='w-[200px]'> | |||
| <div | |||
| className='text-xs font-semibold leading-4 text-gray-700' | |||
| > | |||
| {`${t(`${i18nPrefix}.class`)} ${index}`} | |||
| </div> | |||
| </div> | |||
| </div>} | |||
| <Editor | |||
| title={`${t(`${i18nPrefix}.class`)} ${index}`} | |||
| placeholder={t(`${i18nPrefix}.topicPlaceholder`)!} | |||
| value={payload.name} | |||
| onChange={handleNameChange} | |||
| placeholder={t(`${i18nPrefix}.topicPlaceholder`)!} | |||
| headerRight={( | |||
| <div className='flex h-full items-center'> | |||
| <div className='text-xs font-medium text-gray-500'>{payload.name.length}</div> | |||
| <div className='mx-3 h-3 w-px bg-gray-200'></div> | |||
| {!readonly && ( | |||
| <RiDeleteBinLine | |||
| className='mr-1 h-3.5 w-3.5 cursor-pointer text-gray-500' | |||
| onClick={onRemove} | |||
| /> | |||
| )} | |||
| </div> | |||
| )} | |||
| readonly={readonly} | |||
| minHeight={64} | |||
| showRemove | |||
| onRemove={onRemove} | |||
| nodesOutputVars={availableVars} | |||
| availableNodes={availableNodesWithParent} | |||
| readOnly={readonly} // ? | |||
| justVar // ? | |||
| isSupportFileVar // ? | |||
| /> | |||
| ) | |||
| } | |||
| @@ -7,21 +7,24 @@ import { useEdgesInteractions } from '../../../hooks' | |||
| import AddButton from '../../_base/components/add-button' | |||
| import Item from './class-item' | |||
| import type { Topic } from '@/app/components/workflow/nodes/question-classifier/types' | |||
| import type { ValueSelector, Var } from '@/app/components/workflow/types' | |||
| const i18nPrefix = 'workflow.nodes.questionClassifiers' | |||
| type Props = { | |||
| id: string | |||
| nodeId: string | |||
| list: Topic[] | |||
| onChange: (list: Topic[]) => void | |||
| readonly?: boolean | |||
| filterVar: (payload: Var, valueSelector: ValueSelector) => boolean | |||
| } | |||
| const ClassList: FC<Props> = ({ | |||
| id, | |||
| nodeId, | |||
| list, | |||
| onChange, | |||
| readonly, | |||
| filterVar, | |||
| }) => { | |||
| const { t } = useTranslation() | |||
| const { handleEdgeDeleteByDeleteBranch } = useEdgesInteractions() | |||
| @@ -44,13 +47,13 @@ const ClassList: FC<Props> = ({ | |||
| const handleRemoveClass = useCallback((index: number) => { | |||
| return () => { | |||
| handleEdgeDeleteByDeleteBranch(id, list[index].id) | |||
| handleEdgeDeleteByDeleteBranch(nodeId, list[index].id) | |||
| const newList = produce(list, (draft) => { | |||
| draft.splice(index, 1) | |||
| }) | |||
| onChange(newList) | |||
| } | |||
| }, [list, onChange, handleEdgeDeleteByDeleteBranch, id]) | |||
| }, [list, onChange, handleEdgeDeleteByDeleteBranch, nodeId]) | |||
| // Todo Remove; edit topic name | |||
| return ( | |||
| @@ -59,12 +62,14 @@ const ClassList: FC<Props> = ({ | |||
| list.map((item, index) => { | |||
| return ( | |||
| <Item | |||
| nodeId={nodeId} | |||
| key={index} | |||
| payload={item} | |||
| onChange={handleClassChange(index)} | |||
| onRemove={handleRemoveClass(index)} | |||
| index={index + 1} | |||
| readonly={readonly} | |||
| filterVar={filterVar} | |||
| /> | |||
| ) | |||
| }) | |||
| @@ -9,13 +9,14 @@ import { | |||
| useTextGenerationCurrentProviderAndModelAndModelList, | |||
| } 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' | |||
| const i18nPrefix = 'workflow.nodes.questionClassifiers' | |||
| const Node: FC<NodeProps<QuestionClassifierNodeType>> = (props) => { | |||
| const { t } = useTranslation() | |||
| const { data } = props | |||
| const { data, id } = props | |||
| const { provider, name: modelId } = data.model | |||
| // const tempTopics = data.topics | |||
| const topics = data.classes | |||
| @@ -47,7 +48,12 @@ const Node: FC<NodeProps<QuestionClassifierNodeType>> = (props) => { | |||
| > | |||
| <InfoPanel | |||
| title={`${t(`${i18nPrefix}.class`)} ${index + 1}`} | |||
| content={topic.name} | |||
| content={ | |||
| <ReadonlyInputWithSelectVar | |||
| value={topic.name} | |||
| nodeId={id} | |||
| /> | |||
| } | |||
| /> | |||
| <NodeSourceHandle | |||
| {...props} | |||
| @@ -145,10 +145,11 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({ | |||
| title={t(`${i18nPrefix}.class`)} | |||
| > | |||
| <ClassList | |||
| id={id} | |||
| nodeId={id} | |||
| list={inputs.classes} | |||
| onChange={handleTopicsChange} | |||
| readonly={readOnly} | |||
| filterVar={filterVar} | |||
| /> | |||
| </Field> | |||
| <Split /> | |||