mirror of https://github.com/langgenius/dify.git
feat: allow user close the tab to sync the draft (#30034)
This commit is contained in:
parent
aea3a6f80c
commit
870a6427c9
|
|
@ -224,23 +224,31 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||
return () => {
|
||||
handleSyncWorkflowDraft(true, true)
|
||||
}
|
||||
}, [])
|
||||
}, [handleSyncWorkflowDraft])
|
||||
|
||||
const { handleRefreshWorkflowDraft } = useWorkflowRefreshDraft()
|
||||
const handleSyncWorkflowDraftWhenPageClose = useCallback(() => {
|
||||
if (document.visibilityState === 'hidden')
|
||||
syncWorkflowDraftWhenPageClose()
|
||||
|
||||
else if (document.visibilityState === 'visible')
|
||||
setTimeout(() => handleRefreshWorkflowDraft(), 500)
|
||||
}, [syncWorkflowDraftWhenPageClose, handleRefreshWorkflowDraft])
|
||||
}, [syncWorkflowDraftWhenPageClose, handleRefreshWorkflowDraft, workflowStore])
|
||||
|
||||
// Also add beforeunload handler as additional safety net for tab close
|
||||
const handleBeforeUnload = useCallback(() => {
|
||||
syncWorkflowDraftWhenPageClose()
|
||||
}, [syncWorkflowDraftWhenPageClose])
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('visibilitychange', handleSyncWorkflowDraftWhenPageClose)
|
||||
window.addEventListener('beforeunload', handleBeforeUnload)
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', handleSyncWorkflowDraftWhenPageClose)
|
||||
window.removeEventListener('beforeunload', handleBeforeUnload)
|
||||
}
|
||||
}, [handleSyncWorkflowDraftWhenPageClose])
|
||||
}, [handleSyncWorkflowDraftWhenPageClose, handleBeforeUnload])
|
||||
|
||||
useEventListener('keydown', (e) => {
|
||||
if ((e.key === 'd' || e.key === 'D') && (e.ctrlKey || e.metaKey))
|
||||
|
|
@ -419,7 +427,7 @@ export const Workflow: FC<WorkflowProps> = memo(({
|
|||
onPaneContextMenu={handlePaneContextMenu}
|
||||
onSelectionContextMenu={handleSelectionContextMenu}
|
||||
connectionLineComponent={CustomConnectionLine}
|
||||
// TODO: For LOOP node, how to distinguish between ITERATION and LOOP here? Maybe both are the same?
|
||||
// NOTE: For LOOP node, how to distinguish between ITERATION and LOOP here? Maybe both are the same?
|
||||
connectionLineContainerStyle={{ zIndex: ITERATION_CHILDREN_Z_INDEX }}
|
||||
defaultViewport={viewport}
|
||||
multiSelectionKeyCode={null}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@ import type {
|
|||
} from '@/app/components/workflow/types'
|
||||
import { debounce } from 'lodash-es'
|
||||
|
||||
type DebouncedFunc = {
|
||||
(fn: () => void): void
|
||||
cancel?: () => void
|
||||
flush?: () => void
|
||||
}
|
||||
|
||||
export type WorkflowDraftSliceShape = {
|
||||
backupDraft?: {
|
||||
nodes: Node[]
|
||||
|
|
@ -16,7 +22,7 @@ export type WorkflowDraftSliceShape = {
|
|||
environmentVariables: EnvironmentVariable[]
|
||||
}
|
||||
setBackupDraft: (backupDraft?: WorkflowDraftSliceShape['backupDraft']) => void
|
||||
debouncedSyncWorkflowDraft: (fn: () => void) => void
|
||||
debouncedSyncWorkflowDraft: DebouncedFunc
|
||||
syncWorkflowDraftHash: string
|
||||
setSyncWorkflowDraftHash: (hash: string) => void
|
||||
isSyncingWorkflowDraft: boolean
|
||||
|
|
@ -25,20 +31,31 @@ export type WorkflowDraftSliceShape = {
|
|||
setIsWorkflowDataLoaded: (loaded: boolean) => void
|
||||
nodes: Node[]
|
||||
setNodes: (nodes: Node[]) => void
|
||||
flushPendingSync: () => void
|
||||
}
|
||||
|
||||
export const createWorkflowDraftSlice: StateCreator<WorkflowDraftSliceShape> = set => ({
|
||||
backupDraft: undefined,
|
||||
setBackupDraft: backupDraft => set(() => ({ backupDraft })),
|
||||
debouncedSyncWorkflowDraft: debounce((syncWorkflowDraft) => {
|
||||
export const createWorkflowDraftSlice: StateCreator<WorkflowDraftSliceShape> = (set) => {
|
||||
// Create the debounced function and store it with access to cancel/flush methods
|
||||
const debouncedFn = debounce((syncWorkflowDraft) => {
|
||||
syncWorkflowDraft()
|
||||
}, 5000),
|
||||
syncWorkflowDraftHash: '',
|
||||
setSyncWorkflowDraftHash: syncWorkflowDraftHash => set(() => ({ syncWorkflowDraftHash })),
|
||||
isSyncingWorkflowDraft: false,
|
||||
setIsSyncingWorkflowDraft: isSyncingWorkflowDraft => set(() => ({ isSyncingWorkflowDraft })),
|
||||
isWorkflowDataLoaded: false,
|
||||
setIsWorkflowDataLoaded: loaded => set(() => ({ isWorkflowDataLoaded: loaded })),
|
||||
nodes: [],
|
||||
setNodes: nodes => set(() => ({ nodes })),
|
||||
})
|
||||
}, 5000)
|
||||
|
||||
return {
|
||||
backupDraft: undefined,
|
||||
setBackupDraft: backupDraft => set(() => ({ backupDraft })),
|
||||
debouncedSyncWorkflowDraft: debouncedFn,
|
||||
syncWorkflowDraftHash: '',
|
||||
setSyncWorkflowDraftHash: syncWorkflowDraftHash => set(() => ({ syncWorkflowDraftHash })),
|
||||
isSyncingWorkflowDraft: false,
|
||||
setIsSyncingWorkflowDraft: isSyncingWorkflowDraft => set(() => ({ isSyncingWorkflowDraft })),
|
||||
isWorkflowDataLoaded: false,
|
||||
setIsWorkflowDataLoaded: loaded => set(() => ({ isWorkflowDataLoaded: loaded })),
|
||||
nodes: [],
|
||||
setNodes: nodes => set(() => ({ nodes })),
|
||||
flushPendingSync: () => {
|
||||
// Flush any pending debounced sync operations
|
||||
if (debouncedFn.flush)
|
||||
debouncedFn.flush()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue