Commit 235bec64 authored by Joel's avatar Joel

feat: new var input editor

parent ee616ee6
'use client'
import type { FC } from 'react'
import React from 'react'
type Props = {
title: string
children: JSX.Element
}
const Field: FC<Props> = ({
title,
children,
}) => {
return (
<div>
<div className='leading-8 text-[13px] font-medium text-gray-700'>{title}</div>
<div>{children}</div>
</div>
)
}
export default React.memo(Field)
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React, { useEffect, useState } from 'react' import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector' import { useContext } from 'use-context-selector'
import ModalFoot from '../modal-foot' import ModalFoot from '../modal-foot'
import type { Options } from '../config-select'
import ConfigSelect from '../config-select' import ConfigSelect from '../config-select'
import ConfigString from '../config-string' import ConfigString from '../config-string'
import SelectTypeItem from '../select-type-item' import SelectTypeItem from '../select-type-item'
import s from './style.module.css' import Field from './field'
import Toast from '@/app/components/base/toast' import Toast from '@/app/components/base/toast'
import type { PromptVariable } from '@/models/debug' import { getNewVarInWorkflow } from '@/utils/var'
import { getNewVar } from '@/utils/var'
import ConfigContext from '@/context/debug-configuration' import ConfigContext from '@/context/debug-configuration'
import { type InputVar, InputVarType } from '@/app/components/workflow/types'
import Modal from '@/app/components/base/modal' import Modal from '@/app/components/base/modal'
import Switch from '@/app/components/base/switch'
export type IConfigModalProps = { export type IConfigModalProps = {
payload: PromptVariable isCreate?: boolean
payload?: InputVar
type?: string type?: string
isShow: boolean isShow: boolean
onClose: () => void onClose: () => void
onConfirm: (newValue: { type: string; value: any }) => void // onConfirm: (newValue: { type: string; value: any }) => void
onConfirm: (newValue: InputVar) => void
} }
const inputClassName = 'w-full px-3 text-sm leading-9 text-gray-900 border-0 rounded-lg grow h-9 bg-gray-50 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200'
const ConfigModal: FC<IConfigModalProps> = ({ const ConfigModal: FC<IConfigModalProps> = ({
isCreate,
payload, payload,
isShow, isShow,
onClose, onClose,
...@@ -32,45 +37,36 @@ const ConfigModal: FC<IConfigModalProps> = ({ ...@@ -32,45 +37,36 @@ const ConfigModal: FC<IConfigModalProps> = ({
}) => { }) => {
const { modelConfig } = useContext(ConfigContext) const { modelConfig } = useContext(ConfigContext)
const { t } = useTranslation() const { t } = useTranslation()
const { type, name, key, options, max_length } = payload || getNewVar('') const [tempPayload, setTempPayload] = useState<InputVar>(payload || getNewVarInWorkflow('') as any)
// const { type, name, key, options, max_length } = tempPayload; name => label; variable => key
const { type, label, variable, options, max_length } = tempPayload
const isStringInput = type === InputVarType.textInput || type === InputVarType.paragraph
const [tempType, setTempType] = useState(type) const handlePayloadChange = useCallback((key: string) => {
useEffect(() => { return (value: any) => {
setTempType(type) setTempPayload((prev) => {
}, [type]) return {
const handleTypeChange = (type: string) => { ...prev,
return () => { [key]: value,
setTempType(type)
} }
})
} }
}, [])
const isStringInput = tempType === 'string' || tempType === 'paragraph'
const title = isStringInput ? t('appDebug.variableConig.maxLength') : t('appDebug.variableConig.options')
// string type
const [tempMaxLength, setTempMaxValue] = useState(max_length)
useEffect(() => {
setTempMaxValue(max_length)
}, [max_length])
// select type
const [tempOptions, setTempOptions] = useState<Options>(options || [])
useEffect(() => {
setTempOptions(options || [])
}, [options])
const handleConfirm = () => { const handleConfirm = () => {
if (isStringInput) { if (isStringInput) {
onConfirm({ type: tempType, value: tempMaxLength }) onConfirm(tempPayload)
// onConfirm({ type: type, value: tempMaxLength })
} }
else { else {
if (tempOptions.length === 0) { if (options?.length === 0) {
Toast.notify({ type: 'error', message: 'At least one option requied' }) Toast.notify({ type: 'error', message: 'At least one option requied' })
return return
} }
const obj: Record<string, boolean> = {} const obj: Record<string, boolean> = {}
let hasRepeatedItem = false let hasRepeatedItem = false
tempOptions.forEach((o) => { options?.forEach((o) => {
if (obj[o]) { if (obj[o]) {
hasRepeatedItem = true hasRepeatedItem = true
return return
...@@ -81,39 +77,62 @@ const ConfigModal: FC<IConfigModalProps> = ({ ...@@ -81,39 +77,62 @@ const ConfigModal: FC<IConfigModalProps> = ({
Toast.notify({ type: 'error', message: 'Has repeat items' }) Toast.notify({ type: 'error', message: 'Has repeat items' })
return return
} }
onConfirm({ type: tempType, value: tempOptions }) onConfirm(tempPayload)
} }
} }
return ( return (
<Modal <Modal
title={t('appDebug.variableConig.modalTitle')} title={t(`appDebug.variableConig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`)}
isShow={isShow} isShow={isShow}
onClose={onClose} onClose={onClose}
wrapperClassName='!z-[100]'
> >
<div className='mb-8'> <div className='mb-8'>
<div className='mt-2 mb-8 text-sm text-gray-500'>{t('appDebug.variableConig.description', { varName: `{{${name || key}}}` })}</div> <div className='space-y-2'>
<div className='mb-2'>
<div className={s.title}>{t('appDebug.variableConig.fieldType')}</div> <Field title={t('appDebug.variableConig.fieldType')}>
<div className='flex space-x-2'> <div className='flex space-x-2'>
<SelectTypeItem type='string' selected={tempType === 'string'} onClick={handleTypeChange('string')} /> {/* TODO handlePayloadChange(string) */}
<SelectTypeItem type='paragraph' selected={tempType === 'paragraph'} onClick={handleTypeChange('paragraph')} /> <SelectTypeItem type={InputVarType.textInput} selected={type === InputVarType.textInput} onClick={() => handlePayloadChange('type')(InputVarType.textInput)} />
<SelectTypeItem type='select' selected={tempType === 'select'} onClick={handleTypeChange('select')} /> <SelectTypeItem type={InputVarType.paragraph} selected={type === InputVarType.paragraph} onClick={() => handlePayloadChange('type')(InputVarType.paragraph)} />
</div> <SelectTypeItem type={InputVarType.select} selected={type === InputVarType.select} onClick={() => handlePayloadChange('type')(InputVarType.select)} />
</div> </div>
</Field>
<Field title={t('appDebug.variableConig.varName')}>
<input
type='text'
className={inputClassName}
value={variable}
onChange={e => handlePayloadChange('variable')(e.target.value)}
/>
</Field>
<Field title={t('appDebug.variableConig.labelName')}>
<input
type='text'
className={inputClassName}
value={label}
onChange={e => handlePayloadChange('label')(e.target.value)}
/>
</Field>
{isStringInput && (
<Field title={t('appDebug.variableConig.maxLength')}>
<ConfigString modelId={modelConfig.model_id} value={max_length} onChange={handlePayloadChange('max_length')} />
</Field>
{tempType !== 'paragraph' && (
<div className='mt-6'>
<div className={s.title}>{title}</div>
{isStringInput
? (
<ConfigString modelId={modelConfig.model_id} value={tempMaxLength} onChange={setTempMaxValue} />
)
: (
<ConfigSelect options={tempOptions} onChange={setTempOptions} />
)} )}
</div> {type === InputVarType.select && (
<Field title={t('appDebug.variableConig.options')}>
<ConfigSelect options={options!} onChange={handlePayloadChange('options')} />
</Field>
)} )}
<Field title={t('appDebug.variableConig.required')}>
<Switch defaultValue={tempPayload.required} onChange={handlePayloadChange('required')} />
</Field>
</div>
</div> </div>
<ModalFoot <ModalFoot
onConfirm={handleConfirm} onConfirm={handleConfirm}
......
.title {
margin-bottom: 8px;
font-size: 13px;
line-height: 18px;
font-weight: 500;
color: #101828;
text-transform: capitalize;
}
\ No newline at end of file
...@@ -25,6 +25,8 @@ import { AppType } from '@/types/app' ...@@ -25,6 +25,8 @@ import { AppType } from '@/types/app'
import type { ExternalDataTool } from '@/models/common' import type { ExternalDataTool } from '@/models/common'
import { useModalContext } from '@/context/modal-context' import { useModalContext } from '@/context/modal-context'
import { useEventEmitterContextContext } from '@/context/event-emitter' import { useEventEmitterContextContext } from '@/context/event-emitter'
import type { InputVar } from '@/app/components/workflow/types'
import { InputVarType } from '@/app/components/workflow/types'
export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL' export const ADD_EXTERNAL_DATA_TOOL = 'ADD_EXTERNAL_DATA_TOOL'
...@@ -71,6 +73,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar ...@@ -71,6 +73,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
} }
const batchUpdatePromptVariable = (key: string, updateKeys: string[], newValues: any[], isParagraph?: boolean) => { const batchUpdatePromptVariable = (key: string, updateKeys: string[], newValues: any[], isParagraph?: boolean) => {
console.log(key)
const newPromptVariables = promptVariables.map((item) => { const newPromptVariables = promptVariables.map((item) => {
if (item.key === key) { if (item.key === key) {
const newItem: any = { ...item } const newItem: any = { ...item }
...@@ -111,7 +114,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar ...@@ -111,7 +114,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
}) })
conflictTimer = setTimeout(() => { conflictTimer = setTimeout(() => {
const isKeyExists = promptVariables.some(item => item.key.trim() === newKey.trim()) const isKeyExists = promptVariables.some(item => item.key?.trim() === newKey.trim())
if (isKeyExists) { if (isKeyExists) {
Toast.notify({ Toast.notify({
type: 'error', type: 'error',
...@@ -242,6 +245,17 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar ...@@ -242,6 +245,17 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
const [currKey, setCurrKey] = useState<string | null>(null) const [currKey, setCurrKey] = useState<string | null>(null)
const currItem = currKey ? promptVariables.find(item => item.key === currKey) : null const currItem = currKey ? promptVariables.find(item => item.key === currKey) : null
const currItemToEdit: InputVar | null = (() => {
if (!currItem)
return null
return {
...currItem,
label: currItem.name,
variable: currItem.key,
type: currItem.type === 'string' ? InputVarType.textInput : currItem.type,
} as InputVar
})()
const [isShowEditModal, { setTrue: showEditModal, setFalse: hideEditModal }] = useBoolean(false) const [isShowEditModal, { setTrue: showEditModal, setFalse: hideEditModal }] = useBoolean(false)
const handleConfig = ({ key, type, index, name, config, icon, icon_background }: ExternalDataToolParams) => { const handleConfig = ({ key, type, index, name, config, icon, icon_background }: ExternalDataToolParams) => {
...@@ -297,6 +311,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar ...@@ -297,6 +311,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
<tr key={index} className="h-9 leading-9"> <tr key={index} className="h-9 leading-9">
<td className="w-[160px] border-b border-gray-100 pl-3"> <td className="w-[160px] border-b border-gray-100 pl-3">
<div className='flex items-center space-x-1'> <div className='flex items-center space-x-1'>
{type}
<IconTypeIcon type={type as IInputTypeIconProps['type']} className='text-gray-400' /> <IconTypeIcon type={type as IInputTypeIconProps['type']} className='text-gray-400' />
{!readonly {!readonly
? ( ? (
...@@ -358,14 +373,17 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar ...@@ -358,14 +373,17 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
{isShowEditModal && ( {isShowEditModal && (
<EditModal <EditModal
payload={currItem as PromptVariable} payload={currItemToEdit!}
isShow={isShowEditModal} isShow={isShowEditModal}
onClose={hideEditModal} onClose={hideEditModal}
onConfirm={({ type, value }) => { onConfirm={(item) => {
if (type === 'string') const { type, max_length, options } = item
batchUpdatePromptVariable(currKey as string, ['type', 'max_length'], [type, value || DEFAULT_VALUE_MAX_LEN]) if (type === InputVarType.textInput)
batchUpdatePromptVariable(currKey as string, ['type', 'max_length'], ['string', max_length || DEFAULT_VALUE_MAX_LEN])
if (type === InputVarType.paragraph)
batchUpdatePromptVariable(currKey as string, ['type', 'max_length'], [InputVarType.paragraph, max_length || DEFAULT_VALUE_MAX_LEN], true)
else else
batchUpdatePromptVariable(currKey as string, ['type', 'options'], [type, value || []], type === 'paragraph') batchUpdatePromptVariable(currKey as string, ['type', 'options'], [type, options || []], false)
hideEditModal() hideEditModal()
}} }}
......
...@@ -3,18 +3,18 @@ import type { FC } from 'react' ...@@ -3,18 +3,18 @@ import type { FC } from 'react'
import React from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import cn from 'classnames' import cn from 'classnames'
import s from './style.module.css' import s from './style.module.css'
import { InputVarType } from '@/app/components/workflow/types'
export type ISelectTypeItemProps = { export type ISelectTypeItemProps = {
type: string type: InputVarType
selected: boolean selected: boolean
onClick: () => void onClick: () => void
} }
const Icon = ({ type, selected }: Partial<ISelectTypeItemProps>) => { const Icon = ({ type, selected }: Partial<ISelectTypeItemProps>) => {
switch (type) { switch (type) {
case 'select': case InputVarType.select:
return selected return selected
? ( ? (
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
...@@ -28,16 +28,16 @@ const Icon = ({ type, selected }: Partial<ISelectTypeItemProps>) => { ...@@ -28,16 +28,16 @@ const Icon = ({ type, selected }: Partial<ISelectTypeItemProps>) => {
<path d="M12.8923 0.666672H7.77427C7.42285 0.666661 7.11966 0.666651 6.86995 0.687053C6.60639 0.708587 6.34424 0.756131 6.09199 0.884661C5.71567 1.07641 5.40971 1.38237 5.21796 1.75869C5.08943 2.01095 5.04188 2.27309 5.02035 2.53665C5.00206 2.76051 5.00018 3.02733 4.99999 3.33336L8.92055 3.33335C9.2463 3.33327 9.59951 3.33319 9.90523 3.35816C10.2512 3.38644 10.7084 3.4564 11.1799 3.69667C11.8071 4.01625 12.3171 4.52618 12.6367 5.15339C12.8769 5.62493 12.9469 6.08208 12.9752 6.42809C13.0001 6.73382 13.0001 7.08702 13 7.41279L13 11.3333C13.306 11.3331 13.5728 11.3313 13.7967 11.313C14.0602 11.2914 14.3224 11.2439 14.5746 11.1154C14.9509 10.9236 15.2569 10.6176 15.4487 10.2413C15.5772 9.98907 15.6247 9.72692 15.6463 9.46336C15.6667 9.21366 15.6666 8.91051 15.6666 8.5591V3.44099C15.6666 3.08959 15.6667 2.78635 15.6463 2.53665C15.6247 2.27309 15.5772 2.01095 15.4487 1.75869C15.2569 1.38237 14.9509 1.07641 14.5746 0.884661C14.3224 0.756131 14.0602 0.708587 13.7967 0.687053C13.5469 0.666651 13.2438 0.666661 12.8923 0.666672Z" fill="#667085" /> <path d="M12.8923 0.666672H7.77427C7.42285 0.666661 7.11966 0.666651 6.86995 0.687053C6.60639 0.708587 6.34424 0.756131 6.09199 0.884661C5.71567 1.07641 5.40971 1.38237 5.21796 1.75869C5.08943 2.01095 5.04188 2.27309 5.02035 2.53665C5.00206 2.76051 5.00018 3.02733 4.99999 3.33336L8.92055 3.33335C9.2463 3.33327 9.59951 3.33319 9.90523 3.35816C10.2512 3.38644 10.7084 3.4564 11.1799 3.69667C11.8071 4.01625 12.3171 4.52618 12.6367 5.15339C12.8769 5.62493 12.9469 6.08208 12.9752 6.42809C13.0001 6.73382 13.0001 7.08702 13 7.41279L13 11.3333C13.306 11.3331 13.5728 11.3313 13.7967 11.313C14.0602 11.2914 14.3224 11.2439 14.5746 11.1154C14.9509 10.9236 15.2569 10.6176 15.4487 10.2413C15.5772 9.98907 15.6247 9.72692 15.6463 9.46336C15.6667 9.21366 15.6666 8.91051 15.6666 8.5591V3.44099C15.6666 3.08959 15.6667 2.78635 15.6463 2.53665C15.6247 2.27309 15.5772 2.01095 15.4487 1.75869C15.2569 1.38237 14.9509 1.07641 14.5746 0.884661C14.3224 0.756131 14.0602 0.708587 13.7967 0.687053C13.5469 0.666651 13.2438 0.666661 12.8923 0.666672Z" fill="#667085" />
</svg> </svg>
) )
case 'paragraph': case InputVarType.paragraph:
return selected return selected
? ( ? (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="align-left"> <g id="align-left">
<g id="Solid"> <g id="Solid">
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 6.66665C1.33334 6.29846 1.63182 5.99998 2.00001 5.99998H10.6667C11.0349 5.99998 11.3333 6.29846 11.3333 6.66665C11.3333 7.03484 11.0349 7.33331 10.6667 7.33331H2.00001C1.63182 7.33331 1.33334 7.03484 1.33334 6.66665Z" fill="#155EEF"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 6.66665C1.33334 6.29846 1.63182 5.99998 2.00001 5.99998H10.6667C11.0349 5.99998 11.3333 6.29846 11.3333 6.66665C11.3333 7.03484 11.0349 7.33331 10.6667 7.33331H2.00001C1.63182 7.33331 1.33334 7.03484 1.33334 6.66665Z" fill="#155EEF" />
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 3.99998C1.33334 3.63179 1.63182 3.33331 2.00001 3.33331H13.3333C13.7015 3.33331 14 3.63179 14 3.99998C14 4.36817 13.7015 4.66665 13.3333 4.66665H2.00001C1.63182 4.66665 1.33334 4.36817 1.33334 3.99998Z" fill="#155EEF"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 3.99998C1.33334 3.63179 1.63182 3.33331 2.00001 3.33331H13.3333C13.7015 3.33331 14 3.63179 14 3.99998C14 4.36817 13.7015 4.66665 13.3333 4.66665H2.00001C1.63182 4.66665 1.33334 4.36817 1.33334 3.99998Z" fill="#155EEF" />
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 9.33331C1.33334 8.96512 1.63182 8.66665 2.00001 8.66665H13.3333C13.7015 8.66665 14 8.96512 14 9.33331C14 9.7015 13.7015 9.99998 13.3333 9.99998H2.00001C1.63182 9.99998 1.33334 9.7015 1.33334 9.33331Z" fill="#155EEF"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 9.33331C1.33334 8.96512 1.63182 8.66665 2.00001 8.66665H13.3333C13.7015 8.66665 14 8.96512 14 9.33331C14 9.7015 13.7015 9.99998 13.3333 9.99998H2.00001C1.63182 9.99998 1.33334 9.7015 1.33334 9.33331Z" fill="#155EEF" />
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 12C1.33334 11.6318 1.63182 11.3333 2.00001 11.3333H10.6667C11.0349 11.3333 11.3333 11.6318 11.3333 12C11.3333 12.3682 11.0349 12.6666 10.6667 12.6666H2.00001C1.63182 12.6666 1.33334 12.3682 1.33334 12Z" fill="#155EEF"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 12C1.33334 11.6318 1.63182 11.3333 2.00001 11.3333H10.6667C11.0349 11.3333 11.3333 11.6318 11.3333 12C11.3333 12.3682 11.0349 12.6666 10.6667 12.6666H2.00001C1.63182 12.6666 1.33334 12.3682 1.33334 12Z" fill="#155EEF" />
</g> </g>
</g> </g>
</svg> </svg>
...@@ -46,15 +46,15 @@ const Icon = ({ type, selected }: Partial<ISelectTypeItemProps>) => { ...@@ -46,15 +46,15 @@ const Icon = ({ type, selected }: Partial<ISelectTypeItemProps>) => {
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="align-left"> <g id="align-left">
<g id="Solid"> <g id="Solid">
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 6.66666C1.33334 6.29847 1.63182 5.99999 2.00001 5.99999H10.6667C11.0349 5.99999 11.3333 6.29847 11.3333 6.66666C11.3333 7.03485 11.0349 7.33333 10.6667 7.33333H2.00001C1.63182 7.33333 1.33334 7.03485 1.33334 6.66666Z" fill="#667085"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 6.66666C1.33334 6.29847 1.63182 5.99999 2.00001 5.99999H10.6667C11.0349 5.99999 11.3333 6.29847 11.3333 6.66666C11.3333 7.03485 11.0349 7.33333 10.6667 7.33333H2.00001C1.63182 7.33333 1.33334 7.03485 1.33334 6.66666Z" fill="#667085" />
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 3.99999C1.33334 3.63181 1.63182 3.33333 2.00001 3.33333H13.3333C13.7015 3.33333 14 3.63181 14 3.99999C14 4.36818 13.7015 4.66666 13.3333 4.66666H2.00001C1.63182 4.66666 1.33334 4.36818 1.33334 3.99999Z" fill="#667085"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 3.99999C1.33334 3.63181 1.63182 3.33333 2.00001 3.33333H13.3333C13.7015 3.33333 14 3.63181 14 3.99999C14 4.36818 13.7015 4.66666 13.3333 4.66666H2.00001C1.63182 4.66666 1.33334 4.36818 1.33334 3.99999Z" fill="#667085" />
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 9.33333C1.33334 8.96514 1.63182 8.66666 2.00001 8.66666H13.3333C13.7015 8.66666 14 8.96514 14 9.33333C14 9.70152 13.7015 10 13.3333 10H2.00001C1.63182 10 1.33334 9.70152 1.33334 9.33333Z" fill="#667085"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 9.33333C1.33334 8.96514 1.63182 8.66666 2.00001 8.66666H13.3333C13.7015 8.66666 14 8.96514 14 9.33333C14 9.70152 13.7015 10 13.3333 10H2.00001C1.63182 10 1.33334 9.70152 1.33334 9.33333Z" fill="#667085" />
<path fillRule="evenodd" clipRule="evenodd" d="M1.33334 12C1.33334 11.6318 1.63182 11.3333 2.00001 11.3333H10.6667C11.0349 11.3333 11.3333 11.6318 11.3333 12C11.3333 12.3682 11.0349 12.6667 10.6667 12.6667H2.00001C1.63182 12.6667 1.33334 12.3682 1.33334 12Z" fill="#667085"/> <path fillRule="evenodd" clipRule="evenodd" d="M1.33334 12C1.33334 11.6318 1.63182 11.3333 2.00001 11.3333H10.6667C11.0349 11.3333 11.3333 11.6318 11.3333 12C11.3333 12.3682 11.0349 12.6667 10.6667 12.6667H2.00001C1.63182 12.6667 1.33334 12.3682 1.33334 12Z" fill="#667085" />
</g> </g>
</g> </g>
</svg> </svg>
) )
case 'string': case InputVarType.textInput:
default: default:
return selected return selected
? ( ? (
......
...@@ -7,6 +7,7 @@ import Split from '@/app/components/workflow/nodes/_base/components/split' ...@@ -7,6 +7,7 @@ import Split from '@/app/components/workflow/nodes/_base/components/split'
import Field from '@/app/components/workflow/nodes/_base/components/field' import Field from '@/app/components/workflow/nodes/_base/components/field'
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars' import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
import AddButton from '@/app/components/base/button/add-button' import AddButton from '@/app/components/base/button/add-button'
import ConfigVarModal from '@/app/components/app/configuration/config-var/config-modal'
const i18nPrefix = 'workflow.nodes.start' const i18nPrefix = 'workflow.nodes.start'
...@@ -15,6 +16,10 @@ const Panel: FC = () => { ...@@ -15,6 +16,10 @@ const Panel: FC = () => {
const readOnly = false const readOnly = false
const { const {
inputs, inputs,
isShowAddVarModal,
showAddVarModal,
handleAddVariable,
hideAddVarModal,
handleVarListChange, handleVarListChange,
} = useConfig(mockData) } = useConfig(mockData)
...@@ -24,7 +29,7 @@ const Panel: FC = () => { ...@@ -24,7 +29,7 @@ const Panel: FC = () => {
<Field <Field
title={t(`${i18nPrefix}.inputField`)} title={t(`${i18nPrefix}.inputField`)}
operations={ operations={
<AddButton onClick={() => { }} /> <AddButton onClick={showAddVarModal} />
} }
> >
<VarList <VarList
...@@ -69,6 +74,17 @@ const Panel: FC = () => { ...@@ -69,6 +74,17 @@ const Panel: FC = () => {
</> </>
</OutputVars> </OutputVars>
</div> </div>
{isShowAddVarModal && (
<ConfigVarModal
isCreate
isShow={isShowAddVarModal}
onClose={hideAddVarModal}
onConfirm={(payload) => {
handleAddVariable(payload)
hideAddVarModal()
}}
/>
)}
</div> </div>
) )
} }
......
import { useCallback, useState } from 'react' import { useCallback, useState } from 'react'
import produce from 'immer' import produce from 'immer'
import { useBoolean } from 'ahooks'
import type { StartNodeType } from './types' import type { StartNodeType } from './types'
import type { InputVar } from '@/app/components/workflow/types' import type { InputVar } from '@/app/components/workflow/types'
const useConfig = (initInputs: StartNodeType) => { const useConfig = (initInputs: StartNodeType) => {
const [inputs, setInputs] = useState<StartNodeType>(initInputs) const [inputs, setInputs] = useState<StartNodeType>(initInputs)
const [isShowAddVarModal, {
setTrue: showAddVarModal,
setFalse: hideAddVarModal,
}] = useBoolean(true)
const handleVarListChange = useCallback((newList: InputVar[]) => { const handleVarListChange = useCallback((newList: InputVar[]) => {
const newInputs = produce(inputs, (draft: any) => { const newInputs = produce(inputs, (draft: any) => {
draft.variables = newList draft.variables = newList
...@@ -21,6 +27,9 @@ const useConfig = (initInputs: StartNodeType) => { ...@@ -21,6 +27,9 @@ const useConfig = (initInputs: StartNodeType) => {
}, [inputs, setInputs]) }, [inputs, setInputs])
return { return {
inputs, inputs,
isShowAddVarModal,
showAddVarModal,
hideAddVarModal,
handleVarListChange, handleVarListChange,
handleAddVariable, handleAddVariable,
} }
......
/* eslint-disable import/no-mutable-exports */ /* eslint-disable import/no-mutable-exports */
import { InputVarType } from '@/app/components/workflow/types'
import { AgentStrategy } from '@/types/app' import { AgentStrategy } from '@/types/app'
export let apiPrefix = '' export let apiPrefix = ''
...@@ -115,6 +116,15 @@ export const VAR_ITEM_TEMPLATE = { ...@@ -115,6 +116,15 @@ export const VAR_ITEM_TEMPLATE = {
required: true, required: true,
} }
export const VAR_ITEM_TEMPLATE_IN_WORKFLOW = {
variable: '',
label: '',
type: InputVarType.textInput,
max_length: DEFAULT_VALUE_MAX_LEN,
required: true,
options: [],
}
export const appDefaultIconBackground = '#D5F5F6' export const appDefaultIconBackground = '#D5F5F6'
export const NEED_REFRESH_APP_LIST_KEY = 'needRefreshAppList' export const NEED_REFRESH_APP_LIST_KEY = 'needRefreshAppList'
......
...@@ -266,18 +266,23 @@ const translation = { ...@@ -266,18 +266,23 @@ const translation = {
queryNoBeEmpty: 'Query must be set in the prompt', queryNoBeEmpty: 'Query must be set in the prompt',
}, },
variableConig: { variableConig: {
modalTitle: 'Field settings', 'addModalTitle': 'Add Input Field',
description: 'Setting for variable {{varName}}', 'editModalTitle': 'Edit Input Field',
fieldType: 'Field type', 'description': 'Setting for variable {{varName}}',
string: 'Short Text', 'fieldType': 'Field type',
paragraph: 'Paragraph', 'string': 'Short Text',
select: 'Select', 'text-input': 'Short Text',
notSet: 'Not set, try typing {{input}} in the prefix prompt', 'paragraph': 'Paragraph',
stringTitle: 'Form text box options', 'select': 'Select',
maxLength: 'Max length', 'notSet': 'Not set, try typing {{input}} in the prefix prompt',
options: 'Options', 'stringTitle': 'Form text box options',
addOption: 'Add option', 'maxLength': 'Max length',
apiBasedVar: 'API-based Variable', 'options': 'Options',
'addOption': 'Add option',
'apiBasedVar': 'API-based Variable',
'varName': 'Variable Name',
'labelName': 'Label Name',
'required': 'Required',
}, },
vision: { vision: {
name: 'Vision', name: 'Vision',
......
...@@ -266,18 +266,19 @@ const translation = { ...@@ -266,18 +266,19 @@ const translation = {
queryNoBeEmpty: 'A consulta deve ser definida na solicitação', queryNoBeEmpty: 'A consulta deve ser definida na solicitação',
}, },
variableConig: { variableConig: {
modalTitle: 'Configurações do Campo', 'addModalTitle': 'Configurações do Campo',
description: 'Configuração para a variável {{varName}}', 'description': 'Configuração para a variável {{varName}}',
fieldType: 'Tipo de Campo', 'fieldType': 'Tipo de Campo',
string: 'Texto Curto', 'string': 'Texto Curto',
paragraph: 'Parágrafo', 'text-input': 'Texto Curto',
select: 'Selecionar', 'paragraph': 'Parágrafo',
notSet: 'Não definido, tente digitar {{input}} na solicitação', 'select': 'Selecionar',
stringTitle: 'Opções da Caixa de Texto do Formulário', 'notSet': 'Não definido, tente digitar {{input}} na solicitação',
maxLength: 'Comprimento Máximo', 'stringTitle': 'Opções da Caixa de Texto do Formulário',
options: 'Opções', 'maxLength': 'Comprimento Máximo',
addOption: 'Adicionar opção', 'options': 'Opções',
apiBasedVar: 'Variável Baseada em API', 'addOption': 'Adicionar opção',
'apiBasedVar': 'Variável Baseada em API',
}, },
vision: { vision: {
name: 'Visão', name: 'Visão',
......
...@@ -260,18 +260,19 @@ const translation = { ...@@ -260,18 +260,19 @@ const translation = {
queryNoBeEmpty: 'Запит має бути встановлений у підказці', // Query must be set in the prompt queryNoBeEmpty: 'Запит має бути встановлений у підказці', // Query must be set in the prompt
}, },
variableConig: { variableConig: {
modalTitle: 'Налаштування поля', // Field settings 'addModalTitle': 'Налаштування поля', // Field settings
description: 'Налаштування для змінної {{varName}}', // Setting for variable {{varName}} 'description': 'Налаштування для змінної {{varName}}', // Setting for variable {{varName}}
fieldType: 'Тип поля', // Field type 'fieldType': 'Тип поля', // Field type
string: 'Короткий текст', // Short Text 'string': 'Короткий текст', // Short Text
paragraph: 'Абзац', // Paragraph 'text-input': 'Короткий текст', // Short Text
select: 'Вибрати', // Select 'paragraph': 'Абзац', // Paragraph
notSet: 'Не налаштовано, спробуйте ввести {{input}} у префіксну підказку', // Not set, try typing {{input}} in the prefix prompt 'select': 'Вибрати', // Select
stringTitle: 'Опції текстового поля форми', // Form text box options 'notSet': 'Не налаштовано, спробуйте ввести {{input}} у префіксну підказку', // Not set, try typing {{input}} in the prefix prompt
maxLength: 'Максимальна довжина', // Max length 'stringTitle': 'Опції текстового поля форми', // Form text box options
options: 'Опції', // Options 'maxLength': 'Максимальна довжина', // Max length
addOption: 'Додати опцію', // Add option 'options': 'Опції', // Options
apiBasedVar: 'Змінна на основі API', // API-based Variable 'addOption': 'Додати опцію', // Add option
'apiBasedVar': 'Змінна на основі API', // API-based Variable
}, },
vision: { vision: {
name: 'Зображення', // Vision name: 'Зображення', // Vision
......
...@@ -248,6 +248,9 @@ const translation = { ...@@ -248,6 +248,9 @@ const translation = {
action: '操作', action: '操作',
typeString: '文本', typeString: '文本',
typeSelect: '下拉选项', typeSelect: '下拉选项',
varName: '变量名称',
labelName: '显示名称',
required: '必填',
}, },
varKeyError: { varKeyError: {
canNoBeEmpty: '变量不能为空', canNoBeEmpty: '变量不能为空',
...@@ -262,18 +265,20 @@ const translation = { ...@@ -262,18 +265,20 @@ const translation = {
queryNoBeEmpty: '提示词中必须设置查询内容', queryNoBeEmpty: '提示词中必须设置查询内容',
}, },
variableConig: { variableConig: {
modalTitle: '变量设置', 'addModalTitle': '添加变量',
description: '设置变量 {{varName}}', 'editModalTitle': '编辑变量',
fieldType: '字段类型', 'description': '设置变量 {{varName}}',
string: '文本', 'fieldType': '字段类型',
paragraph: '段落', 'string': '文本',
select: '下拉选项', 'text-input': '文本',
notSet: '未设置,在 Prompt 中输入 {{input}} 试试', 'paragraph': '段落',
stringTitle: '文本框设置', 'select': '下拉选项',
maxLength: '最大长度', 'notSet': '未设置,在 Prompt 中输入 {{input}} 试试',
options: '选项', 'stringTitle': '文本框设置',
addOption: '添加选项', 'maxLength': '最大长度',
apiBasedVar: '基于 API 的变量', 'options': '选项',
'addOption': '添加选项',
'apiBasedVar': '基于 API 的变量',
}, },
vision: { vision: {
name: '视觉', name: '视觉',
......
import { MAX_VAR_KEY_LENGHT, VAR_ITEM_TEMPLATE, getMaxVarNameLength } from '@/config' import { MAX_VAR_KEY_LENGHT, VAR_ITEM_TEMPLATE, VAR_ITEM_TEMPLATE_IN_WORKFLOW, getMaxVarNameLength } from '@/config'
import { CONTEXT_PLACEHOLDER_TEXT, HISTORY_PLACEHOLDER_TEXT, PRE_PROMPT_PLACEHOLDER_TEXT, QUERY_PLACEHOLDER_TEXT } from '@/app/components/base/prompt-editor/constants' import { CONTEXT_PLACEHOLDER_TEXT, HISTORY_PLACEHOLDER_TEXT, PRE_PROMPT_PLACEHOLDER_TEXT, QUERY_PLACEHOLDER_TEXT } from '@/app/components/base/prompt-editor/constants'
import { InputVarType } from '@/app/components/workflow/types'
const otherAllowedRegex = /^[a-zA-Z0-9_]+$/ const otherAllowedRegex = /^[a-zA-Z0-9_]+$/
...@@ -21,6 +22,24 @@ export const getNewVar = (key: string, type: string) => { ...@@ -21,6 +22,24 @@ export const getNewVar = (key: string, type: string) => {
} }
} }
export const getNewVarInWorkflow = (key: string, type = InputVarType.textInput) => {
const { max_length, ...rest } = VAR_ITEM_TEMPLATE_IN_WORKFLOW
if (type !== InputVarType.textInput) {
return {
...rest,
type,
variable: key,
label: key.slice(0, getMaxVarNameLength(key)),
}
}
return {
...VAR_ITEM_TEMPLATE_IN_WORKFLOW,
type,
variable: key,
label: key.slice(0, getMaxVarNameLength(key)),
}
}
const checkKey = (key: string, canBeEmpty?: boolean) => { const checkKey = (key: string, canBeEmpty?: boolean) => {
if (key.length === 0 && !canBeEmpty) if (key.length === 0 && !canBeEmpty)
return 'canNoBeEmpty' return 'canNoBeEmpty'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment