condition-wrap.tsx 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useCallback, useState } from 'react'
  4. import { useTranslation } from 'react-i18next'
  5. import { ReactSortable } from 'react-sortablejs'
  6. import {
  7. RiAddLine,
  8. RiDeleteBinLine,
  9. RiDraggable,
  10. } from '@remixicon/react'
  11. import type { CaseItem, HandleAddCondition, HandleAddSubVariableCondition, HandleRemoveCondition, HandleToggleConditionLogicalOperator, HandleToggleSubVariableConditionLogicalOperator, HandleUpdateCondition, HandleUpdateSubVariableCondition, handleRemoveSubVariableCondition } from '../types'
  12. import type { Node, NodeOutPutVar, Var } from '../../../types'
  13. import { VarType } from '../../../types'
  14. import { useGetAvailableVars } from '../../variable-assigner/hooks'
  15. import { SUB_VARIABLES } from '../default'
  16. import ConditionList from './condition-list'
  17. import ConditionAdd from './condition-add'
  18. import cn from '@/utils/classnames'
  19. import Button from '@/app/components/base/button'
  20. import { PortalSelect as Select } from '@/app/components/base/select'
  21. type Props = {
  22. isSubVariable?: boolean
  23. caseId?: string
  24. conditionId?: string
  25. cases: CaseItem[]
  26. readOnly: boolean
  27. handleSortCase?: (sortedCases: (CaseItem & { id: string })[]) => void
  28. handleRemoveCase?: (caseId: string) => void
  29. handleAddCondition?: HandleAddCondition
  30. handleRemoveCondition?: HandleRemoveCondition
  31. handleUpdateCondition?: HandleUpdateCondition
  32. handleToggleConditionLogicalOperator?: HandleToggleConditionLogicalOperator
  33. handleAddSubVariableCondition?: HandleAddSubVariableCondition
  34. handleRemoveSubVariableCondition?: handleRemoveSubVariableCondition
  35. handleUpdateSubVariableCondition?: HandleUpdateSubVariableCondition
  36. handleToggleSubVariableConditionLogicalOperator?: HandleToggleSubVariableConditionLogicalOperator
  37. nodeId: string
  38. nodesOutputVars: NodeOutPutVar[]
  39. availableNodes: Node[]
  40. varsIsVarFileAttribute?: Record<string, boolean>
  41. filterVar: (varPayload: Var) => boolean
  42. }
  43. const ConditionWrap: FC<Props> = ({
  44. isSubVariable,
  45. caseId,
  46. conditionId,
  47. nodeId: id = '',
  48. cases = [],
  49. readOnly,
  50. handleSortCase = () => { },
  51. handleRemoveCase,
  52. handleUpdateCondition,
  53. handleAddCondition,
  54. handleRemoveCondition,
  55. handleToggleConditionLogicalOperator,
  56. handleAddSubVariableCondition,
  57. handleRemoveSubVariableCondition,
  58. handleUpdateSubVariableCondition,
  59. handleToggleSubVariableConditionLogicalOperator,
  60. nodesOutputVars = [],
  61. availableNodes = [],
  62. varsIsVarFileAttribute = {},
  63. filterVar = () => true,
  64. }) => {
  65. const { t } = useTranslation()
  66. const getAvailableVars = useGetAvailableVars()
  67. const [willDeleteCaseId, setWillDeleteCaseId] = useState('')
  68. const casesLength = cases.length
  69. const filterNumberVar = useCallback((varPayload: Var) => {
  70. return varPayload.type === VarType.number
  71. }, [])
  72. const subVarOptions = SUB_VARIABLES.map(item => ({
  73. name: item,
  74. value: item,
  75. }))
  76. return (
  77. <>
  78. <ReactSortable
  79. list={cases.map(caseItem => ({ ...caseItem, id: caseItem.case_id }))}
  80. setList={handleSortCase}
  81. handle='.handle'
  82. ghostClass='bg-components-panel-bg'
  83. animation={150}
  84. disabled={readOnly || isSubVariable}
  85. >
  86. {
  87. cases.map((item, index) => (
  88. <div key={item.case_id}>
  89. <div
  90. className={cn(
  91. 'group relative rounded-[10px] bg-components-panel-bg',
  92. willDeleteCaseId === item.case_id && 'bg-state-destructive-hover',
  93. !isSubVariable && 'py-1 px-3 min-h-[40px] ',
  94. isSubVariable && 'px-1 py-2',
  95. )}
  96. >
  97. {!isSubVariable && (
  98. <>
  99. <RiDraggable className={cn(
  100. 'hidden handle absolute top-2 left-1 w-3 h-3 text-text-quaternary cursor-pointer',
  101. casesLength > 1 && 'group-hover:block',
  102. )} />
  103. <div className={cn(
  104. 'absolute left-4 leading-4 text-[13px] font-semibold text-text-secondary',
  105. casesLength === 1 ? 'top-2.5' : 'top-1',
  106. )}>
  107. {
  108. index === 0 ? 'IF' : 'ELIF'
  109. }
  110. {
  111. casesLength > 1 && (
  112. <div className='text-[10px] text-text-tertiary font-medium'>CASE {index + 1}</div>
  113. )
  114. }
  115. </div>
  116. </>
  117. )}
  118. {
  119. !!item.conditions.length && (
  120. <div className='mb-2'>
  121. <ConditionList
  122. disabled={readOnly}
  123. caseItem={item}
  124. caseId={isSubVariable ? caseId! : item.case_id}
  125. conditionId={conditionId}
  126. onUpdateCondition={handleUpdateCondition}
  127. onRemoveCondition={handleRemoveCondition}
  128. onToggleConditionLogicalOperator={handleToggleConditionLogicalOperator}
  129. nodeId={id}
  130. nodesOutputVars={nodesOutputVars}
  131. availableNodes={availableNodes}
  132. filterVar={filterVar}
  133. numberVariables={getAvailableVars(id, '', filterNumberVar)}
  134. varsIsVarFileAttribute={varsIsVarFileAttribute}
  135. onAddSubVariableCondition={handleAddSubVariableCondition}
  136. onRemoveSubVariableCondition={handleRemoveSubVariableCondition}
  137. onUpdateSubVariableCondition={handleUpdateSubVariableCondition}
  138. onToggleSubVariableConditionLogicalOperator={handleToggleSubVariableConditionLogicalOperator}
  139. isSubVariable={isSubVariable}
  140. />
  141. </div>
  142. )
  143. }
  144. <div className={cn(
  145. 'flex items-center justify-between pr-[30px]',
  146. !item.conditions.length && !isSubVariable && 'mt-1',
  147. !item.conditions.length && isSubVariable && 'mt-2',
  148. !isSubVariable && ' pl-[60px]',
  149. )}>
  150. {isSubVariable
  151. ? (
  152. <Select
  153. popupInnerClassName='w-[165px] max-h-none'
  154. onSelect={value => handleAddSubVariableCondition?.(caseId!, conditionId!, value.value as string)}
  155. items={subVarOptions}
  156. value=''
  157. renderTrigger={() => (
  158. <Button
  159. size='small'
  160. disabled={readOnly}
  161. >
  162. <RiAddLine className='mr-1 w-3.5 h-3.5' />
  163. {t('workflow.nodes.ifElse.addSubVariable')}
  164. </Button>
  165. )}
  166. hideChecked
  167. />
  168. )
  169. : (
  170. <ConditionAdd
  171. disabled={readOnly}
  172. caseId={item.case_id}
  173. variables={getAvailableVars(id, '', filterVar)}
  174. onSelectVariable={handleAddCondition!}
  175. />
  176. )}
  177. {
  178. ((index === 0 && casesLength > 1) || (index > 0)) && (
  179. <Button
  180. className='hover:text-components-button-destructive-ghost-text hover:bg-components-button-destructive-ghost-bg-hover'
  181. size='small'
  182. variant='ghost'
  183. disabled={readOnly}
  184. onClick={() => handleRemoveCase?.(item.case_id)}
  185. onMouseEnter={() => setWillDeleteCaseId(item.case_id)}
  186. onMouseLeave={() => setWillDeleteCaseId('')}
  187. >
  188. <RiDeleteBinLine className='mr-1 w-3.5 h-3.5' />
  189. {t('common.operation.remove')}
  190. </Button>
  191. )
  192. }
  193. </div>
  194. </div>
  195. {!isSubVariable && (
  196. <div className='my-2 mx-3 h-[1px] bg-divider-subtle'></div>
  197. )}
  198. </div>
  199. ))
  200. }
  201. </ReactSortable>
  202. {(cases.length === 0) && (
  203. <Button
  204. size='small'
  205. disabled={readOnly}
  206. onClick={() => handleAddSubVariableCondition?.(caseId!, conditionId!)}
  207. >
  208. <RiAddLine className='mr-1 w-3.5 h-3.5' />
  209. {t('workflow.nodes.ifElse.addSubVariable')}
  210. </Button>
  211. )}
  212. </>
  213. )
  214. }
  215. export default React.memo(ConditionWrap)