mirror of
https://github.com/langgenius/dify.git
synced 2026-03-07 08:35:58 +08:00
fix(workflow): disable view switch during preview run instead of mounted guard
Simpler approach: disable the view picker toggle when preview is running, preventing users from switching views during active runs. This replaces the previous mounted ref guard approach (commitsa0188bd9b5,b7f1eb9b7b,8332f0de2b) which added complexity to handle post-unmount operations. Disabling the toggle is more direct and follows KISS principle. Changes: - Add disabled prop to ViewPicker based on isResponding state - Revert mounted ref guards in use-chat-flow-control.ts - Revert isMountedRef parameter in use-nodes/edges-interactions-without-sync.ts - Revert defensive type check in markdown-utils.ts (no longer needed)
This commit is contained in:
@ -8,7 +8,7 @@ import { ALLOW_UNSAFE_DATA_SCHEME } from '@/config'
|
||||
|
||||
export const preprocessLaTeX = (content: string) => {
|
||||
if (typeof content !== 'string')
|
||||
return ''
|
||||
return content
|
||||
|
||||
const codeBlockRegex = /```[\s\S]*?```/g
|
||||
const codeBlocks = content.match(codeBlockRegex) || []
|
||||
@ -32,9 +32,6 @@ export const preprocessLaTeX = (content: string) => {
|
||||
}
|
||||
|
||||
export const preprocessThinkTag = (content: string) => {
|
||||
if (typeof content !== 'string')
|
||||
return ''
|
||||
|
||||
const thinkOpenTagRegex = /(<think>\s*)+/g
|
||||
const thinkCloseTagRegex = /(\s*<\/think>)+/g
|
||||
return flow([
|
||||
|
||||
@ -23,7 +23,7 @@ import {
|
||||
WorkflowContextProvider,
|
||||
} from '@/app/components/workflow/context'
|
||||
import { HeaderShell } from '@/app/components/workflow/header'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { useStore, useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { useTriggerStatusStore } from '@/app/components/workflow/store/trigger-status'
|
||||
import {
|
||||
SupportUploadFileTypes,
|
||||
@ -63,6 +63,7 @@ const WorkflowViewContent = ({
|
||||
}: WorkflowViewContentProps) => {
|
||||
const features = useFeatures(s => s.features)
|
||||
const isSupportSandbox = !!features.sandbox?.enabled
|
||||
const isResponding = useStore(s => s.isResponding)
|
||||
const [viewType, doSetViewType] = useQueryState(WORKFLOW_VIEW_PARAM_KEY, parseAsViewType)
|
||||
const { syncWorkflowDraftImmediately } = useNodesSyncDraft()
|
||||
const pendingSyncRef = useRef<Promise<void> | null>(null)
|
||||
@ -101,6 +102,7 @@ const WorkflowViewContent = ({
|
||||
<ViewPicker
|
||||
value={viewType}
|
||||
onChange={handleViewTypeChange}
|
||||
disabled={isResponding}
|
||||
/>
|
||||
)
|
||||
const viewPickerDock = (
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
import type { RefObject } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useCallback } from 'react'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
|
||||
export const useEdgesInteractionsWithoutSync = (isMountedRef?: RefObject<boolean>) => {
|
||||
export const useEdgesInteractionsWithoutSync = () => {
|
||||
const store = useStoreApi()
|
||||
|
||||
const handleEdgeCancelRunningStatus = useCallback(() => {
|
||||
if (isMountedRef && isMountedRef.current === false)
|
||||
return
|
||||
|
||||
const {
|
||||
edges,
|
||||
setEdges,
|
||||
@ -23,7 +19,7 @@ export const useEdgesInteractionsWithoutSync = (isMountedRef?: RefObject<boolean
|
||||
})
|
||||
})
|
||||
setEdges(newEdges)
|
||||
}, [store, isMountedRef])
|
||||
}, [store])
|
||||
|
||||
return {
|
||||
handleEdgeCancelRunningStatus,
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
import type { RefObject } from 'react'
|
||||
import { produce } from 'immer'
|
||||
import { useCallback } from 'react'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import { NodeRunningStatus } from '../types'
|
||||
|
||||
export const useNodesInteractionsWithoutSync = (isMountedRef?: RefObject<boolean>) => {
|
||||
export const useNodesInteractionsWithoutSync = () => {
|
||||
const store = useStoreApi()
|
||||
|
||||
const handleNodeCancelRunningStatus = useCallback(() => {
|
||||
if (isMountedRef && isMountedRef.current === false)
|
||||
return
|
||||
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
@ -24,12 +20,9 @@ export const useNodesInteractionsWithoutSync = (isMountedRef?: RefObject<boolean
|
||||
})
|
||||
})
|
||||
setNodes(newNodes)
|
||||
}, [store, isMountedRef])
|
||||
}, [store])
|
||||
|
||||
const handleCancelAllNodeSuccessStatus = useCallback(() => {
|
||||
if (isMountedRef && isMountedRef.current === false)
|
||||
return
|
||||
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
@ -43,12 +36,9 @@ export const useNodesInteractionsWithoutSync = (isMountedRef?: RefObject<boolean
|
||||
})
|
||||
})
|
||||
setNodes(newNodes)
|
||||
}, [store, isMountedRef])
|
||||
}, [store])
|
||||
|
||||
const handleCancelNodeSuccessStatus = useCallback((nodeId: string) => {
|
||||
if (isMountedRef && isMountedRef.current === false)
|
||||
return
|
||||
|
||||
const {
|
||||
getNodes,
|
||||
setNodes,
|
||||
@ -62,7 +52,7 @@ export const useNodesInteractionsWithoutSync = (isMountedRef?: RefObject<boolean
|
||||
}
|
||||
})
|
||||
setNodes(newNodes)
|
||||
}, [store, isMountedRef])
|
||||
}, [store])
|
||||
|
||||
return {
|
||||
handleNodeCancelRunningStatus,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { useCallback } from 'react'
|
||||
import { DEFAULT_ITER_TIMES, DEFAULT_LOOP_TIMES } from '../../../constants'
|
||||
import { useEdgesInteractionsWithoutSync } from '../../../hooks/use-edges-interactions-without-sync'
|
||||
import { useNodesInteractionsWithoutSync } from '../../../hooks/use-nodes-interactions-without-sync'
|
||||
@ -19,17 +19,8 @@ export function useChatFlowControl({
|
||||
const setHasStopResponded = useStore(s => s.setHasStopResponded)
|
||||
const setSuggestedQuestionsAbortController = useStore(s => s.setSuggestedQuestionsAbortController)
|
||||
const invalidateRun = useStore(s => s.invalidateRun)
|
||||
|
||||
const isMountedRef = useRef(true)
|
||||
useEffect(() => {
|
||||
isMountedRef.current = true
|
||||
return () => {
|
||||
isMountedRef.current = false
|
||||
}
|
||||
}, [])
|
||||
|
||||
const { handleNodeCancelRunningStatus } = useNodesInteractionsWithoutSync(isMountedRef)
|
||||
const { handleEdgeCancelRunningStatus } = useEdgesInteractionsWithoutSync(isMountedRef)
|
||||
const { handleNodeCancelRunningStatus } = useNodesInteractionsWithoutSync()
|
||||
const { handleEdgeCancelRunningStatus } = useEdgesInteractionsWithoutSync()
|
||||
|
||||
const { setIterTimes, setLoopTimes } = workflowStore.getState()
|
||||
|
||||
|
||||
@ -12,18 +12,20 @@ type ViewPickerProps = {
|
||||
value: ViewType
|
||||
onChange: (value: ViewType) => void
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const ViewPicker: FC<ViewPickerProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
className,
|
||||
disabled,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const options = useMemo(() => ([
|
||||
{ value: ViewType.graph, text: t('viewPicker.graph', { ns: 'workflow' }) },
|
||||
{ value: ViewType.skill, text: t('viewPicker.skill', { ns: 'workflow' }) },
|
||||
]), [t])
|
||||
{ value: ViewType.graph, text: t('viewPicker.graph', { ns: 'workflow' }), disabled: disabled && value !== ViewType.graph },
|
||||
{ value: ViewType.skill, text: t('viewPicker.skill', { ns: 'workflow' }), disabled: disabled && value !== ViewType.skill },
|
||||
]), [t, disabled, value])
|
||||
|
||||
const handleChange = useCallback((nextValue: string | number | symbol) => {
|
||||
if (nextValue === value)
|
||||
|
||||
Reference in New Issue
Block a user