use-config.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import { useCallback, useEffect, useState } from 'react'
  2. import produce from 'immer'
  3. import useVarList from '../_base/hooks/use-var-list'
  4. import useOutputVarList from '../_base/hooks/use-output-var-list'
  5. import { BlockEnum, VarType } from '../../types'
  6. import type { Var } from '../../types'
  7. import { useStore } from '../../store'
  8. import type { CodeDependency, CodeNodeType, OutputVar } from './types'
  9. import { CodeLanguage } from './types'
  10. import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
  11. import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run'
  12. import { fetchNodeDefault } from '@/service/workflow'
  13. import { useStore as useAppStore } from '@/app/components/app/store'
  14. import {
  15. useNodesReadOnly,
  16. } from '@/app/components/workflow/hooks'
  17. const useConfig = (id: string, payload: CodeNodeType) => {
  18. const { nodesReadOnly: readOnly } = useNodesReadOnly()
  19. const appId = useAppStore.getState().appDetail?.id
  20. const [allLanguageDefault, setAllLanguageDefault] = useState<Record<CodeLanguage, CodeNodeType> | null>(null)
  21. const [allLanguageDependencies, setAllLanguageDependencies] = useState<Record<CodeLanguage, CodeDependency[]> | null>(null)
  22. useEffect(() => {
  23. if (appId) {
  24. (async () => {
  25. const { config: javaScriptConfig } = await fetchNodeDefault(appId, BlockEnum.Code, { code_language: CodeLanguage.javascript }) as any
  26. const { config: pythonConfig, available_dependencies: pythonDependencies } = await fetchNodeDefault(appId, BlockEnum.Code, { code_language: CodeLanguage.python3 }) as any
  27. setAllLanguageDefault({
  28. [CodeLanguage.javascript]: javaScriptConfig as CodeNodeType,
  29. [CodeLanguage.python3]: pythonConfig as CodeNodeType,
  30. } as any)
  31. setAllLanguageDependencies({
  32. [CodeLanguage.python3]: pythonDependencies as CodeDependency[],
  33. } as any)
  34. })()
  35. }
  36. }, [appId])
  37. const defaultConfig = useStore(s => s.nodesDefaultConfigs)[payload.type]
  38. const { inputs, setInputs } = useNodeCrud<CodeNodeType>(id, payload)
  39. const { handleVarListChange, handleAddVariable } = useVarList<CodeNodeType>({
  40. inputs,
  41. setInputs,
  42. })
  43. const handleAddDependency = useCallback((dependency: CodeDependency) => {
  44. const newInputs = produce(inputs, (draft) => {
  45. if (!draft.dependencies)
  46. draft.dependencies = []
  47. draft.dependencies.push(dependency)
  48. })
  49. setInputs(newInputs)
  50. }, [inputs, setInputs])
  51. const handleRemoveDependency = useCallback((index: number) => {
  52. const newInputs = produce(inputs, (draft) => {
  53. if (!draft.dependencies)
  54. draft.dependencies = []
  55. draft.dependencies.splice(index, 1)
  56. })
  57. setInputs(newInputs)
  58. }, [inputs, setInputs])
  59. const handleChangeDependency = useCallback((index: number, dependency: CodeDependency) => {
  60. const newInputs = produce(inputs, (draft) => {
  61. if (!draft.dependencies)
  62. draft.dependencies = []
  63. draft.dependencies[index] = dependency
  64. })
  65. setInputs(newInputs)
  66. }, [inputs, setInputs])
  67. const [allowDependencies, setAllowDependencies] = useState<boolean>(false)
  68. useEffect(() => {
  69. if (!inputs.code_language)
  70. return
  71. if (!allLanguageDependencies)
  72. return
  73. const newAllowDependencies = !!allLanguageDependencies[inputs.code_language]
  74. setAllowDependencies(newAllowDependencies)
  75. }, [allLanguageDependencies, inputs.code_language])
  76. const [availableDependencies, setAvailableDependencies] = useState<CodeDependency[]>([])
  77. useEffect(() => {
  78. if (!inputs.code_language)
  79. return
  80. if (!allLanguageDependencies)
  81. return
  82. const newAvailableDependencies = produce(allLanguageDependencies[inputs.code_language], (draft) => {
  83. const currentLanguage = inputs.code_language
  84. if (!currentLanguage || !draft || !inputs.dependencies)
  85. return []
  86. return draft.filter((dependency) => {
  87. return !inputs.dependencies?.find(d => d.name === dependency.name)
  88. })
  89. })
  90. setAvailableDependencies(newAvailableDependencies || [])
  91. }, [allLanguageDependencies, inputs.code_language, inputs.dependencies])
  92. const [outputKeyOrders, setOutputKeyOrders] = useState<string[]>([])
  93. const syncOutputKeyOrders = useCallback((outputs: OutputVar) => {
  94. setOutputKeyOrders(Object.keys(outputs))
  95. }, [])
  96. useEffect(() => {
  97. if (inputs.code) {
  98. if (inputs.outputs && Object.keys(inputs.outputs).length > 0)
  99. syncOutputKeyOrders(inputs.outputs)
  100. return
  101. }
  102. const isReady = defaultConfig && Object.keys(defaultConfig).length > 0
  103. if (isReady) {
  104. setInputs({
  105. ...inputs,
  106. ...defaultConfig,
  107. })
  108. syncOutputKeyOrders(defaultConfig.outputs)
  109. }
  110. // eslint-disable-next-line react-hooks/exhaustive-deps
  111. }, [defaultConfig])
  112. const handleCodeChange = useCallback((code: string) => {
  113. const newInputs = produce(inputs, (draft) => {
  114. draft.code = code
  115. })
  116. setInputs(newInputs)
  117. }, [inputs, setInputs])
  118. const handleCodeLanguageChange = useCallback((codeLanguage: CodeLanguage) => {
  119. const currDefaultConfig = allLanguageDefault?.[codeLanguage]
  120. const newInputs = produce(inputs, (draft) => {
  121. draft.code_language = codeLanguage
  122. if (!currDefaultConfig)
  123. return
  124. draft.code = currDefaultConfig.code
  125. draft.variables = currDefaultConfig.variables
  126. draft.outputs = currDefaultConfig.outputs
  127. })
  128. setInputs(newInputs)
  129. }, [allLanguageDefault, inputs, setInputs])
  130. const {
  131. handleVarsChange,
  132. handleAddVariable: handleAddOutputVariable,
  133. handleRemoveVariable,
  134. isShowRemoveVarConfirm,
  135. hideRemoveVarConfirm,
  136. onRemoveVarConfirm,
  137. } = useOutputVarList<CodeNodeType>({
  138. id,
  139. inputs,
  140. setInputs,
  141. outputKeyOrders,
  142. onOutputKeyOrdersChange: setOutputKeyOrders,
  143. })
  144. const filterVar = useCallback((varPayload: Var) => {
  145. return [VarType.string, VarType.number, VarType.secret, VarType.object, VarType.array, VarType.arrayNumber, VarType.arrayString, VarType.arrayObject].includes(varPayload.type)
  146. }, [])
  147. // single run
  148. const {
  149. isShowSingleRun,
  150. hideSingleRun,
  151. toVarInputs,
  152. runningStatus,
  153. isCompleted,
  154. handleRun,
  155. handleStop,
  156. runInputData,
  157. setRunInputData,
  158. runResult,
  159. } = useOneStepRun<CodeNodeType>({
  160. id,
  161. data: inputs,
  162. defaultRunInputData: {},
  163. })
  164. const varInputs = toVarInputs(inputs.variables)
  165. const inputVarValues = (() => {
  166. const vars: Record<string, any> = {}
  167. Object.keys(runInputData)
  168. .forEach((key) => {
  169. vars[key] = runInputData[key]
  170. })
  171. return vars
  172. })()
  173. const setInputVarValues = useCallback((newPayload: Record<string, any>) => {
  174. setRunInputData(newPayload)
  175. }, [setRunInputData])
  176. return {
  177. readOnly,
  178. inputs,
  179. outputKeyOrders,
  180. handleVarListChange,
  181. handleAddVariable,
  182. handleRemoveVariable,
  183. handleCodeChange,
  184. handleCodeLanguageChange,
  185. handleVarsChange,
  186. filterVar,
  187. handleAddOutputVariable,
  188. isShowRemoveVarConfirm,
  189. hideRemoveVarConfirm,
  190. onRemoveVarConfirm,
  191. // single run
  192. isShowSingleRun,
  193. hideSingleRun,
  194. runningStatus,
  195. isCompleted,
  196. handleRun,
  197. handleStop,
  198. varInputs,
  199. inputVarValues,
  200. setInputVarValues,
  201. runResult,
  202. availableDependencies,
  203. allowDependencies,
  204. handleAddDependency,
  205. handleRemoveDependency,
  206. handleChangeDependency,
  207. }
  208. }
  209. export default useConfig