use-checklist.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import {
  2. useCallback,
  3. useMemo,
  4. } from 'react'
  5. import { useTranslation } from 'react-i18next'
  6. import { useStoreApi } from 'reactflow'
  7. import type {
  8. Edge,
  9. Node,
  10. } from '../types'
  11. import { BlockEnum } from '../types'
  12. import { useStore } from '../store'
  13. import {
  14. getToolCheckParams,
  15. getValidTreeNodes,
  16. } from '../utils'
  17. import {
  18. CUSTOM_NODE,
  19. MAX_TREE_DEPTH,
  20. } from '../constants'
  21. import type { ToolNodeType } from '../nodes/tool/types'
  22. import { useIsChatMode } from './use-workflow'
  23. import { useNodesExtraData } from './use-nodes-data'
  24. import { useToastContext } from '@/app/components/base/toast'
  25. import { CollectionType } from '@/app/components/tools/types'
  26. import { useGetLanguage } from '@/context/i18n'
  27. export const useChecklist = (nodes: Node[], edges: Edge[]) => {
  28. const { t } = useTranslation()
  29. const language = useGetLanguage()
  30. const nodesExtraData = useNodesExtraData()
  31. const isChatMode = useIsChatMode()
  32. const buildInTools = useStore(s => s.buildInTools)
  33. const customTools = useStore(s => s.customTools)
  34. const workflowTools = useStore(s => s.workflowTools)
  35. const needWarningNodes = useMemo(() => {
  36. const list = []
  37. const { validNodes } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges)
  38. for (let i = 0; i < nodes.length; i++) {
  39. const node = nodes[i]
  40. let toolIcon
  41. let moreDataForCheckValid
  42. if (node.data.type === BlockEnum.Tool) {
  43. const { provider_type } = node.data
  44. moreDataForCheckValid = getToolCheckParams(node.data as ToolNodeType, buildInTools, customTools, workflowTools, language)
  45. if (provider_type === CollectionType.builtIn)
  46. toolIcon = buildInTools.find(tool => tool.id === node.data.provider_id)?.icon
  47. if (provider_type === CollectionType.custom)
  48. toolIcon = customTools.find(tool => tool.id === node.data.provider_id)?.icon
  49. if (provider_type === CollectionType.workflow)
  50. toolIcon = workflowTools.find(tool => tool.id === node.data.provider_id)?.icon
  51. }
  52. if (node.type === CUSTOM_NODE) {
  53. const { errorMessage } = nodesExtraData[node.data.type].checkValid(node.data, t, moreDataForCheckValid)
  54. if (errorMessage || !validNodes.find(n => n.id === node.id)) {
  55. list.push({
  56. id: node.id,
  57. type: node.data.type,
  58. title: node.data.title,
  59. toolIcon,
  60. unConnected: !validNodes.find(n => n.id === node.id),
  61. errorMessage,
  62. })
  63. }
  64. }
  65. }
  66. if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) {
  67. list.push({
  68. id: 'answer-need-added',
  69. type: BlockEnum.Answer,
  70. title: t('workflow.blocks.answer'),
  71. errorMessage: t('workflow.common.needAnswerNode'),
  72. })
  73. }
  74. if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) {
  75. list.push({
  76. id: 'end-need-added',
  77. type: BlockEnum.End,
  78. title: t('workflow.blocks.end'),
  79. errorMessage: t('workflow.common.needEndNode'),
  80. })
  81. }
  82. return list
  83. }, [t, nodes, edges, nodesExtraData, buildInTools, customTools, workflowTools, language, isChatMode])
  84. return needWarningNodes
  85. }
  86. export const useChecklistBeforePublish = () => {
  87. const { t } = useTranslation()
  88. const language = useGetLanguage()
  89. const buildInTools = useStore(s => s.buildInTools)
  90. const customTools = useStore(s => s.customTools)
  91. const workflowTools = useStore(s => s.workflowTools)
  92. const { notify } = useToastContext()
  93. const isChatMode = useIsChatMode()
  94. const store = useStoreApi()
  95. const nodesExtraData = useNodesExtraData()
  96. const handleCheckBeforePublish = useCallback(() => {
  97. const {
  98. getNodes,
  99. edges,
  100. } = store.getState()
  101. const nodes = getNodes().filter(node => node.type === CUSTOM_NODE)
  102. const {
  103. validNodes,
  104. maxDepth,
  105. } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges)
  106. if (maxDepth > MAX_TREE_DEPTH) {
  107. notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) })
  108. return false
  109. }
  110. for (let i = 0; i < nodes.length; i++) {
  111. const node = nodes[i]
  112. let moreDataForCheckValid
  113. if (node.data.type === BlockEnum.Tool)
  114. moreDataForCheckValid = getToolCheckParams(node.data as ToolNodeType, buildInTools, customTools, workflowTools, language)
  115. const { errorMessage } = nodesExtraData[node.data.type as BlockEnum].checkValid(node.data, t, moreDataForCheckValid)
  116. if (errorMessage) {
  117. notify({ type: 'error', message: `[${node.data.title}] ${errorMessage}` })
  118. return false
  119. }
  120. if (!validNodes.find(n => n.id === node.id)) {
  121. notify({ type: 'error', message: `[${node.data.title}] ${t('workflow.common.needConnectTip')}` })
  122. return false
  123. }
  124. }
  125. if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) {
  126. notify({ type: 'error', message: t('workflow.common.needAnswerNode') })
  127. return false
  128. }
  129. if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) {
  130. notify({ type: 'error', message: t('workflow.common.needEndNode') })
  131. return false
  132. }
  133. return true
  134. }, [nodesExtraData, notify, t, store, isChatMode, buildInTools, customTools, workflowTools, language])
  135. return {
  136. handleCheckBeforePublish,
  137. }
  138. }