You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

all-tools.tsx 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import type {
  2. Dispatch,
  3. SetStateAction,
  4. } from 'react'
  5. import {
  6. useEffect,
  7. useMemo,
  8. useRef,
  9. useState,
  10. } from 'react'
  11. import type {
  12. BlockEnum,
  13. OnSelectBlock,
  14. ToolWithProvider,
  15. } from '../types'
  16. import type { ToolDefaultValue, ToolValue } from './types'
  17. import { ToolTypeEnum } from './types'
  18. import Tools from './tools'
  19. import { useToolTabs } from './hooks'
  20. import ViewTypeSelect, { ViewType } from './view-type-select'
  21. import cn from '@/utils/classnames'
  22. import { useGetLanguage } from '@/context/i18n'
  23. import type { ListRef } from '@/app/components/workflow/block-selector/market-place-plugin/list'
  24. import PluginList, { type ListProps } from '@/app/components/workflow/block-selector/market-place-plugin/list'
  25. import { PluginType } from '../../plugins/types'
  26. import { useMarketplacePlugins } from '../../plugins/marketplace/hooks'
  27. import { useGlobalPublicStore } from '@/context/global-public-context'
  28. import RAGToolSuggestions from './rag-tool-suggestions'
  29. type AllToolsProps = {
  30. className?: string
  31. toolContentClassName?: string
  32. searchText: string
  33. tags: ListProps['tags']
  34. buildInTools: ToolWithProvider[]
  35. customTools: ToolWithProvider[]
  36. workflowTools: ToolWithProvider[]
  37. mcpTools: ToolWithProvider[]
  38. onSelect: OnSelectBlock
  39. canNotSelectMultiple?: boolean
  40. onSelectMultiple?: (type: BlockEnum, tools: ToolDefaultValue[]) => void
  41. selectedTools?: ToolValue[]
  42. canChooseMCPTool?: boolean
  43. onTagsChange: Dispatch<SetStateAction<string[]>>
  44. isInRAGPipeline?: boolean
  45. }
  46. const DEFAULT_TAGS: AllToolsProps['tags'] = []
  47. const AllTools = ({
  48. className,
  49. toolContentClassName,
  50. searchText,
  51. tags = DEFAULT_TAGS,
  52. onSelect,
  53. canNotSelectMultiple,
  54. onSelectMultiple,
  55. buildInTools,
  56. workflowTools,
  57. customTools,
  58. mcpTools = [],
  59. selectedTools,
  60. canChooseMCPTool,
  61. onTagsChange,
  62. isInRAGPipeline = false,
  63. }: AllToolsProps) => {
  64. const language = useGetLanguage()
  65. const tabs = useToolTabs()
  66. const [activeTab, setActiveTab] = useState(ToolTypeEnum.All)
  67. const [activeView, setActiveView] = useState<ViewType>(ViewType.flat)
  68. const hasFilter = searchText || tags.length > 0
  69. const isMatchingKeywords = (text: string, keywords: string) => {
  70. return text.toLowerCase().includes(keywords.toLowerCase())
  71. }
  72. const tools = useMemo(() => {
  73. let mergedTools: ToolWithProvider[] = []
  74. if (activeTab === ToolTypeEnum.All)
  75. mergedTools = [...buildInTools, ...customTools, ...workflowTools, ...mcpTools]
  76. if (activeTab === ToolTypeEnum.BuiltIn)
  77. mergedTools = buildInTools
  78. if (activeTab === ToolTypeEnum.Custom)
  79. mergedTools = customTools
  80. if (activeTab === ToolTypeEnum.Workflow)
  81. mergedTools = workflowTools
  82. if (activeTab === ToolTypeEnum.MCP)
  83. mergedTools = mcpTools
  84. if (!hasFilter)
  85. return mergedTools.filter(toolWithProvider => toolWithProvider.tools.length > 0)
  86. return mergedTools.filter((toolWithProvider) => {
  87. return isMatchingKeywords(toolWithProvider.name, searchText) || toolWithProvider.tools.some((tool) => {
  88. return tool.label[language].toLowerCase().includes(searchText.toLowerCase()) || tool.name.toLowerCase().includes(searchText.toLowerCase())
  89. })
  90. })
  91. }, [activeTab, buildInTools, customTools, workflowTools, mcpTools, searchText, language, hasFilter])
  92. const {
  93. queryPluginsWithDebounced: fetchPlugins,
  94. plugins: notInstalledPlugins = [],
  95. } = useMarketplacePlugins()
  96. const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
  97. useEffect(() => {
  98. if (!enable_marketplace) return
  99. if (searchText || tags.length > 0) {
  100. fetchPlugins({
  101. query: searchText,
  102. tags,
  103. category: PluginType.tool,
  104. })
  105. }
  106. }, [searchText, tags, enable_marketplace])
  107. const pluginRef = useRef<ListRef>(null)
  108. const wrapElemRef = useRef<HTMLDivElement>(null)
  109. const isSupportGroupView = [ToolTypeEnum.All, ToolTypeEnum.BuiltIn].includes(activeTab)
  110. const isShowRAGRecommendations = isInRAGPipeline && activeTab === ToolTypeEnum.All && !hasFilter
  111. return (
  112. <div className={cn('min-w-[400px] max-w-[500px]', className)}>
  113. <div className='flex items-center justify-between border-b border-divider-subtle px-3'>
  114. <div className='flex h-8 items-center space-x-1'>
  115. {
  116. tabs.map(tab => (
  117. <div
  118. className={cn(
  119. 'flex h-6 cursor-pointer items-center rounded-md px-2 hover:bg-state-base-hover',
  120. 'text-xs font-medium text-text-secondary',
  121. activeTab === tab.key && 'bg-state-base-hover-alt',
  122. )}
  123. key={tab.key}
  124. onClick={() => setActiveTab(tab.key)}
  125. >
  126. {tab.name}
  127. </div>
  128. ))
  129. }
  130. </div>
  131. {isSupportGroupView && (
  132. <ViewTypeSelect viewType={activeView} onChange={setActiveView} />
  133. )}
  134. </div>
  135. <div
  136. ref={wrapElemRef}
  137. className='max-h-[464px] overflow-y-auto'
  138. onScroll={pluginRef.current?.handleScroll}
  139. >
  140. {isShowRAGRecommendations && (
  141. <RAGToolSuggestions
  142. viewType={isSupportGroupView ? activeView : ViewType.flat}
  143. onSelect={onSelect}
  144. onTagsChange={onTagsChange}
  145. />
  146. )}
  147. <Tools
  148. className={toolContentClassName}
  149. tools={tools}
  150. onSelect={onSelect}
  151. canNotSelectMultiple={canNotSelectMultiple}
  152. onSelectMultiple={onSelectMultiple}
  153. toolType={activeTab}
  154. viewType={isSupportGroupView ? activeView : ViewType.flat}
  155. hasSearchText={!!searchText}
  156. selectedTools={selectedTools}
  157. canChooseMCPTool={canChooseMCPTool}
  158. isShowRAGRecommendations={isShowRAGRecommendations}
  159. />
  160. {/* Plugins from marketplace */}
  161. {enable_marketplace && (
  162. <PluginList
  163. ref={pluginRef}
  164. wrapElemRef={wrapElemRef}
  165. list={notInstalledPlugins}
  166. searchText={searchText}
  167. toolContentClassName={toolContentClassName}
  168. tags={tags}
  169. />
  170. )}
  171. </div>
  172. </div>
  173. )
  174. }
  175. export default AllTools