number type

This commit is contained in:
JzoNg
2025-06-09 20:27:08 +08:00
parent cadd226e84
commit 900c9e589d
7 changed files with 367 additions and 17 deletions

View File

@ -0,0 +1,133 @@
'use client'
import type { FC } from 'react'
import type { ToolVarInputs } from '@/app/components/workflow/nodes/tool/types'
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
import { VarType } from '@/app/components/workflow/types'
import type { ValueSelector } from '@/app/components/workflow/types'
import FormInputTypeSwitch from './form-input-type-switch'
import Input from '@/app/components/base/input'
import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
// import cn from '@/utils/classnames'
type Props = {
readOnly: boolean
nodeId: string
schema: CredentialFormSchema
value: ToolVarInputs
onChange: (value: any) => void
onOpen?: (index: number) => void
hideTypeSwitch?: boolean
}
const FormInputItem: FC<Props> = ({
readOnly,
nodeId,
schema,
value,
onChange,
hideTypeSwitch,
}) => {
const {
placeholder,
variable,
type,
default: defaultValue,
// scope,
} = schema as any
const language = useLanguage()
const varInput = value[variable]
const isString = type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput
const isNumber = type === FormTypeEnum.textNumber
const isBoolean = type === FormTypeEnum.boolean
const isSelect = type === FormTypeEnum.select
const isFile = type === FormTypeEnum.file || type === FormTypeEnum.files
const isAppSelector = type === FormTypeEnum.appSelector
const isModelSelector = type === FormTypeEnum.modelSelector
const isObject = type === FormTypeEnum.object
const isArray = type === FormTypeEnum.array
const showTypeSwitch = isNumber || isObject || isArray
const handleTypeChange = (newType: string) => {
if (newType === VarKindType.variable) {
onChange({
...value,
[variable]: {
...varInput,
type: VarKindType.variable,
value: '',
},
})
}
else {
onChange({
...value,
[variable]: {
...varInput,
type: VarKindType.constant,
value: defaultValue,
},
})
}
}
const handleValueChange = (newValue: any) => {
onChange({
...value,
[variable]: {
...varInput,
type: varInput.type,
value: newValue,
},
})
}
const handleVariableSelectorChange = (newValue: ValueSelector | string, variable: string) => {
onChange({
...value,
[variable]: {
...varInput,
type: VarKindType.variable,
value: newValue || '',
},
})
}
return (
<div className='flex gap-1'>
{showTypeSwitch && !hideTypeSwitch && (
<FormInputTypeSwitch value={varInput.type} onChange={handleTypeChange}/>
)}
{isNumber && varInput.type === VarKindType.constant && (
<Input
className='h-8 grow'
type='number'
value={varInput.value || ''}
onChange={e => handleValueChange(e.target.value)}
placeholder={placeholder?.[language] || placeholder?.en_US}
/>
)}
{isNumber && varInput.type === VarKindType.variable && (
<VarReferencePicker
className='h-8 grow'
readonly={readOnly}
isShowNodeName
nodeId={nodeId}
value={varInput?.value || []}
onChange={value => handleVariableSelectorChange(value, variable)}
filterVar={varPayload => varPayload.type === VarType.number}
schema={schema}
valueTypePlaceHolder={VarType.number}
/>
)}
{!isNumber && (
<div className='h-8 grow rounded-lg bg-components-input-bg-normal'></div>
)}
</div>
)
}
export default FormInputItem

View File

@ -0,0 +1,47 @@
'use client'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import {
RiEditLine,
} from '@remixicon/react'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import Tooltip from '@/app/components/base/tooltip'
import { VarType } from '@/app/components/workflow/nodes/tool/types'
import cn from '@/utils/classnames'
type Props = {
value: string
onChange: (value: string) => void
}
const FormInputTypeSwitch: FC<Props> = ({
value,
onChange,
}) => {
const { t } = useTranslation()
return (
<div className='flex h-8 shrink-0 gap-px rounded-[10px] bg-components-segmented-control-bg-normal p-0.5'>
<Tooltip
popupContent={value === VarType.variable ? '' : t('workflow.nodes.common.typeSwitch.variable')}
>
<div
className={cn('cursor-pointer rounded-lg px-2.5 py-1.5 text-text-tertiary hover:bg-state-base-hover', value === VarType.variable && 'bg-components-segmented-control-item-active-bg text-text-secondary shadow-xs hover:bg-components-segmented-control-item-active-bg')}
onClick={() => onChange(VarType.variable)}
>
<Variable02 className='h-4 w-4' />
</div>
</Tooltip>
<Tooltip
popupContent={value === VarType.constant ? '' : t('workflow.nodes.common.typeSwitch.input')}
>
<div
className={cn('cursor-pointer rounded-lg px-2.5 py-1.5 text-text-tertiary hover:bg-state-base-hover', value === VarType.constant && 'bg-components-segmented-control-item-active-bg text-text-secondary shadow-xs hover:bg-components-segmented-control-item-active-bg')}
onClick={() => onChange(VarType.constant)}
>
<RiEditLine className='h-4 w-4' />
</div>
</Tooltip>
</div>
)
}
export default FormInputTypeSwitch

View File

@ -0,0 +1,47 @@
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import type { ToolVarInputs } from '../../types'
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { noop } from 'lodash-es'
import ToolFormItem from './item'
type Props = {
readOnly: boolean
nodeId: string
schema: CredentialFormSchema[]
value: ToolVarInputs
onChange: (value: ToolVarInputs) => void
onOpen?: (index: number) => void
}
const ToolForm: FC<Props> = ({
readOnly,
nodeId,
schema,
value,
onChange,
onOpen = noop,
}) => {
const handleOpen = useCallback((index: number) => {
return () => onOpen(index)
}, [onOpen])
return (
<div className='space-y-1'>
{
schema.map((schema, index) => (
<ToolFormItem
key={index}
readOnly={readOnly}
nodeId={nodeId}
schema={schema}
value={value}
onChange={onChange}
onOpen={handleOpen(index)}
/>
))
}
</div>
)
}
export default ToolForm

View File

@ -0,0 +1,83 @@
'use client'
import type { FC } from 'react'
import {
RiBracesLine,
} from '@remixicon/react'
import type { ToolVarInputs } from '../../types'
import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
import Button from '@/app/components/base/button'
import Tooltip from '@/app/components/base/tooltip'
import FormInputItem from '@/app/components/workflow/nodes/_base/components/form-input-item'
type Props = {
readOnly: boolean
nodeId: string
schema: CredentialFormSchema
value: ToolVarInputs
onChange: (value: ToolVarInputs) => void
onOpen?: (index: number) => void
showDescription?: boolean
}
const ToolFormItem: FC<Props> = ({
readOnly,
nodeId,
schema,
value,
onChange,
showDescription,
}) => {
const language = useLanguage()
const { label, type, required, tooltip } = schema
const showSchemaButton = type === FormTypeEnum.object || type === FormTypeEnum.array
return (
<div className='space-y-0.5 py-1'>
<div>
<div className='flex h-6 items-center'>
<div className='system-sm-medium text-text-secondary'>{label[language] || label.en_US}</div>
{required && (
<div className='system-xs-regular ml-1 text-text-destructive-secondary'>*</div>
)}
{!showDescription && tooltip && (
<Tooltip
popupContent={<div className='w-[200px]'>
{tooltip[language] || tooltip.en_US}
</div>}
triggerClassName='ml-1 w-4 h-4'
asChild={false}
/>
)}
{showSchemaButton && (
<>
<div className='system-xs-regular ml-1 text-text-quaternary'>·</div>
<Button
variant='ghost'
size='small'
onClick={() => {
// onOpen?.(index)
}}
>
<RiBracesLine className='mr-1' />
<span>JSON Schema</span>
</Button>
</>
)}
</div>
{showDescription && tooltip && (
<div className='body-xs-regular pb-0.5 text-text-tertiary'>{tooltip[language] || tooltip.en_US}</div>
)}
</div>
<FormInputItem
readOnly={readOnly}
nodeId={nodeId}
schema={schema}
value={value}
onChange={onChange}
/>
</div>
)
}
export default ToolFormItem

View File

@ -5,10 +5,11 @@ import Split from '../_base/components/split'
import type { ToolNodeType } from './types'
import useConfig from './use-config'
import InputVarList from './components/input-var-list'
import ToolForm from './components/tool-form'
import Button from '@/app/components/base/button'
import Field from '@/app/components/workflow/nodes/_base/components/field'
import type { NodePanelProps } from '@/app/components/workflow/types'
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
// import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
import Loading from '@/app/components/base/loading'
import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
@ -63,6 +64,8 @@ const Panel: FC<NodePanelProps<ToolNodeType>> = ({
return formatToTracingNodeList([runResult], t)[0]
}, [runResult, t])
const [collapsed, setCollapsed] = React.useState(false)
if (isLoading) {
return <div className='flex h-[200px] items-center justify-center'>
<Loading />
@ -84,10 +87,11 @@ const Panel: FC<NodePanelProps<ToolNodeType>> = ({
</div>
</>
)}
{!isShowAuthBtn && <>
<div className='space-y-4 px-4'>
{!isShowAuthBtn && (
<div className='relative'>
{toolInputVarSchema.length > 0 && (
<Field
className='px-4'
title={t(`${i18nPrefix}.inputVars`)}
>
<InputVarList
@ -100,6 +104,14 @@ const Panel: FC<NodePanelProps<ToolNodeType>> = ({
isSupportConstantValue
onOpen={handleOnVarOpen}
/>
{/* <ToolForm
readOnly={readOnly}
nodeId={id}
schema={toolInputVarSchema as any}
value={inputs.tool_parameters}
onChange={setInputVar}
onOpen={handleOnVarOpen}
/> */}
</Field>
)}
@ -107,21 +119,39 @@ const Panel: FC<NodePanelProps<ToolNodeType>> = ({
<Split />
)}
<Form
className='space-y-4'
itemClassName='!py-0'
fieldLabelClassName='!text-[13px] !font-semibold !text-text-secondary uppercase'
value={toolSettingValue}
onChange={setToolSettingValue}
formSchemas={toolSettingSchema as any}
isEditMode={false}
showOnVariableMap={{}}
validating={false}
// inputClassName='!bg-gray-50'
readonly={readOnly}
/>
{toolSettingSchema.length > 0 && (
<>
<OutputVars
title={t(`${i18nPrefix}.settings`)}
collapsed={collapsed}
onCollapse={setCollapsed}
>
{/* <Form
className='space-y-4'
itemClassName='!py-0'
fieldLabelClassName='!text-[13px] !font-semibold !text-text-secondary uppercase'
value={toolSettingValue}
onChange={setToolSettingValue}
formSchemas={toolSettingSchema as any}
isEditMode={false}
showOnVariableMap={{}}
validating={false}
// inputClassName='!bg-gray-50'
readonly={readOnly}
/> */}
<ToolForm
readOnly={readOnly}
nodeId={id}
schema={toolSettingSchema as any}
value={toolSettingValue}
onChange={setToolSettingValue}
/>
</OutputVars>
<Split />
</>
)}
</div>
</>}
)}
{showSetAuth && (
<ConfigCredential

View File

@ -365,6 +365,10 @@ const translation = {
ms: 'ms',
retries: '{{num}} Retries',
},
typeSwitch: {
input: 'Input value',
variable: 'Use variable',
},
},
start: {
required: 'required',
@ -654,6 +658,7 @@ const translation = {
tool: {
toAuthorize: 'To authorize',
inputVars: 'Input Variables',
settings: 'Settings',
outputVars: {
text: 'tool generated content',
files: {

View File

@ -366,6 +366,10 @@ const translation = {
ms: '毫秒',
retries: '{{num}} 重试次数',
},
typeSwitch: {
input: '输入值',
variable: '使用变量',
},
},
start: {
required: '必填',
@ -655,6 +659,7 @@ const translation = {
tool: {
toAuthorize: '授权',
inputVars: '输入变量',
settings: '设置',
outputVars: {
text: '工具生成的内容',
files: {