You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

panel.tsx 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import type { FC } from 'react'
  2. import { useCallback, useEffect, useMemo, useState } from 'react'
  3. import { useTranslation } from 'react-i18next'
  4. import {
  5. RiCloseLine,
  6. } from '@remixicon/react'
  7. import { useStore } from '../store'
  8. import useCurrentVars from '../hooks/use-inspect-vars-crud'
  9. import Empty from './empty'
  10. import Left from './left'
  11. import Right from './right'
  12. import ActionButton from '@/app/components/base/action-button'
  13. import type { VarInInspect } from '@/types/workflow'
  14. import { VarInInspectType } from '@/types/workflow'
  15. import cn from '@/utils/classnames'
  16. import type { NodeProps } from '../types'
  17. import useMatchSchemaType from '../nodes/_base/components/variable/use-match-schema-type'
  18. export type currentVarType = {
  19. nodeId: string
  20. nodeType: string
  21. title: string
  22. isValueFetched?: boolean
  23. var: VarInInspect
  24. nodeData: NodeProps['data']
  25. }
  26. const Panel: FC = () => {
  27. const { t } = useTranslation()
  28. const bottomPanelWidth = useStore(s => s.bottomPanelWidth)
  29. const setShowVariableInspectPanel = useStore(s => s.setShowVariableInspectPanel)
  30. const [showLeftPanel, setShowLeftPanel] = useState(true)
  31. const environmentVariables = useStore(s => s.environmentVariables)
  32. const currentFocusNodeId = useStore(s => s.currentFocusNodeId)
  33. const setCurrentFocusNodeId = useStore(s => s.setCurrentFocusNodeId)
  34. const [currentVarId, setCurrentVarId] = useState('')
  35. const {
  36. conversationVars,
  37. systemVars,
  38. nodesWithInspectVars,
  39. fetchInspectVarValue,
  40. } = useCurrentVars()
  41. const isEmpty = useMemo(() => {
  42. const allVars = [...environmentVariables, ...conversationVars, ...systemVars, ...nodesWithInspectVars]
  43. return allVars.length === 0
  44. }, [environmentVariables, conversationVars, systemVars, nodesWithInspectVars])
  45. const currentNodeInfo = useMemo(() => {
  46. if (!currentFocusNodeId) return
  47. if (currentFocusNodeId === VarInInspectType.environment) {
  48. const currentVar = environmentVariables.find(v => v.id === currentVarId)
  49. const res = {
  50. nodeId: VarInInspectType.environment,
  51. title: VarInInspectType.environment,
  52. nodeType: VarInInspectType.environment,
  53. }
  54. if (currentVar) {
  55. return {
  56. ...res,
  57. var: {
  58. ...currentVar,
  59. type: VarInInspectType.environment,
  60. visible: true,
  61. ...(currentVar.value_type === 'secret' ? { value: '******************' } : {}),
  62. },
  63. }
  64. }
  65. return res
  66. }
  67. if (currentFocusNodeId === VarInInspectType.conversation) {
  68. const currentVar = conversationVars.find(v => v.id === currentVarId)
  69. const res = {
  70. nodeId: VarInInspectType.conversation,
  71. title: VarInInspectType.conversation,
  72. nodeType: VarInInspectType.conversation,
  73. }
  74. if (currentVar) {
  75. return {
  76. ...res,
  77. var: {
  78. ...currentVar,
  79. type: VarInInspectType.conversation,
  80. },
  81. }
  82. }
  83. return res
  84. }
  85. if (currentFocusNodeId === VarInInspectType.system) {
  86. const currentVar = systemVars.find(v => v.id === currentVarId)
  87. const res = {
  88. nodeId: VarInInspectType.system,
  89. title: VarInInspectType.system,
  90. nodeType: VarInInspectType.system,
  91. }
  92. if (currentVar) {
  93. return {
  94. ...res,
  95. var: {
  96. ...currentVar,
  97. type: VarInInspectType.system,
  98. },
  99. }
  100. }
  101. return res
  102. }
  103. const targetNode = nodesWithInspectVars.find(node => node.nodeId === currentFocusNodeId)
  104. if (!targetNode) return
  105. const currentVar = targetNode.vars.find(v => v.id === currentVarId)
  106. return {
  107. nodeId: targetNode.nodeId,
  108. nodeType: targetNode.nodeType,
  109. title: targetNode.title,
  110. isSingRunRunning: targetNode.isSingRunRunning,
  111. isValueFetched: targetNode.isValueFetched,
  112. nodeData: targetNode.nodePayload,
  113. ...(currentVar ? { var: currentVar } : {}),
  114. }
  115. }, [currentFocusNodeId, currentVarId, environmentVariables, conversationVars, systemVars, nodesWithInspectVars])
  116. const isCurrentNodeVarValueFetching = useMemo(() => {
  117. if (!currentNodeInfo) return false
  118. const targetNode = nodesWithInspectVars.find(node => node.nodeId === currentNodeInfo.nodeId)
  119. if (!targetNode) return false
  120. return !targetNode.isValueFetched
  121. }, [currentNodeInfo, nodesWithInspectVars])
  122. const handleNodeVarSelect = useCallback((node: currentVarType) => {
  123. setCurrentFocusNodeId(node.nodeId)
  124. setCurrentVarId(node.var.id)
  125. }, [setCurrentFocusNodeId, setCurrentVarId])
  126. const { isLoading, schemaTypeDefinitions } = useMatchSchemaType()
  127. useEffect(() => {
  128. if (currentFocusNodeId && currentVarId && !isLoading) {
  129. const targetNode = nodesWithInspectVars.find(node => node.nodeId === currentFocusNodeId)
  130. if (targetNode && !targetNode.isValueFetched)
  131. fetchInspectVarValue([currentFocusNodeId], schemaTypeDefinitions!)
  132. }
  133. }, [currentFocusNodeId, currentVarId, nodesWithInspectVars, fetchInspectVarValue, schemaTypeDefinitions, isLoading])
  134. if (isEmpty) {
  135. return (
  136. <div className={cn('flex h-full flex-col')}>
  137. <div className='flex shrink-0 items-center justify-between pl-4 pr-2 pt-2'>
  138. <div className='system-sm-semibold-uppercase text-text-primary'>{t('workflow.debug.variableInspect.title')}</div>
  139. <ActionButton onClick={() => setShowVariableInspectPanel(false)}>
  140. <RiCloseLine className='h-4 w-4' />
  141. </ActionButton>
  142. </div>
  143. <div className='grow p-2'>
  144. <Empty />
  145. </div>
  146. </div>
  147. )
  148. }
  149. return (
  150. <div className={cn('relative flex h-full')}>
  151. {/* left */}
  152. {bottomPanelWidth < 488 && showLeftPanel && <div className='absolute left-0 top-0 h-full w-full' onClick={() => setShowLeftPanel(false)}></div>}
  153. <div
  154. className={cn(
  155. 'w-60 shrink-0 border-r border-divider-burn',
  156. bottomPanelWidth < 488
  157. ? showLeftPanel
  158. ? 'absolute left-0 top-0 z-10 h-full w-[217px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg backdrop-blur-sm'
  159. : 'hidden'
  160. : 'block',
  161. )}
  162. >
  163. <Left
  164. currentNodeVar={currentNodeInfo as currentVarType}
  165. handleVarSelect={handleNodeVarSelect}
  166. />
  167. </div>
  168. {/* right */}
  169. <div className='w-0 grow'>
  170. <Right
  171. nodeId={currentFocusNodeId!}
  172. isValueFetching={isCurrentNodeVarValueFetching}
  173. currentNodeVar={currentNodeInfo as currentVarType}
  174. handleOpenMenu={() => setShowLeftPanel(true)}
  175. />
  176. </div>
  177. </div>
  178. )
  179. }
  180. export default Panel