node-group-item.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import {
  2. memo,
  3. useMemo,
  4. } from 'react'
  5. import { useTranslation } from 'react-i18next'
  6. import { useNodes } from 'reactflow'
  7. import { useStore } from '../../../store'
  8. import { BlockEnum } from '../../../types'
  9. import type {
  10. Node,
  11. ValueSelector,
  12. VarType,
  13. } from '../../../types'
  14. import type { VariableAssignerNodeType } from '../types'
  15. import {
  16. useGetAvailableVars,
  17. useVariableAssigner,
  18. } from '../hooks'
  19. import { filterVar } from '../utils'
  20. import AddVariable from './add-variable'
  21. import NodeVariableItem from './node-variable-item'
  22. import { isConversationVar, isENV, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
  23. import cn from '@/utils/classnames'
  24. import { isExceptionVariable } from '@/app/components/workflow/utils'
  25. const i18nPrefix = 'workflow.nodes.variableAssigner'
  26. type GroupItem = {
  27. groupEnabled: boolean
  28. targetHandleId: string
  29. title: string
  30. type: string
  31. variables: ValueSelector[]
  32. variableAssignerNodeId: string
  33. variableAssignerNodeData: VariableAssignerNodeType
  34. }
  35. type NodeGroupItemProps = {
  36. item: GroupItem
  37. }
  38. const NodeGroupItem = ({
  39. item,
  40. }: NodeGroupItemProps) => {
  41. const { t } = useTranslation()
  42. const enteringNodePayload = useStore(s => s.enteringNodePayload)
  43. const hoveringAssignVariableGroupId = useStore(s => s.hoveringAssignVariableGroupId)
  44. const nodes: Node[] = useNodes()
  45. const {
  46. handleGroupItemMouseEnter,
  47. handleGroupItemMouseLeave,
  48. } = useVariableAssigner()
  49. const getAvailableVars = useGetAvailableVars()
  50. const groupEnabled = item.groupEnabled
  51. const outputType = useMemo(() => {
  52. if (!groupEnabled)
  53. return item.variableAssignerNodeData.output_type
  54. const group = item.variableAssignerNodeData.advanced_settings?.groups.find(group => group.groupId === item.targetHandleId)
  55. return group?.output_type || ''
  56. }, [item.variableAssignerNodeData, item.targetHandleId, groupEnabled])
  57. const availableVars = getAvailableVars(item.variableAssignerNodeId, item.targetHandleId, filterVar(outputType as VarType), true)
  58. const showSelectionBorder = useMemo(() => {
  59. if (groupEnabled && enteringNodePayload?.nodeId === item.variableAssignerNodeId) {
  60. if (hoveringAssignVariableGroupId)
  61. return hoveringAssignVariableGroupId !== item.targetHandleId
  62. else
  63. return enteringNodePayload?.nodeData.advanced_settings?.groups[0].groupId !== item.targetHandleId
  64. }
  65. return false
  66. }, [enteringNodePayload, groupEnabled, hoveringAssignVariableGroupId, item.targetHandleId, item.variableAssignerNodeId])
  67. const showSelectedBorder = useMemo(() => {
  68. if (groupEnabled && enteringNodePayload?.nodeId === item.variableAssignerNodeId) {
  69. if (hoveringAssignVariableGroupId)
  70. return hoveringAssignVariableGroupId === item.targetHandleId
  71. else
  72. return enteringNodePayload?.nodeData.advanced_settings?.groups[0].groupId === item.targetHandleId
  73. }
  74. return false
  75. }, [enteringNodePayload, groupEnabled, hoveringAssignVariableGroupId, item.targetHandleId, item.variableAssignerNodeId])
  76. return (
  77. <div
  78. className={cn(
  79. 'relative pt-1 px-1.5 pb-1.5 rounded-lg border-[1.5px] border-transparent',
  80. showSelectionBorder && '!border-gray-300 !border-dashed bg-black/[0.02]',
  81. showSelectedBorder && '!border-primary-600 !bg-primary-50',
  82. )}
  83. onMouseEnter={() => groupEnabled && handleGroupItemMouseEnter(item.targetHandleId)}
  84. onMouseLeave={handleGroupItemMouseLeave}
  85. >
  86. <div className='flex items-center justify-between h-4 text-[10px] font-medium text-gray-500'>
  87. <span
  88. className={cn(
  89. 'grow uppercase truncate',
  90. showSelectedBorder && 'text-primary-600',
  91. )}
  92. title={item.title}
  93. >
  94. {item.title}
  95. </span>
  96. <div className='flex items-center'>
  97. <span className='shrink-0 ml-2'>{item.type}</span>
  98. <div className='ml-2 mr-1 w-[1px] h-2.5 bg-gray-200'></div>
  99. <AddVariable
  100. availableVars={availableVars}
  101. variableAssignerNodeId={item.variableAssignerNodeId}
  102. variableAssignerNodeData={item.variableAssignerNodeData}
  103. handleId={item.targetHandleId}
  104. />
  105. </div>
  106. </div>
  107. {
  108. !item.variables.length && (
  109. <div
  110. className={cn(
  111. 'relative flex items-center px-1 h-[22px] justify-between bg-gray-100 rounded-md space-x-1 text-[10px] font-normal text-gray-400 uppercase',
  112. (showSelectedBorder || showSelectionBorder) && '!bg-black/[0.02]',
  113. )}
  114. >
  115. {t(`${i18nPrefix}.varNotSet`)}
  116. </div>
  117. )
  118. }
  119. {
  120. !!item.variables.length && item.variables.map((variable = [], index) => {
  121. const isSystem = isSystemVar(variable)
  122. const isEnv = isENV(variable)
  123. const isChatVar = isConversationVar(variable)
  124. const node = isSystem ? nodes.find(node => node.data.type === BlockEnum.Start) : nodes.find(node => node.id === variable[0])
  125. const varName = isSystem ? `sys.${variable[variable.length - 1]}` : variable.slice(1).join('.')
  126. const isException = isExceptionVariable(varName, node?.data.type)
  127. return (
  128. <NodeVariableItem
  129. key={index}
  130. isEnv={isEnv}
  131. isChatVar={isChatVar}
  132. isException={isException}
  133. node={node as Node}
  134. varName={varName}
  135. showBorder={showSelectedBorder || showSelectionBorder}
  136. />
  137. )
  138. })
  139. }
  140. </div>
  141. )
  142. }
  143. export default memo(NodeGroupItem)