feat: support search tool after @

This commit is contained in:
Joel
2026-01-30 15:49:30 +08:00
parent bf2e3d5151
commit f5b84384cf
2 changed files with 44 additions and 21 deletions

View File

@@ -54,6 +54,9 @@ type Props = {
preventFocusLoss?: boolean
hideFeaturedTool?: boolean
hideSelectedInfo?: boolean
searchText?: string
onSearchTextChange?: (value: string) => void
hideSearchBox?: boolean
}
const ToolPicker: FC<Props> = ({
@@ -73,9 +76,20 @@ const ToolPicker: FC<Props> = ({
preventFocusLoss = false,
hideFeaturedTool = false,
hideSelectedInfo = false,
searchText: controlledSearchText,
onSearchTextChange,
hideSearchBox = false,
}) => {
const { t } = useTranslation()
const [searchText, setSearchText] = useState('')
const isSearchControlled = controlledSearchText !== undefined
const effectiveSearchText = isSearchControlled ? controlledSearchText : searchText
const handleSearchTextChange = (value: string) => {
if (isSearchControlled)
onSearchTextChange?.(value)
else
setSearchText(value)
}
const [tags, setTags] = useState<string[]>([])
const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures)
@@ -190,26 +204,28 @@ const ToolPicker: FC<Props> = ({
e.preventDefault()
}}
>
<div
className="p-2 pb-1"
>
<SearchBox
search={searchText}
onSearchChange={setSearchText}
tags={tags}
onTagsChange={setTags}
placeholder={t('searchTools', { ns: 'plugin' })!}
supportAddCustomTool={supportAddCustomTool}
onAddedCustomTool={handleAddedCustomTool}
onShowAddCustomCollectionModal={showEditCustomCollectionModal}
inputClassName="grow"
/>
</div>
{!hideSearchBox && (
<div
className="p-2 pb-1"
>
<SearchBox
search={effectiveSearchText}
onSearchChange={handleSearchTextChange}
tags={tags}
onTagsChange={setTags}
placeholder={t('searchTools', { ns: 'plugin' })!}
supportAddCustomTool={supportAddCustomTool}
onAddedCustomTool={handleAddedCustomTool}
onShowAddCustomCollectionModal={showEditCustomCollectionModal}
inputClassName="grow"
/>
</div>
)}
<AllTools
className="mt-1"
toolContentClassName="max-w-[100%]"
tags={tags}
searchText={searchText}
searchText={effectiveSearchText}
onSelect={handleSelect as OnSelectBlock}
onSelectMultiple={handleSelectMultiple}
buildInTools={builtinToolList || []}

View File

@@ -8,7 +8,7 @@ import {
$insertNodes,
} from 'lexical'
import * as React from 'react'
import { useCallback, useMemo } from 'react'
import { useCallback, useMemo, useState } from 'react'
import ReactDOM from 'react-dom'
import { v4 as uuid } from 'uuid'
import { useBasicTypeaheadTriggerMatch } from '@/app/components/base/prompt-editor/hooks'
@@ -35,11 +35,12 @@ const ToolPickerBlock = ({ scope = 'all' }: ToolPickerBlockProps) => {
const [editor] = useLexicalComposerContext()
const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('@', {
minLength: 0,
maxLength: 0,
maxLength: 75,
})
const storeApi = useWorkflowStore()
const toolBlockContext = useToolBlockContext()
const isUsingExternalMetadata = Boolean(toolBlockContext?.onMetadataChange)
const [queryString, setQueryString] = useState('')
const options = useMemo(() => [new ToolPickerMenuOption()], [])
@@ -132,7 +133,10 @@ const ToolPickerBlock = ({ scope = 'all' }: ToolPickerBlockProps) => {
if (!anchorElementRef.current)
return null
const closeMenu = () => selectOptionAndCleanUp(options[0])
const closeMenu = () => {
setQueryString('')
selectOptionAndCleanUp(options[0])
}
return ReactDOM.createPortal(
<ToolPicker
@@ -156,19 +160,22 @@ const ToolPickerBlock = ({ scope = 'all' }: ToolPickerBlockProps) => {
insertTools(tools)
closeMenu()
}}
searchText={queryString}
onSearchTextChange={setQueryString}
hideSearchBox
scope={scope}
hideFeaturedTool
preventFocusLoss
/>,
anchorElementRef.current,
)
}, [insertTools, options, scope])
}, [insertTools, options, queryString, scope])
return (
<LexicalTypeaheadMenuPlugin
options={options}
onSelectOption={() => { }}
onQueryChange={() => { }}
onQueryChange={matchingString => setQueryString(matchingString || '')}
menuRenderFn={renderMenu}
triggerFn={checkForTriggerMatch}
anchorClassName="z-[999999] translate-y-[calc(-100%-3px)]"