選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

panel.tsx 6.3KB

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