use-checklist.ts 4.8 KB

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