Commit 8b8fdb48 authored by Joel's avatar Joel

feat: output var

parent b4437ccd
......@@ -48,7 +48,7 @@ const Page: FC = () => {
* 2 directAnswer 3: llm 5: questionClassifier
* 7 Code, 8 TemplateTransform
*/
selectedNodeId='3'
selectedNodeId='7'
/>
</div>
)
......
'use client'
import type { FC } from 'react'
import React, { useCallback } from 'react'
import produce from 'immer'
import type { OutputVar } from '../../../code/types'
import VarTypePicker from './var-type-picker'
import { Trash03 } from '@/app/components/base/icons/src/vender/line/general'
type Props = {
readonly: boolean
list: OutputVar[]
onChange: (list: OutputVar[]) => void
}
const OutputVarList: FC<Props> = ({
readonly,
list,
onChange,
}) => {
const handleVarNameChange = useCallback((index: number) => {
return (e: React.ChangeEvent<HTMLInputElement>) => {
const newList = produce(list, (draft) => {
draft[index].variable = e.target.value
})
onChange(newList)
}
}, [list, onChange])
const handleVarChange = useCallback((index: number) => {
return (value: string) => {
const newList = produce(list, (draft) => {
draft[index].variable_type = value
})
onChange(newList)
}
}, [list, onChange])
const handleVarRemove = useCallback((index: number) => {
return () => {
const newList = produce(list, (draft) => {
draft.splice(index, 1)
})
onChange(newList)
}
}, [list, onChange])
return (
<div className='space-y-2'>
{list.map((item, index) => (
<div className='flex items-center space-x-1' key={index}>
<input
readOnly={readonly}
value={item.variable}
onChange={handleVarNameChange(index)}
className='w-0 grow h-8 leading-8 px-2.5 rounded-lg border-0 bg-gray-100 text-gray-900 text-[13px] placeholder:text-gray-400 focus:outline-none focus:ring-1 focus:ring-inset focus:ring-gray-200'
type='text' />
<VarTypePicker
readonly={readonly}
value={item.variable_type}
onChange={handleVarChange(index)}
/>
<div
className='p-2 rounded-lg bg-gray-100 hover:bg-gray-200 cursor-pointer'
onClick={handleVarRemove(index)}
>
<Trash03 className='w-4 h-4 text-gray-500' />
</div>
</div>
))}
</div>
)
}
export default React.memo(OutputVarList)
'use client'
import type { FC } from 'react'
import React, { useCallback, useState } from 'react'
import cn from 'classnames'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import { Check } from '@/app/components/base/icons/src/vender/line/general'
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
type Props = {
className?: string
readonly: boolean
value: string
onChange: (value: string) => void
}
const TYPES = ['string', 'number']
const VarReferencePicker: FC<Props> = ({
readonly,
className,
value,
onChange,
}) => {
const [open, setOpen] = useState(false)
const handleChange = useCallback((type: string) => {
return () => {
setOpen(false)
onChange(type)
}
}, [onChange])
return (
<div className={cn(className, !readonly && 'cursor-pointer select-none')}>
<PortalToFollowElem
open={open}
onOpenChange={setOpen}
placement='bottom-start'
offset={4}
>
<PortalToFollowElemTrigger onClick={() => setOpen(!open)} className='w-[120px] cursor-pointer'>
<div className='flex items-center h-8 justify-between px-2.5 rounded-lg border-0 bg-gray-100 text-gray-900 text-[13px]'>
<div className='capitalize'>{value}</div>
<ChevronDown className='w-3.5 h-3.5 text-gray-700' />
</div>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent style={{
zIndex: 100,
}}>
<div className='w-[120px] p-1 bg-white rounded-lg shadow-sm'>
{TYPES.map(type => (
<div
key={type}
className='flex items-center h-[30px] justify-between pl-3 pr-2 rounded-lg hover:bg-gray-100 text-gray-900 text-[13px] cursor-pointer'
onClick={handleChange(type)}
>
<div className='capitalize'>{type}</div>
{type === value && <Check className='w-4 h-4 text-primary-600' />}
</div>
))}
</div>
</PortalToFollowElemContent>
</PortalToFollowElem>
</div>
)
}
export default React.memo(VarReferencePicker)
import { useCallback } from 'react'
import produce from 'immer'
import type { OutputVar } from '../../code/types'
type Params<T> = {
inputs: T
setInputs: (newInputs: T) => void
varKey?: string
}
function useOutputVarList<T>({
inputs,
setInputs,
varKey = 'outputs',
}: Params<T>) {
const handleVarListChange = useCallback((newList: OutputVar[]) => {
const newInputs = produce(inputs, (draft: any) => {
draft[varKey] = newList
})
setInputs(newInputs)
}, [inputs, setInputs, varKey])
const handleAddVariable = useCallback(() => {
const newInputs = produce(inputs, (draft: any) => {
draft[varKey].push({
variable: '',
variable_type: 'string',
})
})
setInputs(newInputs)
}, [inputs, setInputs, varKey])
return {
handleVarListChange,
handleAddVariable,
}
}
export default useOutputVarList
......@@ -4,6 +4,7 @@ import useConfig from './use-config'
import { mockData } from './mock'
import { CodeLanguage } from './types'
import VarList from '@/app/components/workflow/nodes/_base/components/variable/var-list'
import OutputVarList from '@/app/components/workflow/nodes/_base/components/variable/output-var-list'
import AddButton from '@/app/components/base/button/add-button'
import Field from '@/app/components/workflow/nodes/_base/components/field'
import Split from '@/app/components/workflow/nodes/_base/components/split'
......@@ -31,6 +32,8 @@ const Panel: FC = () => {
handleAddVariable,
handleCodeChange,
handleCodeLanguageChange,
handleOutputVarListChange,
handleAddOutputVariable,
} = useConfig(mockData)
return (
<div className='mt-2'>
......@@ -62,7 +65,18 @@ const Panel: FC = () => {
</div>
<Split />
<div className='px-4 pt-4 pb-2'>
output var
<Field
title={t(`${i18nPrefix}.outputVars`)}
operations={
<AddButton onClick={handleAddOutputVariable} />
}
>
<OutputVarList
readonly={readOnly}
list={inputs.outputs}
onChange={handleOutputVarListChange}
/>
</Field>
</div>
</div>
)
......
......@@ -5,12 +5,14 @@ export enum CodeLanguage {
javascript = 'javascript',
}
export type OutputVar = {
variable: string
variable_type: string
}
export type CodeNodeType = CommonNodeType & {
variables: Variable[]
code_language: CodeLanguage
code: string
outputs: {
variable: string
variable_type: string
}[]
outputs: OutputVar[]
}
import { useCallback, useState } from 'react'
import useVarList from '../_base/hooks/use-var-list'
import useOutputVarList from '../_base/hooks/use-output-var-list'
import type { CodeLanguage, CodeNodeType } from './types'
const useConfig = (initInputs: CodeNodeType) => {
......@@ -17,12 +18,19 @@ const useConfig = (initInputs: CodeNodeType) => {
setInputs(prev => ({ ...prev, code_language: codeLanguage }))
}, [setInputs])
const { handleVarListChange: handleOutputVarListChange, handleAddVariable: handleAddOutputVariable } = useOutputVarList<CodeNodeType>({
inputs,
setInputs,
})
return {
inputs,
handleVarListChange,
handleAddVariable,
handleCodeChange,
handleCodeLanguageChange,
handleOutputVarListChange,
handleAddOutputVariable,
}
}
......
......@@ -21,6 +21,7 @@ const translation = {
},
code: {
inputVars: 'Input Variables',
outputVars: 'Output Variables',
},
templateTransform: {
inputVars: 'Input Variables',
......
......@@ -21,6 +21,7 @@ const translation = {
},
code: {
inputVars: '输入变量',
outputVars: '输出变量',
},
templateTransform: {
inputVars: '输入变量',
......
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