fix(workflow): reset onboarding auto-open flag across flows

This commit is contained in:
lyzno1 2025-10-21 11:19:26 +08:00
parent f02d575379
commit 075173e67d
No known key found for this signature in database
7 changed files with 108 additions and 22 deletions

View File

@ -18,6 +18,7 @@ describe('Workflow Onboarding Integration Logic', () => {
const mockSetShowOnboarding = jest.fn()
const mockSetHasSelectedStartNode = jest.fn()
const mockSetHasShownOnboarding = jest.fn()
const mockSetShouldAutoOpenStartNodeSelector = jest.fn()
beforeEach(() => {
jest.clearAllMocks()
@ -31,6 +32,8 @@ describe('Workflow Onboarding Integration Logic', () => {
hasShownOnboarding: false,
setHasShownOnboarding: mockSetHasShownOnboarding,
notInitialWorkflow: false,
shouldAutoOpenStartNodeSelector: false,
setShouldAutoOpenStartNodeSelector: mockSetShouldAutoOpenStartNodeSelector,
})
})
@ -180,17 +183,17 @@ describe('Workflow Onboarding Integration Logic', () => {
})
})
describe('Auto-expand Logic for Node Handles', () => {
describe('Auto-open Logic for Node Handles', () => {
/**
* Test the auto-expand logic from node-handle.tsx
* This ensures all trigger types auto-expand the block selector
* Test the auto-open logic from node-handle.tsx
* This ensures all trigger types auto-open the block selector when flagged
*/
it('should auto-expand for Start node in new workflow', () => {
const notInitialWorkflow = true
const shouldAutoOpenStartNodeSelector = true
const nodeType = BlockEnum.Start
const isChatMode = false
const shouldAutoExpand = notInitialWorkflow && (
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
@ -201,11 +204,11 @@ describe('Workflow Onboarding Integration Logic', () => {
})
it('should auto-expand for TriggerSchedule in new workflow', () => {
const notInitialWorkflow = true
const shouldAutoOpenStartNodeSelector = true
const nodeType = BlockEnum.TriggerSchedule
const isChatMode = false
const shouldAutoExpand = notInitialWorkflow && (
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
@ -216,11 +219,11 @@ describe('Workflow Onboarding Integration Logic', () => {
})
it('should auto-expand for TriggerWebhook in new workflow', () => {
const notInitialWorkflow = true
const shouldAutoOpenStartNodeSelector = true
const nodeType = BlockEnum.TriggerWebhook
const isChatMode = false
const shouldAutoExpand = notInitialWorkflow && (
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
@ -231,11 +234,11 @@ describe('Workflow Onboarding Integration Logic', () => {
})
it('should auto-expand for TriggerPlugin in new workflow', () => {
const notInitialWorkflow = true
const shouldAutoOpenStartNodeSelector = true
const nodeType = BlockEnum.TriggerPlugin
const isChatMode = false
const shouldAutoExpand = notInitialWorkflow && (
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
@ -246,11 +249,11 @@ describe('Workflow Onboarding Integration Logic', () => {
})
it('should not auto-expand for non-trigger nodes', () => {
const notInitialWorkflow = true
const shouldAutoOpenStartNodeSelector = true
const nodeType = BlockEnum.LLM
const isChatMode = false
const shouldAutoExpand = notInitialWorkflow && (
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
@ -261,11 +264,11 @@ describe('Workflow Onboarding Integration Logic', () => {
})
it('should not auto-expand in chat mode', () => {
const notInitialWorkflow = true
const shouldAutoOpenStartNodeSelector = true
const nodeType = BlockEnum.Start
const isChatMode = true
const shouldAutoExpand = notInitialWorkflow && (
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
@ -276,11 +279,11 @@ describe('Workflow Onboarding Integration Logic', () => {
})
it('should not auto-expand for existing workflows', () => {
const notInitialWorkflow = false
const shouldAutoOpenStartNodeSelector = false
const nodeType = BlockEnum.Start
const isChatMode = false
const shouldAutoExpand = notInitialWorkflow && (
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
@ -289,6 +292,24 @@ describe('Workflow Onboarding Integration Logic', () => {
expect(shouldAutoExpand).toBe(false)
})
it('should reset auto-open flag after triggering once', () => {
let shouldAutoOpenStartNodeSelector = true
const nodeType = BlockEnum.Start
const isChatMode = false
const shouldAutoExpand = shouldAutoOpenStartNodeSelector && (
nodeType === BlockEnum.Start
|| nodeType === BlockEnum.TriggerSchedule
|| nodeType === BlockEnum.TriggerWebhook
|| nodeType === BlockEnum.TriggerPlugin
) && !isChatMode
if (shouldAutoExpand)
shouldAutoOpenStartNodeSelector = false
expect(shouldAutoExpand).toBe(true)
expect(shouldAutoOpenStartNodeSelector).toBe(false)
})
})
describe('Node Creation Without Auto-selection', () => {
@ -450,12 +471,19 @@ describe('Workflow Onboarding Integration Logic', () => {
notInitialWorkflow: false,
setShowOnboarding: mockSetShowOnboarding,
setHasShownOnboarding: mockSetHasShownOnboarding,
hasSelectedStartNode: false,
setHasSelectedStartNode: mockSetHasSelectedStartNode,
shouldAutoOpenStartNodeSelector: false,
setShouldAutoOpenStartNodeSelector: mockSetShouldAutoOpenStartNodeSelector,
getState: () => ({
showOnboarding: false,
hasShownOnboarding: false,
notInitialWorkflow: false,
setShowOnboarding: mockSetShowOnboarding,
setHasShownOnboarding: mockSetHasShownOnboarding,
hasSelectedStartNode: false,
setHasSelectedStartNode: mockSetHasSelectedStartNode,
setShouldAutoOpenStartNodeSelector: mockSetShouldAutoOpenStartNodeSelector,
}),
})
@ -526,12 +554,19 @@ describe('Workflow Onboarding Integration Logic', () => {
notInitialWorkflow: false,
setShowOnboarding: mockSetShowOnboarding,
setHasShownOnboarding: mockSetHasShownOnboarding,
hasSelectedStartNode: false,
setHasSelectedStartNode: mockSetHasSelectedStartNode,
shouldAutoOpenStartNodeSelector: false,
setShouldAutoOpenStartNodeSelector: mockSetShouldAutoOpenStartNodeSelector,
getState: () => ({
showOnboarding: false,
hasShownOnboarding: true,
notInitialWorkflow: false,
setShowOnboarding: mockSetShowOnboarding,
setHasShownOnboarding: mockSetHasShownOnboarding,
hasSelectedStartNode: false,
setHasSelectedStartNode: mockSetHasSelectedStartNode,
setShouldAutoOpenStartNodeSelector: mockSetShouldAutoOpenStartNodeSelector,
}),
})
@ -553,12 +588,19 @@ describe('Workflow Onboarding Integration Logic', () => {
notInitialWorkflow: true, // Initial workflow creation
setShowOnboarding: mockSetShowOnboarding,
setHasShownOnboarding: mockSetHasShownOnboarding,
hasSelectedStartNode: false,
setHasSelectedStartNode: mockSetHasSelectedStartNode,
shouldAutoOpenStartNodeSelector: false,
setShouldAutoOpenStartNodeSelector: mockSetShouldAutoOpenStartNodeSelector,
getState: () => ({
showOnboarding: false,
hasShownOnboarding: false,
notInitialWorkflow: true,
setShowOnboarding: mockSetShowOnboarding,
setHasShownOnboarding: mockSetHasShownOnboarding,
hasSelectedStartNode: false,
setHasSelectedStartNode: mockSetHasSelectedStartNode,
setShouldAutoOpenStartNodeSelector: mockSetShouldAutoOpenStartNodeSelector,
}),
})

View File

@ -60,7 +60,10 @@ export const usePipelineInit = () => {
if (error && error.json && !error.bodyUsed && datasetId) {
error.json().then((err: any) => {
if (err.code === 'draft_workflow_not_exist') {
workflowStore.setState({ notInitialWorkflow: true })
workflowStore.setState({
notInitialWorkflow: true,
shouldAutoOpenStartNodeSelector: true,
})
syncWorkflowDraft({
url: `/rag/pipelines/${datasetId}/workflows/draft`,
params: {

View File

@ -75,6 +75,7 @@ const WorkflowChildren = () => {
const showOnboarding = useStore(s => s.showOnboarding)
const setShowOnboarding = useStore(s => s.setShowOnboarding)
const setHasSelectedStartNode = useStore(s => s.setHasSelectedStartNode)
const setShouldAutoOpenStartNodeSelector = useStore(s => s.setShouldAutoOpenStartNodeSelector)
const reactFlowStore = useStoreApi()
const availableNodesMetaData = useAvailableNodesMetaData()
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
@ -142,6 +143,7 @@ const WorkflowChildren = () => {
setShowOnboarding?.(false)
setHasSelectedStartNode?.(true)
setShouldAutoOpenStartNodeSelector?.(true)
handleSyncWorkflowDraft(true, false, {
onSuccess: () => {

View File

@ -14,6 +14,7 @@ export const useAutoOnboarding = () => {
notInitialWorkflow,
setShowOnboarding,
setHasShownOnboarding,
setShouldAutoOpenStartNodeSelector,
} = workflowStore.getState()
// Skip if already showing onboarding or it's the initial workflow creation
@ -30,13 +31,24 @@ export const useAutoOnboarding = () => {
if (isCompletelyEmpty && !hasShownOnboarding) {
setShowOnboarding?.(true)
setHasShownOnboarding?.(true)
setShouldAutoOpenStartNodeSelector?.(true)
}
}, [store, workflowStore])
const handleOnboardingClose = useCallback(() => {
const { setShowOnboarding, setHasShownOnboarding } = workflowStore.getState()
const {
setShowOnboarding,
setHasShownOnboarding,
setShouldAutoOpenStartNodeSelector,
hasSelectedStartNode,
setHasSelectedStartNode,
} = workflowStore.getState()
setShowOnboarding?.(false)
setHasShownOnboarding?.(true)
if (hasSelectedStartNode)
setHasSelectedStartNode?.(false)
else
setShouldAutoOpenStartNodeSelector?.(false)
}, [workflowStore])
// Check on mount and when nodes change

View File

@ -77,6 +77,7 @@ export const useWorkflowInit = () => {
workflowStore.setState({
notInitialWorkflow: true,
showOnboarding: !isAdvancedChat,
shouldAutoOpenStartNodeSelector: !isAdvancedChat,
hasShownOnboarding: false,
})
const nodesData = isAdvancedChat ? nodesTemplate : []

View File

@ -5,6 +5,8 @@ export type WorkflowSliceShape = {
appName: string
notInitialWorkflow: boolean
setNotInitialWorkflow: (notInitialWorkflow: boolean) => void
shouldAutoOpenStartNodeSelector: boolean
setShouldAutoOpenStartNodeSelector: (shouldAutoOpen: boolean) => void
nodesDefaultConfigs: Record<string, any>
setNodesDefaultConfigs: (nodesDefaultConfigs: Record<string, any>) => void
showOnboarding: boolean
@ -21,6 +23,8 @@ export const createWorkflowSlice: StateCreator<WorkflowSliceShape> = set => ({
appName: '',
notInitialWorkflow: false,
setNotInitialWorkflow: notInitialWorkflow => set(() => ({ notInitialWorkflow })),
shouldAutoOpenStartNodeSelector: false,
setShouldAutoOpenStartNodeSelector: shouldAutoOpenStartNodeSelector => set(() => ({ shouldAutoOpenStartNodeSelector })),
nodesDefaultConfigs: {},
setNodesDefaultConfigs: nodesDefaultConfigs => set(() => ({ nodesDefaultConfigs })),
showOnboarding: false,

View File

@ -25,6 +25,7 @@ import {
} from '../../../hooks'
import {
useStore,
useWorkflowStore,
} from '../../../store'
import cn from '@/utils/classnames'
@ -127,7 +128,10 @@ export const NodeSourceHandle = memo(({
showExceptionStatus,
}: NodeHandleProps) => {
const { t } = useTranslation()
const notInitialWorkflow = useStore(s => s.notInitialWorkflow)
const shouldAutoOpenStartNodeSelector = useStore(s => s.shouldAutoOpenStartNodeSelector)
const setShouldAutoOpenStartNodeSelector = useStore(s => s.setShouldAutoOpenStartNodeSelector)
const setHasSelectedStartNode = useStore(s => s.setHasSelectedStartNode)
const workflowStoreApi = useWorkflowStore()
const [open, setOpen] = useState(false)
const { handleNodeAdd } = useNodesInteractions()
const { getNodesReadOnly } = useNodesReadOnly()
@ -157,9 +161,27 @@ export const NodeSourceHandle = memo(({
}, [handleNodeAdd, id, handleId])
useEffect(() => {
if (notInitialWorkflow && (data.type === BlockEnum.Start || data.type === BlockEnum.TriggerSchedule || data.type === BlockEnum.TriggerWebhook || data.type === BlockEnum.TriggerPlugin) && !isChatMode)
if (!shouldAutoOpenStartNodeSelector)
return
if (isChatMode) {
setShouldAutoOpenStartNodeSelector?.(false)
return
}
if (data.type === BlockEnum.Start || data.type === BlockEnum.TriggerSchedule || data.type === BlockEnum.TriggerWebhook || data.type === BlockEnum.TriggerPlugin) {
setOpen(true)
}, [notInitialWorkflow, data.type, isChatMode])
if (setShouldAutoOpenStartNodeSelector)
setShouldAutoOpenStartNodeSelector(false)
else
workflowStoreApi?.setState?.({ shouldAutoOpenStartNodeSelector: false })
if (setHasSelectedStartNode)
setHasSelectedStartNode(false)
else
workflowStoreApi?.setState?.({ hasSelectedStartNode: false })
}
}, [shouldAutoOpenStartNodeSelector, data.type, isChatMode, setShouldAutoOpenStartNodeSelector, setHasSelectedStartNode, workflowStoreApi])
return (
<Handle