123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- 'use client'
- import type { FC } from 'react'
- import React from 'react'
- import { useMemo, useState } from 'react'
- import {
- PortalToFollowElem,
- PortalToFollowElemContent,
- PortalToFollowElemTrigger,
- } from '@/app/components/base/portal-to-follow-elem'
- import type {
- OffsetOptions,
- Placement,
- } from '@floating-ui/react'
- import AllTools from '@/app/components/workflow/block-selector/all-tools'
- import type { ToolDefaultValue, ToolValue } from './types'
- import type { BlockEnum } from '@/app/components/workflow/types'
- import SearchBox from '@/app/components/plugins/marketplace/search-box'
- import { useTranslation } from 'react-i18next'
- import { useBoolean } from 'ahooks'
- import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-modal/modal'
- import {
- createCustomCollection,
- } from '@/service/tools'
- import type { CustomCollectionBackend } from '@/app/components/tools/types'
- import Toast from '@/app/components/base/toast'
- import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools, useInvalidateAllCustomTools } from '@/service/use-tools'
- import cn from '@/utils/classnames'
- type Props = {
- panelClassName?: string
- disabled: boolean
- trigger: React.ReactNode
- placement?: Placement
- offset?: OffsetOptions
- isShow: boolean
- onShowChange: (isShow: boolean) => void
- onSelect: (tool: ToolDefaultValue) => void
- supportAddCustomTool?: boolean
- scope?: string
- selectedTools?: ToolValue[]
- }
- const ToolPicker: FC<Props> = ({
- disabled,
- trigger,
- placement = 'right-start',
- offset = 0,
- isShow,
- onShowChange,
- onSelect,
- supportAddCustomTool,
- scope = 'all',
- selectedTools,
- panelClassName,
- }) => {
- const { t } = useTranslation()
- const [searchText, setSearchText] = useState('')
- const [tags, setTags] = useState<string[]>([])
- const { data: buildInTools } = useAllBuiltInTools()
- const { data: customTools } = useAllCustomTools()
- const invalidateCustomTools = useInvalidateAllCustomTools()
- const { data: workflowTools } = useAllWorkflowTools()
- const { builtinToolList, customToolList, workflowToolList } = useMemo(() => {
- if (scope === 'plugins') {
- return {
- builtinToolList: buildInTools,
- customToolList: [],
- workflowToolList: [],
- }
- }
- if (scope === 'custom') {
- return {
- builtinToolList: [],
- customToolList: customTools,
- workflowToolList: [],
- }
- }
- if (scope === 'workflow') {
- return {
- builtinToolList: [],
- customToolList: [],
- workflowToolList: workflowTools,
- }
- }
- return {
- builtinToolList: buildInTools,
- customToolList: customTools,
- workflowToolList: workflowTools,
- }
- }, [scope, buildInTools, customTools, workflowTools])
- const handleAddedCustomTool = invalidateCustomTools
- const handleTriggerClick = () => {
- if (disabled) return
- onShowChange(true)
- }
- const handleSelect = (_type: BlockEnum, tool?: ToolDefaultValue) => {
- onSelect(tool!)
- }
- const [isShowEditCollectionToolModal, {
- setFalse: hideEditCustomCollectionModal,
- setTrue: showEditCustomCollectionModal,
- }] = useBoolean(false)
- const doCreateCustomToolCollection = async (data: CustomCollectionBackend) => {
- await createCustomCollection(data)
- Toast.notify({
- type: 'success',
- message: t('common.api.actionSuccess'),
- })
- hideEditCustomCollectionModal()
- handleAddedCustomTool()
- }
- if (isShowEditCollectionToolModal) {
- return (
- <EditCustomToolModal
- positionLeft
- payload={null}
- onHide={hideEditCustomCollectionModal}
- onAdd={doCreateCustomToolCollection}
- />
- )
- }
- return (
- <PortalToFollowElem
- placement={placement}
- offset={offset}
- open={isShow}
- onOpenChange={onShowChange}
- >
- <PortalToFollowElemTrigger
- onClick={handleTriggerClick}
- >
- {trigger}
- </PortalToFollowElemTrigger>
- <PortalToFollowElemContent className='z-[1000]'>
- <div className={cn('relative w-[356px] min-h-20 rounded-xl backdrop-blur-sm bg-components-panel-bg-blur border-[0.5px] border-components-panel-border shadow-lg', panelClassName)}>
- <div className='p-2 pb-1'>
- <SearchBox
- search={searchText}
- onSearchChange={setSearchText}
- tags={tags}
- onTagsChange={setTags}
- size='small'
- placeholder={t('plugin.searchTools')!}
- />
- </div>
- <AllTools
- className='mt-1'
- toolContentClassName='max-w-[360px]'
- tags={tags}
- searchText={searchText}
- onSelect={handleSelect}
- buildInTools={builtinToolList || []}
- customTools={customToolList || []}
- workflowTools={workflowToolList || []}
- supportAddCustomTool={supportAddCustomTool}
- onAddedCustomTool={handleAddedCustomTool}
- onShowAddCustomCollectionModal={showEditCustomCollectionModal}
- selectedTools={selectedTools}
- />
- </div>
- </PortalToFollowElemContent>
- </PortalToFollowElem>
- )
- }
- export default React.memo(ToolPicker)
|