fix: no data placeholder

pull/22091/head
Joel 11 months ago
parent 1be4a43fc6
commit 29deab509c

@ -0,0 +1,7 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M28.0049 16C28.0049 20.4183 24.4231 24 20.0049 24C15.5866 24 12.0049 20.4183 12.0049 16C12.0049 11.5817 15.5866 8 20.0049 8C24.4231 8 28.0049 11.5817 28.0049 16Z" stroke="#676F83" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.00488 16H6.67155" stroke="#676F83" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.00488 9.33334H8.00488" stroke="#676F83" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.00488 22.6667H8.00488" stroke="#676F83" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M26 22L29.3333 25.3333" stroke="#676F83" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 823 B

@ -0,0 +1,77 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "32",
"height": "32",
"viewBox": "0 0 32 32",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"d": "M28.0049 16C28.0049 20.4183 24.4231 24 20.0049 24C15.5866 24 12.0049 20.4183 12.0049 16C12.0049 11.5817 15.5866 8 20.0049 8C24.4231 8 28.0049 11.5817 28.0049 16Z",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M4.00488 16H6.67155",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M4.00488 9.33334H8.00488",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M4.00488 22.6667H8.00488",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"d": "M26 22L29.3333 25.3333",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
},
"name": "SearchMenu"
}

@ -0,0 +1,20 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './SearchMenu.json'
import IconBase from '@/app/components/base/icons/IconBase'
import type { IconData } from '@/app/components/base/icons/IconBase'
const Icon = (
{
ref,
...props
}: React.SVGProps<SVGSVGElement> & {
ref?: React.RefObject<React.MutableRefObject<HTMLOrSVGElement>>;
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'SearchMenu'
export default Icon

@ -9,4 +9,5 @@ export { default as GlobalVariable } from './GlobalVariable'
export { default as Icon3Dots } from './Icon3Dots'
export { default as LongArrowLeft } from './LongArrowLeft'
export { default as LongArrowRight } from './LongArrowRight'
export { default as SearchMenu } from './SearchMenu'
export { default as Tools } from './Tools'

@ -1,19 +1,46 @@
'use client'
import { useSearchParams } from 'next/navigation'
import { useTranslation } from 'react-i18next'
const Empty = () => {
import { ToolTypeEnum } from '../../workflow/block-selector/types'
import { RiArrowRightUpLine } from '@remixicon/react'
import Link from 'next/link'
import cn from '@/utils/classnames'
type Props = {
type?: ToolTypeEnum
isAgent?: boolean
}
const getLink = (type?: ToolTypeEnum) => {
switch (type) {
case ToolTypeEnum.Custom:
return '/tools?category=api'
case ToolTypeEnum.MCP:
return '/tools?category=mcp'
default:
return '/tools?category=api'
}
}
const Empty = ({
type,
isAgent,
}: Props) => {
const { t } = useTranslation()
const searchParams = useSearchParams()
const hasLink = type && [ToolTypeEnum.Custom, ToolTypeEnum.MCP].includes(type)
const Comp = (hasLink ? Link : 'div') as any
const linkProps = hasLink ? { href: getLink(type), target: '_blank' } : {}
const renderType = isAgent ? 'agent' : type
return (
<div className='flex flex-col items-center'>
<div className="h-[149px] w-[163px] shrink-0 bg-[url('~@/app/components/tools/add-tool-modal/empty.png')] bg-cover bg-no-repeat"></div>
<div className='mb-1 text-[13px] font-medium leading-[18px] text-text-primary'>
{t(`tools.addToolModal.${searchParams.get('category') === 'workflow' ? 'emptyTitle' : 'emptyTitleCustom'}`)}
</div>
<div className='text-[13px] leading-[18px] text-text-tertiary'>
{t(`tools.addToolModal.${searchParams.get('category') === 'workflow' ? 'emptyTip' : 'emptyTipCustom'}`)}
{t(`tools.addToolModal.${renderType}.title`)}
</div>
{!isAgent && (
<Comp className={cn('flex items-center text-[13px] leading-[18px] text-text-tertiary', hasLink && 'cursor-pointer hover:text-text-accent')} {...linkProps}>
{t(`tools.addToolModal.${renderType}.tip`)} {hasLink && <RiArrowRightUpLine className='ml-0.5 h-3 w-3' />}
</Comp>
)}
</div>
)
}

@ -19,8 +19,25 @@ import MCPList from './mcp'
import { useAllToolProviders } from '@/service/use-tools'
import { useInstalledPluginList, useInvalidateInstalledPluginList } from '@/service/use-plugins'
import { useGlobalPublicStore } from '@/context/global-public-context'
import { ToolTypeEnum } from '../workflow/block-selector/types'
const getToolType = (type: string) => {
switch (type) {
case 'builtin':
return ToolTypeEnum.BuiltIn
case 'api':
return ToolTypeEnum.Custom
case 'workflow':
return ToolTypeEnum.Workflow
case 'mcp':
return ToolTypeEnum.MCP
default:
return ToolTypeEnum.BuiltIn
}
}
const ProviderList = () => {
// const searchParams = useSearchParams()
// searchParams.get('category') === 'workflow'
const { t } = useTranslation()
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
const containerRef = useRef<HTMLDivElement>(null)
@ -131,7 +148,7 @@ const ProviderList = () => {
/>
</div>
))}
{!filteredCollectionList.length && activeTab === 'workflow' && <div className='absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'><WorkflowToolEmpty /></div>}
{!filteredCollectionList.length && activeTab === 'workflow' && <div className='absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2'><WorkflowToolEmpty type={getToolType(activeTab)} /></div>}
</div>
)}
{!filteredCollectionList.length && activeTab === 'builtin' && (

@ -93,9 +93,8 @@ const AllTools = ({
} = useMarketplacePlugins()
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
useEffect(() => {
if (enable_marketplace) return
if (!enable_marketplace) return
if (searchText || tags.length > 0) {
fetchPlugins({
query: searchText,
@ -142,11 +141,11 @@ const AllTools = ({
>
<Tools
className={toolContentClassName}
showWorkflowEmpty={activeTab === ToolTypeEnum.Workflow}
tools={tools}
onSelect={onSelect}
canNotSelectMultiple={canNotSelectMultiple}
onSelectMultiple={onSelectMultiple}
toolType={activeTab}
viewType={isSupportGroupView ? activeView : ViewType.flat}
hasSearchText={!!searchText}
selectedTools={selectedTools}

@ -80,7 +80,7 @@ const List = forwardRef<ListRef, ListProps>(({
)
}
const maxWidthClassName = toolContentClassName || 'max-w-[300px]'
const maxWidthClassName = toolContentClassName || 'max-w-[100%]'
return (
<>

@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next'
import type { BlockEnum, ToolWithProvider } from '../types'
import IndexBar, { groupItems } from './index-bar'
import type { ToolDefaultValue, ToolValue } from './types'
import type { ToolTypeEnum } from './types'
import { ViewType } from './view-type-select'
import Empty from '@/app/components/tools/add-tool-modal/empty'
import { useGetLanguage } from '@/context/i18n'
@ -15,33 +16,36 @@ import ToolListFlatView from './tool/tool-list-flat-view/list'
import classNames from '@/utils/classnames'
type ToolsProps = {
showWorkflowEmpty: boolean
onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
canNotSelectMultiple?: boolean
onSelectMultiple?: (type: BlockEnum, tools: ToolDefaultValue[]) => void
tools: ToolWithProvider[]
viewType: ViewType
hasSearchText: boolean
toolType?: ToolTypeEnum
isAgent?: boolean
className?: string
indexBarClassName?: string
selectedTools?: ToolValue[]
canChooseMCPTool?: boolean
hasScrollBar: boolean
hasScrollBar?: boolean
}
const Blocks = ({
showWorkflowEmpty,
onSelect,
canNotSelectMultiple,
onSelectMultiple,
tools,
viewType,
hasSearchText,
toolType,
isAgent,
className,
indexBarClassName,
selectedTools,
canChooseMCPTool,
hasScrollBar,
}: ToolsProps) => {
// const tools: any = []
const { t } = useTranslation()
const language = useGetLanguage()
const isFlatView = viewType === ViewType.flat
@ -95,15 +99,19 @@ const Blocks = ({
const toolRefs = useRef({})
return (
<div className={classNames('p-1 max-w-[100%]', className)}>
<div className={classNames('max-w-[100%] p-1', className)}>
{
!tools.length && !showWorkflowEmpty && (
<div className='flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary'>{t('workflow.tabs.noResult')}</div>
!tools.length && hasSearchText && (
// <div className='flex h-[257px] flex-col items-center justify-center'>
// <SearchMenu className='size-8 text-text-tertiary' />
// Small spacing for marketplace search results
<div className='mt-2 flex h-[22px] items-center px-3 text-xs font-medium text-text-secondary'>{t('workflow.tabs.noResult')}</div>
// </div>
)
}
{!tools.length && showWorkflowEmpty && (
{!tools.length && !hasSearchText && (
<div className='py-10'>
<Empty />
<Empty type={toolType!} isAgent={isAgent}/>
</div>
)}
{!!tools.length && (
@ -133,7 +141,7 @@ const Blocks = ({
)
)}
{isShowLetterIndex && <IndexBar hasScrollBar={hasScrollBar} letters={letters} itemRefs={toolRefs} className={indexBarClassName} />}
{isShowLetterIndex && <IndexBar hasScrollBar={!!hasScrollBar} letters={letters} itemRefs={toolRefs} className={indexBarClassName} />}
</div>
)
}

@ -22,6 +22,7 @@ import type { ListRef } from '@/app/components/workflow/block-selector/market-pl
import PluginList, { type ListProps } from '@/app/components/workflow/block-selector/market-place-plugin/list'
import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks'
import { ToolTipContent } from '@/app/components/base/tooltip/content'
import { useGlobalPublicStore } from '@/context/global-public-context'
const DEFAULT_TAGS: ListProps['tags'] = []
@ -93,6 +94,8 @@ export type AgentStrategySelectorProps = {
}
export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) => {
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
const { value, onChange, canChooseMCPTool } = props
const [open, setOpen] = useState(false)
const [viewType, setViewType] = useState<ViewType>(ViewType.flat)
@ -160,7 +163,7 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
alt='icon'
/></div>}
<p
className={classNames(value ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder', 'text-xs px-1')}
className={classNames(value ? 'text-components-input-text-filled' : 'text-components-input-text-placeholder', 'px-1 text-xs')}
>
{value?.agent_strategy_label || t('workflow.nodes.agent.strategy.selectTip')}
</p>
@ -218,19 +221,19 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) =>
}}
className='h-full max-h-full max-w-none overflow-y-auto'
indexBarClassName='top-0 xl:top-36'
showWorkflowEmpty={false}
hasSearchText={false}
canNotSelectMultiple
canChooseMCPTool={canChooseMCPTool}
isAgent
/>
<PluginList
{enable_marketplace && <PluginList
ref={pluginRef}
wrapElemRef={wrapElemRef}
list={notInstalledPlugins}
searchText={query}
tags={DEFAULT_TAGS}
disableMaxWidth
/>
/>}
</main>
</div>
</PortalToFollowElemContent>

@ -28,10 +28,21 @@ const translation = {
add: 'add',
added: 'added',
manageInTools: 'Manage in Tools',
emptyTitle: 'No workflow tool available',
emptyTip: 'Go to "Workflow -> Publish as Tool"',
emptyTitleCustom: 'No custom tool available',
emptyTipCustom: 'Create a custom tool',
custom: {
title: 'No custom tool available',
tip: 'Create a custom tool',
},
workflow: {
title: 'No workflow tool available',
tip: 'Publish workflows as tools in Studio',
},
mcp: {
title: 'No MCP tool available',
tip: 'Add a MCP server',
},
agent: {
title: 'No agent strategy available',
},
},
createTool: {
title: 'Create Custom Tool',

@ -28,10 +28,21 @@ const translation = {
add: '添加',
added: '已添加',
manageInTools: '去工具列表管理',
emptyTitle: '没有可用的工作流工具',
emptyTip: '去“工作流 -> 发布为工具”添加',
emptyTitleCustom: '没有可用的自定义工具',
emptyTipCustom: '创建自定义工具',
custom: {
title: '没有可用的自定义工具',
tip: '创建自定义工具',
},
workflow: {
title: '没有可用的工作流工具',
tip: '在工作室中发布工作流作为工具',
},
mcp: {
title: '没有可用的 MCP 工具',
tip: '添加 MCP 服务器',
},
agent: {
title: '没有可用的 agent 策略',
},
},
createTool: {
title: '创建自定义工具',

Loading…
Cancel
Save