|  | @@ -12,6 +12,7 @@ import { SimpleSelect } from '@/app/components/base/select'
 | 
	
		
			
				|  |  |  import TagInput from '@/app/components/base/tag-input'
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  export type ParameterValue = number | string | string[] | boolean | undefined
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  type ParameterItemProps = {
 | 
	
		
			
				|  |  |    parameterRule: ModelParameterRule
 | 
	
		
			
				|  |  |    value?: ParameterValue
 | 
	
	
		
			
				|  | @@ -28,48 +29,29 @@ const ParameterItem: FC<ParameterItemProps> = ({
 | 
	
		
			
				|  |  |  }) => {
 | 
	
		
			
				|  |  |    const language = useLanguage()
 | 
	
		
			
				|  |  |    const [localValue, setLocalValue] = useState(value)
 | 
	
		
			
				|  |  | -  const mergedValue = isNullOrUndefined(value) ? localValue : value
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const getDefaultValue = () => {
 | 
	
		
			
				|  |  |      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
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (parameterRule.type === 'tag')
 | 
	
		
			
				|  |  | +    else if (parameterRule.type === 'tag')
 | 
	
		
			
				|  |  |        defaultValue = !isNullOrUndefined(parameterRule.default) ? parameterRule.default : []
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      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>) => {
 | 
	
	
		
			
				|  | @@ -81,45 +63,127 @@ const ParameterItem: FC<ParameterItemProps> = ({
 | 
	
		
			
				|  |  |      if (!isNullOrUndefined(parameterRule.min) && num < parameterRule.min!)
 | 
	
		
			
				|  |  |        num = parameterRule.min as number
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    handleChange(num)
 | 
	
		
			
				|  |  | +    handleInputChange(num)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const handleSlideChange = (num: number) => {
 | 
	
		
			
				|  |  | -    handleChange(num)
 | 
	
		
			
				|  |  | +    handleInputChange(num)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const handleRadioChange = (v: number) => {
 | 
	
		
			
				|  |  | -    handleChange(v === 1)
 | 
	
		
			
				|  |  | +    handleInputChange(v === 1)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const handleStringInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
	
		
			
				|  |  | -    handleChange(e.target.value)
 | 
	
		
			
				|  |  | +    handleInputChange(e.target.value)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const handleSelect = (option: { value: string | number; name: string }) => {
 | 
	
		
			
				|  |  | -    handleChange(option.value)
 | 
	
		
			
				|  |  | +    handleInputChange(option.value)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const handleTagChange = (newSequences: string[]) => {
 | 
	
		
			
				|  |  | -    handleChange(newSequences)
 | 
	
		
			
				|  |  | +    handleInputChange(newSequences)
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const handleSwitch = (checked: boolean) => {
 | 
	
		
			
				|  |  |      if (onSwitch) {
 | 
	
		
			
				|  |  | -      let assignValue: ParameterValue = localValue
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      if (isNullOrUndefined(localValue))
 | 
	
		
			
				|  |  | -        assignValue = getDefaultValue()
 | 
	
		
			
				|  |  | +      const assignValue: ParameterValue = localValue || getDefaultValue()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        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.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 (
 | 
	
		
			
				|  |  |      <div className={`flex items-center justify-between ${className}`}>
 | 
	
	
		
			
				|  | @@ -161,82 +225,7 @@ const ParameterItem: FC<ParameterItemProps> = ({
 | 
	
		
			
				|  |  |            )
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |        </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>
 | 
	
		
			
				|  |  |    )
 | 
	
		
			
				|  |  |  }
 |