tools.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import {
  2. memo,
  3. useCallback,
  4. useMemo,
  5. } from 'react'
  6. import { useTranslation } from 'react-i18next'
  7. import BlockIcon from '../block-icon'
  8. import { BlockEnum } from '../types'
  9. import type { ToolWithProvider } from '../types'
  10. import { useStore } from '../store'
  11. import type { ToolDefaultValue } from './types'
  12. import Tooltip from '@/app/components/base/tooltip'
  13. import { useGetLanguage } from '@/context/i18n'
  14. type ToolsProps = {
  15. isCustom?: boolean
  16. onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
  17. searchText: string
  18. }
  19. const Blocks = ({
  20. isCustom,
  21. searchText,
  22. onSelect,
  23. }: ToolsProps) => {
  24. const { t } = useTranslation()
  25. const language = useGetLanguage()
  26. const buildInTools = useStore(s => s.buildInTools)
  27. const customTools = useStore(s => s.customTools)
  28. const tools = useMemo(() => {
  29. const currentTools = isCustom ? customTools : buildInTools
  30. return currentTools.filter((toolWithProvider) => {
  31. return toolWithProvider.tools.some((tool) => {
  32. return tool.label[language].toLowerCase().includes(searchText.toLowerCase())
  33. })
  34. })
  35. }, [isCustom, customTools, buildInTools, searchText, language])
  36. const renderGroup = useCallback((toolWithProvider: ToolWithProvider) => {
  37. const list = toolWithProvider.tools
  38. return (
  39. <div
  40. key={toolWithProvider.id}
  41. className='mb-1 last-of-type:mb-0'
  42. >
  43. <div className='flex items-start px-3 h-[22px] text-xs font-medium text-gray-500'>
  44. {toolWithProvider.label[language]}
  45. </div>
  46. {
  47. list.map(tool => (
  48. <Tooltip
  49. key={tool.name}
  50. selector={`workflow-block-tool-${tool.name}`}
  51. position='right'
  52. className='!p-0 !px-3 !py-2.5 !w-[200px] !leading-[18px] !text-xs !text-gray-700 !border-[0.5px] !border-black/5 !bg-transparent !rounded-xl !shadow-lg'
  53. htmlContent={(
  54. <div>
  55. <BlockIcon
  56. size='md'
  57. className='mb-2'
  58. type={BlockEnum.Tool}
  59. toolIcon={toolWithProvider.icon}
  60. />
  61. <div className='mb-1 text-sm leading-5 text-gray-900'>{tool.label[language]}</div>
  62. <div className='text-xs text-gray-700 leading-[18px]'>{tool.description[language]}</div>
  63. </div>
  64. )}
  65. noArrow
  66. >
  67. <div
  68. className='flex items-center px-3 w-full h-8 rounded-lg hover:bg-gray-50 cursor-pointer'
  69. onClick={() => onSelect(BlockEnum.Tool, {
  70. provider_id: toolWithProvider.id,
  71. provider_type: toolWithProvider.type,
  72. provider_name: toolWithProvider.name,
  73. tool_name: tool.name,
  74. tool_label: tool.label[language],
  75. title: tool.label[language],
  76. })}
  77. >
  78. <BlockIcon
  79. className='mr-2 shrink-0'
  80. type={BlockEnum.Tool}
  81. toolIcon={toolWithProvider.icon}
  82. />
  83. <div className='text-sm text-gray-900 truncate'>{tool.label[language]}</div>
  84. </div>
  85. </Tooltip>
  86. ))
  87. }
  88. </div>
  89. )
  90. }, [onSelect, language])
  91. return (
  92. <div className='p-1 max-w-[320px] max-h-[464px] overflow-y-auto'>
  93. {
  94. !tools.length && (
  95. <div className='flex items-center px-3 h-[22px] text-xs font-medium text-gray-500'>{t('workflow.tabs.noResult')}</div>
  96. )
  97. }
  98. {
  99. !!tools.length && tools.map(renderGroup)
  100. }
  101. </div>
  102. )
  103. }
  104. export default memo(Blocks)