mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-05-20 09:38:38 +08:00
feat: add search input field (#18409)
This commit is contained in:
parent
67eefd0ba1
commit
94e22ba0fd
@ -31,6 +31,7 @@ import { useOptions } from './hooks'
|
|||||||
import type { PickerBlockMenuOption } from './menu'
|
import type { PickerBlockMenuOption } from './menu'
|
||||||
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
|
||||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||||
|
import { KEY_ESCAPE_COMMAND } from 'lexical'
|
||||||
|
|
||||||
type ComponentPickerProps = {
|
type ComponentPickerProps = {
|
||||||
triggerString: string
|
triggerString: string
|
||||||
@ -118,6 +119,13 @@ const ComponentPicker = ({
|
|||||||
editor.dispatchCommand(INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND, variables)
|
editor.dispatchCommand(INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND, variables)
|
||||||
}, [editor, checkForTriggerMatch, triggerString])
|
}, [editor, checkForTriggerMatch, triggerString])
|
||||||
|
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
ReactDOM.flushSync(() => {
|
||||||
|
const escapeEvent = new KeyboardEvent('keydown', { key: 'Escape' })
|
||||||
|
editor.dispatchCommand(KEY_ESCAPE_COMMAND, escapeEvent)
|
||||||
|
})
|
||||||
|
}, [editor])
|
||||||
|
|
||||||
const renderMenu = useCallback<MenuRenderFn<PickerBlockMenuOption>>((
|
const renderMenu = useCallback<MenuRenderFn<PickerBlockMenuOption>>((
|
||||||
anchorElementRef,
|
anchorElementRef,
|
||||||
{ options, selectedIndex, selectOptionAndCleanUp, setHighlightedIndex },
|
{ options, selectedIndex, selectOptionAndCleanUp, setHighlightedIndex },
|
||||||
@ -141,7 +149,31 @@ const ComponentPicker = ({
|
|||||||
visibility: isPositioned ? 'visible' : 'hidden',
|
visibility: isPositioned ? 'visible' : 'hidden',
|
||||||
}}
|
}}
|
||||||
ref={refs.setFloating}
|
ref={refs.setFloating}
|
||||||
|
data-testid="component-picker-container"
|
||||||
>
|
>
|
||||||
|
{
|
||||||
|
workflowVariableBlock?.show && (
|
||||||
|
<div className='p-1'>
|
||||||
|
<VarReferenceVars
|
||||||
|
searchBoxClassName='mt-1'
|
||||||
|
vars={workflowVariableOptions}
|
||||||
|
onChange={(variables: string[]) => {
|
||||||
|
handleSelectWorkflowVariable(variables)
|
||||||
|
}}
|
||||||
|
maxHeightClass='max-h-[34vh]'
|
||||||
|
isSupportFileVar={isSupportFileVar}
|
||||||
|
onClose={handleClose}
|
||||||
|
onBlur={handleClose}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
workflowVariableBlock?.show && !!options.length && (
|
||||||
|
<div className='my-1 h-px w-full -translate-x-1 bg-divider-subtle'></div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<div data-testid="options-list">
|
||||||
{
|
{
|
||||||
options.map((option, index) => (
|
options.map((option, index) => (
|
||||||
<Fragment key={option.key}>
|
<Fragment key={option.key}>
|
||||||
@ -164,28 +196,7 @@ const ComponentPicker = ({
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
{
|
|
||||||
workflowVariableBlock?.show && (
|
|
||||||
<>
|
|
||||||
{
|
|
||||||
(!!options.length) && (
|
|
||||||
<div className='my-1 h-px w-full -translate-x-1 bg-divider-subtle'></div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
<div className='p-1'>
|
|
||||||
<VarReferenceVars
|
|
||||||
hideSearch
|
|
||||||
vars={workflowVariableOptions}
|
|
||||||
onChange={(variables: string[]) => {
|
|
||||||
handleSelectWorkflowVariable(variables)
|
|
||||||
}}
|
|
||||||
maxHeightClass='max-h-[34vh]'
|
|
||||||
isSupportFileVar={isSupportFileVar}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
anchorElementRef.current,
|
anchorElementRef.current,
|
||||||
@ -193,7 +204,7 @@ const ComponentPicker = ({
|
|||||||
}
|
}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}, [allFlattenOptions.length, workflowVariableBlock?.show, refs, isPositioned, floatingStyles, queryString, workflowVariableOptions, handleSelectWorkflowVariable])
|
}, [allFlattenOptions.length, workflowVariableBlock?.show, refs, isPositioned, floatingStyles, queryString, workflowVariableOptions, handleSelectWorkflowVariable, handleClose, isSupportFileVar])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LexicalTypeaheadMenuPlugin
|
<LexicalTypeaheadMenuPlugin
|
||||||
|
@ -37,14 +37,16 @@ const OnBlurBlock: FC<OnBlurBlockProps> = ({
|
|||||||
),
|
),
|
||||||
editor.registerCommand(
|
editor.registerCommand(
|
||||||
BLUR_COMMAND,
|
BLUR_COMMAND,
|
||||||
() => {
|
(event) => {
|
||||||
|
// Check if the clicked target element is var-search-input
|
||||||
|
const target = event?.relatedTarget as HTMLElement
|
||||||
|
if (!target?.classList?.contains('var-search-input')) {
|
||||||
ref.current = setTimeout(() => {
|
ref.current = setTimeout(() => {
|
||||||
editor.dispatchCommand(KEY_ESCAPE_COMMAND, new KeyboardEvent('keydown', { key: 'Escape' }))
|
editor.dispatchCommand(KEY_ESCAPE_COMMAND, new KeyboardEvent('keydown', { key: 'Escape' }))
|
||||||
}, 200)
|
}, 200)
|
||||||
|
|
||||||
if (onBlur)
|
if (onBlur)
|
||||||
onBlur()
|
onBlur()
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
COMMAND_PRIORITY_EDITOR,
|
COMMAND_PRIORITY_EDITOR,
|
||||||
|
@ -258,6 +258,8 @@ type Props = {
|
|||||||
onChange: (value: ValueSelector, item: Var) => void
|
onChange: (value: ValueSelector, item: Var) => void
|
||||||
itemWidth?: number
|
itemWidth?: number
|
||||||
maxHeightClass?: string
|
maxHeightClass?: string
|
||||||
|
onClose?: () => void
|
||||||
|
onBlur?: () => void
|
||||||
}
|
}
|
||||||
const VarReferenceVars: FC<Props> = ({
|
const VarReferenceVars: FC<Props> = ({
|
||||||
hideSearch,
|
hideSearch,
|
||||||
@ -267,10 +269,19 @@ const VarReferenceVars: FC<Props> = ({
|
|||||||
onChange,
|
onChange,
|
||||||
itemWidth,
|
itemWidth,
|
||||||
maxHeightClass,
|
maxHeightClass,
|
||||||
|
onClose,
|
||||||
|
onBlur,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [searchText, setSearchText] = useState('')
|
const [searchText, setSearchText] = useState('')
|
||||||
|
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault()
|
||||||
|
onClose?.()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const filteredVars = vars.filter((v) => {
|
const filteredVars = vars.filter((v) => {
|
||||||
const children = v.vars.filter(v => checkKeys([v.variable], false).isValid || v.variable.startsWith('sys.') || v.variable.startsWith('env.') || v.variable.startsWith('conversation.'))
|
const children = v.vars.filter(v => checkKeys([v.variable], false).isValid || v.variable.startsWith('sys.') || v.variable.startsWith('env.') || v.variable.startsWith('conversation.'))
|
||||||
return children.length > 0
|
return children.length > 0
|
||||||
@ -301,14 +312,17 @@ const VarReferenceVars: FC<Props> = ({
|
|||||||
{
|
{
|
||||||
!hideSearch && (
|
!hideSearch && (
|
||||||
<>
|
<>
|
||||||
<div className={cn('mx-2 mb-1 mt-2', searchBoxClassName)} onClick={e => e.stopPropagation()}>
|
<div className={cn('var-search-input-wrapper mx-2 mb-1 mt-2', searchBoxClassName)} onClick={e => e.stopPropagation()}>
|
||||||
<Input
|
<Input
|
||||||
|
className='var-search-input'
|
||||||
showLeftIcon
|
showLeftIcon
|
||||||
showClearIcon
|
showClearIcon
|
||||||
value={searchText}
|
value={searchText}
|
||||||
placeholder={t('workflow.common.searchVar') || ''}
|
placeholder={t('workflow.common.searchVar') || ''}
|
||||||
onChange={e => setSearchText(e.target.value)}
|
onChange={e => setSearchText(e.target.value)}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
onClear={() => setSearchText('')}
|
onClear={() => setSearchText('')}
|
||||||
|
onBlur={onBlur}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user