mirror of https://github.com/langgenius/dify.git
add block-selector
This commit is contained in:
parent
e624c33d51
commit
56407a910d
|
|
@ -0,0 +1,80 @@
|
|||
export const TABS = [
|
||||
{
|
||||
key: 'blocks',
|
||||
name: 'Blocks',
|
||||
},
|
||||
{
|
||||
key: 'built-in-tool',
|
||||
name: 'Built-in Tool',
|
||||
},
|
||||
{
|
||||
key: 'custom-tool',
|
||||
name: 'Custom Tool',
|
||||
},
|
||||
]
|
||||
|
||||
export const BLOCKS = [
|
||||
{
|
||||
type: 'start',
|
||||
title: 'Start',
|
||||
description: '',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
type: 'llm',
|
||||
title: 'LLM',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
type: 'end',
|
||||
title: 'End',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
type: 'direct-answer',
|
||||
title: 'Direct Answer',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
classification: 'Question Understand',
|
||||
type: 'knowledge-retrieval',
|
||||
title: 'Knowledge Retrieval',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
classification: 'Question Understand',
|
||||
type: 'question-classifier',
|
||||
title: 'Question Classifier',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
classification: 'Logic',
|
||||
type: 'if-else',
|
||||
title: 'IF/ELSE',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
classification: 'Transform',
|
||||
type: 'code',
|
||||
title: 'Code',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
classification: 'Transform',
|
||||
type: 'template-transform',
|
||||
title: 'Templating Transform',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
classification: 'Transform',
|
||||
type: 'variable-assigner',
|
||||
title: 'Variable Assigner',
|
||||
icon: '',
|
||||
},
|
||||
{
|
||||
classification: 'Utilities',
|
||||
type: 'http-request',
|
||||
title: 'HTTP Request',
|
||||
icon: '',
|
||||
},
|
||||
]
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
import type { FC, ReactElement } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useState,
|
||||
} from 'react'
|
||||
import Tabs from './tabs'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { SearchLg } from '@/app/components/base/icons/src/vender/line/general'
|
||||
|
||||
type NodeSelectorProps = {
|
||||
children: ReactElement
|
||||
}
|
||||
const NodeSelector: FC<NodeSelectorProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
const handleTrigger: any = useCallback((e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
setOpen(v => !v)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
placement='right-start'
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={handleTrigger}>
|
||||
{children}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent>
|
||||
<div className='w-[256px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg'>
|
||||
<div className='px-2 pt-2'>
|
||||
<div className='flex items-center px-2 rounded-lg bg-gray-100'>
|
||||
<SearchLg className='shrink-0 ml-[1px] mr-[5px] w-3.5 h-3.5 text-gray-400' />
|
||||
<input
|
||||
className='grow px-0.5 py-[7px] text-[13px] bg-transparent appearance-none outline-none'
|
||||
placeholder='Search block'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs />
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(NodeSelector)
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { useState } from 'react'
|
||||
import {
|
||||
BLOCKS,
|
||||
TABS,
|
||||
} from './constants'
|
||||
|
||||
const Tabs = () => {
|
||||
const [activeTab, setActiveTab] = useState(TABS[0].key)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='flex items-center justify-between px-3 h-[34px] border-b-[0.5px] border-b-black/5'>
|
||||
{
|
||||
TABS.map(tab => (
|
||||
<div
|
||||
key={tab.key}
|
||||
className={`
|
||||
text-[13px] font-medium cursor-pointer
|
||||
${activeTab === tab.key ? 'text-gray-700' : 'text-gray-500'}
|
||||
`}
|
||||
onClick={() => setActiveTab(tab.key)}
|
||||
>
|
||||
{tab.name}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div className='p-1'>
|
||||
{
|
||||
BLOCKS.map(block => (
|
||||
<div
|
||||
key={block.type}
|
||||
className='flex items-center h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
|
||||
>
|
||||
<div className='mr-2 w-5 h-5' />
|
||||
<div className='text-sm text-gray-900'>{block.title}</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Tabs
|
||||
|
|
@ -8,6 +8,7 @@ import {
|
|||
useNodeId,
|
||||
} from 'reactflow'
|
||||
import { useWorkflowContext } from '../../context'
|
||||
import BlockSelector from '../../block-selector'
|
||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||
|
||||
type BaseNodeProps = {
|
||||
|
|
@ -48,15 +49,17 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
<div className='px-3 pt-1 pb-1 text-xs text-gray-500'>
|
||||
Define the initial parameters for launching a workflow
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
hidden absolute -bottom-2 left-1/2 -translate-x-1/2 items-center justify-center
|
||||
w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10
|
||||
${!outgoers.length && 'group-hover:flex'}
|
||||
`}
|
||||
>
|
||||
<Plus className='w-2.5 h-2.5 text-white' />
|
||||
</div>
|
||||
<BlockSelector>
|
||||
<div
|
||||
className={`
|
||||
hidden absolute -bottom-2 left-1/2 -translate-x-1/2 items-center justify-center
|
||||
w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10
|
||||
${!outgoers.length && 'group-hover:flex'}
|
||||
`}
|
||||
>
|
||||
<Plus className='w-2.5 h-2.5 text-white' />
|
||||
</div>
|
||||
</BlockSelector>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue