use-checklist.ts 5.1 KB

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