Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

index.tsx 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useCallback, useState } from 'react'
  4. import { useTranslation } from 'react-i18next'
  5. import { useContext } from 'use-context-selector'
  6. import ModalFoot from '../modal-foot'
  7. import ConfigSelect from '../config-select'
  8. import ConfigString from '../config-string'
  9. import SelectTypeItem from '../select-type-item'
  10. import Field from './field'
  11. import Toast from '@/app/components/base/toast'
  12. import { checkKeys, getNewVarInWorkflow } from '@/utils/var'
  13. import ConfigContext from '@/context/debug-configuration'
  14. import type { InputVar, MoreInfo } from '@/app/components/workflow/types'
  15. import Modal from '@/app/components/base/modal'
  16. import Switch from '@/app/components/base/switch'
  17. import { ChangeType, InputVarType } from '@/app/components/workflow/types'
  18. const TEXT_MAX_LENGTH = 256
  19. export type IConfigModalProps = {
  20. isCreate?: boolean
  21. payload?: InputVar
  22. isShow: boolean
  23. varKeys?: string[]
  24. onClose: () => void
  25. onConfirm: (newValue: InputVar, moreInfo?: MoreInfo) => void
  26. }
  27. const inputClassName = 'w-full px-3 text-sm leading-9 text-gray-900 border-0 rounded-lg grow h-9 bg-gray-100 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200'
  28. const ConfigModal: FC<IConfigModalProps> = ({
  29. isCreate,
  30. payload,
  31. isShow,
  32. onClose,
  33. onConfirm,
  34. }) => {
  35. const { modelConfig } = useContext(ConfigContext)
  36. const { t } = useTranslation()
  37. const [tempPayload, setTempPayload] = useState<InputVar>(payload || getNewVarInWorkflow('') as any)
  38. const { type, label, variable, options, max_length } = tempPayload
  39. const isStringInput = type === InputVarType.textInput || type === InputVarType.paragraph
  40. const checkVariableName = useCallback((value: string) => {
  41. const { isValid, errorMessageKey } = checkKeys([value], false)
  42. if (!isValid) {
  43. Toast.notify({
  44. type: 'error',
  45. message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: t('appDebug.variableConfig.varName') }),
  46. })
  47. return false
  48. }
  49. return true
  50. }, [t])
  51. const handlePayloadChange = useCallback((key: string) => {
  52. return (value: any) => {
  53. setTempPayload((prev) => {
  54. const newPayload = {
  55. ...prev,
  56. [key]: value,
  57. }
  58. return newPayload
  59. })
  60. }
  61. }, [])
  62. const handleVarKeyBlur = useCallback((e: any) => {
  63. const varName = e.target.value
  64. if (!checkVariableName(varName) || tempPayload.label)
  65. return
  66. setTempPayload((prev) => {
  67. return {
  68. ...prev,
  69. label: varName,
  70. }
  71. })
  72. }, [checkVariableName, tempPayload.label])
  73. const handleConfirm = () => {
  74. const moreInfo = tempPayload.variable === payload?.variable
  75. ? undefined
  76. : {
  77. type: ChangeType.changeVarName,
  78. payload: { beforeKey: payload?.variable || '', afterKey: tempPayload.variable },
  79. }
  80. const isVariableNameValid = checkVariableName(tempPayload.variable)
  81. if (!isVariableNameValid)
  82. return
  83. // TODO: check if key already exists. should the consider the edit case
  84. // if (varKeys.map(key => key?.trim()).includes(tempPayload.variable.trim())) {
  85. // Toast.notify({
  86. // type: 'error',
  87. // message: t('appDebug.varKeyError.keyAlreadyExists', { key: tempPayload.variable }),
  88. // })
  89. // return
  90. // }
  91. if (!tempPayload.label) {
  92. Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.labelNameRequired') })
  93. return
  94. }
  95. if (isStringInput || type === InputVarType.number) {
  96. onConfirm(tempPayload, moreInfo)
  97. }
  98. else {
  99. if (options?.length === 0) {
  100. Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.atLeastOneOption') })
  101. return
  102. }
  103. const obj: Record<string, boolean> = {}
  104. let hasRepeatedItem = false
  105. options?.forEach((o) => {
  106. if (obj[o]) {
  107. hasRepeatedItem = true
  108. return
  109. }
  110. obj[o] = true
  111. })
  112. if (hasRepeatedItem) {
  113. Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.optionRepeat') })
  114. return
  115. }
  116. onConfirm(tempPayload, moreInfo)
  117. }
  118. }
  119. return (
  120. <Modal
  121. title={t(`appDebug.variableConfig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`)}
  122. isShow={isShow}
  123. onClose={onClose}
  124. >
  125. <div className='mb-8'>
  126. <div className='space-y-2'>
  127. <Field title={t('appDebug.variableConfig.fieldType')}>
  128. <div className='flex space-x-2'>
  129. <SelectTypeItem type={InputVarType.textInput} selected={type === InputVarType.textInput} onClick={() => handlePayloadChange('type')(InputVarType.textInput)} />
  130. <SelectTypeItem type={InputVarType.paragraph} selected={type === InputVarType.paragraph} onClick={() => handlePayloadChange('type')(InputVarType.paragraph)} />
  131. <SelectTypeItem type={InputVarType.select} selected={type === InputVarType.select} onClick={() => handlePayloadChange('type')(InputVarType.select)} />
  132. <SelectTypeItem type={InputVarType.number} selected={type === InputVarType.number} onClick={() => handlePayloadChange('type')(InputVarType.number)} />
  133. </div>
  134. </Field>
  135. <Field title={t('appDebug.variableConfig.varName')}>
  136. <input
  137. type='text'
  138. className={inputClassName}
  139. value={variable}
  140. onChange={e => handlePayloadChange('variable')(e.target.value)}
  141. onBlur={handleVarKeyBlur}
  142. placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
  143. />
  144. </Field>
  145. <Field title={t('appDebug.variableConfig.labelName')}>
  146. <input
  147. type='text'
  148. className={inputClassName}
  149. value={label as string}
  150. onChange={e => handlePayloadChange('label')(e.target.value)}
  151. placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
  152. />
  153. </Field>
  154. {isStringInput && (
  155. <Field title={t('appDebug.variableConfig.maxLength')}>
  156. <ConfigString maxLength={type === InputVarType.textInput ? TEXT_MAX_LENGTH : Infinity} modelId={modelConfig.model_id} value={max_length} onChange={handlePayloadChange('max_length')} />
  157. </Field>
  158. )}
  159. {type === InputVarType.select && (
  160. <Field title={t('appDebug.variableConfig.options')}>
  161. <ConfigSelect options={options || []} onChange={handlePayloadChange('options')} />
  162. </Field>
  163. )}
  164. <Field title={t('appDebug.variableConfig.required')}>
  165. <Switch defaultValue={tempPayload.required} onChange={handlePayloadChange('required')} />
  166. </Field>
  167. </div>
  168. </div>
  169. <ModalFoot
  170. onConfirm={handleConfirm}
  171. onCancel={onClose}
  172. />
  173. </Modal>
  174. )
  175. }
  176. export default React.memo(ConfigModal)