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

@@ -23,6 +23,7 @@ import SuggestedQuestions from '@/app/components/base/chat/chat/answer/suggested
import { Markdown } from '@/app/components/base/markdown'
import cn from '@/utils/classnames'
import type { FileEntity } from '../../file-uploader/types'
import { formatBooleanInputs } from '@/utils/model-config'
import Avatar from '../../avatar'
const ChatWrapper = () => {
@@ -89,7 +90,7 @@ const ChatWrapper = () => {
let hasEmptyInput = ''
let fileIsUploading = false
const requiredVars = inputsForms.filter(({ required }) => required)
const requiredVars = inputsForms.filter(({ required, type }) => required && type !== InputVarType.checkbox)
if (requiredVars.length) {
requiredVars.forEach(({ variable, label, type }) => {
if (hasEmptyInput)
@@ -131,7 +132,7 @@ const ChatWrapper = () => {
const data: any = {
query: message,
files,
inputs: currentConversationId ? currentConversationInputs : newConversationInputs,
inputs: formatBooleanInputs(inputsForms, currentConversationId ? currentConversationInputs : newConversationInputs),
conversation_id: currentConversationId,
parent_message_id: (isRegenerate ? parentAnswer?.id : getLastAnswer(chatList)?.id) || null,
}

View File

@@ -222,6 +222,14 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
type: 'number',
}
}
if(item.checkbox) {
return {
...item.checkbox,
default: false,
type: 'checkbox',
}
}
if (item.select) {
const isInputInOptions = item.select.options.includes(initInputs[item.select.variable])
return {
@@ -245,6 +253,13 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
}
}
if (item.json_object) {
return {
...item.json_object,
type: 'json_object',
}
}
let value = initInputs[item['text-input'].variable]
if (value && item['text-input'].max_length && value.length > item['text-input'].max_length)
value = value.slice(0, item['text-input'].max_length)
@@ -340,7 +355,7 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
let hasEmptyInput = ''
let fileIsUploading = false
const requiredVars = inputsForms.filter(({ required }) => required)
const requiredVars = inputsForms.filter(({ required, type }) => required && type !== InputVarType.checkbox)
if (requiredVars.length) {
requiredVars.forEach(({ variable, label, type }) => {
if (hasEmptyInput)

View File

@@ -6,6 +6,9 @@ import Textarea from '@/app/components/base/textarea'
import { PortalSelect } from '@/app/components/base/select'
import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
import { InputVarType } from '@/app/components/workflow/types'
import BoolInput from '@/app/components/workflow/nodes/_base/components/before-run-form/bool-input'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
type Props = {
showTip?: boolean
@@ -42,12 +45,14 @@ const InputsFormContent = ({ showTip }: Props) => {
<div className='space-y-4'>
{visibleInputsForms.map(form => (
<div key={form.variable} className='space-y-1'>
<div className='flex h-6 items-center gap-1'>
<div className='system-md-semibold text-text-secondary'>{form.label}</div>
{!form.required && (
<div className='system-xs-regular text-text-tertiary'>{t('appDebug.variableTable.optional')}</div>
)}
</div>
{form.type !== InputVarType.checkbox && (
<div className='flex h-6 items-center gap-1'>
<div className='system-md-semibold text-text-secondary'>{form.label}</div>
{!form.required && (
<div className='system-xs-regular text-text-tertiary'>{t('appDebug.variableTable.optional')}</div>
)}
</div>
)}
{form.type === InputVarType.textInput && (
<Input
value={inputsFormValue?.[form.variable] || ''}
@@ -70,6 +75,14 @@ const InputsFormContent = ({ showTip }: Props) => {
placeholder={form.label}
/>
)}
{form.type === InputVarType.checkbox && (
<BoolInput
name={form.label}
value={!!inputsFormValue?.[form.variable]}
required={form.required}
onChange={value => handleFormChange(form.variable, value)}
/>
)}
{form.type === InputVarType.select && (
<PortalSelect
popupClassName='w-[200px]'
@@ -105,6 +118,18 @@ const InputsFormContent = ({ showTip }: Props) => {
}}
/>
)}
{form.type === InputVarType.jsonObject && (
<CodeEditor
language={CodeLanguage.json}
value={inputsFormValue?.[form.variable] || ''}
onChange={v => handleFormChange(form.variable, v)}
noWrapper
className='bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1'
placeholder={
<div className='whitespace-pre'>{form.json_schema}</div>
}
/>
)}
</div>
))}
{showTip && (

View File

@@ -12,7 +12,7 @@ export const useCheckInputsForms = () => {
const checkInputsForm = useCallback((inputs: Record<string, any>, inputsForm: InputForm[]) => {
let hasEmptyInput = ''
let fileIsUploading = false
const requiredVars = inputsForm.filter(({ required }) => required)
const requiredVars = inputsForm.filter(({ required, type }) => required && type !== InputVarType.checkbox) // boolean can be not checked
if (requiredVars?.length) {
requiredVars.forEach(({ variable, label, type }) => {

View File

@@ -31,6 +31,12 @@ export const getProcessedInputs = (inputs: Record<string, any>, inputsForm: Inpu
inputsForm.forEach((item) => {
const inputValue = inputs[item.variable]
// set boolean type default value
if(item.type === InputVarType.checkbox) {
processedInputs[item.variable] = !!inputValue
return
}
if (!inputValue)
return

View File

@@ -90,7 +90,7 @@ const ChatWrapper = () => {
let hasEmptyInput = ''
let fileIsUploading = false
const requiredVars = inputsForms.filter(({ required }) => required)
const requiredVars = inputsForms.filter(({ required, type }) => required && type !== InputVarType.checkbox) // boolean can be not checked
if (requiredVars.length) {
requiredVars.forEach(({ variable, label, type }) => {
if (hasEmptyInput)

View File

@@ -195,6 +195,13 @@ export const useEmbeddedChatbot = () => {
type: 'number',
}
}
if (item.checkbox) {
return {
...item.checkbox,
default: false,
type: 'checkbox',
}
}
if (item.select) {
const isInputInOptions = item.select.options.includes(initInputs[item.select.variable])
return {
@@ -218,6 +225,13 @@ export const useEmbeddedChatbot = () => {
}
}
if (item.json_object) {
return {
...item.json_object,
type: 'json_object',
}
}
let value = initInputs[item['text-input'].variable]
if (value && item['text-input'].max_length && value.length > item['text-input'].max_length)
value = value.slice(0, item['text-input'].max_length)
@@ -312,7 +326,7 @@ export const useEmbeddedChatbot = () => {
let hasEmptyInput = ''
let fileIsUploading = false
const requiredVars = inputsForms.filter(({ required }) => required)
const requiredVars = inputsForms.filter(({ required, type }) => required && type !== InputVarType.checkbox)
if (requiredVars.length) {
requiredVars.forEach(({ variable, label, type }) => {
if (hasEmptyInput)

View File

@@ -6,6 +6,9 @@ import Textarea from '@/app/components/base/textarea'
import { PortalSelect } from '@/app/components/base/select'
import { FileUploaderInAttachmentWrapper } from '@/app/components/base/file-uploader'
import { InputVarType } from '@/app/components/workflow/types'
import BoolInput from '@/app/components/workflow/nodes/_base/components/before-run-form/bool-input'
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
type Props = {
showTip?: boolean
@@ -42,12 +45,14 @@ const InputsFormContent = ({ showTip }: Props) => {
<div className='space-y-4'>
{visibleInputsForms.map(form => (
<div key={form.variable} className='space-y-1'>
{form.type !== InputVarType.checkbox && (
<div className='flex h-6 items-center gap-1'>
<div className='system-md-semibold text-text-secondary'>{form.label}</div>
{!form.required && (
<div className='system-xs-regular text-text-tertiary'>{t('appDebug.variableTable.optional')}</div>
)}
</div>
)}
{form.type === InputVarType.textInput && (
<Input
value={inputsFormValue?.[form.variable] || ''}
@@ -70,6 +75,14 @@ const InputsFormContent = ({ showTip }: Props) => {
placeholder={form.label}
/>
)}
{form.type === InputVarType.checkbox && (
<BoolInput
name={form.label}
value={inputsFormValue?.[form.variable]}
required={form.required}
onChange={value => handleFormChange(form.variable, value)}
/>
)}
{form.type === InputVarType.select && (
<PortalSelect
popupClassName='w-[200px]'
@@ -105,6 +118,18 @@ const InputsFormContent = ({ showTip }: Props) => {
}}
/>
)}
{form.type === InputVarType.jsonObject && (
<CodeEditor
language={CodeLanguage.json}
value={inputsFormValue?.[form.variable] || ''}
onChange={v => handleFormChange(form.variable, v)}
noWrapper
className='bg h-[80px] overflow-y-auto rounded-[10px] bg-components-input-bg-normal p-1'
placeholder={
<div className='whitespace-pre'>{form.json_schema}</div>
}
/>
)}
</div>
))}
{showTip && (

View File

@@ -24,7 +24,7 @@ export enum FormTypeEnum {
secretInput = 'secret-input',
select = 'select',
radio = 'radio',
boolean = 'boolean',
checkbox = 'checkbox',
files = 'files',
file = 'file',
modelSelector = 'model-selector',

View File

@@ -53,7 +53,6 @@ const CurrentBlockReplacementBlock = ({
return mergeRegister(
editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createCurrentBlockNode)),
)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return null

View File

@@ -52,7 +52,6 @@ const ErrorMessageBlockReplacementBlock = ({
return mergeRegister(
editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createErrorMessageBlockNode)),
)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return null

View File

@@ -52,7 +52,6 @@ const LastRunReplacementBlock = ({
return mergeRegister(
editor.registerNodeTransform(CustomTextNode, textNode => decoratorTransform(textNode, getMatch, createLastRunBlockNode)),
)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return null