add datasource empty node

This commit is contained in:
zxhlyh
2025-07-22 16:48:24 +08:00
parent 3b8d96f45c
commit d76e37b018
22 changed files with 307 additions and 21 deletions

View File

@ -2,6 +2,9 @@ import {
useCallback,
useRef,
} from 'react'
import Link from 'next/link'
import { useTranslation } from 'react-i18next'
import { RiArrowRightUpLine } from '@remixicon/react'
import { BlockEnum } from '../types'
import type {
OnSelectBlock,
@ -12,6 +15,8 @@ import Tools from './tools'
import { ViewType } from './view-type-select'
import cn from '@/utils/classnames'
import type { ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import { getMarketplaceUrl } from '@/utils/var'
import { useGlobalPublicStore } from '@/context/global-public-context'
type AllToolsProps = {
className?: string
@ -28,6 +33,7 @@ const DataSources = ({
onSelect,
dataSources,
}: AllToolsProps) => {
const { t } = useTranslation()
const pluginRef = useRef<ListRef>(null)
const wrapElemRef = useRef<HTMLDivElement>(null)
const handleSelect = useCallback((_: any, toolDefaultValue: ToolDefaultValue) => {
@ -40,6 +46,7 @@ const DataSources = ({
title: toolDefaultValue?.title,
})
}, [onSelect])
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
return (
<div className={cn(className)}>
@ -56,6 +63,18 @@ const DataSources = ({
hasSearchText={!!searchText}
canNotSelectMultiple
/>
{
enable_marketplace && (
<Link
className='system-sm-medium sticky bottom-0 z-10 flex h-8 cursor-pointer items-center rounded-b-lg border-[0.5px] border-t border-components-panel-border bg-components-panel-bg-blur px-4 py-1 text-text-accent-light-mode-only shadow-lg'
href={getMarketplaceUrl('')}
target='_blank'
>
<span>{t('plugin.findMoreInMarketplace')}</span>
<RiArrowRightUpLine className='ml-0.5 h-3 w-3' />
</Link>
)
}
</div>
</div>
)

View File

@ -8,7 +8,7 @@ import {
ToolTypeEnum,
} from './types'
export const useTabs = (noBlocks?: boolean, noSources?: boolean) => {
export const useTabs = (noBlocks?: boolean, noSources?: boolean, noTools?: boolean) => {
const { t } = useTranslation()
const tabs = useMemo(() => {
return [
@ -32,18 +32,27 @@ export const useTabs = (noBlocks?: boolean, noSources?: boolean) => {
},
]
),
{
key: TabsEnum.Tools,
name: t('workflow.tabs.tools'),
},
...(
noTools
? []
: [
{
key: TabsEnum.Tools,
name: t('workflow.tabs.tools'),
},
]
),
]
}, [t, noBlocks, noSources])
}, [t, noBlocks, noSources, noTools])
const initialTab = useMemo(() => {
if (noBlocks)
return noSources ? TabsEnum.Tools : TabsEnum.Sources
return noTools ? TabsEnum.Sources : TabsEnum.Tools
if (noTools)
return noBlocks ? TabsEnum.Sources : TabsEnum.Blocks
return TabsEnum.Blocks
}, [noBlocks, noSources])
}, [noBlocks, noSources, noTools])
const [activeTab, setActiveTab] = useState(initialTab)
return {

View File

@ -30,6 +30,9 @@ const NodeSelectorWrapper = (props: NodeSelectorProps) => {
if (block.metaData.type === BlockEnum.LoopStart)
return false
if (block.metaData.type === BlockEnum.DataSourceEmpty)
return false
return true
})
}, [availableNodesMetaData?.nodes])

View File

@ -50,6 +50,7 @@ export type NodeSelectorProps = {
blocks?: NodeDefault[]
dataSources?: ToolWithProvider[]
noBlocks?: boolean
noTools?: boolean
}
const NodeSelector: FC<NodeSelectorProps> = ({
open: openFromProps,
@ -68,6 +69,7 @@ const NodeSelector: FC<NodeSelectorProps> = ({
blocks = [],
dataSources = [],
noBlocks = false,
noTools = false,
}) => {
const { t } = useTranslation()
const [searchText, setSearchText] = useState('')
@ -98,7 +100,7 @@ const NodeSelector: FC<NodeSelectorProps> = ({
activeTab,
setActiveTab,
tabs,
} = useTabs(!blocks.length, !dataSources.length)
} = useTabs(noBlocks, !dataSources.length, noTools)
const handleActiveTabChange = useCallback((newActiveTab: TabsEnum) => {
setActiveTab(newActiveTab)
@ -165,6 +167,17 @@ const NodeSelector: FC<NodeSelectorProps> = ({
onClear={() => setSearchText('')}
/>
)}
{activeTab === TabsEnum.Sources && (
<Input
showLeftIcon
showClearIcon
autoFocus
value={searchText}
placeholder={searchPlaceholder}
onChange={e => setSearchText(e.target.value)}
onClear={() => setSearchText('')}
/>
)}
{activeTab === TabsEnum.Tools && (
<SearchBox
search={searchText}
@ -184,6 +197,7 @@ const NodeSelector: FC<NodeSelectorProps> = ({
availableBlocksTypes={availableBlocksTypes}
noBlocks={noBlocks}
dataSources={dataSources}
noTools={noTools}
/>
</div>
</PortalToFollowElemContent>

View File

@ -28,6 +28,7 @@ export type TabsProps = {
}>
filterElem: React.ReactNode
noBlocks?: boolean
noTools?: boolean
}
const Tabs: FC<TabsProps> = ({
activeTab,
@ -41,6 +42,7 @@ const Tabs: FC<TabsProps> = ({
tabs = [],
filterElem,
noBlocks,
noTools,
}) => {
const { data: buildInTools } = useAllBuiltInTools()
const { data: customTools } = useAllCustomTools()
@ -96,7 +98,7 @@ const Tabs: FC<TabsProps> = ({
)
}
{
activeTab === TabsEnum.Tools && (
activeTab === TabsEnum.Tools && !noTools && (
<AllTools
searchText={searchText}
onSelect={onSelect}