mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 08:58:09 +08:00
block selector & data source node
This commit is contained in:
@ -109,7 +109,7 @@ const Blocks = ({
|
||||
}, [groups, nodesExtraData, onSelect, t])
|
||||
|
||||
return (
|
||||
<div className='p-1'>
|
||||
<div className='max-h-[480px] overflow-y-auto p-1'>
|
||||
{
|
||||
isEmpty && (
|
||||
<div className='flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary'>{t('workflow.tabs.noResult')}</div>
|
||||
|
||||
@ -3,6 +3,12 @@ import { BlockEnum } from '../types'
|
||||
import { BlockClassificationEnum } from './types'
|
||||
|
||||
export const BLOCKS: Block[] = [
|
||||
{
|
||||
classification: BlockClassificationEnum.Default,
|
||||
type: BlockEnum.DataSource,
|
||||
title: 'File upload',
|
||||
description: '',
|
||||
},
|
||||
{
|
||||
classification: BlockClassificationEnum.Default,
|
||||
type: BlockEnum.Start,
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { BLOCKS } from './constants'
|
||||
import {
|
||||
@ -16,19 +20,43 @@ export const useBlocks = () => {
|
||||
})
|
||||
}
|
||||
|
||||
export const useTabs = () => {
|
||||
export const useTabs = (noBlocks?: boolean) => {
|
||||
const { t } = useTranslation()
|
||||
const tabs = useMemo(() => {
|
||||
return [
|
||||
...(
|
||||
noBlocks
|
||||
? []
|
||||
: [
|
||||
{
|
||||
key: TabsEnum.Blocks,
|
||||
name: t('workflow.tabs.blocks'),
|
||||
},
|
||||
]
|
||||
),
|
||||
{
|
||||
key: TabsEnum.Sources,
|
||||
name: t('workflow.tabs.sources'),
|
||||
},
|
||||
{
|
||||
key: TabsEnum.Tools,
|
||||
name: t('workflow.tabs.tools'),
|
||||
},
|
||||
]
|
||||
}, [t, noBlocks])
|
||||
const initialTab = useMemo(() => {
|
||||
if (noBlocks)
|
||||
return TabsEnum.Sources
|
||||
|
||||
return [
|
||||
{
|
||||
key: TabsEnum.Blocks,
|
||||
name: t('workflow.tabs.blocks'),
|
||||
},
|
||||
{
|
||||
key: TabsEnum.Tools,
|
||||
name: t('workflow.tabs.tools'),
|
||||
},
|
||||
]
|
||||
return TabsEnum.Blocks
|
||||
}, [noBlocks])
|
||||
const [activeTab, setActiveTab] = useState(initialTab)
|
||||
|
||||
return {
|
||||
tabs,
|
||||
activeTab,
|
||||
setActiveTab,
|
||||
}
|
||||
}
|
||||
|
||||
export const useToolTabs = () => {
|
||||
|
||||
@ -16,13 +16,15 @@ import type {
|
||||
import type { BlockEnum, OnSelectBlock } from '../types'
|
||||
import Tabs from './tabs'
|
||||
import { TabsEnum } from './types'
|
||||
import { useTabs } from './hooks'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import Input from '@/app/components/base/input'
|
||||
import SearchBox from '@/app/components/plugins/marketplace/search-box'
|
||||
// import SearchBox from '@/app/components/plugins/marketplace/search-box'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
import {
|
||||
Plus02,
|
||||
@ -85,10 +87,12 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
||||
onSelect(type, toolDefaultValue)
|
||||
}, [handleOpenChange, onSelect])
|
||||
|
||||
const [activeTab, setActiveTab] = useState(noBlocks ? TabsEnum.Tools : TabsEnum.Blocks)
|
||||
const handleActiveTabChange = useCallback((newActiveTab: TabsEnum) => {
|
||||
setActiveTab(newActiveTab)
|
||||
}, [])
|
||||
const {
|
||||
activeTab,
|
||||
setActiveTab,
|
||||
tabs,
|
||||
} = useTabs()
|
||||
|
||||
const searchPlaceholder = useMemo(() => {
|
||||
if (activeTab === TabsEnum.Blocks)
|
||||
return t('workflow.tabs.searchBlock')
|
||||
@ -128,9 +132,31 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
||||
}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className={`rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg ${popupClassName}`}>
|
||||
<div className='px-2 pt-2' onClick={e => e.stopPropagation()}>
|
||||
{activeTab === TabsEnum.Blocks && (
|
||||
<div className={cn(
|
||||
'overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg backdrop-blur-[5px]',
|
||||
popupClassName,
|
||||
)}>
|
||||
<div className='border-b border-divider-subtle bg-background-section-burn'>
|
||||
<div className='flex h-9 items-center px-1 pt-1'>
|
||||
{
|
||||
tabs.map(tab => (
|
||||
<div
|
||||
key={tab.key}
|
||||
className={cn(
|
||||
'system-sm-medium mr-0.5 cursor-pointer rounded-t-lg px-3 py-2 text-text-tertiary hover:bg-state-base-hover',
|
||||
activeTab === tab.key && 'bg-components-panel-bg text-text-accent shadow-sm',
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setActiveTab(tab.key)
|
||||
}}
|
||||
>
|
||||
{tab.name}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div className='relative z-[1] bg-components-panel-bg p-2'>
|
||||
<Input
|
||||
showLeftIcon
|
||||
showClearIcon
|
||||
@ -140,6 +166,10 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
||||
onChange={e => setSearchText(e.target.value)}
|
||||
onClear={() => setSearchText('')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className='p-2' onClick={e => e.stopPropagation()}>
|
||||
{activeTab === TabsEnum.Blocks && (
|
||||
)}
|
||||
{activeTab === TabsEnum.Tools && (
|
||||
<SearchBox
|
||||
@ -151,11 +181,9 @@ const NodeSelector: FC<NodeSelectorProps> = ({
|
||||
placeholder={t('plugin.searchTools')!}
|
||||
/>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div> */}
|
||||
<Tabs
|
||||
activeTab={activeTab}
|
||||
onActiveTabChange={handleActiveTabChange}
|
||||
onSelect={handleSelect}
|
||||
searchText={searchText}
|
||||
tags={tags}
|
||||
|
||||
@ -2,16 +2,13 @@ import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools } from '@/service/use-tools'
|
||||
import type { BlockEnum } from '../types'
|
||||
import { useTabs } from './hooks'
|
||||
import type { ToolDefaultValue } from './types'
|
||||
import { TabsEnum } from './types'
|
||||
import Blocks from './blocks'
|
||||
import AllTools from './all-tools'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
export type TabsProps = {
|
||||
activeTab: TabsEnum
|
||||
onActiveTabChange: (activeTab: TabsEnum) => void
|
||||
searchText: string
|
||||
tags: string[]
|
||||
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
|
||||
@ -20,42 +17,18 @@ export type TabsProps = {
|
||||
}
|
||||
const Tabs: FC<TabsProps> = ({
|
||||
activeTab,
|
||||
onActiveTabChange,
|
||||
tags,
|
||||
searchText,
|
||||
onSelect,
|
||||
availableBlocksTypes,
|
||||
noBlocks,
|
||||
}) => {
|
||||
const tabs = useTabs()
|
||||
const { data: buildInTools } = useAllBuiltInTools()
|
||||
const { data: customTools } = useAllCustomTools()
|
||||
const { data: workflowTools } = useAllWorkflowTools()
|
||||
|
||||
return (
|
||||
<div onClick={e => e.stopPropagation()}>
|
||||
{
|
||||
!noBlocks && (
|
||||
<div className='flex items-center border-b-[0.5px] border-divider-subtle px-3'>
|
||||
{
|
||||
tabs.map(tab => (
|
||||
<div
|
||||
key={tab.key}
|
||||
className={cn(
|
||||
'system-sm-medium relative mr-4 cursor-pointer pb-2 pt-1',
|
||||
activeTab === tab.key
|
||||
? 'text-text-primary after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-full after:bg-util-colors-blue-brand-blue-brand-600'
|
||||
: 'text-text-tertiary',
|
||||
)}
|
||||
onClick={() => onActiveTabChange(tab.key)}
|
||||
>
|
||||
{tab.name}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
activeTab === TabsEnum.Blocks && !noBlocks && (
|
||||
<Blocks
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
export enum TabsEnum {
|
||||
Blocks = 'blocks',
|
||||
Tools = 'tools',
|
||||
Sources = 'sources',
|
||||
}
|
||||
|
||||
export enum ToolTypeEnum {
|
||||
|
||||
Reference in New Issue
Block a user