Commit ada558be authored by Joel's avatar Joel

feat: add picker shower

parent 6caca3aa
...@@ -16,7 +16,7 @@ import { ...@@ -16,7 +16,7 @@ import {
} from '@floating-ui/react' } from '@floating-ui/react'
import type { OffsetOptions, Placement } from '@floating-ui/react' import type { OffsetOptions, Placement } from '@floating-ui/react'
import cn from 'classnames'
export type PortalToFollowElemOptions = { export type PortalToFollowElemOptions = {
/* /*
* top, bottom, left, right * top, bottom, left, right
...@@ -129,7 +129,7 @@ React.HTMLProps<HTMLElement> & { asChild?: boolean } ...@@ -129,7 +129,7 @@ React.HTMLProps<HTMLElement> & { asChild?: boolean }
return ( return (
<div <div
ref={ref} ref={ref}
className='inline-block' className={cn('inline-block', props.className)}
// The user can style the trigger based on the state // The user can style the trigger based on the state
data-state={context.open ? 'open' : 'closed'} data-state={context.open ? 'open' : 'closed'}
{...context.getReferenceProps(props)} {...context.getReferenceProps(props)}
......
'use client' 'use client'
import type { FC } from 'react' import type { FC } from 'react'
import React from 'react' import React, { useState } from 'react'
import cn from 'classnames' import cn from 'classnames'
import { mockNodesData } from '../../../mock' import { mockNodeOutputVars, mockNodesData } from '../../../mock'
import VarReferencePopup from './var-reference-popup'
import type { ValueSelector } from '@/app/components/workflow/types' import type { ValueSelector } from '@/app/components/workflow/types'
import { VarBlockIcon } from '@/app/components/workflow/block-icon' import { VarBlockIcon } from '@/app/components/workflow/block-icon'
import { Line3 } from '@/app/components/base/icons/src/public/common' import { Line3 } from '@/app/components/base/icons/src/public/common'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
type Props = { type Props = {
className?: string className?: string
isShowNodeName: boolean isShowNodeName: boolean
...@@ -15,6 +22,14 @@ type Props = { ...@@ -15,6 +22,14 @@ type Props = {
onChange: (value: ValueSelector) => void onChange: (value: ValueSelector) => void
} }
// const toShowVarType = (type: string) => {
// if (['text-input', 'paragraph', 'select', 'url'].includes(type))
// return 'String'
// return type.charAt(0).toUpperCase() + type.substring(1)
// }
// TODO: get data from context
const getNodeInfoById = (id: string) => { const getNodeInfoById = (id: string) => {
return mockNodesData[id] return mockNodesData[id]
} }
...@@ -25,6 +40,7 @@ const VarReferencePicker: FC<Props> = ({ ...@@ -25,6 +40,7 @@ const VarReferencePicker: FC<Props> = ({
isShowNodeName, isShowNodeName,
value, value,
}) => { }) => {
const [open, setOpen] = useState(false)
const hasValue = value.length > 0 const hasValue = value.length > 0
const node = hasValue ? getNodeInfoById(value[0]) : null const node = hasValue ? getNodeInfoById(value[0]) : null
const varName = hasValue ? value[value.length - 1] : '' const varName = hasValue ? value[value.length - 1] : ''
...@@ -32,33 +48,48 @@ const VarReferencePicker: FC<Props> = ({ ...@@ -32,33 +48,48 @@ const VarReferencePicker: FC<Props> = ({
const getVarType = () => { const getVarType = () => {
return 'string' return 'string'
} }
return ( return (
<div className={cn(className, !readonly && 'cursor-pointer')}> <div className={cn(className, !readonly && 'cursor-pointer')}>
<div className={cn('w-full h-8 p-1 rounded-lg bg-gray-100')}> <PortalToFollowElem
<div className={cn('inline-flex h-full items-center px-1.5 rounded-[5px]', hasValue && 'bg-white')}> open={open}
{hasValue && ( onOpenChange={setOpen}
<> placement='bottom-start'
{isShowNodeName && ( >
<div className='flex items-center'> <PortalToFollowElemTrigger onClick={() => setOpen(!open)} className='!flex'>
<div className='p-[1px]'> <div className={cn('w-full h-8 p-1 rounded-lg bg-gray-100')}>
<VarBlockIcon <div className={cn('inline-flex h-full items-center px-1.5 rounded-[5px]', hasValue && 'bg-white')}>
className='!text-gray-900' {hasValue && (
type={node?.type} <>
/> {isShowNodeName && (
<div className='flex items-center'>
<div className='p-[1px]'>
<VarBlockIcon
className='!text-gray-900'
type={node?.type}
/>
</div>
<div className='mx-0.5 text-xs font-medium text-gray-700'>{node?.title}</div>
<Line3 className='mr-0.5'></Line3>
</div>
)}
<div className='flex items-center text-primary-600'>
<Variable02 className='w-3.5 h-3.5' />
<div className='ml-0.5 text-xs font-medium'>{varName}</div>
</div> </div>
<div className='mx-0.5 text-xs font-medium text-gray-700'>{node?.title}</div> <div className='ml-0.5 text-xs font-normal text-gray-500'>{getVarType()}</div>
<Line3 className='mr-0.5'></Line3> </>
</div>
)} )}
<div className='flex items-center text-primary-600'> </div>
<Variable02 className='w-3.5 h-3.5' /> </div>
<div className='ml-0.5 text-xs font-medium'>{varName}</div> </PortalToFollowElemTrigger>
</div> <PortalToFollowElemContent style={{
<div className='ml-0.5 text-xs font-normal text-gray-500'>{getVarType()}</div> zIndex: 100,
</> width: 227,
)} }}>
</div> <VarReferencePopup vars={mockNodeOutputVars} />
</div> </PortalToFollowElemContent>
</PortalToFollowElem>
</div> </div>
) )
} }
......
'use client'
import type { FC } from 'react'
import React from 'react'
import type { NodeOutPutVar } from '@/app/components/workflow/types'
import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
type Props = {
vars: NodeOutPutVar[]
}
const VarReferencePopup: FC<Props> = ({
vars,
}) => {
return (
<div className='p-1 bg-white rounded-lg border border-gray-200 shadow-lg space-y-1'>
{vars.map((item, i) => (
<div key={i}>
<div className='flex items-center h-[22px] px-3 text-xs font-medium text-gray-500 uppercase'>{item.title}</div>
{item.vars.map((v, j) => (
<div key={j} className='flex items-center h-6 pl-3 pr-[18px] rounded-md cursor-pointer hover:bg-gray-50'>
<div className='flex items-center w-0 grow'>
<Variable02 className='shrink-0 w-3.5 h-3.5 text-primary-500' />
<div className='ml-1 w-0 grow text-ellipsis text-[13px] font-normal text-gray-900'>{v.variable}</div>
</div>
<div className='ml-1 shrink-0 text-xs font-normal text-gray-500'>{v.type}</div>
</div>
))}
</div>
))}
</div>
)
}
export default React.memo(VarReferencePopup)
...@@ -2,7 +2,7 @@ import type { FC } from 'react' ...@@ -2,7 +2,7 @@ import type { FC } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import BasePanel from '../_base/panel' import BasePanel from '../_base/panel'
import VarList from '../_base/components/variable/var-list' import VarList from '../_base/components/variable/var-list'
import useInput from './use-input' import useConfig from './use-config'
import { mockLLMNodeData } from './mock' import { mockLLMNodeData } from './mock'
import Field from '@/app/components/workflow/nodes/_base/components/field' import Field from '@/app/components/workflow/nodes/_base/components/field'
import AddButton from '@/app/components/base/button/add-button' import AddButton from '@/app/components/base/button/add-button'
...@@ -23,10 +23,10 @@ const Panel: FC = () => { ...@@ -23,10 +23,10 @@ const Panel: FC = () => {
handleVarListChange, handleVarListChange,
handleAddVariable, handleAddVariable,
toggleContextEnabled, toggleContextEnabled,
} = useInput(mockLLMNodeData) } = useConfig(mockLLMNodeData)
const model = inputs.model const model = inputs.model
const modelMode = inputs.model?.mode // const modelMode = inputs.model?.mode
const isChatMode = modelMode === 'chat' // const isChatMode = modelMode === 'chat'
return ( return (
<BasePanel <BasePanel
......
import type { NodeOutPutVar } from '@/app/components/workflow/types'
import { BlockEnum } from '@/app/components/workflow/types' import { BlockEnum } from '@/app/components/workflow/types'
export const mockNodesData: Record<string, any> = { export const mockNodesData: Record<string, any> = {
aaa: { aaa: {
title: 'Start', title: 'Start',
type: BlockEnum.Start, type: BlockEnum.Start,
}, },
bbb: { bbb: {
title: 'Knowledge', title: 'Knowledge',
type: BlockEnum.KnowledgeRetrieval, type: BlockEnum.KnowledgeRetrieval,
}, },
ccc: {
title: 'Code',
type: BlockEnum.Code,
},
} }
export const mockNodeOutputVars: NodeOutPutVar[] = [
{
title: 'Start',
vars: [
{
variable: 'query',
type: 'string',
},
{
variable: 'age',
type: 'number',
},
],
},
{
title: 'LLM',
vars: [
{
variable: 'usage',
type: 'object',
struct: ['token', 'value'],
},
],
},
]
...@@ -83,6 +83,15 @@ export type LLMNodeData = { ...@@ -83,6 +83,15 @@ export type LLMNodeData = {
} }
} }
export type NodeOutPutVar = {
title: string
vars: {
variable: string
type: string
struct?: string[]
}[]
}
export type Block = { export type Block = {
classification?: string classification?: string
type: BlockEnum type: BlockEnum
......
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