mirror of
https://github.com/langgenius/dify.git
synced 2026-04-28 03:36:36 +08:00
checklist
This commit is contained in:
parent
cf73faf174
commit
eff123a11c
@ -1,4 +1,8 @@
|
|||||||
import { memo } from 'react'
|
import {
|
||||||
|
memo,
|
||||||
|
useCallback,
|
||||||
|
useState,
|
||||||
|
} from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RiArrowDownSLine } from '@remixicon/react'
|
import { RiArrowDownSLine } from '@remixicon/react'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
@ -7,20 +11,31 @@ import {
|
|||||||
PortalToFollowElemContent,
|
PortalToFollowElemContent,
|
||||||
PortalToFollowElemTrigger,
|
PortalToFollowElemTrigger,
|
||||||
} from '@/app/components/base/portal-to-follow-elem'
|
} from '@/app/components/base/portal-to-follow-elem'
|
||||||
|
import { useNodesSyncDraft } from '@/app/components/workflow/hooks'
|
||||||
import Popup from './popup'
|
import Popup from './popup'
|
||||||
|
|
||||||
const Publisher = () => {
|
const Publisher = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
|
||||||
|
|
||||||
|
const handleOpenChange = useCallback((newOpen: boolean) => {
|
||||||
|
if (newOpen)
|
||||||
|
handleSyncWorkflowDraft()
|
||||||
|
setOpen(newOpen)
|
||||||
|
}, [handleSyncWorkflowDraft])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PortalToFollowElem
|
<PortalToFollowElem
|
||||||
|
open={open}
|
||||||
|
onOpenChange={setOpen}
|
||||||
placement='bottom-end'
|
placement='bottom-end'
|
||||||
offset={{
|
offset={{
|
||||||
mainAxis: 4,
|
mainAxis: 4,
|
||||||
crossAxis: 40,
|
crossAxis: 40,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PortalToFollowElemTrigger>
|
<PortalToFollowElemTrigger onClick={() => handleOpenChange(!open)}>
|
||||||
<Button variant='primary'>
|
<Button variant='primary'>
|
||||||
{t('workflow.common.publish')}
|
{t('workflow.common.publish')}
|
||||||
<RiArrowDownSLine className='h-4 w-4' />
|
<RiArrowDownSLine className='h-4 w-4' />
|
||||||
|
|||||||
@ -9,11 +9,22 @@ import {
|
|||||||
RiPlayCircleLine,
|
RiPlayCircleLine,
|
||||||
RiTerminalBoxLine,
|
RiTerminalBoxLine,
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
|
import { useKeyPress } from 'ahooks'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useStore } from '@/app/components/workflow/store'
|
import {
|
||||||
|
useStore,
|
||||||
|
useWorkflowStore,
|
||||||
|
} from '@/app/components/workflow/store'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
import { useFormatTimeFromNow } from '@/app/components/workflow/hooks'
|
import {
|
||||||
|
useChecklistBeforePublish,
|
||||||
|
useFormatTimeFromNow,
|
||||||
|
} from '@/app/components/workflow/hooks'
|
||||||
import Divider from '@/app/components/base/divider'
|
import Divider from '@/app/components/base/divider'
|
||||||
|
import { getKeyboardKeyCodeBySystem } from '@/app/components/workflow/utils'
|
||||||
|
import { usePublishWorkflow } from '@/service/use-workflow'
|
||||||
|
import type { PublishWorkflowParams } from '@/types/workflow'
|
||||||
|
import { useToastContext } from '@/app/components/base/toast'
|
||||||
|
|
||||||
const PUBLISH_SHORTCUT = ['⌘', '⇧', 'P']
|
const PUBLISH_SHORTCUT = ['⌘', '⇧', 'P']
|
||||||
|
|
||||||
@ -22,16 +33,40 @@ const Popup = () => {
|
|||||||
const [published, setPublished] = useState(false)
|
const [published, setPublished] = useState(false)
|
||||||
const publishedAt = useStore(s => s.publishedAt)
|
const publishedAt = useStore(s => s.publishedAt)
|
||||||
const draftUpdatedAt = useStore(s => s.draftUpdatedAt)
|
const draftUpdatedAt = useStore(s => s.draftUpdatedAt)
|
||||||
|
const pipelineId = useStore(s => s.pipelineId)
|
||||||
const { formatTimeFromNow } = useFormatTimeFromNow()
|
const { formatTimeFromNow } = useFormatTimeFromNow()
|
||||||
|
const { handleCheckBeforePublish } = useChecklistBeforePublish()
|
||||||
|
const { mutateAsync: publishWorkflow } = usePublishWorkflow()
|
||||||
|
const { notify } = useToastContext()
|
||||||
|
const workflowStore = useWorkflowStore()
|
||||||
|
|
||||||
const handlePublish = useCallback(async () => {
|
const handlePublish = useCallback(async (params?: PublishWorkflowParams) => {
|
||||||
try {
|
if (await handleCheckBeforePublish()) {
|
||||||
|
const res = await publishWorkflow({
|
||||||
|
url: `/rag/pipelines/${pipelineId}/workflows/publish`,
|
||||||
|
title: params?.title || '',
|
||||||
|
releaseNotes: params?.releaseNotes || '',
|
||||||
|
})
|
||||||
setPublished(true)
|
setPublished(true)
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
notify({ type: 'success', message: t('common.api.actionSuccess') })
|
||||||
|
workflowStore.getState().setPublishedAt(res.created_at)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch {
|
else {
|
||||||
setPublished(false)
|
throw new Error('Checklist failed')
|
||||||
}
|
}
|
||||||
}, [])
|
}, [workflowStore, notify, t, publishWorkflow, pipelineId, handleCheckBeforePublish])
|
||||||
|
|
||||||
|
useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.shift.p`, (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (published)
|
||||||
|
return
|
||||||
|
handlePublish()
|
||||||
|
},
|
||||||
|
{ exactMatch: true, useCapture: true },
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-[320px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl shadow-shadow-shadow-5'>
|
<div className='w-[320px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl shadow-shadow-shadow-5'>
|
||||||
|
|||||||
@ -12,8 +12,21 @@ export const useAvailableNodesMetaData = () => {
|
|||||||
|
|
||||||
const mergedNodesMetaData = useMemo(() => [
|
const mergedNodesMetaData = useMemo(() => [
|
||||||
...WORKFLOW_COMMON_NODES,
|
...WORKFLOW_COMMON_NODES,
|
||||||
knowledgeBaseDefault,
|
{
|
||||||
dataSourceDefault,
|
...dataSourceDefault,
|
||||||
|
metaData: {
|
||||||
|
...dataSourceDefault.metaData,
|
||||||
|
isStart: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...knowledgeBaseDefault,
|
||||||
|
metaData: {
|
||||||
|
...knowledgeBaseDefault.metaData,
|
||||||
|
isRequired: true,
|
||||||
|
isUndeletable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
], [])
|
], [])
|
||||||
|
|
||||||
const prefixLink = useMemo(() => {
|
const prefixLink = useMemo(() => {
|
||||||
|
|||||||
@ -1,6 +1,25 @@
|
|||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { generateNewNode } from '@/app/components/workflow/utils'
|
||||||
|
import {
|
||||||
|
START_INITIAL_POSITION,
|
||||||
|
} from '@/app/components/workflow/constants'
|
||||||
|
import type { KnowledgeBaseNodeType } from '@/app/components/workflow/nodes/knowledge-base/types'
|
||||||
|
import knowledgeBaseDefault from '@/app/components/workflow/nodes/knowledge-base/default'
|
||||||
|
|
||||||
export const usePipelineTemplate = () => {
|
export const usePipelineTemplate = () => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
const { newNode: knowledgeBaseNode } = generateNewNode({
|
||||||
|
data: {
|
||||||
|
...knowledgeBaseDefault.defaultValue as KnowledgeBaseNodeType,
|
||||||
|
type: knowledgeBaseDefault.metaData.type,
|
||||||
|
title: t(`workflow.blocks.${knowledgeBaseDefault.metaData.type}`),
|
||||||
|
},
|
||||||
|
position: START_INITIAL_POSITION,
|
||||||
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodes: [],
|
nodes: [knowledgeBaseNode],
|
||||||
edges: [],
|
edges: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,7 +78,7 @@ const FeaturesTrigger = () => {
|
|||||||
setShowFeaturesPanel(!showFeaturesPanel)
|
setShowFeaturesPanel(!showFeaturesPanel)
|
||||||
}, [workflowStore, getNodesReadOnly])
|
}, [workflowStore, getNodesReadOnly])
|
||||||
|
|
||||||
const resetWorkflowVersionHistory = useResetWorkflowVersionHistory(appDetail!.id)
|
const resetWorkflowVersionHistory = useResetWorkflowVersionHistory()
|
||||||
|
|
||||||
const updateAppDetail = useCallback(async () => {
|
const updateAppDetail = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@ -89,10 +89,11 @@ const FeaturesTrigger = () => {
|
|||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}, [appID, setAppDetail])
|
}, [appID, setAppDetail])
|
||||||
const { mutateAsync: publishWorkflow } = usePublishWorkflow(appID!)
|
const { mutateAsync: publishWorkflow } = usePublishWorkflow()
|
||||||
const onPublish = useCallback(async (params?: PublishWorkflowParams) => {
|
const onPublish = useCallback(async (params?: PublishWorkflowParams) => {
|
||||||
if (await handleCheckBeforePublish()) {
|
if (await handleCheckBeforePublish()) {
|
||||||
const res = await publishWorkflow({
|
const res = await publishWorkflow({
|
||||||
|
url: `/apps/${appID}/workflows/publish`,
|
||||||
title: params?.title || '',
|
title: params?.title || '',
|
||||||
releaseNotes: params?.releaseNotes || '',
|
releaseNotes: params?.releaseNotes || '',
|
||||||
})
|
})
|
||||||
@ -107,7 +108,7 @@ const FeaturesTrigger = () => {
|
|||||||
else {
|
else {
|
||||||
throw new Error('Checklist failed')
|
throw new Error('Checklist failed')
|
||||||
}
|
}
|
||||||
}, [handleCheckBeforePublish, notify, t, workflowStore, publishWorkflow, resetWorkflowVersionHistory, updateAppDetail])
|
}, [handleCheckBeforePublish, notify, appID, t, workflowStore, publishWorkflow, resetWorkflowVersionHistory, updateAppDetail])
|
||||||
|
|
||||||
const onPublisherToggle = useCallback((state: boolean) => {
|
const onPublisherToggle = useCallback((state: boolean) => {
|
||||||
if (state)
|
if (state)
|
||||||
|
|||||||
@ -15,11 +15,35 @@ export const useAvailableNodesMetaData = () => {
|
|||||||
|
|
||||||
const mergedNodesMetaData = useMemo(() => [
|
const mergedNodesMetaData = useMemo(() => [
|
||||||
...WORKFLOW_COMMON_NODES,
|
...WORKFLOW_COMMON_NODES,
|
||||||
StartDefault,
|
{
|
||||||
|
...StartDefault,
|
||||||
|
metaData: {
|
||||||
|
...StartDefault.metaData,
|
||||||
|
isStart: true,
|
||||||
|
isRequired: true,
|
||||||
|
isUndeletable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
...(
|
...(
|
||||||
isChatMode
|
isChatMode
|
||||||
? [AnswerDefault]
|
? [
|
||||||
: [EndDefault]
|
{
|
||||||
|
...AnswerDefault,
|
||||||
|
metaData: {
|
||||||
|
...AnswerDefault.metaData,
|
||||||
|
isRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
...EndDefault,
|
||||||
|
metaData: {
|
||||||
|
...EndDefault.metaData,
|
||||||
|
isRequired: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
),
|
),
|
||||||
], [isChatMode])
|
], [isChatMode])
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,9 @@ const NodeSelectorWrapper = (props: NodeSelectorProps) => {
|
|||||||
if (block.metaData.type === BlockEnum.DataSource)
|
if (block.metaData.type === BlockEnum.DataSource)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
if (block.metaData.type === BlockEnum.Tool)
|
||||||
|
return false
|
||||||
|
|
||||||
if (block.metaData.type === BlockEnum.IterationStart)
|
if (block.metaData.type === BlockEnum.IterationStart)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,7 @@ export const SUPPORT_OUTPUT_VARS_NODE = [
|
|||||||
BlockEnum.HttpRequest, BlockEnum.Tool, BlockEnum.VariableAssigner, BlockEnum.VariableAggregator, BlockEnum.QuestionClassifier,
|
BlockEnum.HttpRequest, BlockEnum.Tool, BlockEnum.VariableAssigner, BlockEnum.VariableAggregator, BlockEnum.QuestionClassifier,
|
||||||
BlockEnum.ParameterExtractor, BlockEnum.Iteration, BlockEnum.Loop,
|
BlockEnum.ParameterExtractor, BlockEnum.Iteration, BlockEnum.Loop,
|
||||||
BlockEnum.DocExtractor, BlockEnum.ListFilter,
|
BlockEnum.DocExtractor, BlockEnum.ListFilter,
|
||||||
BlockEnum.Agent,
|
BlockEnum.Agent, BlockEnum.DataSource,
|
||||||
]
|
]
|
||||||
|
|
||||||
export const LLM_OUTPUT_STRUCT: Var[] = [
|
export const LLM_OUTPUT_STRUCT: Var[] = [
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import assignerDefault from '@/app/components/workflow/nodes/assigner/default'
|
|||||||
import httpRequestDefault from '@/app/components/workflow/nodes/http/default'
|
import httpRequestDefault from '@/app/components/workflow/nodes/http/default'
|
||||||
import parameterExtractorDefault from '@/app/components/workflow/nodes/parameter-extractor/default'
|
import parameterExtractorDefault from '@/app/components/workflow/nodes/parameter-extractor/default'
|
||||||
import listOperatorDefault from '@/app/components/workflow/nodes/list-operator/default'
|
import listOperatorDefault from '@/app/components/workflow/nodes/list-operator/default'
|
||||||
|
import toolDefault from '@/app/components/workflow/nodes/tool/default'
|
||||||
|
|
||||||
export const WORKFLOW_COMMON_NODES = [
|
export const WORKFLOW_COMMON_NODES = [
|
||||||
llmDefault,
|
llmDefault,
|
||||||
@ -39,4 +40,5 @@ export const WORKFLOW_COMMON_NODES = [
|
|||||||
parameterExtractorDefault,
|
parameterExtractorDefault,
|
||||||
httpRequestDefault,
|
httpRequestDefault,
|
||||||
listOperatorDefault,
|
listOperatorDefault,
|
||||||
|
toolDefault,
|
||||||
]
|
]
|
||||||
|
|||||||
@ -21,13 +21,13 @@ export const useAvailableBlocks = (nodeType?: BlockEnum, inContainer?: boolean)
|
|||||||
} = useNodesMetaData()
|
} = useNodesMetaData()
|
||||||
const availableNodesType = useMemo(() => availableNodes.map(node => node.metaData.type), [availableNodes])
|
const availableNodesType = useMemo(() => availableNodes.map(node => node.metaData.type), [availableNodes])
|
||||||
const availablePrevBlocks = useMemo(() => {
|
const availablePrevBlocks = useMemo(() => {
|
||||||
if (!nodeType || nodeType === BlockEnum.Start)
|
if (!nodeType || nodeType === BlockEnum.Start || nodeType === BlockEnum.DataSource)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return availableNodesType
|
return availableNodesType
|
||||||
}, [availableNodesType, nodeType])
|
}, [availableNodesType, nodeType])
|
||||||
const availableNextBlocks = useMemo(() => {
|
const availableNextBlocks = useMemo(() => {
|
||||||
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd)
|
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd || nodeType === BlockEnum.KnowledgeBase)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return availableNodesType
|
return availableNodesType
|
||||||
@ -35,11 +35,11 @@ export const useAvailableBlocks = (nodeType?: BlockEnum, inContainer?: boolean)
|
|||||||
|
|
||||||
const getAvailableBlocks = useCallback((nodeType?: BlockEnum, inContainer?: boolean) => {
|
const getAvailableBlocks = useCallback((nodeType?: BlockEnum, inContainer?: boolean) => {
|
||||||
let availablePrevBlocks = availableNodesType
|
let availablePrevBlocks = availableNodesType
|
||||||
if (!nodeType || nodeType === BlockEnum.Start)
|
if (!nodeType || nodeType === BlockEnum.Start || nodeType === BlockEnum.DataSource)
|
||||||
availablePrevBlocks = []
|
availablePrevBlocks = []
|
||||||
|
|
||||||
let availableNextBlocks = availableNodesType
|
let availableNextBlocks = availableNodesType
|
||||||
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd)
|
if (!nodeType || nodeType === BlockEnum.End || nodeType === BlockEnum.LoopEnd || nodeType === BlockEnum.KnowledgeBase)
|
||||||
availableNextBlocks = []
|
availableNextBlocks = []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import {
|
|||||||
MAX_TREE_DEPTH,
|
MAX_TREE_DEPTH,
|
||||||
} from '../constants'
|
} from '../constants'
|
||||||
import type { ToolNodeType } from '../nodes/tool/types'
|
import type { ToolNodeType } from '../nodes/tool/types'
|
||||||
import { useIsChatMode } from './use-workflow'
|
|
||||||
import { useNodesMetaData } from './use-nodes-meta-data'
|
import { useNodesMetaData } from './use-nodes-meta-data'
|
||||||
import { useToastContext } from '@/app/components/base/toast'
|
import { useToastContext } from '@/app/components/base/toast'
|
||||||
import { CollectionType } from '@/app/components/tools/types'
|
import { CollectionType } from '@/app/components/tools/types'
|
||||||
@ -38,7 +37,6 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const language = useGetLanguage()
|
const language = useGetLanguage()
|
||||||
const { nodesMap: nodesExtraData } = useNodesMetaData()
|
const { nodesMap: nodesExtraData } = useNodesMetaData()
|
||||||
const isChatMode = useIsChatMode()
|
|
||||||
const buildInTools = useStore(s => s.buildInTools)
|
const buildInTools = useStore(s => s.buildInTools)
|
||||||
const customTools = useStore(s => s.customTools)
|
const customTools = useStore(s => s.customTools)
|
||||||
const workflowTools = useStore(s => s.workflowTools)
|
const workflowTools = useStore(s => s.workflowTools)
|
||||||
@ -101,7 +99,6 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
|||||||
if (node.type === CUSTOM_NODE) {
|
if (node.type === CUSTOM_NODE) {
|
||||||
const checkData = getCheckData(node.data)
|
const checkData = getCheckData(node.data)
|
||||||
const { errorMessage } = nodesExtraData![node.data.type].checkValid(checkData, t, moreDataForCheckValid)
|
const { errorMessage } = nodesExtraData![node.data.type].checkValid(checkData, t, moreDataForCheckValid)
|
||||||
|
|
||||||
if (errorMessage || !validNodes.find(n => n.id === node.id)) {
|
if (errorMessage || !validNodes.find(n => n.id === node.id)) {
|
||||||
list.push({
|
list.push({
|
||||||
id: node.id,
|
id: node.id,
|
||||||
@ -115,26 +112,21 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) {
|
const isRequiredNodesType = Object.keys(nodesExtraData!).filter((key: any) => (nodesExtraData as any)[key].metaData.isRequired)
|
||||||
list.push({
|
|
||||||
id: 'answer-need-added',
|
|
||||||
type: BlockEnum.Answer,
|
|
||||||
title: t('workflow.blocks.answer'),
|
|
||||||
errorMessage: t('workflow.common.needAnswerNode'),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) {
|
isRequiredNodesType.forEach((type: string) => {
|
||||||
list.push({
|
if (!nodes.find(node => node.data.type === type)) {
|
||||||
id: 'end-need-added',
|
list.push({
|
||||||
type: BlockEnum.End,
|
id: `${type}-need-added`,
|
||||||
title: t('workflow.blocks.end'),
|
type,
|
||||||
errorMessage: t('workflow.common.needEndNode'),
|
title: t(`workflow.blocks.${type}`),
|
||||||
})
|
errorMessage: t('workflow.common.needAdd', { node: t(`workflow.blocks.${type}`) }),
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return list
|
return list
|
||||||
}, [nodes, edges, isChatMode, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders, getCheckData])
|
}, [nodes, edges, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders, getCheckData])
|
||||||
|
|
||||||
return needWarningNodes
|
return needWarningNodes
|
||||||
}
|
}
|
||||||
@ -146,7 +138,6 @@ export const useChecklistBeforePublish = () => {
|
|||||||
const customTools = useStore(s => s.customTools)
|
const customTools = useStore(s => s.customTools)
|
||||||
const workflowTools = useStore(s => s.workflowTools)
|
const workflowTools = useStore(s => s.workflowTools)
|
||||||
const { notify } = useToastContext()
|
const { notify } = useToastContext()
|
||||||
const isChatMode = useIsChatMode()
|
|
||||||
const store = useStoreApi()
|
const store = useStoreApi()
|
||||||
const { nodesMap: nodesExtraData } = useNodesMetaData()
|
const { nodesMap: nodesExtraData } = useNodesMetaData()
|
||||||
const { data: strategyProviders } = useStrategyProviders()
|
const { data: strategyProviders } = useStrategyProviders()
|
||||||
@ -241,18 +232,18 @@ export const useChecklistBeforePublish = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) {
|
const isRequiredNodesType = Object.keys(nodesExtraData!).filter((key: any) => (nodesExtraData as any)[key].metaData.isRequired)
|
||||||
notify({ type: 'error', message: t('workflow.common.needAnswerNode') })
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) {
|
for(let i = 0; i < isRequiredNodesType.length; i++) {
|
||||||
notify({ type: 'error', message: t('workflow.common.needEndNode') })
|
const type = isRequiredNodesType[i]
|
||||||
return false
|
if (!nodes.find(node => node.data.type === type)) {
|
||||||
|
notify({ type: 'error', message: t('workflow.common.needAdd', { node: t(`workflow.blocks.${type}`) }) })
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}, [store, isChatMode, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData])
|
}, [store, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handleCheckBeforePublish,
|
handleCheckBeforePublish,
|
||||||
|
|||||||
@ -549,7 +549,7 @@ export const useNodesInteractions = () => {
|
|||||||
if (!currentNode)
|
if (!currentNode)
|
||||||
return
|
return
|
||||||
|
|
||||||
if (currentNode.data.type === BlockEnum.Start)
|
if (nodesMetaDataMap?.[currentNode.data.type as BlockEnum].metaData.isUndeletable)
|
||||||
return
|
return
|
||||||
|
|
||||||
if (currentNode.data.type === BlockEnum.Iteration) {
|
if (currentNode.data.type === BlockEnum.Iteration) {
|
||||||
@ -656,7 +656,7 @@ export const useNodesInteractions = () => {
|
|||||||
|
|
||||||
else
|
else
|
||||||
saveStateToHistory(WorkflowHistoryEvent.NodeDelete)
|
saveStateToHistory(WorkflowHistoryEvent.NodeDelete)
|
||||||
}, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, t])
|
}, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, t, nodesMetaDataMap])
|
||||||
|
|
||||||
const handleNodeAdd = useCallback<OnNodeAdd>((
|
const handleNodeAdd = useCallback<OnNodeAdd>((
|
||||||
{
|
{
|
||||||
|
|||||||
@ -302,6 +302,9 @@ export type NodeDefault<T = {}> = {
|
|||||||
author: string
|
author: string
|
||||||
description?: string
|
description?: string
|
||||||
helpLinkUri?: string
|
helpLinkUri?: string
|
||||||
|
isRequired?: boolean
|
||||||
|
isUndeletable?: boolean
|
||||||
|
isStart?: boolean
|
||||||
}
|
}
|
||||||
defaultValue: Partial<T>
|
defaultValue: Partial<T>
|
||||||
checkValid: (payload: T, t: any, moreDataForCheckValid?: any) => { isValid: boolean; errorMessage?: string }
|
checkValid: (payload: T, t: any, moreDataForCheckValid?: any) => { isValid: boolean; errorMessage?: string }
|
||||||
|
|||||||
@ -46,6 +46,7 @@ const translation = {
|
|||||||
setVarValuePlaceholder: 'Set variable',
|
setVarValuePlaceholder: 'Set variable',
|
||||||
needConnectTip: 'This step is not connected to anything',
|
needConnectTip: 'This step is not connected to anything',
|
||||||
maxTreeDepth: 'Maximum limit of {{depth}} nodes per branch',
|
maxTreeDepth: 'Maximum limit of {{depth}} nodes per branch',
|
||||||
|
needAdd: '{{node}} block must be added',
|
||||||
needEndNode: 'The End block must be added',
|
needEndNode: 'The End block must be added',
|
||||||
needAnswerNode: 'The Answer block must be added',
|
needAnswerNode: 'The Answer block must be added',
|
||||||
workflowProcess: 'Workflow Process',
|
workflowProcess: 'Workflow Process',
|
||||||
|
|||||||
@ -45,6 +45,7 @@ const translation = {
|
|||||||
setVarValuePlaceholder: '设置变量值',
|
setVarValuePlaceholder: '设置变量值',
|
||||||
needConnectTip: '此节点尚未连接到其他节点',
|
needConnectTip: '此节点尚未连接到其他节点',
|
||||||
maxTreeDepth: '每个分支最大限制 {{depth}} 个节点',
|
maxTreeDepth: '每个分支最大限制 {{depth}} 个节点',
|
||||||
|
needAdd: '必须添加{{node}}节点',
|
||||||
needEndNode: '必须添加结束节点',
|
needEndNode: '必须添加结束节点',
|
||||||
needAnswerNode: '必须添加直接回复节点',
|
needAnswerNode: '必须添加直接回复节点',
|
||||||
workflowProcess: '工作流',
|
workflowProcess: '工作流',
|
||||||
|
|||||||
@ -76,10 +76,10 @@ export const useDeleteWorkflow = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePublishWorkflow = (appId: string) => {
|
export const usePublishWorkflow = () => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: [NAME_SPACE, 'publish'],
|
mutationKey: [NAME_SPACE, 'publish'],
|
||||||
mutationFn: (params: PublishWorkflowParams) => post<CommonResponse & { created_at: number }>(`/apps/${appId}/workflows/publish`, {
|
mutationFn: (params: PublishWorkflowParams) => post<CommonResponse & { created_at: number }>(params.url, {
|
||||||
body: {
|
body: {
|
||||||
marked_name: params.title,
|
marked_name: params.title,
|
||||||
marked_comment: params.releaseNotes,
|
marked_comment: params.releaseNotes,
|
||||||
|
|||||||
@ -345,6 +345,7 @@ export type WorkflowConfigResponse = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type PublishWorkflowParams = {
|
export type PublishWorkflowParams = {
|
||||||
|
url: string
|
||||||
title: string
|
title: string
|
||||||
releaseNotes: string
|
releaseNotes: string
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user