refactor(workflow): streamline node metadata structure and enhance filtering logic

This commit is contained in:
twwu 2025-09-11 16:02:06 +08:00
parent 9458ebe320
commit 274e7f4f09
15 changed files with 86 additions and 76 deletions

View File

@ -19,26 +19,9 @@ export const useAvailableNodesMetaData = () => {
...dataSourceDefault.defaultValue,
_dataSourceStartToAdd: true,
},
metaData: {
...dataSourceDefault.metaData,
isStart: true,
isRequired: true,
},
},
{
...knowledgeBaseDefault,
metaData: {
...knowledgeBaseDefault.metaData,
isRequired: true,
},
},
{
...dataSourceEmptyDefault,
metaData: {
...dataSourceEmptyDefault.metaData,
isUndeletable: true,
},
},
knowledgeBaseDefault,
dataSourceEmptyDefault,
], [])
const prefixLink = useMemo(() => {

View File

@ -15,35 +15,11 @@ export const useAvailableNodesMetaData = () => {
const mergedNodesMetaData = useMemo(() => [
...WORKFLOW_COMMON_NODES,
{
...StartDefault,
metaData: {
...StartDefault.metaData,
isStart: true,
isRequired: true,
isUndeletable: true,
},
},
StartDefault,
...(
isChatMode
? [
{
...AnswerDefault,
metaData: {
...AnswerDefault.metaData,
isRequired: true,
},
},
]
: [
{
...EndDefault,
metaData: {
...EndDefault.metaData,
isRequired: true,
},
},
]
? [AnswerDefault]
: [EndDefault]
),
], [isChatMode])

View File

@ -1256,15 +1256,26 @@ export const useNodesInteractions = () => {
}
else {
// If no nodeId is provided, fall back to the current behavior
const bundledNodes = nodes.filter(node => node.data._isBundled && node.data.type !== BlockEnum.Start && node.data.type !== BlockEnum.DataSource && node.data.type !== BlockEnum.KnowledgeBase && node.data.type !== BlockEnum.DataSourceEmpty
&& !node.data.isInIteration && !node.data.isInLoop)
const bundledNodes = nodes.filter((node) => {
if (!node.data._isBundled)
return false
const { metaData } = nodesMetaDataMap![node.data.type as BlockEnum]
if (metaData.isSingleton)
return false
return !node.data.isInIteration && !node.data.isInLoop
})
if (bundledNodes.length) {
setClipboardElements(bundledNodes)
return
}
const selectedNode = nodes.find(node => node.data.selected && node.data.type !== BlockEnum.Start && node.data.type !== BlockEnum.LoopEnd && node.data.type !== BlockEnum.DataSource)
const selectedNode = nodes.find((node) => {
if (!node.data.selected)
return false
const { metaData } = nodesMetaDataMap![node.data.type as BlockEnum]
return !metaData.isSingleton
})
if (selectedNode)
setClipboardElements([selectedNode])

View File

@ -16,7 +16,6 @@ import {
} from '@/app/components/workflow/hooks'
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
import type { Node } from '@/app/components/workflow/types'
import { BlockEnum } from '@/app/components/workflow/types'
type PanelOperatorPopupProps = {
id: string
@ -43,7 +42,7 @@ const PanelOperatorPopup = ({
const { nodesReadOnly } = useNodesReadOnly()
const edge = edges.find(edge => edge.target === id)
const nodeMetaData = useNodeMetaData({ id, data } as Node)
const showChangeBlock = data.type !== BlockEnum.Start && !nodesReadOnly && data.type !== BlockEnum.Iteration && data.type !== BlockEnum.Loop
const showChangeBlock = !nodeMetaData.isTypeFixed && !nodesReadOnly
const isChildNode = !!(data.isInIteration || data.isInLoop)
return (
@ -85,31 +84,37 @@ const PanelOperatorPopup = ({
)
}
{
data.type !== BlockEnum.Start && !nodesReadOnly && (
!nodesReadOnly && (
<>
<div className='p-1'>
<div
className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
onClick={() => {
onClosePopup()
handleNodesCopy(id)
}}
>
{t('workflow.common.copy')}
<ShortcutsName keys={['ctrl', 'c']} />
</div>
<div
className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
onClick={() => {
onClosePopup()
handleNodesDuplicate(id)
}}
>
{t('workflow.common.duplicate')}
<ShortcutsName keys={['ctrl', 'd']} />
</div>
</div>
<div className='h-px bg-divider-regular'></div>
{
!nodeMetaData.isSingleton && (
<>
<div className='p-1'>
<div
className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
onClick={() => {
onClosePopup()
handleNodesCopy(id)
}}
>
{t('workflow.common.copy')}
<ShortcutsName keys={['ctrl', 'c']} />
</div>
<div
className='flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary hover:bg-state-base-hover'
onClick={() => {
onClosePopup()
handleNodesDuplicate(id)
}}
>
{t('workflow.common.duplicate')}
<ShortcutsName keys={['ctrl', 'd']} />
</div>
</div>
<div className='h-px bg-divider-regular'></div>
</>
)
}
{
!nodeMetaData.isUndeletable && (
<>
@ -117,7 +122,7 @@ const PanelOperatorPopup = ({
<div
className={`
flex h-8 cursor-pointer items-center justify-between rounded-lg px-3 text-sm text-text-secondary
hover:bg-state-destructive-hover hover:text-red-500
hover:bg-state-destructive-hover hover:text-text-destructive
`}
onClick={() => handleNodeDelete(id)}
>

View File

@ -6,6 +6,7 @@ import { BlockEnum } from '@/app/components/workflow/types'
const metaData = genNodeMetaData({
sort: 2.1,
type: BlockEnum.Answer,
isRequired: true,
})
const nodeDefault: NodeDefault<AnswerNodeType> = {
metaData,

View File

@ -6,6 +6,8 @@ import { BlockEnum } from '@/app/components/workflow/types'
const metaData = genNodeMetaData({
sort: -1,
type: BlockEnum.DataSourceEmpty,
isUndeletable: true,
isSingleton: true,
})
const nodeDefault: NodeDefault<DataSourceEmptyNodeType> = {
metaData,

View File

@ -15,6 +15,8 @@ const i18nPrefix = 'workflow.errorMsg'
const metaData = genNodeMetaData({
sort: -1,
type: BlockEnum.DataSource,
isStart: true,
isRequired: true,
})
const nodeDefault: NodeDefault<DataSourceNodeType> = {
metaData,

View File

@ -6,6 +6,7 @@ import { BlockEnum } from '@/app/components/workflow/types'
const metaData = genNodeMetaData({
sort: 2.1,
type: BlockEnum.End,
isRequired: true,
})
const nodeDefault: NodeDefault<EndNodeType> = {
metaData,

View File

@ -9,6 +9,7 @@ const metaData = genNodeMetaData({
classification: BlockClassificationEnum.Logic,
sort: 2,
type: BlockEnum.Iteration,
isTypeFixed: true,
})
const nodeDefault: NodeDefault<IterationNodeType> = {
metaData,

View File

@ -6,6 +6,10 @@ import { BlockEnum } from '@/app/components/workflow/types'
const metaData = genNodeMetaData({
sort: 3.1,
type: BlockEnum.KnowledgeBase,
isRequired: true,
isUndeletable: true,
isSingleton: true,
isTypeFixed: true,
})
const nodeDefault: NodeDefault<KnowledgeBaseNodeType> = {
metaData,

View File

@ -10,6 +10,7 @@ const metaData = genNodeMetaData({
classification: BlockClassificationEnum.Logic,
sort: 2,
type: BlockEnum.LoopEnd,
isSingleton: true,
})
const nodeDefault: NodeDefault<SimpleNodeType> = {
metaData,

View File

@ -14,6 +14,7 @@ const metaData = genNodeMetaData({
sort: 3,
type: BlockEnum.Loop,
author: 'AICT-Team',
isTypeFixed: true,
})
const nodeDefault: NodeDefault<LoopNodeType> = {
metaData,

View File

@ -6,6 +6,11 @@ import { BlockEnum } from '@/app/components/workflow/types'
const metaData = genNodeMetaData({
sort: 0.1,
type: BlockEnum.Start,
isStart: true,
isRequired: true,
isUndeletable: true,
isSingleton: true,
isTypeFixed: true,
})
const nodeDefault: NodeDefault<StartNodeType> = {
metaData,

View File

@ -329,6 +329,8 @@ export type NodeDefault<T = {}> = {
isRequired?: boolean
isUndeletable?: boolean
isStart?: boolean
isSingleton?: boolean
isTypeFixed?: boolean
}
defaultValue: Partial<T>
defaultRunInputData?: Record<string, any>

View File

@ -8,6 +8,11 @@ export type GenNodeMetaDataParams = {
title?: string
author?: string
helpLinkUri?: string
isRequired?: boolean
isUndeletable?: boolean
isStart?: boolean
isSingleton?: boolean
isTypeFixed?: boolean
}
export const genNodeMetaData = ({
classification = BlockClassificationEnum.Default,
@ -16,6 +21,11 @@ export const genNodeMetaData = ({
title = '',
author = 'Dify',
helpLinkUri,
isRequired = false,
isUndeletable = false,
isStart = false,
isSingleton = false,
isTypeFixed = false,
}: GenNodeMetaDataParams) => {
return {
classification,
@ -24,5 +34,10 @@ export const genNodeMetaData = ({
title,
author,
helpLinkUri: helpLinkUri || type,
isRequired,
isUndeletable,
isStart,
isSingleton,
isTypeFixed,
}
}