feat: support bool type variable frontend (#24437)

Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com>
This commit is contained in:
Joel
2025-08-26 18:16:05 +08:00
committed by GitHub
parent b5c2756261
commit dac72b078d
126 changed files with 3832 additions and 512 deletions

View File

@@ -36,6 +36,7 @@ import cn from '@/utils/classnames'
import { SimpleSelect as Select } from '@/app/components/base/select'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import ConditionVarSelector from './condition-var-selector'
import BoolValue from '@/app/components/workflow/panel/chat-variable-panel/components/bool-value'
const optionNameI18NPrefix = 'workflow.nodes.ifElse.optionName'
@@ -129,12 +130,12 @@ const ConditionItem = ({
const isArrayValue = fileAttr?.key === 'transfer_method' || fileAttr?.key === 'type'
const handleUpdateConditionValue = useCallback((value: string) => {
if (value === condition.value || (isArrayValue && value === condition.value?.[0]))
const handleUpdateConditionValue = useCallback((value: string | boolean) => {
if (value === condition.value || (isArrayValue && value === (condition.value as string[])?.[0]))
return
const newCondition = {
...condition,
value: isArrayValue ? [value] : value,
value: isArrayValue ? [value as string] : value,
}
doUpdateCondition(newCondition)
}, [condition, doUpdateCondition, isArrayValue])
@@ -253,7 +254,7 @@ const ConditionItem = ({
/>
</div>
{
!comparisonOperatorNotRequireValue(condition.comparison_operator) && !isNotInput && condition.varType !== VarType.number && (
!comparisonOperatorNotRequireValue(condition.comparison_operator) && !isNotInput && condition.varType !== VarType.number && condition.varType !== VarType.boolean && (
<div className='max-h-[100px] overflow-y-auto border-t border-t-divider-subtle px-2 py-1'>
<ConditionInput
disabled={disabled}
@@ -264,6 +265,14 @@ const ConditionItem = ({
</div>
)
}
{!comparisonOperatorNotRequireValue(condition.comparison_operator) && condition.varType === VarType.boolean
&& <div className='p-1'>
<BoolValue
value={condition.value as boolean}
onChange={handleUpdateConditionValue}
/>
</div>
}
{
!comparisonOperatorNotRequireValue(condition.comparison_operator) && !isNotInput && condition.varType === VarType.number && (
<div className='border-t border-t-divider-subtle px-2 py-1 pt-[3px]'>

View File

@@ -18,33 +18,16 @@ import {
ValueType,
VarType,
} from '@/app/components/workflow/types'
import BoolValue from '@/app/components/workflow/panel/chat-variable-panel/components/bool-value'
const objectPlaceholder = `# example
# {
# "name": "ray",
# "age": 20
# }`
const arrayStringPlaceholder = `# example
# [
# "value1",
# "value2"
# ]`
const arrayNumberPlaceholder = `# example
# [
# 100,
# 200
# ]`
const arrayObjectPlaceholder = `# example
# [
# {
# "name": "ray",
# "age": 20
# },
# {
# "name": "lily",
# "age": 18
# }
# ]`
import {
arrayBoolPlaceholder,
arrayNumberPlaceholder,
arrayObjectPlaceholder,
arrayStringPlaceholder,
objectPlaceholder,
} from '@/app/components/workflow/panel/chat-variable-panel/utils'
import ArrayBoolList from '@/app/components/workflow/panel/chat-variable-panel/components/array-bool-list'
type FormItemProps = {
nodeId: string
@@ -83,6 +66,8 @@ const FormItem = ({
return arrayNumberPlaceholder
if (var_type === VarType.arrayObject)
return arrayObjectPlaceholder
if (var_type === VarType.arrayBoolean)
return arrayBoolPlaceholder
return objectPlaceholder
}, [var_type])
@@ -120,6 +105,14 @@ const FormItem = ({
/>
)
}
{
value_type === ValueType.constant && var_type === VarType.boolean && (
<BoolValue
value={value}
onChange={handleChange}
/>
)
}
{
value_type === ValueType.constant
&& (var_type === VarType.object || var_type === VarType.arrayString || var_type === VarType.arrayNumber || var_type === VarType.arrayObject)
@@ -137,6 +130,15 @@ const FormItem = ({
</div>
)
}
{
value_type === ValueType.constant && var_type === VarType.arrayBoolean && (
<ArrayBoolList
className='mt-2'
list={value || [false]}
onChange={handleChange}
/>
)
}
</div>
)
}

View File

@@ -12,6 +12,7 @@ import type {
} from '@/app/components/workflow/nodes/loop/types'
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
import Toast from '@/app/components/base/toast'
import { ValueType, VarType } from '@/app/components/workflow/types'
type ItemProps = {
item: LoopVariable
@@ -42,12 +43,25 @@ const Item = ({
handleUpdateLoopVariable(item.id, { label: e.target.value })
}, [item.id, handleUpdateLoopVariable])
const getDefaultValue = useCallback((varType: VarType, valueType: ValueType) => {
if(valueType === ValueType.variable)
return undefined
switch (varType) {
case VarType.boolean:
return false
case VarType.arrayBoolean:
return [false]
default:
return undefined
}
}, [])
const handleUpdateItemVarType = useCallback((value: any) => {
handleUpdateLoopVariable(item.id, { var_type: value, value: undefined })
handleUpdateLoopVariable(item.id, { var_type: value, value: getDefaultValue(value, item.value_type) })
}, [item.id, handleUpdateLoopVariable])
const handleUpdateItemValueType = useCallback((value: any) => {
handleUpdateLoopVariable(item.id, { value_type: value, value: undefined })
handleUpdateLoopVariable(item.id, { value_type: value, value: getDefaultValue(item.var_type, value) })
}, [item.id, handleUpdateLoopVariable])
const handleUpdateItemValue = useCallback((value: any) => {

View File

@@ -22,6 +22,10 @@ const VariableTypeSelect = ({
label: 'Object',
value: VarType.object,
},
{
label: 'Boolean',
value: VarType.boolean,
},
{
label: 'Array[string]',
value: VarType.arrayString,
@@ -34,6 +38,10 @@ const VariableTypeSelect = ({
label: 'Array[object]',
value: VarType.arrayObject,
},
{
label: 'Array[boolean]',
value: VarType.arrayBoolean,
},
]
return (

View File

@@ -1,4 +1,4 @@
import { BlockEnum } from '../../types'
import { BlockEnum, VarType } from '../../types'
import type { NodeDefault } from '../../types'
import { ComparisonOperator, LogicalOperator, type LoopNodeType } from './types'
import { isEmptyRelatedOperator } from './utils'
@@ -55,7 +55,7 @@ const nodeDefault: NodeDefault<LoopNodeType> = {
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t(`${i18nPrefix}.fields.variableValue`) })
}
else {
if (!isEmptyRelatedOperator(condition.comparison_operator!) && !condition.value)
if (!isEmptyRelatedOperator(condition.comparison_operator!) && (condition.varType === VarType.boolean ? condition.value === undefined : !condition.value))
errorMessages = t(`${i18nPrefix}.fieldRequired`, { field: t(`${i18nPrefix}.fields.variableValue`) })
}
}

View File

@@ -44,7 +44,7 @@ export type Condition = {
variable_selector?: ValueSelector
key?: string // sub variable key
comparison_operator?: ComparisonOperator
value: string | string[]
value: string | string[] | boolean
numberVarType?: NumberVarType
sub_variable_condition?: CaseItem
}

View File

@@ -63,7 +63,7 @@ const useConfig = (id: string, payload: LoopNodeType) => {
varType: varItem.type,
variable_selector: valueSelector,
comparison_operator: getOperators(varItem.type, getIsVarFileAttribute(valueSelector) ? { key: valueSelector.slice(-1)[0] } : undefined)[0],
value: '',
value: varItem.type === VarType.boolean ? 'false' : '',
})
})
setInputs(newInputs)

View File

@@ -107,7 +107,7 @@ const useSingleRunFormParams = ({
}, [runResult, loopRunResult, t])
const setInputVarValues = useCallback((newPayload: Record<string, any>) => {
setRunInputData(newPayload)
setRunInputData(newPayload)
}, [setRunInputData])
const inputVarValues = (() => {
@@ -149,16 +149,15 @@ const useSingleRunFormParams = ({
})
payload.loop_variables?.forEach((loopVariable) => {
if(loopVariable.value_type === ValueType.variable)
if (loopVariable.value_type === ValueType.variable)
allInputs.push(loopVariable.value)
})
const inputVarsFromValue: InputVar[] = []
const varInputs = [...varSelectorsToVarInputs(allInputs), ...inputVarsFromValue]
const existVarsKey: Record<string, boolean> = {}
const uniqueVarInputs: InputVar[] = []
varInputs.forEach((input) => {
if(!input)
if (!input)
return
if (!existVarsKey[input.variable]) {
existVarsKey[input.variable] = true
@@ -191,7 +190,7 @@ const useSingleRunFormParams = ({
if (condition.variable_selector)
vars.push(condition.variable_selector)
if(condition.sub_variable_condition && condition.sub_variable_condition.conditions?.length)
if (condition.sub_variable_condition && condition.sub_variable_condition.conditions?.length)
vars.push(...getVarFromCaseItem(condition.sub_variable_condition))
return vars
}
@@ -203,7 +202,7 @@ const useSingleRunFormParams = ({
vars.push(...conditionVars)
})
payload.loop_variables?.forEach((loopVariable) => {
if(loopVariable.value_type === ValueType.variable)
if (loopVariable.value_type === ValueType.variable)
vars.push(loopVariable.value)
})
const hasFilterLoopVars = vars.filter(item => item[0] !== id)

View File

@@ -107,6 +107,13 @@ export const getOperators = (type?: VarType, file?: { key: string }) => {
ComparisonOperator.empty,
ComparisonOperator.notEmpty,
]
case VarType.boolean:
return [
ComparisonOperator.is,
ComparisonOperator.isNot,
ComparisonOperator.empty,
ComparisonOperator.notEmpty,
]
case VarType.object:
return [
ComparisonOperator.empty,