mirror of
https://github.com/langgenius/dify.git
synced 2026-03-28 14:01:53 -04:00
Merge branch 'deploy/agent-dev' of github.com:langgenius/dify into deploy/agent-dev
This commit is contained in:
@@ -1,21 +1,17 @@
|
||||
import type { LexicalNode } from 'lexical'
|
||||
import type { Dispatch, SetStateAction } from 'react'
|
||||
import {
|
||||
flip,
|
||||
offset,
|
||||
shift,
|
||||
useFloating,
|
||||
} from '@floating-ui/react'
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import { LexicalTypeaheadMenuPlugin, MenuOption } from '@lexical/react/LexicalTypeaheadMenuPlugin'
|
||||
import {
|
||||
$insertNodes,
|
||||
} from 'lexical'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useLayoutEffect, useMemo } from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useBasicTypeaheadTriggerMatch } from '@/app/components/base/prompt-editor/hooks'
|
||||
import { $splitNodeContainingQuery } from '@/app/components/base/prompt-editor/utils'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
import { FilePickerPanel } from './file-picker-panel'
|
||||
import { $createFileReferenceNode } from './file-reference-block/node'
|
||||
|
||||
@@ -25,29 +21,8 @@ class FilePickerMenuOption extends MenuOption {
|
||||
}
|
||||
}
|
||||
|
||||
type ReferenceSyncProps = {
|
||||
anchor: HTMLElement | null
|
||||
setReference: Dispatch<SetStateAction<HTMLElement | null>> | ((node: HTMLElement | null) => void)
|
||||
}
|
||||
|
||||
const ReferenceSync = ({ anchor, setReference }: ReferenceSyncProps) => {
|
||||
useLayoutEffect(() => {
|
||||
setReference(anchor)
|
||||
}, [anchor, setReference])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const FilePickerBlock = () => {
|
||||
const [editor] = useLexicalComposerContext()
|
||||
const { refs, floatingStyles, isPositioned } = useFloating({
|
||||
placement: 'bottom-start',
|
||||
middleware: [
|
||||
offset(0),
|
||||
shift({ padding: 8 }),
|
||||
flip(),
|
||||
],
|
||||
})
|
||||
const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('/', {
|
||||
minLength: 0,
|
||||
maxLength: 0,
|
||||
@@ -76,16 +51,20 @@ const FilePickerBlock = () => {
|
||||
|
||||
const closeMenu = () => selectOptionAndCleanUp(options[0])
|
||||
|
||||
return ReactDOM.createPortal(
|
||||
<>
|
||||
<ReferenceSync anchor={anchorElementRef.current} setReference={refs.setReference} />
|
||||
<div
|
||||
ref={refs.setFloating}
|
||||
style={{
|
||||
...floatingStyles,
|
||||
visibility: isPositioned ? 'visible' : 'hidden',
|
||||
}}
|
||||
className="z-[1002] outline-none"
|
||||
return (
|
||||
<Popover
|
||||
open
|
||||
onOpenChange={(open) => {
|
||||
if (!open)
|
||||
closeMenu()
|
||||
}}
|
||||
>
|
||||
<PopoverContent
|
||||
placement="bottom-start"
|
||||
sideOffset={4}
|
||||
popupClassName="rounded-none border-none bg-transparent shadow-none"
|
||||
positionerProps={{ anchor: anchorElementRef }}
|
||||
popupProps={{ initialFocus: false, finalFocus: false }}
|
||||
>
|
||||
<FilePickerPanel
|
||||
onSelectNode={(node) => {
|
||||
@@ -93,11 +72,10 @@ const FilePickerBlock = () => {
|
||||
closeMenu()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>,
|
||||
anchorElementRef.current,
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}, [floatingStyles, insertFileReference, isPositioned, options, refs])
|
||||
}, [insertFileReference, options])
|
||||
|
||||
return (
|
||||
<LexicalTypeaheadMenuPlugin
|
||||
|
||||
@@ -77,7 +77,9 @@ describe('FileReferenceBlock', () => {
|
||||
)
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.mouseDown(screen.getByText('contract.pdf'))
|
||||
const target = screen.getByText('contract.pdf')
|
||||
fireEvent.mouseDown(target)
|
||||
fireEvent.click(target)
|
||||
})
|
||||
|
||||
expect(await screen.findByText('workflow.skillEditor.referenceFiles')).toBeInTheDocument()
|
||||
|
||||
@@ -163,7 +163,21 @@ const FileReferenceBlock = ({ nodeKey, resourceId }: FileReferenceBlockProps) =>
|
||||
const fileBlock = (
|
||||
<Popover
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
onOpenChange={(nextOpen, eventDetails) => {
|
||||
if (!nextOpen && eventDetails.reason === 'focus-out')
|
||||
return
|
||||
|
||||
if (
|
||||
!nextOpen
|
||||
&& eventDetails.reason === 'outside-press'
|
||||
&& eventDetails.event.target instanceof Node
|
||||
&& ref.current?.contains(eventDetails.event.target)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
setOpen(nextOpen)
|
||||
}}
|
||||
>
|
||||
<div ref={ref} className="inline-flex">
|
||||
<Tooltip>
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('FileTabItem', () => {
|
||||
|
||||
render(<FileTabItem {...props} />)
|
||||
|
||||
expect(screen.getByText('readme.md')).toHaveClass('italic')
|
||||
expect(screen.getByText('readme.md')).toHaveClass('italic', 'pr-[0.5px]')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ const FileTabItem = ({
|
||||
<span
|
||||
className={cn(
|
||||
'max-w-40 truncate text-[13px] font-normal leading-4',
|
||||
isPreview && 'italic',
|
||||
isPreview && 'pr-[0.5px] italic',
|
||||
isActive
|
||||
? 'text-text-primary'
|
||||
: 'text-text-tertiary',
|
||||
|
||||
@@ -210,7 +210,9 @@ describe('FileTabs', () => {
|
||||
render(<FileTabs />)
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /common\.operation\.close/i }))
|
||||
fireEvent.click(screen.getByRole('button', { name: /workflow\.skillSidebar\.unsavedChanges\.confirmClose/i }))
|
||||
const confirmButton = screen.getByRole('button', { name: /workflow\.skillSidebar\.unsavedChanges\.confirmClose/i })
|
||||
expect(confirmButton.className).toContain('btn-destructive')
|
||||
fireEvent.click(confirmButton)
|
||||
|
||||
expect(mocks.closeTab).toHaveBeenCalledTimes(1)
|
||||
expect(mocks.closeTab).toHaveBeenCalledWith('file-1')
|
||||
|
||||
@@ -134,7 +134,7 @@ const FileTabs = () => {
|
||||
<AlertDialogCancelButton>
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</AlertDialogCancelButton>
|
||||
<AlertDialogConfirmButton destructive={false} onClick={handleConfirmClose}>
|
||||
<AlertDialogConfirmButton onClick={handleConfirmClose}>
|
||||
{t('skillSidebar.unsavedChanges.confirmClose')}
|
||||
</AlertDialogConfirmButton>
|
||||
</AlertDialogActions>
|
||||
|
||||
Reference in New Issue
Block a user