condition-number-input.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import {
  2. memo,
  3. useCallback,
  4. useState,
  5. } from 'react'
  6. import { useTranslation } from 'react-i18next'
  7. import { RiArrowDownSLine } from '@remixicon/react'
  8. import { capitalize } from 'lodash-es'
  9. import { VarType as NumberVarType } from '../../tool/types'
  10. import VariableTag from '../../_base/components/variable-tag'
  11. import {
  12. PortalToFollowElem,
  13. PortalToFollowElemContent,
  14. PortalToFollowElemTrigger,
  15. } from '@/app/components/base/portal-to-follow-elem'
  16. import Button from '@/app/components/base/button'
  17. import cn from '@/utils/classnames'
  18. import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
  19. import type {
  20. NodeOutPutVar,
  21. ValueSelector,
  22. } from '@/app/components/workflow/types'
  23. import { VarType } from '@/app/components/workflow/types'
  24. import { variableTransformer } from '@/app/components/workflow/utils'
  25. import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
  26. const options = [
  27. NumberVarType.variable,
  28. NumberVarType.constant,
  29. ]
  30. type ConditionNumberInputProps = {
  31. numberVarType?: NumberVarType
  32. onNumberVarTypeChange: (v: NumberVarType) => void
  33. value: string
  34. onValueChange: (v: string) => void
  35. variables: NodeOutPutVar[]
  36. }
  37. const ConditionNumberInput = ({
  38. numberVarType = NumberVarType.constant,
  39. onNumberVarTypeChange,
  40. value,
  41. onValueChange,
  42. variables,
  43. }: ConditionNumberInputProps) => {
  44. const { t } = useTranslation()
  45. const [numberVarTypeVisible, setNumberVarTypeVisible] = useState(false)
  46. const [variableSelectorVisible, setVariableSelectorVisible] = useState(false)
  47. const handleSelectVariable = useCallback((valueSelector: ValueSelector) => {
  48. onValueChange(variableTransformer(valueSelector) as string)
  49. setVariableSelectorVisible(false)
  50. }, [onValueChange])
  51. return (
  52. <div className='flex items-center cursor-pointer'>
  53. <PortalToFollowElem
  54. open={numberVarTypeVisible}
  55. onOpenChange={setNumberVarTypeVisible}
  56. placement='bottom-start'
  57. offset={{ mainAxis: 2, crossAxis: 0 }}
  58. >
  59. <PortalToFollowElemTrigger onClick={() => setNumberVarTypeVisible(v => !v)}>
  60. <Button
  61. className='shrink-0'
  62. variant='ghost'
  63. size='small'
  64. >
  65. {capitalize(numberVarType)}
  66. <RiArrowDownSLine className='ml-[1px] w-3.5 h-3.5' />
  67. </Button>
  68. </PortalToFollowElemTrigger>
  69. <PortalToFollowElemContent className='z-[1000]'>
  70. <div className='p-1 w-[112px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'>
  71. {
  72. options.map(option => (
  73. <div
  74. key={option}
  75. className={cn(
  76. 'flex items-center px-3 h-7 rounded-md hover:bg-state-base-hover cursor-pointer',
  77. 'text-[13px] font-medium text-text-secondary',
  78. numberVarType === option && 'bg-state-base-hover',
  79. )}
  80. onClick={() => {
  81. onNumberVarTypeChange(option)
  82. setNumberVarTypeVisible(false)
  83. }}
  84. >
  85. {capitalize(option)}
  86. </div>
  87. ))
  88. }
  89. </div>
  90. </PortalToFollowElemContent>
  91. </PortalToFollowElem>
  92. <div className='mx-1 w-[1px] h-4 bg-divider-regular'></div>
  93. <div className='grow w-0 ml-0.5'>
  94. {
  95. numberVarType === NumberVarType.variable && (
  96. <PortalToFollowElem
  97. open={variableSelectorVisible}
  98. onOpenChange={setVariableSelectorVisible}
  99. placement='bottom-start'
  100. offset={{ mainAxis: 2, crossAxis: 0 }}
  101. >
  102. <PortalToFollowElemTrigger
  103. className='w-full'
  104. onClick={() => setVariableSelectorVisible(v => !v)}>
  105. {
  106. value && (
  107. <VariableTag
  108. valueSelector={variableTransformer(value) as string[]}
  109. varType={VarType.number}
  110. />
  111. )
  112. }
  113. {
  114. !value && (
  115. <div className='flex items-center p-1 h-6 text-components-input-text-placeholder text-[13px]'>
  116. <Variable02 className='mr-1 w-4 h-4' />
  117. {t('workflow.nodes.ifElse.selectVariable')}
  118. </div>
  119. )
  120. }
  121. </PortalToFollowElemTrigger>
  122. <PortalToFollowElemContent className='z-[1000]'>
  123. <div className='w-[296px] bg-components-panel-bg-blur rounded-lg border-[0.5px] border-components-panel-border shadow-lg'>
  124. <VarReferenceVars
  125. vars={variables}
  126. onChange={handleSelectVariable}
  127. />
  128. </div>
  129. </PortalToFollowElemContent>
  130. </PortalToFollowElem>
  131. )
  132. }
  133. {
  134. numberVarType === NumberVarType.constant && (
  135. <input
  136. className='block w-full px-2 text-[13px] text-components-input-text-filled placeholder:text-components-input-text-placeholder outline-none appearance-none bg-transparent'
  137. type='number'
  138. value={value}
  139. onChange={e => onValueChange(e.target.value)}
  140. placeholder={t('workflow.nodes.ifElse.enterValue') || ''}
  141. />
  142. )
  143. }
  144. </div>
  145. </div>
  146. )
  147. }
  148. export default memo(ConditionNumberInput)