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

@@ -0,0 +1,72 @@
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { RiAddLine } from '@remixicon/react'
import produce from 'immer'
import RemoveButton from '@/app/components/workflow/nodes/_base/components/remove-button'
import Button from '@/app/components/base/button'
import BoolValue from './bool-value'
import cn from '@/utils/classnames'
type Props = {
className?: string
list: boolean[]
onChange: (list: boolean[]) => void
}
const ArrayValueList: FC<Props> = ({
className,
list,
onChange,
}) => {
const { t } = useTranslation()
const handleChange = useCallback((index: number) => {
return (value: boolean) => {
const newList = produce(list, (draft: any[]) => {
draft[index] = value
})
onChange(newList)
}
}, [list, onChange])
const handleItemRemove = useCallback((index: number) => {
return () => {
const newList = produce(list, (draft) => {
draft.splice(index, 1)
})
onChange(newList)
}
}, [list, onChange])
const handleItemAdd = useCallback(() => {
const newList = produce(list, (draft: any[]) => {
draft.push(false)
})
onChange(newList)
}, [list, onChange])
return (
<div className={cn('w-full space-y-2', className)}>
{list.map((item, index) => (
<div className='flex items-center space-x-1' key={index}>
<BoolValue
value={item}
onChange={handleChange(index)}
/>
<RemoveButton
className='!bg-gray-100 !p-2 hover:!bg-gray-200'
onClick={handleItemRemove(index)}
/>
</div>
))}
<Button variant='tertiary' className='w-full' onClick={handleItemAdd}>
<RiAddLine className='mr-1 h-4 w-4' />
<span>{t('workflow.chatVariable.modal.addArrayValue')}</span>
</Button>
</div>
)
}
export default React.memo(ArrayValueList)

View File

@@ -0,0 +1,37 @@
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import OptionCard from '../../../nodes/_base/components/option-card'
type Props = {
value: boolean
onChange: (value: boolean) => void
}
const BoolValue: FC<Props> = ({
value,
onChange,
}) => {
const booleanValue = value
const handleChange = useCallback((newValue: boolean) => {
return () => {
onChange(newValue)
}
}, [onChange])
return (
<div className='flex w-full space-x-1'>
<OptionCard className='grow'
selected={booleanValue}
title='True'
onSelect={handleChange(true)}
/>
<OptionCard className='grow'
selected={!booleanValue}
title='False'
onSelect={handleChange(false)}
/>
</div>
)
}
export default React.memo(BoolValue)

View File

@@ -16,6 +16,15 @@ import type { ConversationVariable } from '@/app/components/workflow/types'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type'
import cn from '@/utils/classnames'
import BoolValue from './bool-value'
import ArrayBoolList from './array-bool-list'
import {
arrayBoolPlaceholder,
arrayNumberPlaceholder,
arrayObjectPlaceholder,
arrayStringPlaceholder,
objectPlaceholder,
} from '@/app/components/workflow/panel/chat-variable-panel/utils'
import { checkKeys, replaceSpaceWithUnderscoreInVarNameInput } from '@/utils/var'
export type ModalPropsType = {
@@ -33,39 +42,14 @@ type ObjectValueItem = {
const typeList = [
ChatVarType.String,
ChatVarType.Number,
ChatVarType.Boolean,
ChatVarType.Object,
ChatVarType.ArrayString,
ChatVarType.ArrayNumber,
ChatVarType.ArrayBoolean,
ChatVarType.ArrayObject,
]
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
# }
# ]`
const ChatVariableModal = ({
chatVar,
onClose,
@@ -94,6 +78,8 @@ const ChatVariableModal = ({
return arrayNumberPlaceholder
if (type === ChatVarType.ArrayObject)
return arrayObjectPlaceholder
if (type === ChatVarType.ArrayBoolean)
return arrayBoolPlaceholder
return objectPlaceholder
}, [type])
const getObjectValue = useCallback(() => {
@@ -122,12 +108,16 @@ const ChatVariableModal = ({
return value || ''
case ChatVarType.Number:
return value || 0
case ChatVarType.Boolean:
return value === undefined ? true : value
case ChatVarType.Object:
return editInJSON ? value : formatValueFromObject(objectValue)
case ChatVarType.ArrayString:
case ChatVarType.ArrayNumber:
case ChatVarType.ArrayObject:
return value?.filter(Boolean) || []
case ChatVarType.ArrayBoolean:
return value || []
}
}
@@ -157,6 +147,10 @@ const ChatVariableModal = ({
setEditInJSON(true)
if (v === ChatVarType.String || v === ChatVarType.Number || v === ChatVarType.Object)
setEditInJSON(false)
if(v === ChatVarType.Boolean)
setValue(false)
if (v === ChatVarType.ArrayBoolean)
setValue([false])
setType(v)
}
@@ -202,6 +196,11 @@ const ChatVariableModal = ({
setValue(value?.length ? value : [undefined])
}
}
if(type === ChatVarType.ArrayBoolean) {
if(editInJSON)
setEditorContent(JSON.stringify(value.map((item: boolean) => item ? 'True' : 'False')))
}
setEditInJSON(editInJSON)
}
@@ -213,7 +212,16 @@ const ChatVariableModal = ({
else {
setEditorContent(content)
try {
const newValue = JSON.parse(content)
let newValue = JSON.parse(content)
if(type === ChatVarType.ArrayBoolean) {
newValue = newValue.map((item: string | boolean) => {
if (item === 'True' || item === 'true' || item === true)
return true
if (item === 'False' || item === 'false' || item === false)
return false
return undefined
}).filter((item?: boolean) => item !== undefined)
}
setValue(newValue)
}
catch {
@@ -304,7 +312,7 @@ const ChatVariableModal = ({
<div className='mb-4'>
<div className='system-sm-semibold mb-1 flex h-6 items-center justify-between text-text-secondary'>
<div>{t('workflow.chatVariable.modal.value')}</div>
{(type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber) && (
{(type === ChatVarType.ArrayString || type === ChatVarType.ArrayNumber || type === ChatVarType.ArrayBoolean) && (
<Button
variant='ghost'
size='small'
@@ -345,6 +353,12 @@ const ChatVariableModal = ({
type='number'
/>
)}
{type === ChatVarType.Boolean && (
<BoolValue
value={value}
onChange={setValue}
/>
)}
{type === ChatVarType.Object && !editInJSON && (
<ObjectValueList
list={objectValue}
@@ -365,6 +379,13 @@ const ChatVariableModal = ({
onChange={setValue}
/>
)}
{type === ChatVarType.ArrayBoolean && !editInJSON && (
<ArrayBoolList
list={value || [true]}
onChange={setValue}
/>
)}
{editInJSON && (
<div className='w-full rounded-[10px] bg-components-input-bg-normal py-2 pl-3 pr-1' style={{ height: editorMinHeight }}>
<CodeEditor

View File

@@ -1,8 +1,10 @@
export enum ChatVarType {
Number = 'number',
String = 'string',
Boolean = 'boolean',
Object = 'object',
ArrayString = 'array[string]',
ArrayNumber = 'array[number]',
ArrayBoolean = 'array[boolean]',
ArrayObject = 'array[object]',
}

View File

@@ -0,0 +1,35 @@
export const objectPlaceholder = `# example
# {
# "name": "ray",
# "age": 20
# }`
export const arrayStringPlaceholder = `# example
# [
# "value1",
# "value2"
# ]`
export const arrayNumberPlaceholder = `# example
# [
# 100,
# 200
# ]`
export const arrayObjectPlaceholder = `# example
# [
# {
# "name": "ray",
# "age": 20
# },
# {
# "name": "lily",
# "age": 18
# }
# ]`
export const arrayBoolPlaceholder = `# example
# [
# "True",
# "False"
# ]`