mirror of https://github.com/langgenius/dify.git
node about author
This commit is contained in:
parent
597053c30e
commit
328a3e2e6b
|
|
@ -42,7 +42,7 @@ const nodes = [
|
|||
type: 'custom',
|
||||
position: { x: 330, y: 30 + i * 300 },
|
||||
data: {
|
||||
_selected: i === 0, // for test: always select the first node
|
||||
selected: i === 0, // for test: always select the first node
|
||||
name: item,
|
||||
...payload,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { BlockEnum } from './types'
|
||||
import { useStore } from './store'
|
||||
import {
|
||||
Code,
|
||||
DirectAnswer,
|
||||
|
|
@ -20,7 +21,7 @@ type BlockIconProps = {
|
|||
type: BlockEnum
|
||||
size?: string
|
||||
className?: string
|
||||
icon?: any
|
||||
toolProviderId?: string
|
||||
}
|
||||
const ICON_CONTAINER_CLASSNAME_SIZE_MAP: Record<string, string> = {
|
||||
sm: 'w-5 h-5 rounded-md shadow-xs',
|
||||
|
|
@ -59,8 +60,11 @@ const BlockIcon: FC<BlockIconProps> = ({
|
|||
type,
|
||||
size = 'sm',
|
||||
className,
|
||||
icon,
|
||||
toolProviderId,
|
||||
}) => {
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const icon = toolsets.find(toolset => toolset.id === toolProviderId)?.icon
|
||||
|
||||
return (
|
||||
<div className={`
|
||||
flex items-center justify-center border-[0.5px] border-white/[0.02] text-white
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ const Tools = ({
|
|||
setToolsets(produce(toolsets, (draft) => {
|
||||
const index = draft.findIndex(toolset => toolset.id === toolId)
|
||||
|
||||
if (!toolsMap[toolId].length && !currentToolset.fetching)
|
||||
if (!toolsMap[toolId]?.length && !currentToolset.fetching)
|
||||
draft[index].fetching = true
|
||||
|
||||
draft[index].expanded = true
|
||||
|
|
|
|||
|
|
@ -106,9 +106,6 @@ const Item = ({
|
|||
provider_type: data.type,
|
||||
tool_name: tool.name,
|
||||
title: tool.label[language],
|
||||
_icon: data.icon,
|
||||
_about: tool.description[language],
|
||||
_author: data.author,
|
||||
})}
|
||||
>
|
||||
<div className='absolute left-[22px] w-[1px] h-8 bg-black/5' />
|
||||
|
|
|
|||
|
|
@ -30,7 +30,4 @@ export type ToolDefaultValue = {
|
|||
provider_type: string
|
||||
tool_name: string
|
||||
title: string
|
||||
_icon: Collection['icon']
|
||||
_about: string
|
||||
_author: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,30 +12,77 @@ import ToolDefault from './nodes/tool/default'
|
|||
import VariableAssignerDefault from './nodes/variable-assigner/default'
|
||||
import EndNodeDefault from './nodes/end/default'
|
||||
|
||||
export const NODES_EXTRA_DATA = {
|
||||
[BlockEnum.Start]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.End]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.DirectAnswer]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.LLM]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.KnowledgeRetrieval]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.IfElse]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.Code]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.TemplateTransform]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.QuestionClassifier]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.HttpRequest]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.VariableAssigner]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
[BlockEnum.Tool]: {
|
||||
author: 'Dify',
|
||||
about: '',
|
||||
},
|
||||
}
|
||||
|
||||
export const NODES_INITIAL_DATA = {
|
||||
[BlockEnum.Start]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.Start,
|
||||
title: '',
|
||||
desc: '',
|
||||
...StartNodeDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.End]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.End,
|
||||
title: '',
|
||||
desc: '',
|
||||
...EndNodeDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.DirectAnswer]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.DirectAnswer,
|
||||
title: '',
|
||||
desc: '',
|
||||
...DirectAnswerDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.LLM]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.LLM,
|
||||
title: '',
|
||||
desc: '',
|
||||
|
|
@ -43,7 +90,6 @@ export const NODES_INITIAL_DATA = {
|
|||
...LLMDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.KnowledgeRetrieval]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.KnowledgeRetrieval,
|
||||
title: '',
|
||||
desc: '',
|
||||
|
|
@ -53,14 +99,12 @@ export const NODES_INITIAL_DATA = {
|
|||
...KnowledgeRetrievalDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.IfElse]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.IfElse,
|
||||
title: '',
|
||||
desc: '',
|
||||
...IfElseDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.Code]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.Code,
|
||||
title: '',
|
||||
desc: '',
|
||||
|
|
@ -71,7 +115,6 @@ export const NODES_INITIAL_DATA = {
|
|||
...CodeDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.TemplateTransform]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.TemplateTransform,
|
||||
title: '',
|
||||
desc: '',
|
||||
|
|
@ -80,7 +123,6 @@ export const NODES_INITIAL_DATA = {
|
|||
...TemplateTransformDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.QuestionClassifier]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.QuestionClassifier,
|
||||
title: '',
|
||||
desc: '',
|
||||
|
|
@ -89,7 +131,6 @@ export const NODES_INITIAL_DATA = {
|
|||
...QuestionClassifierDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.HttpRequest]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.HttpRequest,
|
||||
title: '',
|
||||
desc: '',
|
||||
|
|
@ -97,7 +138,6 @@ export const NODES_INITIAL_DATA = {
|
|||
...HttpRequestDefault.defaultValue,
|
||||
},
|
||||
[BlockEnum.VariableAssigner]: {
|
||||
_author: 'Dify',
|
||||
type: BlockEnum.VariableAssigner,
|
||||
title: '',
|
||||
desc: '',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import produce from 'immer'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import type {
|
||||
EdgeMouseHandler,
|
||||
NodeDragHandler,
|
||||
|
|
@ -21,7 +21,10 @@ import type {
|
|||
BlockEnum,
|
||||
Node,
|
||||
} from './types'
|
||||
import { NODES_INITIAL_DATA } from './constants'
|
||||
import {
|
||||
NODES_EXTRA_DATA,
|
||||
NODES_INITIAL_DATA,
|
||||
} from './constants'
|
||||
import { getLayoutByDagre } from './utils'
|
||||
import { useStore } from './store'
|
||||
import type { ToolDefaultValue } from './block-selector/types'
|
||||
|
|
@ -45,13 +48,23 @@ export const useNodesInitialData = () => {
|
|||
})
|
||||
}
|
||||
|
||||
export const useNodesExtraData = () => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return produce(NODES_EXTRA_DATA, (draft) => {
|
||||
Object.keys(draft).forEach((key) => {
|
||||
draft[key as BlockEnum].about = t(`workflow.blocksAbout.${key}`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export const useWorkflow = () => {
|
||||
const store = useStoreApi()
|
||||
const reactFlow = useReactFlow()
|
||||
const nodesInitialData = useNodesInitialData()
|
||||
const featuresStore = useFeaturesStore()
|
||||
|
||||
const handleSyncWorkflowDraft = useCallback(debounce(() => {
|
||||
const shouldDebouncedSyncWorkflowDraft = () => {
|
||||
const {
|
||||
getNodes,
|
||||
edges,
|
||||
|
|
@ -84,7 +97,12 @@ export const useWorkflow = () => {
|
|||
useStore.setState({ draftUpdatedAt: res.updated_at })
|
||||
})
|
||||
}
|
||||
}, 2000, { trailing: true }), [store, reactFlow, featuresStore])
|
||||
}
|
||||
|
||||
const { run: handleSyncWorkflowDraft } = useDebounceFn(shouldDebouncedSyncWorkflowDraft, {
|
||||
wait: 2000,
|
||||
trailing: true,
|
||||
})
|
||||
|
||||
const handleLayout = useCallback(async () => {
|
||||
const {
|
||||
|
|
@ -203,17 +221,17 @@ export const useWorkflow = () => {
|
|||
} = store.getState()
|
||||
|
||||
const nodes = getNodes()
|
||||
const selectedNode = nodes.find(node => node.data._selected)
|
||||
const selectedNode = nodes.find(node => node.data.selected)
|
||||
|
||||
if (!cancelSelection && selectedNode?.id === nodeId)
|
||||
return
|
||||
|
||||
const newNodes = produce(getNodes(), (draft) => {
|
||||
draft.forEach(node => node.data._selected = false)
|
||||
draft.forEach(node => node.data.selected = false)
|
||||
const selectedNode = draft.find(node => node.id === nodeId)!
|
||||
|
||||
if (!cancelSelection)
|
||||
selectedNode.data._selected = true
|
||||
selectedNode.data.selected = true
|
||||
})
|
||||
setNodes(newNodes)
|
||||
handleSyncWorkflowDraft()
|
||||
|
|
@ -312,7 +330,7 @@ export const useWorkflow = () => {
|
|||
data: {
|
||||
...nodesInitialData[nodeType],
|
||||
...(toolDefaultValue || {}),
|
||||
_selected: true,
|
||||
selected: true,
|
||||
},
|
||||
position: {
|
||||
x: currentNode.position.x + 304,
|
||||
|
|
@ -330,7 +348,7 @@ export const useWorkflow = () => {
|
|||
}
|
||||
const newNodes = produce(nodes, (draft) => {
|
||||
draft.forEach((node) => {
|
||||
node.data._selected = false
|
||||
node.data.selected = false
|
||||
})
|
||||
draft.push(nextNode)
|
||||
})
|
||||
|
|
@ -364,7 +382,7 @@ export const useWorkflow = () => {
|
|||
data: {
|
||||
...nodesInitialData[nodeType],
|
||||
...(toolDefaultValue || {}),
|
||||
_selected: currentNode.data._selected,
|
||||
selected: currentNode.data.selected,
|
||||
},
|
||||
position: {
|
||||
x: currentNode.position.x,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ const NextStep = ({
|
|||
<div className='shrink-0 relative flex items-center justify-center w-9 h-9 bg-white rounded-lg border-[0.5px] border-gray-200 shadow-xs'>
|
||||
<BlockIcon
|
||||
type={selectedNode!.data.type}
|
||||
icon={selectedNode!.data._icon}
|
||||
toolProviderId={selectedNode!.data.provider_id}
|
||||
/>
|
||||
</div>
|
||||
<Line linesNumber={branches ? branches.length : 1} />
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ const Item = ({
|
|||
}
|
||||
<BlockIcon
|
||||
type={data.type}
|
||||
icon={data._icon}
|
||||
toolProviderId={data.provider_id}
|
||||
className='shrink-0 mr-1.5'
|
||||
/>
|
||||
<div className='grow'>{data.title}</div>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import produce from 'immer'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useEdges } from 'reactflow'
|
||||
import ChangeBlock from './change-block'
|
||||
import { useWorkflow } from '@/app/components/workflow/hooks'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import {
|
||||
useNodesExtraData,
|
||||
useWorkflow,
|
||||
} from '@/app/components/workflow/hooks'
|
||||
import { DotsHorizontal } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
|
|
@ -14,6 +23,12 @@ import {
|
|||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import type { Node } from '@/app/components/workflow/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import I18n from '@/context/i18n'
|
||||
import { getLanguage } from '@/i18n/language'
|
||||
import {
|
||||
fetchBuiltInToolList,
|
||||
fetchCustomToolList,
|
||||
} from '@/service/tools'
|
||||
|
||||
type PanelOperatorProps = {
|
||||
id: string
|
||||
|
|
@ -24,12 +39,53 @@ const PanelOperator = ({
|
|||
data,
|
||||
}: PanelOperatorProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { locale } = useContext(I18n)
|
||||
const language = getLanguage(locale)
|
||||
const edges = useEdges()
|
||||
const { handleNodeDelete } = useWorkflow()
|
||||
const nodesExtraData = useNodesExtraData()
|
||||
const toolsets = useStore(s => s.toolsets)
|
||||
const toolsMap = useStore(s => s.toolsMap)
|
||||
const setToolsMap = useStore(s => s.setToolsMap)
|
||||
const [open, setOpen] = useState(false)
|
||||
const fetchToolList = useMemo(() => {
|
||||
const toolset = toolsets.find(toolset => toolset.id === data.provider_id)
|
||||
return toolset?.type === 'api' ? fetchCustomToolList : fetchBuiltInToolList
|
||||
}, [toolsets, data.provider_id])
|
||||
|
||||
const handleGetAbout = useCallback(() => {
|
||||
if (data.provider_id && !toolsMap[data.provider_id]?.length) {
|
||||
fetchToolList(data.provider_id).then((list: any) => {
|
||||
setToolsMap(produce(toolsMap, (draft) => {
|
||||
draft[data.provider_id as string] = list
|
||||
}))
|
||||
})
|
||||
}
|
||||
}, [data, toolsMap, fetchToolList, setToolsMap])
|
||||
useEffect(() => {
|
||||
handleGetAbout()
|
||||
}, [handleGetAbout])
|
||||
|
||||
const edge = edges.find(edge => edge.target === id)
|
||||
|
||||
const author = useMemo(() => {
|
||||
if (data.type !== BlockEnum.Tool)
|
||||
return nodesExtraData[data.type].author
|
||||
|
||||
const toolset = toolsets.find(toolset => toolset.id === data.provider_id)
|
||||
|
||||
return toolset?.author
|
||||
}, [data, nodesExtraData, toolsets])
|
||||
|
||||
const about = useMemo(() => {
|
||||
if (data.type !== BlockEnum.Tool)
|
||||
return nodesExtraData[data.type].about
|
||||
|
||||
const tool = toolsMap[data.provider_id as string]?.find(tool => tool.name === data.tool_name)
|
||||
|
||||
return tool?.description[language] || ''
|
||||
}, [data, nodesExtraData, toolsMap, language])
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
placement='bottom-end'
|
||||
|
|
@ -83,10 +139,10 @@ const PanelOperator = ({
|
|||
<div className='flex items-center mb-1 h-[22px] font-medium'>
|
||||
{t('workflow.panel.about')}
|
||||
</div>
|
||||
<div className='text-gray-500 leading-[18px]'>{data._about}</div>
|
||||
<div className='text-gray-500 leading-[18px]'>{about}</div>
|
||||
<div className='my-2 h-[0.5px] bg-black/5'></div>
|
||||
<div className='leading-[18px]'>
|
||||
{t('workflow.panel.createdBy')} {data._author}
|
||||
{t('workflow.panel.createdBy')} {author}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
<div
|
||||
className={`
|
||||
flex border-[2px] rounded-2xl
|
||||
${data._selected ? 'border-primary-600' : 'border-transparent'}
|
||||
${data.selected ? 'border-primary-600' : 'border-transparent'}
|
||||
`}
|
||||
>
|
||||
<div
|
||||
|
|
@ -75,7 +75,7 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
className='shrink-0 mr-2'
|
||||
type={data.type}
|
||||
size='md'
|
||||
icon={data._icon}
|
||||
toolProviderId={data.provider_id}
|
||||
/>
|
||||
<div
|
||||
title={data.title}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ const BasePanel: FC<BasePanelProps> = ({
|
|||
<BlockIcon
|
||||
className='shrink-0 mr-1'
|
||||
type={data.type}
|
||||
icon={data._icon}
|
||||
toolProviderId={data.provider_id}
|
||||
size='md'
|
||||
/>
|
||||
<TitleInput
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const Panel: FC = () => {
|
|||
const isChatMode = useIsChatMode()
|
||||
const runTaskId = useStore(state => state.runTaskId)
|
||||
const nodes = useNodes<CommonNodeType>()
|
||||
const selectedNode = nodes.find(node => node.data._selected)
|
||||
const selectedNode = nodes.find(node => node.data.selected)
|
||||
const showRunHistory = useStore(state => state.showRunHistory)
|
||||
const {
|
||||
showWorkflowInfoPanel,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import type {
|
|||
Edge as ReactFlowEdge,
|
||||
Node as ReactFlowNode,
|
||||
} from 'reactflow'
|
||||
import type { Collection } from '@/app/components/tools/types'
|
||||
import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types'
|
||||
|
||||
export enum BlockEnum {
|
||||
|
|
@ -26,16 +25,13 @@ export type Branch = {
|
|||
}
|
||||
|
||||
export type CommonNodeType<T = {}> = {
|
||||
_selected?: boolean
|
||||
_targetBranches?: Branch[]
|
||||
_isSingleRun?: boolean
|
||||
_icon?: Collection['icon']
|
||||
_about?: string
|
||||
_author?: string
|
||||
selected?: boolean
|
||||
title: string
|
||||
desc: string
|
||||
type: BlockEnum
|
||||
} & T
|
||||
} & T & Partial<Pick<ToolDefaultValue, 'provider_id' | 'provider_type' | 'tool_name'>>
|
||||
|
||||
export type CommonEdgeType = {
|
||||
_hovering: boolean
|
||||
|
|
|
|||
|
|
@ -50,6 +50,19 @@ const translation = {
|
|||
'http-request': 'HTTP Request',
|
||||
'variable-assigner': 'Variable Assigner',
|
||||
},
|
||||
blocksAbout: {
|
||||
'start': 'Define the initial parameters for launching a workflow',
|
||||
'end': 'Define the end and result type of a workflow',
|
||||
'direct-answer': 'Specify a custom text reply',
|
||||
'llm': 'Invoking large language models to answer questions or process natural language',
|
||||
'knowledge-retrieval': 'Allows you to query text content related to user questions from the Knowledge',
|
||||
'question-classifier': 'Define the classification conditions of user questions, LLM can define how the conversation progresses based on the classification description',
|
||||
'if-else': 'Allows you to split the workflow into two branches based on if/else conditions',
|
||||
'code': 'Execute a piece of Python or NodeJS code to implement custom logic',
|
||||
'template-transform': 'Convert data to string using Jinja template syntax',
|
||||
'http-request': 'Allow server requests to be sent over the HTTP protocol',
|
||||
'variable-assigner': 'Assign variables in different branches to the same variable to achieve unified configuration of post-nodes',
|
||||
},
|
||||
operator: {
|
||||
zoomIn: 'Zoom In',
|
||||
zoomOut: 'Zoom Out',
|
||||
|
|
|
|||
|
|
@ -50,6 +50,19 @@ const translation = {
|
|||
'http-request': 'HTTP 请求',
|
||||
'variable-assigner': '变量赋值',
|
||||
},
|
||||
blocksAbout: {
|
||||
'start': '定义一个 workflow 流程启动的初始参数',
|
||||
'end': '定义一个 workflow 流程的结束和结果类型',
|
||||
'direct-answer': '指定一段自定义的文本回复',
|
||||
'llm': '调用大语言模型回答问题或者对自然语言进行处理',
|
||||
'knowledge-retrieval': '允许你从知识库中查询与用户问题相关的文本内容',
|
||||
'question-classifier': '定义用户问题的分类条件,LLM 能够根据分类描述定义对话的进展方式',
|
||||
'if-else': '允许你根据 if/else 条件将 workflow 拆分成两个分支',
|
||||
'code': '执行一段 Python 或 NodeJS 代码实现自定义逻辑',
|
||||
'template-transform': '使用 Jinja 模板语法将数据转换为字符串',
|
||||
'http-request': '允许通过 HTTP 协议发送服务器请求',
|
||||
'variable-assigner': '将不同分支中的变量指派给同一个变量,以实现后置节点统一配置',
|
||||
},
|
||||
operator: {
|
||||
zoomIn: '放大',
|
||||
zoomOut: '缩小',
|
||||
|
|
|
|||
Loading…
Reference in New Issue