tool.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useEffect, useMemo } from 'react'
  4. import cn from '@/utils/classnames'
  5. import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react'
  6. import { useGetLanguage } from '@/context/i18n'
  7. import type { Tool as ToolType } from '../../../tools/types'
  8. import { CollectionType } from '../../../tools/types'
  9. import type { ToolWithProvider } from '../../types'
  10. import { BlockEnum } from '../../types'
  11. import type { ToolDefaultValue, ToolValue } from '../types'
  12. import { ViewType } from '../view-type-select'
  13. import ActonItem from './action-item'
  14. import BlockIcon from '../../block-icon'
  15. import { useTranslation } from 'react-i18next'
  16. type Props = {
  17. className?: string
  18. payload: ToolWithProvider
  19. viewType: ViewType
  20. isShowLetterIndex: boolean
  21. hasSearchText: boolean
  22. onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void
  23. selectedTools?: ToolValue[]
  24. }
  25. const Tool: FC<Props> = ({
  26. className,
  27. payload,
  28. viewType,
  29. isShowLetterIndex,
  30. hasSearchText,
  31. onSelect,
  32. selectedTools,
  33. }) => {
  34. const { t } = useTranslation()
  35. const language = useGetLanguage()
  36. const isFlatView = viewType === ViewType.flat
  37. const actions = payload.tools
  38. const hasAction = true // Now always support actions
  39. const [isFold, setFold] = React.useState<boolean>(true)
  40. const getIsDisabled = (tool: ToolType) => {
  41. if (!selectedTools || !selectedTools.length) return false
  42. return selectedTools.some(selectedTool => selectedTool.provider_name === payload.name && selectedTool.tool_name === tool.name)
  43. }
  44. useEffect(() => {
  45. if (hasSearchText && isFold) {
  46. setFold(false)
  47. return
  48. }
  49. if (!hasSearchText && !isFold)
  50. setFold(true)
  51. // eslint-disable-next-line react-hooks/exhaustive-deps
  52. }, [hasSearchText])
  53. const FoldIcon = isFold ? RiArrowRightSLine : RiArrowDownSLine
  54. const groupName = useMemo(() => {
  55. if (payload.type === CollectionType.builtIn)
  56. return payload.author
  57. if (payload.type === CollectionType.custom)
  58. return t('workflow.tabs.customTool')
  59. if (payload.type === CollectionType.workflow)
  60. return t('workflow.tabs.workflowTool')
  61. return ''
  62. }, [payload.author, payload.type, t])
  63. return (
  64. <div
  65. key={payload.id}
  66. className={cn('mb-1 last-of-type:mb-0', isShowLetterIndex && 'mr-6')}
  67. >
  68. <div className={cn(className)}>
  69. <div
  70. className='flex items-center justify-between pl-3 pr-1 w-full rounded-lg hover:bg-state-base-hover cursor-pointer select-none'
  71. onClick={() => {
  72. if (hasAction)
  73. setFold(!isFold)
  74. // Now always support actions
  75. // if (payload.parameters) {
  76. // payload.parameters.forEach((item) => {
  77. // params[item.name] = ''
  78. // })
  79. // }
  80. // onSelect(BlockEnum.Tool, {
  81. // provider_id: payload.id,
  82. // provider_type: payload.type,
  83. // provider_name: payload.name,
  84. // tool_name: payload.name,
  85. // tool_label: payload.label[language],
  86. // title: payload.label[language],
  87. // params: {},
  88. // })
  89. }}
  90. >
  91. <div className='flex grow items-center h-8'>
  92. <BlockIcon
  93. className='shrink-0'
  94. type={BlockEnum.Tool}
  95. toolIcon={payload.icon}
  96. />
  97. <div className='ml-2 text-sm text-text-primary flex-1 w-0 grow truncate'>{payload.label[language]}</div>
  98. </div>
  99. <div className='flex items-center'>
  100. {isFlatView && (
  101. <div className='text-text-tertiary system-xs-regular'>{groupName}</div>
  102. )}
  103. {hasAction && (
  104. <FoldIcon className={cn('w-4 h-4 text-text-quaternary shrink-0', isFold && 'text-text-tertiary')} />
  105. )}
  106. </div>
  107. </div>
  108. {hasAction && !isFold && (
  109. actions.map(action => (
  110. <ActonItem
  111. key={action.name}
  112. provider={payload}
  113. payload={action}
  114. onSelect={onSelect}
  115. disabled={getIsDisabled(action)}
  116. />
  117. ))
  118. )}
  119. </div>
  120. </div>
  121. )
  122. }
  123. export default React.memo(Tool)