| import TagInput from '@/app/components/base/tag-input' | import TagInput from '@/app/components/base/tag-input' | ||||
| export type ParameterValue = number | string | string[] | boolean | undefined | export type ParameterValue = number | string | string[] | boolean | undefined | ||||
| type ParameterItemProps = { | type ParameterItemProps = { | ||||
| parameterRule: ModelParameterRule | parameterRule: ModelParameterRule | ||||
| value?: ParameterValue | value?: ParameterValue | ||||
| }) => { | }) => { | ||||
| const language = useLanguage() | const language = useLanguage() | ||||
| const [localValue, setLocalValue] = useState(value) | const [localValue, setLocalValue] = useState(value) | ||||
| const mergedValue = isNullOrUndefined(value) ? localValue : value | |||||
| const getDefaultValue = () => { | const getDefaultValue = () => { | ||||
| let defaultValue: ParameterValue | let defaultValue: ParameterValue | ||||
| if (parameterRule.type === 'int' || parameterRule.type === 'float') { | |||||
| if (isNullOrUndefined(parameterRule.default)) { | |||||
| if (parameterRule.min) | |||||
| defaultValue = parameterRule.min | |||||
| else | |||||
| defaultValue = 0 | |||||
| } | |||||
| else { | |||||
| defaultValue = parameterRule.default | |||||
| } | |||||
| } | |||||
| if (parameterRule.type === 'string' && !parameterRule.options?.length) | |||||
| defaultValue = parameterRule.default || '' | |||||
| if (parameterRule.type === 'string' && parameterRule.options?.length) | |||||
| defaultValue = parameterRule.default || '' | |||||
| if (parameterRule.type === 'boolean') | |||||
| if (parameterRule.type === 'int' || parameterRule.type === 'float') | |||||
| defaultValue = isNullOrUndefined(parameterRule.default) ? (parameterRule.min || 0) : parameterRule.default | |||||
| else if (parameterRule.type === 'string') | |||||
| defaultValue = parameterRule.options?.length ? (parameterRule.default || '') : (parameterRule.default || '') | |||||
| else if (parameterRule.type === 'boolean') | |||||
| defaultValue = !isNullOrUndefined(parameterRule.default) ? parameterRule.default : false | defaultValue = !isNullOrUndefined(parameterRule.default) ? parameterRule.default : false | ||||
| if (parameterRule.type === 'tag') | |||||
| else if (parameterRule.type === 'tag') | |||||
| defaultValue = !isNullOrUndefined(parameterRule.default) ? parameterRule.default : [] | defaultValue = !isNullOrUndefined(parameterRule.default) ? parameterRule.default : [] | ||||
| return defaultValue | return defaultValue | ||||
| } | } | ||||
| const renderValue = isNullOrUndefined(mergedValue) ? getDefaultValue() : mergedValue | |||||
| const handleChange = (v: ParameterValue) => { | |||||
| setLocalValue(v) | |||||
| const renderValue = value ?? localValue ?? getDefaultValue() | |||||
| if (onChange) { | |||||
| if (parameterRule.name === 'stop') | |||||
| onChange(v) | |||||
| else if (!isNullOrUndefined(value)) | |||||
| onChange(v) | |||||
| } | |||||
| const handleInputChange = (newValue: ParameterValue) => { | |||||
| setLocalValue(newValue) | |||||
| if (onChange && (parameterRule.name === 'stop' || !isNullOrUndefined(value))) | |||||
| onChange(newValue) | |||||
| } | } | ||||
| const handleNumberInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | const handleNumberInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||||
| if (!isNullOrUndefined(parameterRule.min) && num < parameterRule.min!) | if (!isNullOrUndefined(parameterRule.min) && num < parameterRule.min!) | ||||
| num = parameterRule.min as number | num = parameterRule.min as number | ||||
| handleChange(num) | |||||
| handleInputChange(num) | |||||
| } | } | ||||
| const handleSlideChange = (num: number) => { | const handleSlideChange = (num: number) => { | ||||
| handleChange(num) | |||||
| handleInputChange(num) | |||||
| } | } | ||||
| const handleRadioChange = (v: number) => { | const handleRadioChange = (v: number) => { | ||||
| handleChange(v === 1) | |||||
| handleInputChange(v === 1) | |||||
| } | } | ||||
| const handleStringInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | const handleStringInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||||
| handleChange(e.target.value) | |||||
| handleInputChange(e.target.value) | |||||
| } | } | ||||
| const handleSelect = (option: { value: string | number; name: string }) => { | const handleSelect = (option: { value: string | number; name: string }) => { | ||||
| handleChange(option.value) | |||||
| handleInputChange(option.value) | |||||
| } | } | ||||
| const handleTagChange = (newSequences: string[]) => { | const handleTagChange = (newSequences: string[]) => { | ||||
| handleChange(newSequences) | |||||
| handleInputChange(newSequences) | |||||
| } | } | ||||
| const handleSwitch = (checked: boolean) => { | const handleSwitch = (checked: boolean) => { | ||||
| if (onSwitch) { | if (onSwitch) { | ||||
| let assignValue: ParameterValue = localValue | |||||
| if (isNullOrUndefined(localValue)) | |||||
| assignValue = getDefaultValue() | |||||
| const assignValue: ParameterValue = localValue || getDefaultValue() | |||||
| onSwitch(checked, assignValue) | onSwitch(checked, assignValue) | ||||
| } | } | ||||
| } | } | ||||
| const numberInputWithSlide = (parameterRule.type === 'int' || parameterRule.type === 'float') | |||||
| const renderInput = () => { | |||||
| const numberInputWithSlide = (parameterRule.type === 'int' || parameterRule.type === 'float') | |||||
| && !isNullOrUndefined(parameterRule.min) | && !isNullOrUndefined(parameterRule.min) | ||||
| && !isNullOrUndefined(parameterRule.max) | && !isNullOrUndefined(parameterRule.max) | ||||
| const numberInput = (parameterRule.type === 'int' || parameterRule.type === 'float') | |||||
| && (isNullOrUndefined(parameterRule.min) || isNullOrUndefined(parameterRule.max)) | |||||
| if (parameterRule.type === 'int' || parameterRule.type === 'float') { | |||||
| let step = 100 | |||||
| if (parameterRule.max) { | |||||
| if (parameterRule.max < 10) | |||||
| step = 0.1 | |||||
| else if (parameterRule.max < 100) | |||||
| step = 1 | |||||
| else if (parameterRule.max < 1000) | |||||
| step = 10 | |||||
| else if (parameterRule.max < 10000) | |||||
| step = 100 | |||||
| } | |||||
| return ( | |||||
| <> | |||||
| {numberInputWithSlide && <Slider | |||||
| className='w-[120px]' | |||||
| value={renderValue as number} | |||||
| min={parameterRule.min} | |||||
| max={parameterRule.max} | |||||
| step={step} | |||||
| onChange={handleSlideChange} | |||||
| />} | |||||
| <input | |||||
| className='shrink-0 block ml-4 pl-3 w-16 h-8 appearance-none outline-none rounded-lg bg-gray-100 text-[13px] text-gra-900' | |||||
| type='number' | |||||
| max={parameterRule.max} | |||||
| min={parameterRule.min} | |||||
| step={numberInputWithSlide ? step : +`0.${parameterRule.precision || 0}`} | |||||
| value={renderValue as string} | |||||
| onChange={handleNumberInputChange} | |||||
| /> | |||||
| </> | |||||
| ) | |||||
| } | |||||
| if (parameterRule.type === 'boolean') { | |||||
| return ( | |||||
| <Radio.Group | |||||
| className='w-[200px] flex items-center' | |||||
| value={renderValue ? 1 : 0} | |||||
| onChange={handleRadioChange} | |||||
| > | |||||
| <Radio value={1} className='!mr-1 w-[94px]'>True</Radio> | |||||
| <Radio value={0} className='w-[94px]'>False</Radio> | |||||
| </Radio.Group> | |||||
| ) | |||||
| } | |||||
| if (parameterRule.type === 'string' && !parameterRule.options?.length) { | |||||
| return ( | |||||
| <input | |||||
| className='flex items-center px-3 w-[200px] h-8 appearance-none outline-none rounded-lg bg-gray-100 text-[13px] text-gra-900' | |||||
| value={renderValue as string} | |||||
| onChange={handleStringInputChange} | |||||
| /> | |||||
| ) | |||||
| } | |||||
| if (parameterRule.type === 'string' && !!parameterRule?.options?.length) { | |||||
| return ( | |||||
| <SimpleSelect | |||||
| className='!py-0' | |||||
| wrapperClassName='!w-[200px] !h-8' | |||||
| defaultValue={renderValue as string} | |||||
| onSelect={handleSelect} | |||||
| items={parameterRule.options.map(option => ({ value: option, name: option }))} | |||||
| /> | |||||
| ) | |||||
| } | |||||
| if (parameterRule.type === 'tag') { | |||||
| return ( | |||||
| <div className='w-[200px]'> | |||||
| <TagInput | |||||
| items={renderValue as string[]} | |||||
| onChange={handleTagChange} | |||||
| customizedConfirmKey='Tab' | |||||
| /> | |||||
| </div> | |||||
| ) | |||||
| } | |||||
| return null | |||||
| } | |||||
| return ( | return ( | ||||
| <div className={`flex items-center justify-between ${className}`}> | <div className={`flex items-center justify-between ${className}`}> | ||||
| ) | ) | ||||
| } | } | ||||
| </div> | </div> | ||||
| { | |||||
| numberInputWithSlide && ( | |||||
| <div className='flex items-center'> | |||||
| <Slider | |||||
| className='w-[120px]' | |||||
| value={renderValue as number} | |||||
| min={parameterRule.min} | |||||
| max={parameterRule.max} | |||||
| step={+`0.${parameterRule.precision || 0}`} | |||||
| onChange={handleSlideChange} | |||||
| /> | |||||
| <input | |||||
| className='shrink-0 block ml-4 pl-3 w-16 h-8 appearance-none outline-none rounded-lg bg-gray-100 text-[13px] text-gra-900' | |||||
| type='number' | |||||
| max={parameterRule.max} | |||||
| min={parameterRule.min} | |||||
| step={+`0.${parameterRule.precision || 0}`} | |||||
| value={renderValue as string} | |||||
| onChange={handleNumberInputChange} | |||||
| /> | |||||
| </div> | |||||
| ) | |||||
| } | |||||
| { | |||||
| parameterRule.type === 'boolean' && ( | |||||
| <Radio.Group | |||||
| className='w-[200px] flex items-center' | |||||
| value={renderValue ? 1 : 0} | |||||
| onChange={handleRadioChange} | |||||
| > | |||||
| <Radio value={1} className='!mr-1 w-[94px]'>True</Radio> | |||||
| <Radio value={0} className='w-[94px]'>False</Radio> | |||||
| </Radio.Group> | |||||
| ) | |||||
| } | |||||
| { | |||||
| numberInput && ( | |||||
| <input | |||||
| type='number' | |||||
| className='flex items-center px-3 w-[200px] h-8 appearance-none outline-none rounded-lg bg-gray-100 text-[13px] text-gra-900' | |||||
| value={renderValue as string} | |||||
| onChange={handleNumberInputChange} | |||||
| /> | |||||
| ) | |||||
| } | |||||
| { | |||||
| parameterRule.type === 'string' && !parameterRule.options?.length && ( | |||||
| <input | |||||
| className='flex items-center px-3 w-[200px] h-8 appearance-none outline-none rounded-lg bg-gray-100 text-[13px] text-gra-900' | |||||
| value={renderValue as string} | |||||
| onChange={handleStringInputChange} | |||||
| /> | |||||
| ) | |||||
| } | |||||
| { | |||||
| parameterRule.type === 'string' && !!parameterRule?.options?.length && ( | |||||
| <SimpleSelect | |||||
| className='!py-0' | |||||
| wrapperClassName='!w-[200px] !h-8' | |||||
| defaultValue={renderValue as string} | |||||
| onSelect={handleSelect} | |||||
| items={parameterRule.options.map(option => ({ value: option, name: option }))} | |||||
| /> | |||||
| ) | |||||
| } | |||||
| { | |||||
| parameterRule.type === 'tag' && ( | |||||
| <div className='w-[200px]'> | |||||
| <TagInput | |||||
| items={renderValue as string[]} | |||||
| onChange={handleTagChange} | |||||
| customizedConfirmKey='Tab' | |||||
| /> | |||||
| </div> | |||||
| ) | |||||
| } | |||||
| {renderInput()} | |||||
| </div> | </div> | ||||
| ) | ) | ||||
| } | } |