tool-item.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. 'use client'
  2. import React, { useState } from 'react'
  3. import { useTranslation } from 'react-i18next'
  4. import {
  5. RiDeleteBinLine,
  6. RiEqualizer2Line,
  7. RiErrorWarningFill,
  8. } from '@remixicon/react'
  9. import { Group } from '@/app/components/base/icons/src/vender/other'
  10. import AppIcon from '@/app/components/base/app-icon'
  11. import Switch from '@/app/components/base/switch'
  12. import Button from '@/app/components/base/button'
  13. import Indicator from '@/app/components/header/indicator'
  14. import ActionButton from '@/app/components/base/action-button'
  15. import Tooltip from '@/app/components/base/tooltip'
  16. import { ToolTipContent } from '@/app/components/base/tooltip/content'
  17. import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button'
  18. import { SwitchPluginVersion } from '@/app/components/workflow/nodes/_base/components/switch-plugin-version'
  19. import cn from '@/utils/classnames'
  20. type Props = {
  21. icon?: any
  22. providerName?: string
  23. toolLabel?: string
  24. showSwitch?: boolean
  25. switchValue?: boolean
  26. onSwitchChange?: (value: boolean) => void
  27. onDelete?: () => void
  28. noAuth?: boolean
  29. onAuth?: () => void
  30. isError?: boolean
  31. errorTip?: any
  32. uninstalled?: boolean
  33. installInfo?: string
  34. onInstall?: () => void
  35. versionMismatch?: boolean
  36. open: boolean
  37. }
  38. const ToolItem = ({
  39. open,
  40. icon,
  41. providerName,
  42. toolLabel,
  43. showSwitch,
  44. switchValue,
  45. onSwitchChange,
  46. onDelete,
  47. noAuth,
  48. onAuth,
  49. uninstalled,
  50. installInfo,
  51. onInstall,
  52. isError,
  53. errorTip,
  54. versionMismatch,
  55. }: Props) => {
  56. const { t } = useTranslation()
  57. const providerNameText = providerName?.split('/').pop()
  58. const isTransparent = uninstalled || versionMismatch || isError
  59. const [isDeleting, setIsDeleting] = useState(false)
  60. return (
  61. <div className={cn(
  62. 'group p-1.5 pr-2 flex items-center gap-1 bg-components-panel-on-panel-item-bg border-[0.5px] border-components-panel-border-subtle rounded-lg shadow-xs cursor-default hover:bg-components-panel-on-panel-item-bg-hover hover:shadow-sm',
  63. open && 'bg-components-panel-on-panel-item-bg-hover shadow-sm',
  64. isDeleting && 'hover:bg-state-destructive-hover border-state-destructive-border shadow-xs',
  65. )}>
  66. {icon && (
  67. <div className={cn('shrink-0', isTransparent && 'opacity-50')}>
  68. {typeof icon === 'string' && <div className='w-7 h-7 bg-cover bg-center border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge rounded-lg' style={{ backgroundImage: `url(${icon})` }} />}
  69. {typeof icon !== 'string' && <AppIcon className='w-7 h-7 border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge rounded-lg' size='xs' icon={icon?.content} background={icon?.background} />}
  70. </div>
  71. )}
  72. {!icon && (
  73. <div className={cn(
  74. 'flex items-center justify-center w-7 h-7 rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-subtle',
  75. )}>
  76. <div className='flex w-5 h-5 items-center justify-center opacity-35'>
  77. <Group className='text-text-tertiary' />
  78. </div>
  79. </div>
  80. )}
  81. <div className={cn('pl-0.5 grow truncate', isTransparent && 'opacity-50')}>
  82. <div className='text-text-tertiary system-2xs-medium-uppercase'>{providerNameText}</div>
  83. <div className='text-text-secondary system-xs-medium'>{toolLabel}</div>
  84. </div>
  85. <div className='hidden group-hover:flex items-center gap-1'>
  86. {!noAuth && !isError && !uninstalled && !versionMismatch && (
  87. <ActionButton>
  88. <RiEqualizer2Line className='w-4 h-4' />
  89. </ActionButton>
  90. )}
  91. <div
  92. className='p-1 rounded-md text-text-tertiary cursor-pointer hover:text-text-destructive'
  93. onClick={(e) => {
  94. e.stopPropagation()
  95. onDelete?.()
  96. }}
  97. onMouseOver={() => setIsDeleting(true)}
  98. onMouseLeave={() => setIsDeleting(false)}
  99. >
  100. <RiDeleteBinLine className='w-4 h-4' />
  101. </div>
  102. </div>
  103. {!isError && !uninstalled && !noAuth && !versionMismatch && showSwitch && (
  104. <div className='mr-1' onClick={e => e.stopPropagation()}>
  105. <Switch
  106. size='md'
  107. defaultValue={switchValue}
  108. onChange={onSwitchChange}
  109. />
  110. </div>
  111. )}
  112. {!isError && !uninstalled && !versionMismatch && noAuth && (
  113. <Button variant='secondary' size='small' onClick={onAuth}>
  114. {t('tools.notAuthorized')}
  115. <Indicator className='ml-2' color='orange' />
  116. </Button>
  117. )}
  118. {!isError && !uninstalled && versionMismatch && installInfo && (
  119. <div onClick={e => e.stopPropagation()}>
  120. <SwitchPluginVersion
  121. className='-mt-1'
  122. uniqueIdentifier={installInfo}
  123. tooltip={
  124. <ToolTipContent
  125. title={t('plugin.detailPanel.toolSelector.unsupportedTitle')}
  126. >
  127. {`${t('plugin.detailPanel.toolSelector.unsupportedContent')} ${t('plugin.detailPanel.toolSelector.unsupportedContent2')}`}
  128. </ToolTipContent>
  129. }
  130. onChange={() => {
  131. onInstall?.()
  132. }}
  133. />
  134. </div>
  135. )}
  136. {!isError && uninstalled && installInfo && (
  137. <InstallPluginButton
  138. onClick={e => e.stopPropagation()}
  139. size={'small'}
  140. uniqueIdentifier={installInfo}
  141. onSuccess={() => {
  142. onInstall?.()
  143. }}
  144. />
  145. )}
  146. {isError && (
  147. <Tooltip
  148. popupContent={errorTip}
  149. needsDelay
  150. >
  151. <div>
  152. <RiErrorWarningFill className='w-4 h-4 text-text-destructive' />
  153. </div>
  154. </Tooltip>
  155. )}
  156. </div>
  157. )
  158. }
  159. export default ToolItem