mirror of
https://github.com/langgenius/dify.git
synced 2026-06-16 22:11:09 +08:00
fix(workflow): reset block selector tab on reopen (#37469)
This commit is contained in:
parent
de2ec990d8
commit
7bed801b0d
@ -81,4 +81,22 @@ describe('block-selector hooks', () => {
|
||||
expect(result.current.tabs.some(tab => tab.key === TabsEnum.Snippets)).toBe(false)
|
||||
expect(result.current.activeTab).toBe(TabsEnum.Blocks)
|
||||
})
|
||||
|
||||
it('resets the active tab to the current default tab', () => {
|
||||
const { result } = renderHook(() => useTabs({
|
||||
noStart: false,
|
||||
}))
|
||||
|
||||
act(() => {
|
||||
result.current.setActiveTab(TabsEnum.Start)
|
||||
})
|
||||
|
||||
expect(result.current.activeTab).toBe(TabsEnum.Start)
|
||||
|
||||
act(() => {
|
||||
result.current.resetActiveTab()
|
||||
})
|
||||
|
||||
expect(result.current.activeTab).toBe(TabsEnum.Blocks)
|
||||
})
|
||||
})
|
||||
|
||||
@ -127,6 +127,40 @@ describe('NodeSelector', () => {
|
||||
expect(screen.getByText('End')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('resets to the default tab after closing', async () => {
|
||||
const user = userEvent.setup()
|
||||
|
||||
renderNodeSelector(
|
||||
<NodeSelector
|
||||
onSelect={vi.fn()}
|
||||
blocks={[
|
||||
createBlock(BlockEnum.LLM, 'LLM'),
|
||||
]}
|
||||
availableBlocksTypes={[BlockEnum.LLM, BlockEnum.Start]}
|
||||
showStartTab
|
||||
trigger={open => (
|
||||
<button type="button">
|
||||
{open ? 'selector-open' : 'selector-closed'}
|
||||
</button>
|
||||
)}
|
||||
/>,
|
||||
)
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'selector-closed' }))
|
||||
await user.click(screen.getByText('workflow.tabs.start'))
|
||||
|
||||
expect(screen.getByPlaceholderText('workflow.tabs.searchTrigger')).toBeInTheDocument()
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'selector-open' }))
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByPlaceholderText('workflow.tabs.searchTrigger')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
await user.click(screen.getByRole('button', { name: 'selector-closed' }))
|
||||
|
||||
expect(screen.getByPlaceholderText('workflow.tabs.searchBlock')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not open or emit open changes when disabled', async () => {
|
||||
const user = userEvent.setup()
|
||||
const onOpenChange = vi.fn()
|
||||
|
||||
@ -119,17 +119,21 @@ export const useTabs = ({
|
||||
return fallbackTab
|
||||
}, [defaultActiveTab, noBlocks, noSources, noTools, noSnippets, noStart, tabs, getValidTabKey])
|
||||
const [activeTab, setActiveTab] = useState(initialTab)
|
||||
const resetActiveTab = useCallback(() => {
|
||||
setActiveTab(initialTab)
|
||||
}, [initialTab])
|
||||
|
||||
useEffect(() => {
|
||||
const currentTab = tabs.find(tab => tab.key === activeTab)
|
||||
if (!currentTab || currentTab.disabled)
|
||||
setActiveTab(initialTab)
|
||||
}, [tabs, activeTab, initialTab])
|
||||
resetActiveTab()
|
||||
}, [tabs, activeTab, resetActiveTab])
|
||||
|
||||
return {
|
||||
tabs,
|
||||
activeTab,
|
||||
setActiveTab,
|
||||
resetActiveTab,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -135,6 +135,7 @@ function NodeSelector({
|
||||
const disableSnippetsTab = flowType === FlowType.snippet
|
||||
const {
|
||||
activeTab,
|
||||
resetActiveTab,
|
||||
setActiveTab,
|
||||
tabs,
|
||||
} = useTabs({
|
||||
@ -158,6 +159,7 @@ function NodeSelector({
|
||||
if (!newOpen) {
|
||||
setSearchText('')
|
||||
setSnippetsLoading(false)
|
||||
resetActiveTab()
|
||||
}
|
||||
else if (activeTab === TabsEnum.Snippets) {
|
||||
setSnippetsLoading(true)
|
||||
@ -165,7 +167,7 @@ function NodeSelector({
|
||||
|
||||
if (onOpenChange)
|
||||
onOpenChange(newOpen)
|
||||
}, [activeTab, disabled, onOpenChange])
|
||||
}, [activeTab, disabled, onOpenChange, resetActiveTab])
|
||||
const handleTrigger = useCallback<MouseEventHandler<HTMLElement>>((e) => {
|
||||
e.stopPropagation()
|
||||
}, [])
|
||||
|
||||
@ -3,7 +3,6 @@ import { act, screen, waitFor } from '@testing-library/react'
|
||||
import { FlowType } from '@/types/common'
|
||||
import { createNode } from '../../__tests__/fixtures'
|
||||
import { renderWorkflowFlowComponent } from '../../__tests__/workflow-test-env'
|
||||
import { TabsEnum } from '../../block-selector/types'
|
||||
import { BlockEnum } from '../../types'
|
||||
import AddBlock from '../add-block'
|
||||
|
||||
@ -21,7 +20,7 @@ type BlockSelectorMockProps = {
|
||||
popupClassName: string
|
||||
availableBlocksTypes: BlockEnum[]
|
||||
showStartTab: boolean
|
||||
defaultActiveTab?: TabsEnum
|
||||
defaultActiveTab?: unknown
|
||||
}
|
||||
|
||||
const {
|
||||
@ -129,10 +128,10 @@ describe('AddBlock', () => {
|
||||
disabled: false,
|
||||
availableBlocksTypes: mockAvailableNextBlocks,
|
||||
showStartTab: true,
|
||||
defaultActiveTab: TabsEnum.Start,
|
||||
placement: 'right-start',
|
||||
popupClassName: 'min-w-[256px]!',
|
||||
})
|
||||
expect(latestBlockSelectorProps?.defaultActiveTab).toBeUndefined()
|
||||
expect(latestBlockSelectorProps?.offset).toEqual({
|
||||
mainAxis: 4,
|
||||
crossAxis: -8,
|
||||
|
||||
@ -11,16 +11,13 @@ import {
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
useNodes,
|
||||
useStoreApi,
|
||||
} from 'reactflow'
|
||||
import BlockSelector from '@/app/components/workflow/block-selector'
|
||||
import {
|
||||
BlockEnum,
|
||||
isTriggerNode,
|
||||
} from '@/app/components/workflow/types'
|
||||
import { FlowType } from '@/types/common'
|
||||
import { TabsEnum } from '../block-selector/types'
|
||||
import {
|
||||
useAvailableBlocks,
|
||||
useIsChatMode,
|
||||
@ -55,18 +52,10 @@ const AddBlock = ({
|
||||
const { nodesReadOnly } = useNodesReadOnly()
|
||||
const { handlePaneContextmenuCancel } = usePanelInteractions()
|
||||
const [open, setOpen] = useState(false)
|
||||
const nodes = useNodes()
|
||||
const { availableNextBlocks } = useAvailableBlocks(BlockEnum.Start, false)
|
||||
const { nodesMap: nodesMetaDataMap } = useNodesMetaData()
|
||||
const flowType = useHooksStore(s => s.configsMap?.flowType)
|
||||
const showStartTab = flowType !== FlowType.ragPipeline && !isChatMode
|
||||
const hasEntryNode = nodes.some((node) => {
|
||||
const nodeData = node.data as { type?: BlockEnum }
|
||||
const nodeType = nodeData.type
|
||||
return nodeType === BlockEnum.Start || (nodeType ? isTriggerNode(nodeType) : false)
|
||||
})
|
||||
|
||||
const defaultActiveTab = showStartTab && !hasEntryNode ? TabsEnum.Start : undefined
|
||||
|
||||
const handleOpenChange = useCallback((open: boolean) => {
|
||||
setOpen(open)
|
||||
@ -134,7 +123,6 @@ const AddBlock = ({
|
||||
popupClassName="min-w-[256px]!"
|
||||
availableBlocksTypes={availableNextBlocks}
|
||||
showStartTab={showStartTab}
|
||||
defaultActiveTab={defaultActiveTab}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user